We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
这部分主要参照 hax 的 关于前端开发中“模块”和“组件”概念的思考 一文。 在 React 开发中,webpack 是模块加载和打包的利器,基于 webpack 的工作流已经非常完善 。Webpack 使用 JS Module Loader 来加载其他 JS 模块,CSS 依赖以及图片等其他资源。但是,这里只是指明了组件中相关的 CSS 依赖,并没有解决组件化与 CSS 样式全局有效的冲突。
以前在组件化的讨论中,@fouber 和 @xufei 不止一次的说,Web 组件化的价值在于分治而不在于复用。我认为这个需要对组件做更细致的区分才能做出论断。对于基础组件,在于复用;对于业务组件,在于分治。由于基础组件复用性更强,我们可能需要更细致的去设计和实现。常见的 React 基础组件库有:material-ui, ant-design, react-toolbox。从实现来看,最大的区别就是如何组织组件的 CSS,以实现组件 CSS 局域化:
CSS in JS 通过 DOM 的 style 属性来实现 CSS 在组件上的挂载,并且保证了组件的封装性和隔离性。不过,这尼玛是内联样式,不是花了很长时间才把着玩意干掉的吗?这样做是不是违背了结构与样式分离的最佳实践(实际上,JSX 好像也违背了结构与行为的分离)?
Web 发展初期,为什么我们没有分离结构,样式和行为?为什么当时想不到耦合的问题?因为初期 web 页面是局限于很简单的结构,你甚至可以理解为一个页面就是一个组件。由于结构简单,样式和行为基本很容易控制,分离结构,样式和行为显得没有必要,因为实际运行的页面是结构,样式和行为的叠加。
随着 web 页面结构开始变得庞大,样式变得酷炫,交互变得复杂,我们发现内联样式和行为使得代码的可维护性变得很差,于是我们通过『选择器』来进行解耦,样式和行为都通过选择器来和结构挂钩。
Web 发展到现在,早已不局限于简单的 web 页面。Web 应用正大行其道,各种 MV* 框架应接不暇, JS 模块化和 web 组件化早已不是新鲜事。Web 应用一般都是一个 SPA,SPA 的一个典型特征就是部分加载,组件化也就显得很自然。组件蕴含着封装和自治:JS 的模块化已经非常成熟,CSS 并没有类似的模块化机制,我们需要 CSS 模块化或者局域化。实际上我们将解耦的目标从结构、样式和行为(通过选择器)转变为组件间(通过组件属性 props)。组件化开发下,由于层层组合嵌套,单个组件内部实现就会比较简单,组件内聚合反而更好。这样就不难理解 React 在 HTML 中直接绑定事件处理器了,甚至提出了 CSS in JS。
Css-modules 是通过工程化的方法自动生成唯一的 className,以实现 CSS 局域化的初衷,但是这样实现的侵入性太大,而且会造成 class dirty,而且自动生成的 className 与 HTML class 语义相违背。
类似方案如:ant-design 是手动给组件内所有的 className 加一个唯一的组件前缀来实现局域化。
CSS in JS 的主要缺点有:内联样式不支持一些伪类/伪元素/media query 等;内联样式书写起来比较困难。
Css-modules 和给组件内部 className 添加前缀主要的缺点在于:class dirty;不能保证 CSS 绝对局域化。
理想的方案是:使用 style 元素的 scoped 属性(很遗憾,目前只是 LS 阶段)。我们可以使用预处理器(sass/postcss)来实现一些模块化抽象(函数,mixin 等),使用 scoped style 来实现 CSS 局域化(可以利用 webpack 将依赖的的 CSS 插入到组件的根节点,并添加 scoped 属性,比如叫 scoped-style-loader)。
考虑到兼容未来的 scoped style,现阶段,我们可以这样组织组件 CSS:
组件的根节点使用 custom tag(唯一标识组件),内部样式使用标签结构选择器来定制(不使用 className),外面包一层根节点 tag(用来保证 CSS 局域化)。
这样看起来和 ant-design 的做法类似,但是我们『使用 custom tag 而不是 className 来唯一标识组件』,并添加了『内部样式使用标签结构选择器』这一限制:
实验可参考:https://github.com/ustccjw/tech-blog
The text was updated successfully, but these errors were encountered:
Web 组件化的价值在于分治而不在于复用。我认为这个需要对组件做更细致的区分才能做出论断。对于基础组件,在于复用;对于业务组件,在于分治。由于基础组件复用性更强,我们可能需要更细致的去设计和实现。
很赞同这种想法,我理解的楼主说的基础组件是只常见的UI组件(比如modal, panel等)。但是除了UI组件 & 业务组件还有一类组件如:操作cookie, promise, ajax等组件要怎么处理呢?
Css-modules 是通过工程化的方法自动生成唯一的 className,以实现 CSS 局域化的初衷,但是这样实现的侵入性太大,而且会造成 class dirty,而且自动生成的 className 与 HTML class 语义相违背
其实可以在css-loader上传参数避免这种问题。如:css-loader?modules&importLoaders=1&localIdentName=[name]_[local]_[hash:base64:5]。但可能这种做法没有考虑到标准的兼容。
css-loader?modules&importLoaders=1&localIdentName=[name]_[local]_[hash:base64:5]
Sorry, something went wrong.
@rockcoder23 我是觉得组件的规模尽可能小,基于结构就可以控制样式。
在实践中,我发现这样做的好处是让你能够自觉地拆分组件,而且生成的 DOM 结构更加语义化。
之前也曾对该方面进行过探索,试图总结一套完美的组件化方案。
@ustccjw 文章写的非常赞,总结的非常到位!
CSS in JS 方式有一点我感觉比较麻烦的就是,没法用 autoprefixer 类似的插件,兼容性处理较弱,这点是硬伤。
剩下的局部化方案就是 css-module 了,但在编码过程中不难发现,此种方式下的复用不是很方便,所以最终采用了折衷的办法,具体可参考 style 模块化思考。简单的说:需要复用的样式直接 import,而组件或页面级别的样式则通过 css-module 构建。
目前方案存在的问题:1)所有的样式都会打包到 css 文件中,与按需加载的理念相悖,antd 提供的 babel-plugin-import 能从某种层面上解决组件层次的样式冗余问题,但对整个项目工程而言仅供参考。 2)外部想覆盖局部样式时的方式比较hack,舒适度不够。
No branches or pull requests
React 组件中如何组织 CSS
组件和模块
这部分主要参照 hax 的 关于前端开发中“模块”和“组件”概念的思考 一文。
在 React 开发中,webpack 是模块加载和打包的利器,基于 webpack 的工作流已经非常完善 。Webpack 使用 JS Module Loader 来加载其他 JS 模块,CSS 依赖以及图片等其他资源。但是,这里只是指明了组件中相关的 CSS 依赖,并没有解决组件化与 CSS 样式全局有效的冲突。
基础组件和业务组件
以前在组件化的讨论中,@fouber 和 @xufei 不止一次的说,Web 组件化的价值在于分治而不在于复用。我认为这个需要对组件做更细致的区分才能做出论断。对于基础组件,在于复用;对于业务组件,在于分治。由于基础组件复用性更强,我们可能需要更细致的去设计和实现。常见的 React 基础组件库有:material-ui, ant-design, react-toolbox。从实现来看,最大的区别就是如何组织组件的 CSS,以实现组件 CSS 局域化:
CSS in JS
CSS in JS 通过 DOM 的 style 属性来实现 CSS 在组件上的挂载,并且保证了组件的封装性和隔离性。不过,这尼玛是内联样式,不是花了很长时间才把着玩意干掉的吗?这样做是不是违背了结构与样式分离的最佳实践(实际上,JSX 好像也违背了结构与行为的分离)?
Web 发展初期,为什么我们没有分离结构,样式和行为?为什么当时想不到耦合的问题?因为初期 web 页面是局限于很简单的结构,你甚至可以理解为一个页面就是一个组件。由于结构简单,样式和行为基本很容易控制,分离结构,样式和行为显得没有必要,因为实际运行的页面是结构,样式和行为的叠加。
随着 web 页面结构开始变得庞大,样式变得酷炫,交互变得复杂,我们发现内联样式和行为使得代码的可维护性变得很差,于是我们通过『选择器』来进行解耦,样式和行为都通过选择器来和结构挂钩。
Web 发展到现在,早已不局限于简单的 web 页面。Web 应用正大行其道,各种 MV* 框架应接不暇, JS 模块化和 web 组件化早已不是新鲜事。Web 应用一般都是一个 SPA,SPA 的一个典型特征就是部分加载,组件化也就显得很自然。组件蕴含着封装和自治:JS 的模块化已经非常成熟,CSS 并没有类似的模块化机制,我们需要 CSS 模块化或者局域化。实际上我们将解耦的目标从结构、样式和行为(通过选择器)转变为组件间(通过组件属性 props)。组件化开发下,由于层层组合嵌套,单个组件内部实现就会比较简单,组件内聚合反而更好。这样就不难理解 React 在 HTML 中直接绑定事件处理器了,甚至提出了 CSS in JS。
CSS Modules
Css-modules 是通过工程化的方法自动生成唯一的 className,以实现 CSS 局域化的初衷,但是这样实现的侵入性太大,而且会造成 class dirty,而且自动生成的 className 与 HTML class 语义相违背。
类似方案如:ant-design 是手动给组件内所有的 className 加一个唯一的组件前缀来实现局域化。
理想的方案
CSS in JS 的主要缺点有:内联样式不支持一些伪类/伪元素/media query 等;内联样式书写起来比较困难。
Css-modules 和给组件内部 className 添加前缀主要的缺点在于:class dirty;不能保证 CSS 绝对局域化。
理想的方案是:使用 style 元素的 scoped 属性(很遗憾,目前只是 LS 阶段)。我们可以使用预处理器(sass/postcss)来实现一些模块化抽象(函数,mixin 等),使用 scoped style 来实现 CSS 局域化(可以利用 webpack 将依赖的的 CSS 插入到组件的根节点,并添加 scoped 属性,比如叫 scoped-style-loader)。
考虑到兼容未来的 scoped style,现阶段,我们可以这样组织组件 CSS:
组件的根节点使用 custom tag(唯一标识组件),内部样式使用标签结构选择器来定制(不使用 className),外面包一层根节点 tag(用来保证 CSS 局域化)。
这样看起来和 ant-design 的做法类似,但是我们『使用 custom tag 而不是 className 来唯一标识组件』,并添加了『内部样式使用标签结构选择器』这一限制:
实验可参考:https://github.com/ustccjw/tech-blog
The text was updated successfully, but these errors were encountered: