Ant的优势之处

AntDesign目前在前端是使用的非常广泛的一个前端资源库,其拥有丰富的组件

这一点特别是在ant-design-pro上体现的更明显,对比与element-ui上,一般在处理复杂后台业务的时候建议使用ant,在处理想要更好更漂亮的ui时建议使用element

关于Input组件的@clear事件

关于Input输入框组件上,element-ui和ant都提供了clear用于清空当前用户的输入内容

<el-input placeholder="请输入内容" v-model="input" clearable @clear='fireEvent' />

<a-input placeholder="请输入内容" allow-clear @change="onChange" />

<a-input-search placeholder="请输入内容" allow-clear @change="onChange" @search='fireSearch' />

但是他们的不同之处是element提供了clear事件之后的回调,而ant并未提供该功能

ant这里倒是有一个类似的a-input-search的能力(@search)来对事件进行触发,但是回看官方文档就会发现,Enter和Clear动作都会导致(@search)的触发,其定制化并不符合我们的需求,我只想要@clear的回调,因此可能要涉及到对ant组件库中Input组件的功能进行调整

源码跟踪

  1. 首先我们跟踪到ant中Input组件的源码,找到对应的/input/index.js,然后发现实际组件是/input/Input.js文件

    image.png

  2. 跟踪后发现其引用了另一个文件/input/ClearableLabeledInput.js然后跟踪发现在#34有一个renderClearIcon方法,该方法最后渲染出来了一个clear按钮,并且具有onclick事件handleReset

    image.png

  3. 查看调用发现该事件函数的定义在/input/Input.js

        handleReset: function handleReset(e) {
          var _this2 = this;
    
          this.setValue('', function () {
            _this2.focus();
          });
          resolveOnChange(this.$refs.input, e, this.onChange);
        },
  4. 根据3中的发现,其实最终的问题就是onclear之后,事件没有向上抛出一个@clear的emit消息,因此我们只需要在这里增加一行this.$nextTick(() => this.$emit('clear', e))就可以解决这个clear事件的触发
  5. 现在的问题是,我们如何去修改他的源码,并且还能在prod打包的时候也生效

修改方案

这里根据vite的文档我们引入了一个外部的库来ant的原始代码进行变更:@rollup/plugin-replace

文档地址:https://www.npmjs.com/package/@rollup/plugin-replace

其实际原理就是在开发模式和编译模式下,都对其源代码进行拦截并修改

这里提供一下,我这里的修改方案:

const fs = require('fs')
const replace = require('@rollup/plugin-replace')

const defaultReg = /(@ant-design-vue-v1\\design\\es\\input\\Input\.js)|(@ant-design-vue-v1\/design\/es\/input\/Input\.js)/
const exportFn = (reg = defaultReg) => {
  return {
    name: 'vite-plugin-qdesign-input-clear-event-resolver',
    configResolved(config) {
      //  以来预构建时候替换 esbuild
      config.optimizeDeps.esbuildOptions.plugins = config.optimizeDeps
        .esbuildOptions.plugins
        ? config.optimizeDeps.esbuildOptions.plugins
        : []
      config.optimizeDeps.esbuildOptions.plugins.push({
        name: 'replace-code',
        setup(build) {
          // MARK 调试的时候可以尝试直接idea启动debug模式,加断点,确认代码的执行无误
          // MARK 页面debugger确认的时候先用调试编译,触发debug模式的断点,触发资源更新,然后再正常启动触发页面的断点,可能会快一些
          build.onLoad(
            {
              filter: reg,
            },
            (args) => {
              // 首先获取源代码内容
              let source = fs.readFileSync(args.path, 'utf8')
              source = source.replace('var _this2 = this;', `var _this2 = this;this.$nextTick(()=>this.$emit('clear', e))`)
              return {
                contents: source,
              }
            },
          )
        },
      })

      //  添加打包时的替换 rollup
      config.plugins.push(
        replace({
          // MARK 调试的时候断点加在:@rollup/plugin-replace/dist/rollup-plugin-replace.cjs.js
          // MARK 然后调用idea的debug模式,触发断点,调试速度最快
          values: {
            'var _this2 = this;': (id) => {
              return `var _this2 = this;this.$nextTick(()=>this.$emit('clear', e))`
            },
          },
          delimiters: ['', ''], // replace方法在进行匹配的时候是采用的正则,因此会自动带上前缀和后缀['\\b', '\\b(?!\\.)'],按需使用
          include: [reg],
          preventAssignment: true,
        }),
      )
    },
  }
}

module.exports = exportFn

在上面的代码中#4行表示了在rollup中需要匹配的文件正则-适配linux和windows

其主要替换代码在#26和#41行

自此,AntDesignVue的Input输入框就具有了清空会回调的能力,Input.TextArea也有这个问题,可以按需增加

自此,我们就可以正常使用ant中Input组件的@clear事件了

<a-input placeholder="请输入内容" allow-clear @clear="clearEventFire" />
最后修改:2022 年 07 月 27 日
如果你觉得我对你起到了帮助,请随意打赏