天道酬勤,学无止境

CSS-IN-JS 方案 - Emotion 库

CSS-IN-JS

"CSS in JS" 是一种在 JavaScript 文件中集成 CSS 代码的解决方案。

这种方案旨在解决 CSS 的局限性,例如缺乏动态功能,作用域和可移植性。

为什么会有 CSS-IN-JS

  • 缺乏作用域
  • 缺乏可移植性
  • 缺乏动态功能

其它参考:阮一峰 - CSS in JS 简介

缺乏作用域

以前开发 web 项目都是以**“页面”为单位,为了将关注点分离**,一般都是将 CSS、JS 以文件的方式引入 HTML 文件。

而现在开发 web 项目都是以**“组件”**为单位,所以很多开发者更倾向于将同一个组件的 HTML、CSS、JS 代码都集成在一起。(例如 React 中已经通过 JS 编写 HTML 代码)

这样组件与组件间的 CSS 就不会产生冲突,这使用的是作用域的概念,而 CSS 没有作用域。

CSS-IN-JS 方案就是通过 JavaScript 的作用域模拟 CSS 的作用域。

缺乏可移植性

将 CSS 文件集中在组件中,这样在使用组件的时候,可以避免遗漏引入必要的 CSS 文件。

缺乏动态功能

CSS 无法通过条件判断,决定给元素设置哪些样式。

如果将 CSS 写在 JavaScript 的文件中,就可以用 JS 的动态功能给元素添加样式了。

CSS-IN-JS 方案的优缺点

CSS-IN-JS 方案的优点大于缺点,是值得在 React 项目中大力推广的解决方案。

优点

  1. 让 CSS 代码拥有独立的作用域,阻止 CSS 代码泄露到组件外部,防止样式冲突。
  2. 让组件更具可移植性,实现开箱即用,轻松创建松耦合的应用程序。
  3. 让组件更具可重用性,只需编写一次即可,可以在任何地方运行。不仅可以在同一个应用程序中重用组件,而且可以在使用相同框架构建的其它应用程序中重用组件。
  4. 让样式具有动态功能,可以将复杂的逻辑引用于样式规则,如果要创建需要动态功能的复杂 UI,它是理想的解决方案。

缺点

  1. 为项目增加了额外的复杂性,需要了解学习和应用这种解决方案。
  2. 自动生成的选择器大大降低了代码的可读性。

Emotion

本文 Emotion 版本:11

介绍

Emotion 是使用 JavaScript 编写 CSS 样式的库,是众多实施 CSS-IN-JS 方案库的其中一个。

安装

React 使用 Emotion 需要安装:

npm install @emotion/react

css 属性

Emotion 提供一个 css 属性,任何可以设置 className 的组件或元素都可以使用 css 属性。

传入 css 属性的样式将被评估,并将计算出的类名应用于 className

function App() {
  return (
    <div css={{fontSize: '20px', background: red}}>App work</div>
  )
}

Babel 配置支持 css 属性

现在 css 属性并没有生效,因为 React.createElement (JSX 表达式被转换为 React.createElement 方法的调用)并不知道该如何解析 css 属性。

Emotion 提供了 jsx 方法去编译转换 JSX 表达式。

有两种方式可以告诉 Babel 使用 Emiotion 的 jsx 方法替换 React.createElement 方法编译 JSX 表达式:

  • JSX Pragma
  • Babel Preset(推荐)
InputOutput
Before<img src="avatar.png" />React.createElement('img', { src: 'avatar.png' })
After<img src="avatar.png" />jsx('img', { src: 'avatar.png' })

官方文档 - The css Prop

JSX Pragma

Pragma 用于替换编译 JSX 表达式时使用的函数。

  • 使用 JSX Pragma
  • 引入 jsx 方法
// 此注释告诉 Babel 将 jsx 代码转换为 jsx 函数的调用,而不是 React.createElement
/** @jsx jsx */
import { jsx } from '@emotion/react'

function App() {
  return (
    <div css={{fontSize: '20px', background: 'red'}}>App works</div>
  )
}

export default App

如果使用了 React 17+ 版本,它默认采用了新版自动导入运行时(不需要手动引入 React 模块),则会冲突报错:pragma and pragmaFrag cannot be set when runtime is automatic.

需要指定 Emotion 的自动导入运行时:

/** @jsxImportSource @emotion/react */
function App() {
  return (
    <div css={{fontSize: '20px', background: 'red'}}>App works</div>
  )
}

export default App

不需要再手动导入 jsx 方法。

Babel Preset

#下载 preset
npm install @emotion/babel-preset-css-prop

Babel 配置添加预设:

"presets": [
  "@emotion/babel-preset-css-prop"
]

使用 Babel Preset 配置,也不需要在组件文件引入 jsx 方法:

function App() {
  return (
    <div css={{fontSize: '20px', background: 'red'}}>App works</div>
  )
}

export default App

eject 方式(不推荐)

React 需要使用 eject 暴露全部配置,然后在 package.json 中配置:

"babel": {
  "presets": [
    "react-app",
    "@emotion/babel-preset-css-prop"
  ]
}

customize-cra(推荐)

eject 是不可逆的,推荐使用 customize-crareact-app-rewired 进行自定义配置:

# 安装
npm install customize-cra react-app-rewired

修改 package.json

 /* package.json */

  "scripts": {
-   "start": "react-scripts start",
+   "start": "react-app-rewired start",
-   "build": "react-scripts build",
+   "build": "react-app-rewired build",
-   "test": "react-scripts test",
+   "test": "react-app-rewired test",
    "eject": "react-scripts eject"
}

在根目录创建 config-overrides.js 文件:

/* config-overrides.js */

const { override, addBabelPreset } = require('customize-cra')

module.exports = {
  webpack: override(
    // emotion css props support
    addBabelPreset('@emotion/babel-preset-css-prop')
  )
}

设置类型

css 属性有两种设置类型:

  • 对象字面量:对象或对象数组
  • css 方法的返回值

ES6 标签模板

参考 阮一峰 - 标签模板

模板字符串的标签模板功能:在函数后面跟模板字符串(反引号包裹的字符串)。

这样调用的函数,会将模板字符串处理成数组再传递给函数:

alert`Hello`
// 等同于
alert(['Hello'])

如果模板字符串中嵌入了变量或表达式,就会将字符串拆分,嵌入的内容作为后续的参数传给函数:

const a = 10, b = 20

foo`${a} + ${b} = ${a + b}`
// 等同于
foo(['', ' + ', ' = ', ''], 10, 20, 30)

模拟 Emotion 的 css 方法的模板字符串方式的调用(非常不严谨):

function css(style, ...args) {
  let res = ''
  let i = 0
  while(i < style.length) {
    res += style[i]

    if (i<args.length) {
      res += args[i]
    }
    i++
  }
  console.log(res)
}

const fontSize = 14
const bgColor = 'skyblue'

css`
  color:red;
  font-size: ${fontSize}px;
  background:${bgColor};
`

// 打印结果:
/*
  color:red;
  font-size: 14px;
  background:skyblue;
*/

css 方法

css 方法 和 css 属性是配合使用的。

通过 css 方法,可以把原本写在行内的 CSS 样式拿到外面去写,将返回的值传递给 css 属性。

css 方法有两种调用方式:

  • String Styles:模板字符串调用方式
    • 以字符串形式编写样式
  • Object Styles:普通函数调用方式
    • 使用对象或对象数组方式编写样式

css 方法的返回值是一个对象,包含定义的样式和代表这个样式的类名。

不论使用哪种方式,都要先引入:

import { css } from '@emotion'

String Styles

使用标签模板的方式调用 css 方法,可以在模板字符串中编写 CSS 语法的样式。

使用模板字符串方式,设置的数值类样式,需加上单位:

width: 200 // 不生效
width: 200px 生效

函数方式的对象不需要,单位会自动加上(如果使用的字符串,例如 "2000" 则不会自动附加)。

import { css } from '@emotion/react'

const style = css`
  font-size: 20px;
  background: red;
`

console.log(style)

function App() {
  return (
    <div css={style}>App works</div>
  )
}

export default App

打印结果:

在这里插入图片描述

Object Styles

const style = css({
  fontSize: '20px',
  background: 'red'
})

css 属性优先级

props 对象中的 css 属性优先级高于组件内部的 css 属性。

这样,在调用组件的时候可以覆盖组件的默认样式。

// 下面 `styleA` 计算的 `className` 会覆盖 `styleB` 计算的 `className`
// 尽管 css 属性写在 {...props} 后面
// 最终背景颜色是 pink
import { css } from '@emotion/react'

function Foo(props) {
  const styleB = css({
    background: 'red'
  })
  return <div {...props} css={styleB}>123123123</div>
}

function App() {
  const styleA = css({
    background: 'pink'
  })
  return <Foo css={styleA} />
}

export default App

Styled Components 样式化组件

styled 方法可以创建附加样式的 React 组件,它是 Emotion 提供的为组件或元素添加样式的另一种方式。

安装

styled@emotion/styled 提供

# 安装
npm install @emotion/styled
// 引入
import styled from '@emotion/styled'

创建普通元素的样式化组件

styled 为每个 HTML 元素提供了方法,如果创建 HTML 元素的样式化组件,可以直接调用对应方法:

// 直接调用对应方法
styled.div`
	width: 100px;
`

// 将标签名作为参数传入,调用返回的方法
styled('div')`
	color: #333;
`

使用方式

styled 也有两种使用方式:

  • 模板字符串形式
  • 普通函数调用
import styled from '@emotion/styled'

const Button1 = styled.button`
  color: blue;
`
const Button2 = styled.button({
  color: 'red'
})
const Button3 = styled('button')`
  color: pink;
`
const Button4 = styled('button')({
  color: 'green'
})

function App() {
  return (
    <div>
      <Button1>Button1</Button1>
      <Button2>Button2</Button2>
      <Button3>Button3</Button3>
      <Button4>Button4</Button4>
    </div>
  )
}
export default App

基于 props 设置样式

样式化组件定义样式时,可以通过 props 获取组件接收的属性,根据属性设置样式。

  • 模板字符串中可以在 ${} 中使用一个函数,函数接收一个 props 参数,最终返回一段 css
  • 普通函数调用时,可以传递一个函数,函数接收一个 props 参数,最终返回一个对象或数组对象
import styled from '@emotion/styled'

const Div = styled.div`
  width: 200px;
  background: ${props => props.bgColor || 'skyblue'};
  height: 100px;
`

const Button = styled.button(props => ({
  borderRadius: 10,
  fontSize: props.fontSize || 20
}))

function App() {
  return (
    <div>
      <Div>
        <Button>天蓝色 20px</Button>
      </Div>
      <Div bgColor="pink">
        <Button fontSize={30}>粉色 30px</Button>
      </Div>
    </div>
  )
}
export default App

覆盖默认样式

styled 定义样式时,可以向第二个参数传入一个函数,函数接收 props 返回样式对象,用以覆盖第一个参数设置的默认样式。

import styled from '@emotion/styled'

const Div = styled.div`
  width: 200px;
  background: ${props => props.bgColor || 'skyblue'};
  height: 100px;
`

const Button = styled.button({
  // 默认样式
  borderRadius: 10,
  fontSize: 20
}, props => ({
  // 覆盖的样式
  fontSize: props.fontSize
}))

function App() {
  return (
    <div>
      <Div>
        <Button>天蓝色 20px</Button>
      </Div>
      <Div bgColor="pink">
        <Button fontSize={30}>粉色 30px</Button>
      </Div>
    </div>
  )
}
export default App

上面的 粉色 30px 的 Button 样式最终为:

border-radius: 10px;
font-size: 20px;
font-size: 30px;

为组件添加样式

styled 还可以为 React 组件添加样式,只需要这个组件接收 className

类似传递普通元素的名称,给组件添加样式,只需将接收 className 的组件传递给 styled

import styled from '@emotion/styled'

function Basic({ className }) {
  return <div className={className}>Basic</div>
}

const Fancy = styled(Basic)`
  width: 100px;
  height: 100px;
  background: pink;
`

const Fancy2 = styled(Basic)({
  width: 100,
  height: 100,
  background: 'skyblue'
})

function App() {
  return (
    <div>
      <Fancy />
      <Fancy2 />
    </div>
  )
}
export default App

设置子组件样式

styled 创建的组件,应用在定义样式的模板字符串或样式对象中时,Emotion 会将其解析为对应的 className

样式模板中嵌套的样式 和 样式对象中嵌套的对象,会追加上级样式的类名

import styled from '@emotion/styled'

const Child = styled.span({
  color: 'red'
})

const Parent = styled.div`
  ${Child} {
    color: blue;
  }
`

const Parent2 = styled.div({
  // 使用ES6的表达式方式定义属性名
  [Child]: {
    color: 'green'
  }
})

function App() {
  return (
    <div>
      <Child>红色的字</Child>
      <Parent>
        <Child>蓝色的字</Child>
      </Parent>
      <Parent2>
        <Child>绿色的字</Child>
      </Parent2>
    </div>
  )
}
export default App

CSS 选择器 - &

& 表示组件或元素本身

import styled from '@emotion/styled'

const Div = styled.div`
  width: 200px;
  height: 200px;
  background: skyblue;
  &:hover {
    background: pink;
  }
  & > span {
    color: red;
  }
`

function App() {
  return (
    <div>
      <Div>
        <span>red</span>
      </Div>
    </div>
  )
}
export default App

as 属性

要使用样式化组件的样式,但是想更换渲染的元素,可以使用 as 属性。

import styled from '@emotion/styled'

const Span = styled.span`
  &:hover {
    color: blue;
  }
`

function App() {
  return (
    <div>
      <Span as="a" href="http://xxx.com">a标签</Span>
    </div>
  )
}
export default App

样式组合

css 属性可以接收对象数组。数组中的成员可以是 css 方法创建的样式。

数组后面的样式优先级高于前面的样式。

import { css } from '@emotion/react'

const success = css`
  background: pink;
  color: green;
`

const danger = css`
  font-size: 20px;
  color: red;
`

function App() {
  return (
    <div>
      <button css={[success, danger]}>红色</button>
      <button css={[danger, success]}>绿色</button>
    </div>
  )
}
export default App

定义全局样式

Emotion 提供一个 Global 组件用于定义全局样式。

Global 组件的 styles 属性接收和 css 属性一样的值,它定义的样式会应用到全局。

  • Global 组件不需要包裹任何内容
  • Global 组件设置的样式不会生成 className, 它类似直接在项目中引入样式
import { Global, css } from '@emotion/react'

const styles = css`
  body {
    margin: 0;
    background: skyblue;
  }
  a {
    text-decoration: none;
    color: green;
  }
  .main {
    width: 200px;
    height: 200px;
    background: pink;
  }
`

