使用继承思想,去开发一款组件(element-ui collapse组件为例子)

·  阅读 3579

最近在使用element-ui collapse组件的过程中,需要用collapse-item实现拖拽排序,原本组件满足不了,先看下组件的原形。(本文使用的element-ui是用1.4.2版本)

第一版

拖拽结合开源组件 vuedraggable,详细查看vuedraggable组件的用法。

<el-collapse>
  <draggable v-model="arr">
    <el-collapse-item v-for="(item, index) in arr" :key="'key-' + index">
      <template slot="title">
        <span>{{'collapse-item-' + item}}</span>
      </template>
    </el-collapse-item>
  </draggable>
</el-collapse>
复制代码

然后就报错了,呼~ 报错在于,collapse-item组件。

通过阅读element-ui,collapse-item源码路径在 node_modules_element-ui@1.4.2@element-ui\packages\collapse\src\collapse-item.vue

computed: {
  isActive() {
    return this.$parent.activeNames.indexOf(this.name) > -1;
  }
},
复制代码

可以看到计算属性isActive通过父级activeNames来定义的,然而现在组件的层级结构是这样。

collapse-item的父级是draggable, 肯定拿不到原本collapse的父级。

第二版

既然collapse-item拿不到想要的父级,想办法让其拿到collapse,组件重写的思想,可以查看笔者的另外一问: 开发VUE使用第三库,发现有bug怎么办?,当然这里不是组件存在bug,而是扩展,思路是一样的。

创建weCollapseIten.vue组件

<script>
import {
  CollapseItem
} from 'element-ui'
export default {
  // 继承了CollapseItem
  extends: CollapseItem,
  computed: {
    isActive () {
      // 这里重写
      return this.$parent.$parent.activeNames.indexOf(this.name) > -1
    }
  }
}
</script>
复制代码

通过this.parent.parent,拿到父级的父级也就是collapse了。

<el-collapse>
  <draggable v-model="arr">
    // 使用新组件
    <we-collapse-item v-for="(item, index) in arr" :key="'key-' + index">
      <template slot="title">
        <span>{{'collapse-item-' + item}}</span>
      </template>
    </we-collapse-item>
  </draggable>
</el-collapse>
复制代码

大功靠成,功能已经实现。等等,这样是否还不够通用,而且在element-ui组件之间嵌套一个新的组件,对于阅读者来说肯定是一脸懵逼。不够通用而且没有可以读性。

第三版

创建weCollapse.vue组件

// 将element-ui collapse组件的模板重写
<template>
  <draggable 
    class="el-collapse"
    :list="list"">
    <slot></slot>
  </draggable>
</template>

<script>
import draggable from './vuedraggable'

import {
  Collapse
} from 'element-ui'

export default {
  // 重写collapse组件
  extends: Collapse,

  props: {
    list: Array
  },
  
  components: {
    draggable
  }
}
</script>
复制代码

原本是这样,使用draggable这件代替div,引用weCollapse组件就已经嵌入了draggable组件,带有拖拽的功能,同时不影响原本element-ui collapse组件的功能。

<template>
  <div class="el-collapse">
    <slot></slot>
  </div>
</template>
复制代码

最终,代码使用组件如下,跟element-ui原本组件的引用的一样的,而功能上却已经大不相同,这样的好处就很多了,当然这组件编写还不完美,wecollapse是否可以支持拖拽应该是封装成一个属性,不支持拖拽的就不需要用draggable来做包裹了,还有本身draggable支持的属性也应该wecollapse来做支持。

<we-collapse :list="arr">
  <we-collapse-item v-for="(item, index) in arr" :key="'key-' + index">
    <template slot="title">
      <span>{{'collapse-item-' + item}}</span>
    </template>
  </we-collapse-item>
</we-collapse>
复制代码
收藏成功!
已添加到「」, 点击更改