ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

react中的css

2022-02-10 16:02:42  阅读:182  来源: 互联网

标签:current 样式 react color components styled css


css一直是react的痛点,也是被很多开发者诟病的一个点。

在组件化中选择合适的CSS解决方案应该符合以下条件:

  • 可以编写局部css:css具备自己的具备作用域,不会随意污染其他组件内的原生;
  • 可以编写动态的css:可以获取当前组件的一些状态,根据状态的变化生成不同的css样式;
  • 支持所有的css特性:伪类、动画、媒体查询等;
  • 编写起来简洁方便、最好符合一贯的css风格特点;
  • 等等…

在这一点上,Vue做的要远远好于React:

  • Vue通过在.vue文件中编写

Vue在CSS上虽然不能称之为完美,但是已经足够简洁、自然、方便了,至少统一的样式风格不会出现多个开发人员、多个项目采用不一样的样式风格。

相比而言,React官方并没有给出在React中统一的样式风格。由此,从普通的css,到css modules,再到css in js,有几十种不同的解决方案,上百个不同的库。大家一直在寻找最好的或者说最适合自己的CSS方案,但是到目前为止也没有统一的方案。

在这篇文章中,我会介绍挑选四种解决方案来介绍:

  • 方案一:内联样式的写法;
  • 方案二:普通的css写法;
  • 方案三:css modules;
  • 方案四:css in js(styled-components)

方案一:内联样式的写法

内联样式是官方推荐的一种css样式的写法:

  • style 接受一个采用小驼峰命名属性的 JavaScript 对象,,而不是 CSS 字符串;
  • 并且可以引用state中的状态来设置相关的样式;
export default class App extends PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      titleColor: "red"
    }
  }

  render() {
    return (
      <div>
        <h2 style={{color: this.state.titleColor, fontSize: "20px"}}>我是App标题</h2>
        <p style={{color: "green", textDecoration: "underline"}}>我是一段文字描述</p>
      </div>
    )
  }
}

内联样式的优点:

  • 内联样式, 样式之间不会有冲突
  • 可以动态获取当前state中的状态

内联样式的缺点:

  • 写法上都需要使用驼峰标识
  • 某些样式没有提示
  • 大量的样式, 代码混乱
  • 某些样式无法编写(比如伪类/伪元素)

推荐使用内联样式加css modules的写法

方案二:普通的css写法

普通的css我们通常会编写到一个单独的文件。

App.js中编写React逻辑代码:

import React, { PureComponent } from 'react';

import Home from './Home';

import './App.css';

export default class App extends PureComponent {
  render() {
    return (
      <div className="app">
        <h2 className="title">我是App的标题</h2>
        <p className="desc">我是App中的一段文字描述</p>
        <Home/>
      </div>
    )
  }
}

App.css中编写React样式代码:

.title {
  color: red;
  font-size: 20px;
}

.desc {
  color: green;
  text-decoration: underline;
}

但是普通的css都属于全局的css,样式之间会相互影响,不推荐。

方案三:css modules

css modules并不是React特有的解决方案,而是所有使用了类似于webpack配置的环境下都可以使用的。
使用了webpack的话,打开config目录下的webpack.config.js文件进行配置:
在这里插入图片描述
如果是taro小程序框架,需要进行如下配置:

weapp: {
  module: {
    postcss: {
      // css modules 功能开关与相关配置
      cssModules: {
        enable: true, // 默认为 false,如需使用 css modules 功能,则设为 true
        config: {
          namingPattern: 'module', // 转换模式,取值为 global/module,下文详细说明
          generateScopedName: '[name]__[local]___[hash:base64:5]'
        }
      }
    }
  }
}
}

设置了之后.css/.less/.scss文件都要修改成.module.css/.module.less/.module.scss 等
这种方式会使最终生成的class名称全局唯一:
请添加图片描述

css modules确实解决了局部作用域的问题,但是这种方案也有自己的缺陷:

  • 引用的类名,不能使用连接符(.home-title),在JavaScript中是不识别的;
  • 所有的className都必须使用{style.className} 的形式来编写;
  • 不方便动态来修改某些样式,依然需要使用内联样式的方式;

另外,如果想要修改某个ui组件的全局样式,则需要通过:global()来设置
在全局样式前面可以加上属于哪个类名之下,这样可以提高权重,避免覆盖组件类名的样式:

.map :global(.am-navbar){
    margin-top: -45px;
}

方案四:css in js(styled-components)

