关于前端:前端开发之组件库源码修改

3次阅读

共计 4948 个字符,预计需要花费 13 分钟才能阅读完成。

前端开发的同学们或者会遇到这样的问题:产品中须要实现某项性能,罕用的 elementui、antd 等组件库中的确有差不多性能的组件。前端培训但实际上这些组件可能并不能满足你的性能,或多或少都须要你去看看如何批改它能力满足你的需要。
比方我曾遇到过 element-ui 中的「树形控件」暴露出的参数没有我须要的(获取参数);或者是「对话框」组件我须要给它的 body 加上高低两条 border 等(款式批改);还有「级联选择器」的多选可搜寻性能:须要批改级联看板使它放弃开展,且当子节点全副选中时,不展现全副子节点 tag 而只展现它的父节点 tag(源码无此性能)。
例如,我须要的性能是左二(因为我不想选项过多时 tag 占得地位太大),而原组件如左一。我截了两张图比照:

对于组件库可能要批改的中央,我将它们分为以下五类可供参考:
• 款式问题
• 组件裸露的参数和办法不充沛(源码中存在)
• 可利用局部性能,其余性能要本人开发封装
• 2+ 个组件之间的联动,多合一
• 齐全没有合乎的组件

上面具体说说这些问题,以及如何解决这些问题。如果有不满足或更好的倡议,欢送指出。
1、组件款式问题
当批改单个文件的款式时,以 less 为例,如果你想要批改组件的款式,能够应用 /deep/ 或 >>> 来深度抉择到你要批改的款式(这可能帮你省去一大串的类名)。
.dialog-wrapper {

/deep/.el-dialog__body{border: solid 1px #999;}

}

如果你要批改全局的款式,第一种办法,你能够在全局款式文件中写款式笼罩,引入到 main.js 中即可全局失效。如下:
import “./assets/css/index.css”;

第二,跟着组件库提供的『自定义主题』教程批改,个别组件库都会给出相干的教程。
2、组件裸露的参数和办法不充沛
首先提出一个问题,你如何晓得组件裸露的参数和办法不充沛?其实答案很简略:因为我看了组件库的源码。
当咱们想要获取组件的一个参数,首先是看文档中提供了哪些 Attributes、Events、Methods。如果合乎需要,间接拿来用就好。如果没有你要的属性和办法,请你先去看看源码中提供了哪些货色没有向外裸露进去的,然而咱们能拿来用的。
上述的「Cascader 级联选择器」,我想要在选中一个搜寻的选项后不敞开看板。我在组件的 Events、Methods 中没有找到相干的办法管制看板开展,如下:

但当我去 github 上看该组件的源码时,我发现 toggleDropDownVisible() 办法是管制看板开展的。于是我在内部用 $refs 间接调用组件里的这个办法就好了。

具体调用办法如下,这样即便办法没有裸露进去,也能够调用它外部的办法:
<el-cascader

ref="cascader" // ref 获取组件
placeholder="试试搜寻:指南"
:options="options"
:props="{multiple: true}"
filterable></el-cascader
@visible-change="$refs.cascader.toggleDropDownVisible(true)"> // 调用组件及其办法

3、可利用局部性能,其余性能要本人开发封装
第三类其实咱们用到的曾经比拟少了,毕竟当初的组件库曾经十分丰盛了。然而这一步引起的思考确是很重要的,多看他人的源码有助于进步本人封装组件的程度。
当要用到一个组件,但从头开发这个组件既简单又耗时,而组件库中这个组件须要再往上加一些性能就能为你所用时,你能够思考把组件库的代码拿到本人本地,批改它。
第一步你须要将组件代码浏览一遍,理解它的逻辑。看看你须要加什么代码,如果在 vue 中,应用 computed、watch,或是批改 created、mounted、methods 就能实现你的性能,那么就大胆地尝试。
在 element-ui 中,它提供的多选可搜寻级联组件有一个问题:当用户选中全副子节点时不会合并为显示父节点。要想实现这个性能,在经验过上述步骤一番摸索后发现还是要批改源码能力实现。于是我基于本来多选可搜寻的级联选择器,进行以下优化:
• 默认看到级联看板开展,不会收起

@visible-change=”blurCascader(true)” // 可触发开展

mounted() {

this.blurCascader(true)

}

// 失焦后触发开展级联看板(默认失焦后敞开看板)
blurCascader() {

this.$nextTick(() => {this.$refs.cascader.toggleDropDownVisible(true) // 调用组件外部未裸露的办法
})

},

• 搜寻选中后展现级联看板,并勾选搜寻选中的节点

// 响应选中的节点,选中节点后敞开抉择看板,展现级联看板
changecascader(e) {
this.$refs.cascader.handleDropdownLeave()
},

• 当子级节点全副选中后,tag 只展现一个父级节点,而不是全副子节点

// 获取所有勾选的节点

getPresetTags() {const tree = this.panel.menus[0]
  const result = []
  loop(tree)
  // 递归查找选中的节点
  function loop(tree = []) {for (let i = 0; i < tree.length; i++) {const child = tree[i]
      if (child.checked) {                // checked 状态示意选中
        result.push({...child, closable: true})
      } else if (child.indeterminate) {   // indeterminate 状态示意待定,是半选
        child.children && loop(child.children)
      }
    }
  }
  this.presentFormatTags = result // 失去可显示的 tag
},

• 删除节点

因为我批改了 tag 的展现,所以它的 deleteTag 事件也要重写。
deleteTag(index, tag) {

  let _ = this
  if (tag && tag.hasChildren) {
   // 当删除的节点是父节点时
    loop(tag.children)
    function loop(list) {for (let i = 0; i < list.length; i++) {if (list[i].hasChildren) {loop(list[i].children)
        } else {_.checkedValue = _.checkedValue.filter(n => n !== list[i].path)
          _.$emit('remove-tag', tag)
        }
      }
    }
  } else if (tag) {
  // 当删除的是子节点时
    this.checkedValue = this.checkedValue.filter((n, i) => n !== tag.path)
    this.$emit('remove-tag', tag)
  } else {
  // 当以回车键删除时
    const temp = this.presentFormatTags[this.presentFormatTags.length - 1]
    temp && this.deleteTag(null, temp)
  }
  // 本来这个办法的代码如下
  // const {checkedValue} = this
  // const val = checkedValue[index]
  // this.checkedValue = checkedValue.filter((n, i) => i !== index)
  // this.$emit('remove-tag', val)
}

其实批改组件库代码的过程并不难,次要是看懂它的逻辑,以及其中哪些货色是你能够用的。
上述组件的源码能够在 GitHub 查看。
4、2+ 个组件之间的联动,多合一
到这一步,其实你曾经翻越最难的大山了!而这里要说的多个组件之间的联动其实曾经处于优化用户体验的路线上了。思考一下,什么时候会用到多个组件之间的联动呢?
其实场景有很多,例如将「Form 表单」、「Table 表格」和「Pagination 分页」联合起来,封装成一个组件,这样在多表格的我的项目中间接应用就好了;
将 table 和 pagination 放到一个组件中:
<template lang=”pug”>
div
.el-table

template(v-for="(item, index) in columns")
  el-table-column(
    :prop="item.prop"
    :key="index"
    :label="item.label")

el-pagination.pg-wrapper(

layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[10, 20, 50, 100]"
:page-size="pagesize"
:total="total")

</template>

须要传入的参数如下:列信息 columns、单页数据量 pagesize、以后页码 currentPage、表格数据 tableData、数据总数 total、表单查问的参数 query 等。
props: {
// 列信息
columns: {

type: Array,
default: [],

}
// 单页数据量
pagesize: {

type: Number,
default: 10,

},
// 以后页码
currentPage: {

type: Number,
default: 1,

},
// 表格数据
tableData: {

type: Array,
default: [],

},
// 数据总数
total: {

type: Number,
default: 1000,

},
// 获取数据的接口
fetch:{

 type: function,
 default:() => {}

},
// 表单查问的参数
query:{

type: Object,
default: () => {}

}
},
methods: {
// 扭转以后页码 currentPage 时触发
handleCurrentChange: function (currentPage) {

this.$emit('handleChange', this.pagesize, currentPage)
this.fetch(this.query)

},
// 扭转当前页 pageSize 时触发
handleSizeChange: function (pageSize) {

this.$emit('handleChange', pageSize, this.currentPage)
this.fetch(this.query)

}
}

应用时咱们只须要传以上的参数就能够间接调用这两个组件了。
还有「表格中行选中状态数据」,与「展现数据」之间的联动等等,可施展之处有很多。将他们封装后能够大大加重反复的工作量,特地是像后盾治理类的我的项目,页面间类似度很高的,尤其适宜这种办法。
5、齐全没有合乎的组件
如果你要的组件,内部的组件库中都没有提供,那就本人入手封装一个。尽可能将你的组件变得通用,兼容。尝试想一想你的组件是否在其余状况下也能用。另外也能够多看看他人是如何封装组件的,这有助于你本人开发。
如果你能够将你在前端开发路线上本人封装的组件一个个收集起来,大概率能够不便你当前雷同场景下间接复用,也有助于你的代码解耦。
总结
如果你遇到了组件库中的组件不适合的,先考虑看看是否能利用它的办法或属性达到成果,再看看是否批改它的代码达成目标。如果最初切实不行,那么就本人入手造轮子吧!本人造的轮子记得记下来,没准当前就能用上!
最初,Vue Demo Collection 这个我的项目,是我在开发过程中遇到的通用 Vue 组件的 demo 收集,蕴含了 Vue/CSS/Echarts 等一些能够复用的组件,基本上我认为能够复用的组件和代码片段我都会记录在这,不便本人的回顾和应用,也算是个人成长的记录。
来自:掘金,作者:Huup_We

正文完
 0