最近在使用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拿不到想要的父级,想办法让其拿到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,拿到父级的父级也就是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>
复制代码