实际上,官方文档也有提到过CSS in JS这种方案:

  • “CSS-in-JS” 是指一种模式,其中 CSS 由 JavaScript 生成而不是在外部文件中定义;
  • 注意此功能并不是 React 的一部分,而是由第三方库提供。 React对样式如何定义并没有明确态度;

目前比较流行的CSS-in-JS的库有哪些呢?

  • styled-components
  • emotion
  • glamorous

目前可以说styled-components依然是社区最流行的CSS-in-JS库,所以我们以styled-components的讲解为主;

1.安装

yarn add styled-components

2.标签模版字符串
ES6中增加了模板字符串的语法,这个对于很多人来说都会使用。
但是模板字符串还有另外一种用法:标签模板字符串(Tagged Template Literals)。
来看一个普通的JavaScript的函数:

function foo(...args) {
  console.log(args);
}

foo("Hello World");

正常情况下,我们都是通过 函数名() 方式来进行调用的,其实函数还有另外一种调用方式:

foo`Hello World`; // [["Hello World"]]

如果我们在调用的时候插入其他的变量,那么模版字符串就会被拆分,第一个元素是数组,是被模版字符串拆分的字符串组合;后面的元素是一个个模板字符串传入的内容。

foo`Hello ${name}`; // [["Hello ", ""], "kobe"];

在styled component中,就是通过这种方式来解析模块字符串,最终生成我们想要的样式的。

看一个例子:

import React, { useEffect, useRef } from 'react';
import styled from 'styled-components';

const Wrapper = styled.div`
  .text {
    color: #666;
    border: 1px solid #ccc;
    outline: none;
    &.active {
        color: rgb(47, 13, 238) ;
        border-color: rgb(185, 20, 20);
    }
  }
`;

const Test1 = () => {
  const refInput = useRef();
  const refSubmit = useRef();

  useEffect(() => {

    const { current } = refInput;

    const handleFocus = () => {
      current.classList.add('active');
    }

    const handleBlur = () => {
      current.classList.remove('active');

      current.value !== ''
        ? refSubmit.current.removeAttribute('disabled')
        : refSubmit.current.setAttribute('disabled', true);
    }

    current.addEventListener('focus', handleFocus);
    current.addEventListener('blur', handleBlur);

    return () => {
      current.removeEventListener('focus', handleFocus);
      current.removeEventListener('blur', handleBlur);
    }
  },[]);

  return (
    <Wrapper>
      <p>
        <input
          className='text'
          type="text"
          ref={refInput}
          defaultValue="Focus me"
        />
      </p>
      <p>
        <input
          ref={refSubmit}
          type="submit"
          value="Submit"
        />
      </p>
    </Wrapper>
  );
}

export default Test1;

结果如图:
请添加图片描述
这就是一个简单的input框在focus时改变样式的例子。

3.用法
styled-components支持类似于css预处理器一样的样式嵌套:

  • 支持直接子代选择器或后代选择器,并且直接编写样式;
  • 可以通过&符号获取当前元素;
  • 直接伪类选择器、伪元素等;

(1)props属性

const HomeWrapper = styled.div`
  color: ${props => props.color};
}

//使用
<HomeWrapper color="blue">
</HomeWrapper>

使用props需要通过${}传入一个插值函数,props会作为该函数的参数。这种方式可以有效的解决动态样式的问题
(2)attrs属性
标签属性如input的placeholder,a标签的href等,style-components提供了属性attrs

export const NavSearch = styled.input.attrs({
    placeholder: '搜索',
    type: 'text'
}) `
  width: 160px;
  height: 38px;
  margin-top: 9px;
  padding: 0 40px 0 20px;
  box-sizing: border-box;
  background-color: #eee;
  outline: none;
  border: none;
  border-radius: 19px;
  color: #666;
  &::placeholder {
    color: #999;
  }
  &.focused {
    width: 240px;
  }
`;

attrs里是一个对象,如果需要多个属性,以对象的形式添加即可。

styled-components中还有其他一些用法,如样式继承,主题定制等等,但是我觉得用方案三中的css modules更方便一点。
学习styled-components主要是为了解决两个问题:1.动态样式 2.动态添加动画
动态添加动画这一部分的实践请看下面的博文:
这里主要使用了style-components和react-transition-group两种方案。

标签:current,样式,react,color,components,styled,css
来源: https://blog.csdn.net/LittleMoon_lyy/article/details/122862704

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有