c++ 外部组件发生异常_不用fork,轻松魔改 React 第三方组件

业务页面开发过程中,难免会使用到第三方组件,如 antd 或者自己团队提供的第三方组件。那么业务开发同学遇到需要与第三方组件库不一致的页面元素时,应该如何做呢?

首先我们划分一下组件覆写的类型,遇到 UI 不一致的地方,会牵涉到样式覆写;遇到一些交互设计不同的地方,牵涉到源码的改动,如 DatePicker 不支持周选择,需要修改支持,这类覆写为交互复写

样式覆写

以 antd 为例,样式覆写分为两种方式:一个是全局的样式 less 变量修改,一个是外部样式覆盖。

less 变量修改

通过 less.modifyVars 配置来进行 less 变量的覆写

// webpack.config.js
module.exports = {
  rules: [{
    test: /.less$/,
    use: [{
      loader: 'style-loader',
    }, {
      loader: 'css-loader', // translates CSS into CommonJS
    }, {
      loader: 'less-loader', // compiles Less to CSS
+     options: {
+       lessOptions: { // 如果使用less-loader@5,请移除 lessOptions 这一级直接配置选项。
+         modifyVars: {
+           'primary-color': '#1DA57A',
+           'link-color': '#1DA57A',
+           'border-radius-base': '2px',
+         },
+         javascriptEnabled: true,
+       },
+     },
    }],
    // ...other rules
  }],
  // ...other config
}

这种方式修改样式比较直接快捷,但是也有其中自己的局限性,如存在某些组件样式属性没有被抽离成 less 变量,我们应该如何处理呢?我们可以用外部样式覆盖的方式书写

外部样式覆写

外部样式覆写一般又有两种方式:

  1. 项目封装组件

my-button/index.js

const MyButton = ({ className, ...props }) => {
  return <Button className={c('my-button', className)} {...props} />
}

my-button/style.less

.my-button {
   .ant-button {
      // 样式覆盖在这
   }
}

2. 直接全局覆写样式

common.less

.ant-button {
   // 样式覆盖在这
}

个人更喜欢 项目封装组件 方式,这样可以更有利于组件独立,提高组件复用性,降低耦合。

总体来说,样式覆写还是比较简单直接的,不涉及到内部逻辑的修改,但是如果牵涉到交互覆写的话,很可能会需要修改内部逻辑

交互覆写

依旧以 DatePicker 为例,第三方 DatePicker 已经支持日,月,年选择器,但是不支持 周 选择。

这种情况,可能有同学倾向自己 copy 第三方源码,然后再自己单独修改内部逻辑,这样就很容易导致多人协同开发的项目中,其他人使用的是 第三方 DatePicker,而你用的是 MyDatePicker,不仅破坏 DRY 原则,加大理解成本,而且 Webpack 打包会重复打包两份 DatePicker,加大 Bunder Size

以我个人来说,我比较倾向以下方式,使用继承模式来覆写内部逻辑

// 注意!这里继承的是 DatePicker
class ExtendDatePicker extends DatePicker {
   static propTypes = {
      ...DatePicker.propTypes,
      // 扩展 PropType
      mode: PropTypes.oneOf(['day', 'week', 'month', 'year'])
   }
   someDatePickerMethod(...args) {
      // 可以随意注入自己的扩展逻辑
      super.someDatePickerMethod(...args)
   }
}

const MyDatePicker = React.forwardRef(({ className, ...props }, ref) => {
  return <ExtendDatePicker ref={ref} className={c('my-button', className)} {...props} />
})

优点:这种方式能比较快捷的修改组件内部逻辑,而且尽量少的打包重复代码

但是这种方式也有缺陷

  • 对于开发人员能力需要门槛
  • 同时适合于比较稳定的第三方组件,第三方组件迭代频繁的话,很容易导致组件内部逻辑修改,导致这种方式失效
  • 需要理解第三方组件的内部逻辑
  • 不适合于 Function Component

而且对于绑定在实例上的方法,覆写的方式也需要注意,如下:

// 第三方的 DatePicker
class DatePicker extends Component {
  // 该方法绑定在实例上
  bindedMethod = () => {
  }
  // 该方法绑定在原型上
  protoMethod() {}
}

class ExtendedDatePicker extends DatePicker {
  // 这样写是不能覆写 第三方 DatePicker 方法的
  bindedMethod() {}

  constructor(props, context) {
    super(props, context)

    const originMethod = this.bindedMethod
    this.bindedMethod = () => { 
      // 这样才可以覆写
      originMethod()
    }
  }
}

以上便是本人经常使用的组件覆写方式,欢迎讨论

最后!自家团队找人啦,欢迎投递简历

儿葱:美团到店技术 招收 高级 前端/Android/IOS 开发工程师/负责人​zhuanlan.zhihu.com
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值