**
仿elementui cascade级联器组件编写
** 因公司开发需要自己类似element UI 级联器类似得组件 刚好没有封装过 只能自己动手啦 先看下最终实现得效果图吧 ! 样式什么没有仔细调~
因为是树型结构所以用得是递归组件~ 看下具体实现吧 cascaderItem.vue
<template>
<x-view class="cascader-item">
<ul class="ul-position">
<li v-for="(item, index) in list" :key="index">
<x-view class="li-item" @click.native="loadChild(item, $event)">
<x-checkbox-group
v-if="item.level == 3"
@bindchange="item.active = !item.active"
>
<x-label>
<x-checkbox :checked="item.active" />
<span :class="{ bg: item.active }">
{{ item.name || "" }}
</span>
</x-label>
</x-checkbox-group>
<span :class="{ bg: item.active }" v-else>
{{ item.name || "" }}
</span>
<x-image
v-if="item.level != 3"
:src="$Fw.proConfig.getCommonResource('assets/arrows-right.png')"
class="time-x-image"
/>
</x-view>
<!-- 如果有子节点的就继续渲染下一级 -->
<x-view
v-if="item && item.children && item.children.length && item.active"
class="sub-child"
>
<cascaderItem :list="item.children"></cascaderItem>
</x-view>
</li>
</ul>
</x-view>
</template>
<script>
const path = [];
import { mapState, mapGetters, mapMutations } from "vuex";
export default {
name: "cascaderItem",
props: {
list: {
default: function () {
return [];
},
type: Array,
},
},
data() {
return {
};
},
computed: {
...mapGetters('potentialCustomers',["getPath"]),
},
methods: {
...mapMutations('potentialCustomers',["setChoosePath"]),
findNodeBYId(array, id) {
if (!array.length) return;
array.forEach((element) => {
if (element.id == id) {
element.active = element.level == 3 ? !element.active : true;
} else {
/* 如果不是最后一层则需要取消其他层级高亮
如果是叶子节点可多选则不需要取消其他叶子节点的选中效果 */
if (element.level !== 3) {
element.active = false;
element.children &&
element.children.length &&
this.changeChildStatusByParent(element.children);
}
this.findNodeBYId(element.children || [], id);
}
});
},
// 如果父亲是false 那子节点 需要全部是flase
changeChildStatusByParent(data) {
if (!data.length) return;
data.forEach((_) => {
if (!_.active) {
if (_.children && _.children.length) {
_.children.forEach((sub) => {
sub.active = false;
this.changeChildStatusByParent(sub.children || []);
});
}
}
});
},
// 点击字节的事件
loadChild(item, e) {
let pathName = [];
let needDeletItem = [];
let currentLevel = item.level;
// 过滤出来需要删除的路径
needDeletItem = path
.filter((item) => item.level >= currentLevel)
.map((_) => _.id);
console.log(needDeletItem, "needDeletItem");
// 在path中删除对应得id
needDeletItem.forEach(_=>{
path.forEach((sub,idex)=>{
if(sub.id==_){
path.splice(idex,1);
}
})
})
path.push(item);
console.log(this.getPath,'getPath')
pathName = path.map((_) => _.name);
// 存到store中
this.setChoosePath(pathName);
this.findNodeBYId(this.list, item.id);
},
// 复选框选中事件
onchkChange(data, e) {
console.log(data, e);
},
},
};
</script>
<style lang="less" scoped>
.cascader-item {
width: 100px;
height: 150px;
color: #000;
overflow-y: scroll;
.ul-position {
.sub-child {
position: absolute;
width: 100px;
height: 150px;
top: 0;
left: 120px;
}
}
li {
.li-item {
display: flex;
align-items: center;
line-height: 30px;
span {
color: #000;
}
.bg {
color: blue;
}
}
}
.time-x-image {
width: 15px !important;
height: 15px !important;
vertical-align: middle;
}
}
</style>
主页面
<div class="cascader">
<cascaderItem :list='cascadeList' ref="cascaderItem"></cascaderItem>
</div>
这里遇到2个注意得地方
- 递归组件如何调用自己 ? 就是使用组件名称 name: “cascaderItem”, 即可
- props default 必须写成一个函数 猜测是否使用闭包防止 父子组件数据相互污染
|