function App() {
  return (
    <div class="main">
      <Global styles={styles} />
      <a href="http://xxx.com">a标签</a>
    </div>
  )
}
export default App

定义关键帧动画

Emotion 提供 keyframes 方法创建关键帧动画,同样可以使用字符串或对象方式定义。

然后在定义样式的时候使用即可。

import { keyframes, css } from '@emotion/react'

const move = keyframes`
  0% {
    background: skyblue;
    left: 0;
    top: 0;
  }
  100%{
    background: tomato;
    left: 600px;
    top: 300px;
  }
`

const box = css`
  width: 100px;
  height: 100px;
  position: absolute;
  animation: ${move} 2s ease infinite alternate;
`

function App() {
  return (
    <div css={box}>App works</div>
  )
}
export default App

Theming 主题

Emotion 可以将 ThemeProvider 组件放置到视图最外层,通过 theme 属性定义主题样式对象。

这个主题样式对象不是可以直接用的 css 样式,而是用于定义样式的一些key-value

有三种使用方式:

  1. 在样式化组件中通过 props.theme 访问主题对象。
  2. css 属性设置为一个函数时,它接收的参数就是主题对象。
  3. 使用 useTheme 钩子函数获取主题对象。
import styled from '@emotion/styled'
import { useTheme } from '@emotion/react'

const PrimaryDiv = styled.div`
  color: ${props => props.theme.colors.primary}
`

const primaryColor = theme => ({
  color: theme.colors.primary
})

function App() {
  const theme = useTheme()
  return (
    <div>
    <PrimaryDiv>样式化组件</PrimaryDiv>
      <div css={primaryColor}>向css属性传递一个函数</div>
      <div css={{color: theme.colors.primary}}>使用钩子函数</div>
    </div>
  )
}
export default App

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • Emotion CSS-in-JS - 如何基于组件道具添加条件 CSS?(Emotion CSS-in-JS - how to add conditional CSS based on component props?)
    问题 我想要一个带有 Emotion 样式的组件,它采用最终控制样式的道具。 例如,考虑一个GridCol组件,它具有各种改变填充和宽度的道具(宽度可以在不同的视口宽度之间改变)。 我想使用这样的 API: <GridCol gutter size="2> // or alternatively, like this: <GridCol gutter size={{ m: 2, l: 4 }}> 这里发生了三件事: gutter是一个布尔道具,它向列添加一些水平填充 size道具可以是字符串或对象。 如果它是一个字符串,我们只需添加几行 CSS 就可以了,但是,如果它是一个对象,我们需要根据在别处设置的断点对象插入一些媒体查询。 Emotion 的文档不清楚如何处理这种性质的样式,至少我没有见过,所以我希望可以找到一个通用的解决方案。 对于gutter道具,它是微不足道的: const GridCol = props => styled('div')` display: block; box-sizing: border-box; flex: 1 0 0; min-width: 0; padding: ${props.gutter ? `0 10px` : '0'}; ` 对于size道具,它变得更加复杂,我希望生成的 CSS 看起来像这样: const GridCol =
  • Emotion CSS-in-JS - how to add conditional CSS based on component props?
    I'd like to have a component, styled with Emotion, that takes props that ultimately control the styling. For example, consider a GridCol component that has various props that change the padding and width (the width can be changed across different viewport widths). I'd like to use an API like this: <GridCol gutter size="2> // or alternatively, like this: <GridCol gutter size={{ m: 2, l: 4 }}> There are three things happening here: the gutter is a boolean prop that adds some horizontal padding to the column the size prop can be a string or an object. If it is a string, we just add a few lines of
  • 如何在使用 webpack 构建期间将 css-in-js(样式化组件)移动到外部 css 文件 - ReactJS(How to move css-in-js (Styled Components) to an external css files during build using webpack - ReactJS)
    问题 当我构建 react 项目时,我试图找出 CSS 文件所在的位置。 我正在使用 webpack,如果我使用普通的 CSS,我可以为整个项目中使用的所有样式制作一个 CSS 文件。 当我使用样式化组件在 js 中使用 CSS 时,我没有获得外部 CSS 文件。 webpack.config.js var path = require('path'); var hwp = require('html-webpack-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); module.exports = { entry: path.join(__dirname, '/src/index.js'), output: { filename: 'index.js', path: path.join(__dirname, './dist'), publicPath : '/' }, module:{ rules:[{ exclude: /node_modules/, test: /\.js$/, loader: 'babel-loader' }, { test: /\.css$/i, use: [ { loader : MiniCssExtractPlugin.loader, options
  • React 框架原理与实战——04-03-React Hooks、Chakra-UI、组件性能优化、封装组件库
    文章目录 1.Hooks1.1 React Hooks 介绍1.1.1 用来做什么1.1.2 解决什么问题(类组件的不足) 1.2 如何使用1.2.1 useState()1.2.2 useState()1.2.3 useContext()1.2.4 useEffect()1.2.4.1 useEffect 执行机制1.2.4.2 useEffect 使用方法1.2.4.3 useEffect 解决的问题1.2.4.4 只有指定数据发生变化时触发 effect1.2.4.5useEffect 钩子函数结合异步函数 1.2.5 useMemo()1.2.6 memo 方法1.2.7 useCallback()1.2.8 useRef()1.2.8.1 获取DOM元素对象1.2.8.2 保存数据(跨组件周期) 1.3 自定义 Hook (为了在组件之间形成逻辑共享)1.4 React 路由 Hooks1.4.1 react-router-dom 路由提供的钩子函数 1.5 实现原理1.5.1 useState 钩子函数的实现原理1.5.2useEffect 钩子函数的实现原理1.5.3useReducer 钩子函数的实现原理 2.Formik2.1Formik 介绍2.2使用2.2.1 Formik 基本使用2.2.2 表单验证2.2.2.1初始验证方式2.2.2.2表单验2.2.2
  • 最新2021必修 React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目视频教程
    第1章 课程介绍(了解本课程必看) 试看 介绍了整个课程的背景知识、能解决什么问题、学完后你将得到什么 ,以及学习方法与 学习前提。 下载地址:点击下载 共 3 节 (15分钟) 收起列表 1-1 课程导学 (11:06)试看 1-2 学前准备(上) (02:36) 1-3 学前准备(下) (00:44) 第2章 项目起航:项目初始化与配置 本章我们将会⽤Create-React-App初始化项⽬。并配置eslint检验代码质量,prettier检 验代码格式,commitlint检验提交信息,使得⼯程规范化。最后会配置⼀个优秀的后端 Mock⽅案,JSON SERVER 第三、四章使⽤Mock,从第五章开始连接真实服务器。... 共 5 节 (30分钟) 收起列表 2-1 用 Create React App 初始化项目 (07:16) 2-2 配置 eslint、 prettier 和 commitlint 规范工程 (11:46) 2-3 对比常见 Mock 方案 配置 JSON SERVER (10:53) 2-4 【注意了】大家不用再手动引入 React 了 2-5 【扩展学习】Mock 方案对比 第3章 React 与 Hook 应用:实现项目列表 本章专注于React,⾸先我们会使⽤React的基础知识:组件、JSX、列表渲染实现⼯程 列表⻚⾯,让
  • React.js内联样式最佳做法(React.js inline style best practices)
    问题 我知道您可以在React类中指定样式,如下所示: const MyDiv = React.createClass({ render: function() { const style = { color: 'white', fontSize: 200 }; return <div style={style}> Have a good and productive day! </div>; } }); 我是否应该以这种方式进行所有样式设置,并且在CSS文件中完全没有指定任何样式? 还是应该完全避免使用内联样式? 两者兼而有之,似乎很奇怪而且很乱-在调整样式时需要检查两个位置。 回答1 目前还没有很多“最佳实践”。 我们中那些使用内联样式作为React组件的人仍在进行大量试验。 有很多方法大相径庭:React内联风格的lib比较表 全部还是什么都没有? 我们所谓的“样式”实际上包含许多概念: 布局-元素/组件与其他对象的关系的外观外观-元素/组件的特征行为和状态-元素/组件在给定状态下的外观 从状态样式开始 React已经在管理组件的状态,这使得状态和行为样式自然适合与组件逻辑并置。 与其构建要使用条件状态类进行渲染的组件,不如考虑直接添加状态样式: // Typical component with state-classes <li className={classnames
  • vue和react对比小结
    相同点 使用 Virtual DOM提供了响应式 (Reactive) 和组件化 (Composable) 的视图组件。将注意力集中保持在核心库,而将其他功能如路由和全局状态管理交给相关的库。 不同点 运行时性能 在 React 应用中,当某个组件的状态发生变化时,它会以该组件为根,重新渲染整个组件子树。 如要避免不必要的子组件的重渲染,你需要在所有可能的地方使用 PureComponent,或是手动实现 shouldComponentUpdate 方法。同时你可能会需要使用不可变的数据结构来使得你的组件更容易被优化。在 Vue 应用中,组件的依赖是在渲染过程中自动追踪的,所以系统能精确知晓哪个组件确实需要被重渲染。你可以理解为每一个组件都已经自动获得了 shouldComponentUpdate,并且没有上述的子树问题限制。 开发模式 在 React 中,一切都是 JavaScript。不仅仅是 HTML 可以用 JSX 来表达,现在的潮流也越来越多地将 CSS 也纳入到 JavaScript 中来处理。这类方案有其优点,但也存在一些不是每个开发者都能接受的取舍。Vue 的整体思想是拥抱经典的 Web 技术,并在其上进行扩展。我们下面会详细分析一下。 JSX vs Templates 在 React 中,所有的组件的渲染功能都依靠 JSX。JSX 是使用 XML 语法编写
  • CSS-模块化
    前言: “模块化”是指解决一个复杂问题时自顶向下逐层把软件系统划分成若干模块的过程。每个模块完成一个特定的子功能,所有的模块按某种方法组装起来,成为一个整体,完成整个系统所要求的功能。模块具有以下几种基本属性:接口、功能、逻辑、状态,功能、状态与接口反映模块的外部特性,逻辑反映它的内部特性。在软件的体系结构中,模块是可组合、分解和更换的单元。 这里我们对css 的模块化进行介绍: CSS 发展: css发展的几个阶段: 手写源生 CSS使用预处理器 Sass/Less使用后处理器 PostCSS使用 css modules使用 css in js 手写源生 CSS: 行内样式,即直接在 html 中的 style 属性里编写 css 代码。内嵌样式,即在 html 中的 style 标签内编写 class,提供给当前页面使用。导入样式,即在内联样式中 通过 @import 方法,导入其他样式,提供给当前页面使用。外部样式,即使用 html 中的 link 标签,加载样式,提供给当前页面使用。 行内样式的缺点: 样式不能复用。样式权重太高,难以重定义覆盖样式。表现层与结构层没有分离,结构混乱,阅读性差。不能进行缓存,影响加载效率。 导入样式(@import)的缺点: 导入样式,只能放在 style 标签的第一行,放其他行则会无效。@import
  • 如何使React CSS导入组件范围?(How to make React CSS import component-scoped?)
    问题 我有几个具有以下CSS /组件结构的组件 About/style.css .AboutContainer { # Some style } p > code { # Some style } 我将CSS导入组件中,如下所示 About/index.js import './style.css'; export default class About extends Component { render() { # Return some component } } 但是,CSS导入在<header>部分中,并保持全局范围。 我期望CSS是: 组件范围内的方式,即样式仅应用于仅在此组件内呈现的内容。 如果卸载该组件,该组件的样式将消失。 但是,从浏览器进行检查时,样式在<header>部分中指定,并应用于所有组件 <header> // Stuff <style type="text/css">style for component About</style> <style type="text/css">style for component B</style> <style type="text/css">style for component C</style> // Stuff </header> 如何导入CSS进行组件作用域? 似乎我不正确地理解React
  • 从未失约|2017年11月期技术雷达正式发布!
    技术雷达是由 ThoughtWorks 技术战略委员会(TAB)经由多番正式讨论给出的最新技术趋势报告,它以独特的雷达形式对各类最新技术的成熟度进行评估并给出建议,为从程序员到CTO的利益相关者提供参考。技术雷达的内容来自于 ThoughtWorks 的观察、对话以及在应对最令客户棘手的业务挑战时所沉淀下的一线经验,其中既包含现有技术,也包含新兴技术。技术雷达报告使用可视化的方式将技术趋势分为四组,分别涵盖技术、平台、工具和语言与框架,每个领域又进一步细分为暂缓、评估、试验或采用。本期四大主题崛起的中国开源软件市场星星之火,已成燎原之势!在态度和政策发生转变之后,包括阿里巴巴和百度在内的众多大型中国企业正在积极发布开源框架、工具和平台。中国软件生态正伴随着经济扩张而加速成长。从这个巨大而繁荣的软件市场向 GitHub 等开源网站发布的开源项目的数量必将持续增多,质量也将持续提高。中国企业为何热衷于将他们的众多资产开源出来?与硅谷等其他活跃的软件市场一样,各个企业对开发人员的争夺十分激烈。紧紧提升薪酬水平是不够的,让聪明的开发者一起在最前沿的开源软件上共事才能够持续激励他们,这是一个放之四海而皆准的通则。我们预期主要的开源创意会继续保持 README 文件中先有中文版后有英文版的趋势。容器编排首选KubernetesKubernetes
  • 如何将背景 JS 动画集成到我的 React 应用程序中?(How do I integrate a background JS animation into my react app?)
    问题 我正在尝试将萤火虫动画添加到 react 中的组件中(我尝试使用的代码在这里 https://codepen.io/celli/pen/xZgpvN)。 如果我有一个简单的 HTML / CSS / Javascript 设置,我会知道该怎么做,但我对如何在 React 上下文和单个组件范围内集成此动画感到困惑。 我把下面的代码放在哪里? 如何在组件中引用它? var total=40, container=document.getElementById('container'), w=window.innerWidth, h=window.innerHeight, Tweens=[], SPs=1; for (var i=total;i--;){ var Div=document.createElement('div'); TweenLite.set(Div,{attr:{class:'dot'},x:R(w),y:R(h),opacity:0}); container.appendChild(Div); Anim(Div); Tweens.push(Div); }; function Anim(elm){ elm.Tween=TweenLite.to(elm,R(20)+10,{bezier:{values:[{x:R(w),y:R(h)},{x:R(w),y:R(h)}
  • 您如何在ReactJS上悬停? -在快速悬停过程中未注册onMouseLeave(How do you Hover in ReactJS? - onMouseLeave not registered during fast hover over)
    问题 进行内联样式化时,如何在ReactJS中实现悬停事件或活动事件? 我发现onMouseEnter,onMouseLeave方法是有问题的,因此希望有另一种方法可以做到。 具体来说,如果您将鼠标悬停在组件上非常快,则仅会注册onMouseEnter事件。 onMouseLeave从不触发,因此无法更新状态...使该组件看起来好像仍在悬停。 如果您尝试模仿“:active” css伪类,我也会注意到同样的事情。 如果单击得非常快,则只会注册onMouseDown事件。 onMouseUp事件将被忽略...使组件保持活动状态。 这是显示问题的JSFiddle:https://jsfiddle.net/y9swecyu/5/ 有问题的JSFiddle视频:https://vid.me/ZJEO 编码: var Hover = React.createClass({ getInitialState: function() { return { hover: false }; }, onMouseEnterHandler: function() { this.setState({ hover: true }); console.log('enter'); }, onMouseLeaveHandler: function() { this.setState({ hover: false }
  • 如何在 v2 中减小 React Select 的大小(How to reduce the size of React Select in v2)
    问题 新的 v2 react-select 控件很棒,但默认情况下太大了。 是否有(最好)简单的方法可以将高度降低到与标准选择控件相同(使用 Bootstrap v3)? 回答1 反应-选择V2使用情感CSS-在-JS所以在选择组件和子组件控件样式的新方法是通过传递一个样式对象的styles道具。 您还可以使用外部样式表将 className 设置为样式。 更多/更好的信息在这里 CSS-in-JS 方式 const customControlStyles = base => ({ height: 50, }); <Select ... styles={{control: customControlStyles}} ... /> CSS方式 <Select ... className="myClassName" ... /> .myClassName__control { height: 50px; } 回答2 尝试为 maxMenuHeight 道具传递一个值: <Select maxMenuHeight={190} /> 查看文档 回答3 即使您有溢出(从多个选定的值溢出到下一行),设置height属性看起来也会保留该高度,因此您最终会得到落在框外的值。
  • 人脸、情感和语音识别(Human face, emotion and voice recognition)
    问题 我正在C#寻找一种好的面部、情感和语音识别方法。 对于人脸识别,我很早就使用 Emgu CV,它不准确,并且在低光照条件下性能非常低。 我还需要找到用户的情绪。 不管是悲伤还是快乐都是这样。 但我发现 Emgu CV 并不容易。 同样对于语音识别,我还找不到任何解决方案,我找到了语音识别,但这不是我需要的。 我不想使用任何在线 API。 任何人都可以向我推荐用于实现面部、情感和语音识别的任何 SDK 或算法吗? 回答1 人脸识别 在这里你可以细化一个介绍性的 pdf,特别是查看参考资料以获取更多详细信息。 在这里,您可以找到一个很好的教程和演示程序,其中包含免费源代码,用于从网络摄像头(也在 OpenCV 中)实时执行人脸检测和人脸识别。 特征脸和人脸识别主页。 您可以下载CSU人脸识别评估系统5.1版。 一些关于人脸检测的文章。 来自代码项目:实时多人脸检测和识别 - 具有皮肤和运动分析的人脸检测 C++ 库 - C# 中的人脸检测 - 使用 OpenCV 的人脸和眼睛检测。 语音识别 只需看看 System.Speech.Recognition Namespace(看看这个和这个答案)。 回答2 看来你需要Kinect。 http://www.microsoft.com/en-us/kinectforwindows/develop/ 回答3 我知道这个问题很老
  • Reacr -- Chakra-UI
    Chakra-UI 介绍 Chakra UI 是一个简单的, 模块化的易于理解的 UI 组件库. 提供了丰富的构建 React 应用所需的UI组件.文档: https://next.chakra-ui.com/docs/getting-startedChakra UI 内置 Emotion,是 CSS-IN-JS 解决方案的集大成者基于 Styled-Systems https://styled-system.com/支持开箱即用的主题功能默认支持白天和黑夜两种模式拥有大量功能丰富且非常有用的组件使响应式设计变得轻而易举文档清晰而全面. 查找API更加容易适用于构建用于展示的给用户的界面框架正在变得越来越完善 Chakra-UI 快速开始 下载 chakra-ui npm install @chakra-ui/core@1.0.0-next.2 克隆默认主题 Chakra-UI 提供的组件是建立在主题基础之上的, 只有先引入了主题组件才能够使用其他组件npm install @chakra-ui/theme 引入主题 引入 CSS 重置组件 import { ChakraProvider, CSSReset } from "@chakra-ui/core"; import theme from '@chakra-ui/theme'; <ChakraProvider theme=
  • 我们可以用 ES6 模板替换现有的 JS 模板解决方案吗?(Can we get away with replacing existing JS templating solutions with ES6 templates?)
    问题 ES6 的一个非常吸引人的特性是它内置的模板字符串。 此时,由于跨浏览器兼容性必须转译为 ES5,我很好奇转译的 ES6 模板与现有解决方案(例如 Mustache、Handlebars、Jade 等)之间的性能差异。显然,如果您需要来自模板语言,ES6 模板可能无法满足您的所有需求,但是如果您正在执行基本模板,那么说 ES6 模板字符串可以取代您当前的模板引擎是否公平? 回答1 ES6 中的模板字符串与 JavaScript 中实现的各种模板引擎并不真正相关。 大多数模板引擎(Underscore、Lodash、Mustache、Handlebars、Jade 等)都有特殊的语法和特殊的形式。 有些可能使您能够定义块,为各种事物使用特殊标记,或者为逻辑/循环结构提供独特的标签。 ES6 模板字符串为您提供 JavaScript 的全部功能,而无需您学习专门/自以为是的模板引擎。 // underscore var compiled = _.template("hello: <%= name %>"); compiled({name: 'moe'}); // => "hello: moe" // ES6 Template String let name = 'moe'; `hello: ${name}`; // => "hello: moe" 注意到下划线模板中丑陋的<%=
  • 《HelloGitHub》第 40 期
    《HelloGitHub》第 40 期兴趣是最好的老师,HelloGitHub 就是帮你找到兴趣!简介分享 GitHub 上有趣、入门级的开源项目。这是一个面向编程新手、热爱编程、对开源社区感兴趣 人群的月刊,月刊的内容包括:各种编程语言的项目、让生活变得更美好的工具、书籍、学习笔记、教程等,这些开源项目大多都是非常容易上手,而且非常 Cool。主要是希望大家能动手用起来,加入到开源社区中。会编程的可以贡献代码不会编程的可以反馈使用这些工具中的 Bug帮着宣传你觉得优秀的项目Star 项目⭐️在浏览、参与这些项目的过程中,你将学习到更多编程知识、提高编程技巧、找到编程的乐趣。???? 最后 HelloGitHub 这个项目就诞生了 ????以下为本期内容|每个月 28 号发布最新一期|点击查看往期内容C 项目1、SuperWeChatPC:这是一个超级微信电脑客户端。没错,是超级!因为它不仅是一个微信电脑客户端,还支持以下功能:无限多开消息防撤销语音消息备份等等项目里还有相关技术内幕的文章链接,快前去学习吧2、TDengine:一个专门针对物联网等行业以及应用监控进行设计优化的大数据平台。它的数据库插入、查询操作比其它的数据库快了 10 倍!消耗的成本也非常低,和其他典型的此类解决方案相比。TDengine 只需要不到 1/5 的计算资源,它还提供了 Java、C/C++
  • How do you add !important to a CSS-in-JS (JSS) class property?
    I am trying to use some CSS-in-JS classes from this answer with a material UI component in my React project. I need to override the CSS coming from Bootstrap so I want to use the !important modifier, I've only used this in .css files before and I'm unsure how to do it in CSS-in-JS. My styles object to be passed into the Material-UI withStyles function looks like the following, how do I add !important to the fontSize attribute? I've tried 30 !important and a few other things but nothing seems to work. Thanks const styles = { labelRoot: { fontSize: 30 } }
  • 将样式加载器与 webpack 一起使用时出现“未定义窗口”错误('window is not defined' error when using style-loader with webpack)
    问题 构建服务器端 React 应用程序,在使用 Webpack 时,我遇到了 Style-Loader 问题。 我正在使用版本“^0.23.1”,并且在运行脚本来捆绑和构建时,Style-Loader 存在问题。 问题是window is not defined webpack:///./node_modules/style-loader/lib/addStyles.js?:23 return window && document && document.all && !window.atob; 有没有人遇到过这个问题? 在查看堆栈和样式加载器的 Github 问题后,我没有找到任何解决方案。 这是我的 webpack 文件: const path = require('path'); const webpack = require('webpack'); module.exports = { // webpack to use node target: 'node', entry: './src/index.js', output: { filename: 'client-build.js', path: path.resolve(__dirname, 'build/public'), publicPath: '/build/public' }, module: { rules
  • 如何设置带有图像的单选按钮的样式-笑的笑脸代表好,悲伤的笑脸代表坏?(How do I style radio buttons with images - laughing smiley for good, sad smiley for bad?)
    问题 我想创建一个HTML表单供用户反馈。 如果总体反馈良好,则用户应单击笑脸,如果总体反馈较差,则用户应选择悲伤的笑脸。 我认为应该使用单选按钮,而不是单选按钮来使用笑脸。 也许我错了... 你知道我怎么能做到吗? 谢谢! 回答1 让我们保持简单吧。 首先,使用纯HTML + CSS: <div id="emotion"> <input type="radio" name="emotion" id="sad" /> <label for="sad"><img src="sad_image.png" alt="I'm sad" /></label> <input type="radio" name="emotion" id="happy" /> <label for="happy"><img src="happy_image.png" alt="I'm happy" /></label> </div> 如果没有JavaScript,这会很好地降低性能。 使用id并for属性标签和单选按钮连接起来,从而选择图像时,对应的单选按钮将被填充。 这很重要,因为我们需要使用JavaScript隐藏实际的单选按钮。 现在,了解jQuery的优点。 首先,创建我们需要的CSS: .input_hidden { position: absolute; left: -9999px; }