Table of Contents
网址: https://styled-components.com/
概述: 一个 css-in-js 思想下的, 方便写css的库。
为什么使用它? 在使用create-react-app
创建的项目中, 如果在一个地方以import xxx.css
的形式导入某个样式文件, 这个样式文件会被所有的组件共享, 需要注意不同的样式文件中不要起相同的类名. 要想每个组件使用不同的样式文件, 我们可以借助于styled-components
. 此外,我们可以利用js的语法,来增强css,而不是像 sass,less 等通过预处理器来增强css。
原理: styled-components generates an actual stylesheet with classes, and attaches those classes to the DOM nodes of styled components via the className prop.
styled-components
依赖. const Thing = styled.div`color: blue`;
const Thing = styled.div`color: ${props.color}`;
const Thing = styled.div({color: blue}); // 样式对象
const Thing = styled.div(props => {color: props.color}); // 函数, 返回样式对象
const Div = styled.div`color:blue`;
const Div2 = styled(Div);
as
const Div = styled.div`color:blue`;
const link = <Div as="a" href="/">a link</Div>
styled
方法适用于所有的自定义的或者任何第三方组件, 只要他们将传入的 className
这一 prop 给到 DOM 元素上.
const Div = ({ className, children }) => (<div className={className}>{children}</div>);
const StyledDiv = styled(Div)`color: palevioletred; font-weight: bold;`;
&
来引用这一类型. 普通css的作用域是全局的, 但这里的作用域仅限于样式组件内, 默认是只作用于该组件的后代.&&
可以被用于提升组件的规则的 specificity.css
helper function#: 之前说的定义的样式都是绑定到某个HTML元素或是组件上的, 有时候只是想定义与元素无关的可以复用的css样式, 可以借助 css
. props 会从父组件自动传递给 complexMixin. 不使用css
这一 helper function的话,complexMixin会得到 "color: props => (props.whiteColor ? 'white' : 'black')"
这一字符串结果。这是因为 template literals 中,会将表达式直接转成字符串,所以我们不可以在template literal 中使用函数。
const complexMixin = css`color: ${props => props.color}`
const StyledComp = styled.div`${props => props.complex ? complexMixin: "color: blue"}`
.attrs
构造器. 它使得你可以为一个组件附加额外的 props. 当多个样式组件嵌套或继承时子组件可以覆盖父组件的 .attrs
里重复的 props.
const TextInput = styled.div.attrs(props => {type: "text", .color: props.color || "red"})`color: ${props.color}`
keyframes
这一helper function来定义keyframe.keyframes
和 createGlobalStyle
. const userInput = '/api/withdraw-funds'
const ArbitraryComponent = styled.div`
background: url(${userInput});
/* More styles here... */
`
className
添加到节点上. 如果你要添加样式的目标组件已经有一个全局 class 的话, 需要注意一下结合的方式. 如果多个 class 里重复设置了同优先级的某个属性, 会采用最后一个 class 的设置.
class MyComponent extends React.Component {
render() {
// Attach the passed-in className to the DOM node
return <div className={`some-global-class ${this.props.className}`} />
}
}
const link = styled.a``
const Icon = styled.svg`
${Link}:hover & {
fill: blue
}
`
const Component = () => (<Icon><Link href="#"/><Icon>)
// 普通通过 template literal 创建
const Div = styled.div`background: ${props.background}`
// 继承
const Div1 = styled(Div)``
// additional props
const Div2 = styled.div.attr(props => ({
background: 'red'
}))`background: ${props.background}`
/* 不使用 template literals, 直接利用对象创建 */
// Style Objects - static
const Div3 = styled.div({
background: 'red',
});
// Style Objects - based on props
const Div4 = styled.div(props => ({
background: props.background
}));
网址: https://meyerweb.com/eric/tools/css/reset/
概述: 就是一个普通css文件, 定义了一些基本样式.
styled-components
的 createGlobalStyle
设置为全局样式网址: https://www.iconfont.cn/
概述: 阿里巴巴矢量图标库
iconfont 的一般使用方法有三种: Unicode, Font class 以及 Symbol, 使用方法在下载解压后的demo_index.html
里都有详细.
图标下载到本地解压后, 只取iconfont.css
, iconfont.eot
, iconfont.svg
, iconfont.ttf
以及 iconfont.woff
五个文件即可. (其他文件是和使用说明相关的)
将iconfont.css
中的绝对路径修改为相对路径. 并只保留@font-family
和.iconfont
将css改为styled-component的格式. 注意 iconfont 应该作为全局样式.
挑选相应图标并获取字体变法, 应用于界面. 字体的unicode编码可以在demo_index.html
中看到, 也可以在iconfont.css
或 iconfont网站上自己的对应项目中看到.
网址: https://reactcommunity.org/react-transition-group/
“exposes simple components useful for defining entering and exiting transitions…it does not animate styles by itself. Instead it exposes transition stages, manages classes and group elements and manipulates the DOM in useful ways, making the implementation of actual visual transitions much easier.”
Transition
的子元素为函数, CSSTransition
的子元素为组件或基本元素.true
) 从 enter 阶段 (in 为 true
) 中拆了出来.
*
):
appear
属性默认为 false
,即组件刚 mount 时不会触发 enter 。为 true
时会。timeout=
等价于 timeout={1}
transition
属性放且仅在这里, 否则最终效果可能不会如你所想.import {CSSTransition} from 'react-transition-group'
, 使用 <CSSTransition>
标签将要添加动画的组件包裹起来 class MyComponent{
state = {inProp = true}
/* ... */
}
CSSTransition
标签指定属性, 有三个最重要的属性: in
, classNames
和 timeout
<CSSTransition in={inProp} timeout={200} classNames="my-node">
<div>
{"I'll receive my-node-* classes"}
</div>
</CSSTransition>
.my-node-enter{
/* ... */
}
.my-node-enter-active{
/* ... */
}
.my-node-enter-done{
/* ... */
}
概述: 提供了一些常见数据结构的 immutable 版本, 方便创建 immutable 数据和将普通js数据转化为 immutable 数据. 另外还提供了支持 lazy evaluation 的 immutable 数据结构.
核心思想: immutable. immutable data 一旦被创建, 不可被更改. immutalbe 的对象上的操作, 只会返回一个新的对象, 而不会对其本身做任何修改. immutalbe collections(List, Map, Set等) 应该被视为值而不是对象. 对象是可以随时间改变的, 而一个值代表着一个事物在某一具体时间的状态.
const map = Immutable.Map({ a: 1, b: 2, c: 3, d: 4 });
const list = Immutable.List([1, 2, 3]);
Immutable.Seq({ a: 1, b: 2, c: 3 })
.map(x => x * x)
.toObject();
const { fromJS } = require('immutable');
const nested = fromJS({ a: { b: { c: [3, 4, 5] } } });
const nested2 = nested.mergeDeep({ a: { b: { d: 6 } } });
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 6 } } }
console.log(nested2.getIn(['a', 'b', 'd'])); // 6
const nested3 = nested2.updateIn(['a', 'b', 'd'], value => value + 1);
console.log(nested3);
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 7 } } }
const nested4 = nested3.updateIn(['a', 'b', 'c'], list => list.push(6));
// Map { a: Map { b: Map { c: List [ 3, 4, 5, 6 ], d: 7 } } }
===
, 应该使用Immutable.is()
或 .equals()
. (虽然出于性能优化, 如果操作结果不对集合本身做任何修改, 会直接返回集合本身, 而不是新建一个对象再返回)
const { Map } = require('immutable');
const map1 = Map({ a: 1, b: 2, c: 3 });
const map2 = Map({ a: 1, b: 2, c: 3 });
map1.equals(map2); // true
map1 === map2; // false
const { Map } = require('immutable');
const map = Map({ a: 1, b: 2, c: 3 });
const mapCopy = map; // Look, "copies" are free!
const deep = Map({ a: 1, b: 2, c: List([3, 4, 5]) });
console.log(deep.toObject()); // { a: 1, b: 2, c: List [ 3, 4, 5 ] }
console.log(deep.toArray()); // [ 1, 2, List [ 3, 4, 5 ] ]
console.log(deep.toJS()); // { a: 1, b: 2, c: [ 3, 4, 5 ] }
JSON.stringify(deep); // '{"a":1,"b":2,"c":[3,4,5]}'
const oddSquares = Seq([1, 2, 3, 4, 5, 6, 7, 8])
.filter(x => x % 2 !== 0)
.map(x => x * x);
import {Search_Focus_Action, Search_Blur_Action} from "./actionTypes"
import { fromJS } from 'immutable';
const defaultState = fromJS({
focused: false
});
export default (state = defaultState, action) => {
if(action.type === Search_Focus_Action){
if(state.get("focused") === false) {
// immutable对象的set方法,会结合之前immutable对象的值和设置的值,返回一个全新的对象
return state.set("focused", true)
}
} else if(action.type === Search_Blur_Action){
if(state.get("focused") === true) {
// return newState;
return state.set("focused", false);
}
}
return state;
}
const mapStateToProps = (state) => {
return {
focused: state.header.get('focused')
}
}
概述: redux-immutable
用于创建一个与 Redux 的 combineReducers
相同的函数, 但是它创建的全局 state 是 immutable 的.
核心思想: 利用 immutable.js
来增强 combineReducers
, 使得其自动生成的全局 state 变成了一个 immutable 对象.
为什么使用它?
之前的代码看起来很难受. 这是因为, combineReducers 生成的全局 state 是一个普通对象, 通过点或中括号来获取属性值. 而组件自己的 reducer 中使用了 immutable.js, 返回组件的state是 immutable 对象. 我们可以直接让 combineReducers
生成的全局 state 是 immutable 的.
// globle reducer.js
export default combineReducers({
header: headerReducer
})
// Header.js
const mapStateToProps = (state) => {
return ({
focused: state.header.get('focused')
})
}
使用方式:
redux-immutable
中的 combineReducers
, 来替代 Redux 中的 combineReducers
:
//import { combineReducers } from 'redux';
import { combineReducers } from 'redux-immutable';
const mapStateToProps = (state) => {
return {
// focused: state.header.get("focused")
// focused: state.get("header").get("focused")
focused: state.getIn(["header", "focused"])
}
}
Reference: