在前端开发中,使用组件库是必然的。然而有些组件库的样式、功能无法满足需求时应该如何修改呢。下面是我用到的几种方式。本文以 React 和 ant-design 为例(Vue 也有类似的机制)。
1. 定制主题
很多组件库自身就支持定制主题,这种情况适合于有明确组件设计规范的项目使用。下面是一些定制主题的文档:
2. 使用 css-modules 重写组件样式
当 React 项目使用了 css-modules,可以在 component 级别覆盖组件库的样式。比如使用了 antd 的组件,但是组件的样式与设计稿的样式有些许出入,既可以通过 CSS modules 的 global 来进行样式覆盖。
.confirmStyle {
width: 460px;
:global {
.ant-modal-body {
padding: 24px 27px 23px;
}
.ant-modal-confirm-title {
margin-top: 8px;
}
.ant-modal-confirm-btns {
margin-top: 40px;
}
.ant-modal-confirm-btns {
> button {
width: 72px;
height: 36px;
border-radius: 4px;
}
> button:nth-of-type(1) {
margin-right: 10px;
}
}
}
}
如果样式覆盖顺序没有生效,可以加上 !important
.ant-modal-body {
padding: 24px 27px 23px !important;
}
3. 对组件进行二次封装
一般组件都会留有 API 来自定义一些东西。比如容器样式、关闭按钮、内部组件样式、图标替换等。如果这个组件被应用到一个地方,直接在组件 API 上定义改动即可。如果这个组件会被反复使用。就可以进行组件的二次封装。
下面我基于 antd 的 Modal 组件的二次封装,整个项目都改用封装后的 Modal 组件。
import React from 'react'
import { Modal } from 'antd'
import { ModalFuncProps, ModalProps } from 'antd/lib/modal'
import CloseIcon from '@/assets/close.svg'
import WarningIcon from '@/assets/confirm-warning.svg'
import InfoSvg from '@/assets/confirm-info.svg'
import ErrorSvg from '@/assets/confirm-error.svg'
import styles from './index.scss'
interface Props {
children: any
}
const renderCloseIcon = <CloseIcon button className={styles.closeIcon} fill='#8c8c8c' />
const CustomModal = (props: ModalProps & Props) => {
return (
<Modal closeIcon={renderCloseIcon} centered {...props}>
{props.children}
</Modal>
)
}
CustomModal.info = (props: ModalFuncProps) => {
return Modal.info({
closeIcon: renderCloseIcon,
...props,
})
}
CustomModal.success = (props: ModalFuncProps) => {
return Modal.success({
closeIcon: renderCloseIcon,
...props,
})
}
CustomModal.error = (props: ModalFuncProps) => {
return Modal.error({
closeIcon: renderCloseIcon,
...props,
})
}
CustomModal.warn = (props: ModalFuncProps) => {
return Modal.warn({
closeIcon: renderCloseIcon,
...props,
})
}
CustomModal.warning = (props: ModalFuncProps) => {
return Modal.warning({
closeIcon: renderCloseIcon,
...props,
})
}
const ICON_SIZE: number = 44
const WIDTH: number = 460
// 将之前的全局 modal 逻辑合并到一起
CustomModal.confirm = (props: ModalFuncProps) => {
let { type } = props
if (!type) type = 'warning'
const typeMap: { [key: string]: { className: string; icon: React.ReactNode } } = {
warning: {
className: styles.confirmTypeIsWarning,
icon: <WarningIcon style={{ width: ICON_SIZE, height: ICON_SIZE }} />
},
info: {
className: styles.confirmTypeIsInfo,
icon: <InfoSvg style={{ width: ICON_SIZE, height: ICON_SIZE }} />
},
error: {
className: styles.confirmTypeIsError,
icon: <ErrorSvg style={{ width: ICON_SIZE, height: ICON_SIZE }} />
}
}
return Modal.confirm({
icon: typeMap[type as string].icon,
className: typeMap[type as string].className,
width: WIDTH,
okText: '确认',
cancelText: '取消',
closeIcon: renderCloseIcon,
...props
})
}
const { destroyAll, useModal, config } = Modal
CustomModal.destroyAll = destroyAll
CustomModal.useModal = useModal
CustomModal.config = config
export default CustomModal
4. fork 组件库进行修改和同步维护
之前遇到一个需要需要将表格多选功能改为鼠标 hover 的时候显示 checkbox 而非 hover 情况下显示为数字序号。这个需求在我们用到的 ali-react-table 中并没有相关 API 实现。
既然无法实现需求,就放弃用这个库吗?非也!可以通过将项目 fork 下来,修改源码来实现。且如果这个库有后续的更新,也可以将主仓库的改动合并到 fork 的仓库中。
而在 package.json
的引用中,改为引用 fork 下来的项目即可。这里的引用可以直接引用 git 路径,也可以发到 npm 上去引用。
最后
或许还有别的重写组件的方法,但目前来看以上四种方法都是比较优雅的。
网友评论