需求1
原始:
我们封装了一个Icon组件,
type Props={
name:string
}
function Icon(props:Props){
return (
<svg className='icon'>
<use xlinkHref={'#'+props.name}/>
</svg>
)
}
export default Icon
使用:<Icon name='left'/>
添加功能
现在想点击图标,就回退到上一个页面。在使用的时候应该这样写:
const onClickBack=()=>{
window.history.back()
}
<Icon name='left' onClick={onClickBack}/>
可是Icon不是一个普通的html标签,它是一个组件,如果想定义它的onClick函数,需要作为props传进去。所以现在想让Icon组件接受一个onClick的外部属性。
考虑到onClick就是标签自带的属性,我们可以在Icon组件里使用&继承语法,让这个组件接受的props直接继承SVG标签自带的所有属性。
type Props={
name:string
}& React.SVGAttributes<SVGElement> // 1. 继承
function Icon(props:Props){
const {name,children,...rest}=props // 2. 从props里取出
return (
<svg className='icon' {...rest}> // 3. 把props传进来的属性复制到svg上
<use xlinkHref={'#'+props.name}/>
</svg>
)
}
export default Icon
在Icon组件里这样做了以后,使用它的时候,就可以传任意的svg标签支持的属性写法,Icon组件都能通过props接收到,并且用在svg标签上。
className的覆盖
可是用rest有一个问题,如果我在外边给Icon传了一个className,但是svg标签本来就自带了一个icon的className,那么rest里的className就会覆盖svg本来写死的className。<Icon name='left' onClick={onClickBack} className='xxx'/>比如这样,svg的className就变成了xxx。
1. 把className排除
//Icon.tsx
const {name,children,className,...rest}=props
从props里拿出各种属性时,把className单拿出来,这样rest里就没有className了,就不会覆盖原来的值了。即使使用Icon时传了className,由于rest里没有className,也不会生效。
但是,我外边还是想传className,让里边的svg拥有两个className,以空格连接的那种。
2. 插值
type Props={
name:string
}& React.SVGAttributes<SVGElement>
function Icon(props:Props){
const {name,children,className,...rest}=props
return (
<svg className={`icon ${className} `} {...rest}>
<use xlinkHref={'#'+props.name}/>
</svg>
)
}
export default Icon
直接自定义,className是一个icon字符串 空格 再加上className变量的值
<Icon name='left' onClick={onClickBack} className='xxx'/>
从页面可以观察到svg的className是icon xxx 成功了。
又一个bug:如果我没传className,那svg的实际className就变成了:
icon undefined 因为没给传。
怎么办呢?判断一下className有没有:
<svg className={`icon ${className? className:''} `} {...rest}>
问题:这也太麻烦了
3. classnames 库
安装:
yarn add classnames 源代码库
yarn add --dev @types/classnames ts支持
安装之后发现两个版本号不一致,一个是2.2.6 一个是2.2.10,保险起见,最好改成一样的。去package.json里修改,把版本前边的^删掉,把2.2.10改成2.2.6 ,然后运行yarn install
使用:
import classnames from 'classnames';
type Props={
name:string
}& React.SVGAttributes<SVGElement>
function Icon(props:Props){
const {name,children,className,...rest}=props
return (
<svg className={classnames('icon' , className)} {...rest}>
<use xlinkHref={'#'+props.name}/>
</svg>
)
}
export default Icon
首先明确,我们需要一个icon字符串形式的类,和一个className变量形式的类。使用classnames 它可以同时支持不同的形式,会自动在他们中间加上空格。
如果传了className属性,svg的类就是icon xxx ,如果没传,也不会出现undefined,而是只有一个icon
import cs from 'classnames';
可以使用cs 简化代码
2.
怎么看页面是否刷新?
- 看开发者工具的Network,如果刷新了,会有新的网络请求。
- 在入口文件index.tsx里打log,如果刷新了,就会有log