基于element+vue树形结构外加多选框
今天有空整理了之前项目中用到的树形结构外加多选框,并实现一定的逻辑,比如全选,单选,全选和单选之间的联动之前也在网上搜到过有关此功能的实现,于是我也就参考着写了一个,放在了自己的博客里,就当是给自己做了一个笔记,嘿嘿嘿~~~下面我直接贴代码下面是menu.vue的代码<template><div style="width: 600px;"
·
今天有空整理了之前项目中用到的树形结构外加多选框,并实现一定的逻辑,比如全选,单选,全选和单选之间的联动
之前也在网上搜到过有关此功能的实现,于是我也就参考着写了一个,放在了自己的博客里,就当是给自己做了一个笔记,
嘿嘿嘿~~~
下面我直接贴代码
下面是menu.vue的代码
<template>
<div style="width: 600px;">
<Tree :menus = "menus" :depth = "depth" :actId = "actId" :showCheckbox="showCheckbox" @selectItem = "selectItem" @checkItem = "checkItem"></Tree>
</div>
</template>
<script>
import Tree from '@/components/menuTree'
import data from './data.json'
export default {
components: {
Tree
},
data () {
return {
depth: 0,
menus: [],
actId: '',
showCheckbox: true // 是否显示多选的框,默认不显示
}
},
created () {
this.getData()
},
methods: {
// 获取数据
getData () {
this.menus = data
// 在每一项中添加show
this.addShow(this.menus)
},
// 递归函数在每一项中添加show
addShow (arr) {
for (var i = 0; i < arr.length; i++) {
this.$set(arr[i], 'show', false)
if (arr[i].childrenMenus && arr[i].childrenMenus.length > 0) {
this.addShow(arr[i].childrenMenus)
}
}
},
// 点击箭头使树展开收缩
selectItem (data) {
if (data.childrenMenus && data.childrenMenus.length > 0) {
// 如果此项下有childrenMenus且length大于0,则切换展开与折叠状态
data.show = !data.show
}
// 则将选中的menuId赋值给actId
this.actId = data.menuId
},
// 进行多选勾选
checkItem (data) {
if (data.selected) {
// 如果这一项的selected有值,说明是被勾选状态,要把selected置为false,清空勾选
data.selected = false
// 如果此选项清空勾选后,如果下面有childrenMenus的话,那么也同时要清空
if (data.childrenMenus && data.childrenMenus.length > 0) {
this.clearChild(data.childrenMenus)
}
} else {
// 如果这一项的selected为false,说明是未被勾选状态,把selected置为true,添加勾选
data.selected = true
// 如果此选项勾选后,如果下面有childrenMenus的话,那么也同时勾选下面所有的孩子
if (data.childrenMenus && data.childrenMenus.length > 0) {
this.addChild(data.childrenMenus)
}
// 如果此选项勾选后,要判断所有的上级元素是不是应该全部打勾
this.selectFather(this.menus, data)
}
},
// 定义函数清空所有孩子的勾选
clearChild (arr) {
for (var i = 0; i < arr.length; i++) {
arr[i].selected = false
if (arr[i].childrenMenus && arr[i].childrenMenus.length > 0) {
this.clearChild(arr[i].childrenMenus)
}
}
},
// 定义函数添加所有孩子的勾选
addChild (arr) {
for (var i = 0; i < arr.length; i++) {
arr[i].selected = true
if (arr[i].childrenMenus && arr[i].childrenMenus.length > 0) {
this.addChild(arr[i].childrenMenus)
}
}
},
// 定义函数一层一层的往上寻找父元素的childrenMenus
clearFather (father, data) {
for (var i = 0; i < father.length; i++) {
if (father[i].menuId === data.menuId) {
// 找到data所在的childrenMenus为father,然后再通过这个childrenMenus找到拥有这个childrenMenus的父元素
this.clearRealFather(this.menus, father)
} else if (father[i].childrenMenus && father[i].childrenMenus.length > 0) {
this.clearFather(father[i].childrenMenus, data)
}
}
},
// 定义函数根据找到的上层父元素的childrenMenus来寻找父元素,并将他们清除勾选
clearRealFather (menus, arr) {
for (var i = 0; i < menus.length; i++) {
if (menus[i].childrenMenus === arr) {
// 找到这个拥有childrenMenus的父元素后,将此selected置为false
menus[i].selected = false
// 找到这个拥有childrenMenus的父元素后,再调用clearFather,再进行向上寻找父元素,知道没有父元素为止
this.clearFather(this.menus, menus[i])
} else if (menus[i].childrenMenus && menus[i].childrenMenus.length > 0) {
this.clearRealFather(menus[i].childrenMenus, arr)
}
}
},
// 定义函数一层一层的往上寻找父元素的childrenMenus
selectFather (father, data) {
for (var i = 0; i < father.length; i++) {
if (father[i].menuId === data.menuId) {
// 执行selectRealFather,将上层父元素也勾选
this.selectRealFather(this.menus, father[i])
} else if (father[i].childrenMenus && father[i].childrenMenus.length > 0) {
this.selectFather(father[i].childrenMenus, data)
}
}
},
// 定义函数根据找到的上层父元素的childrenMenus来寻找父元素,并将他们勾选
selectRealFather (menus, obj) {
for (var i = 0; i < menus.length; i++) {
if (menus[i].menuId === obj.parentMenuId) {
// 找到这个拥有childrenMenus的父元素后,给selected赋值,使其勾选
menus[i].selected = true
// 找到这个拥有childrenMenus的父元素后,再调用selectRealFather,再进行向上寻找父元素,知道没有父元素为止
this.selectRealFather(this.menus, menus[i])
} else if (menus[i].childrenMenus && menus[i].childrenMenus.length > 0) {
this.selectRealFather(menus[i].childrenMenus, obj)
}
}
}
}
}
</script>
然后是树形组件components文件夹中menuTree.vue的代码
<template>
<ul class = "menu-tree">
<li v-for = "(item,index) in menus" :key = "index">
<!-- 遍历menus-->
<div :class = "{'itemTree':true,'active':actId == item.menuId}" @click = "selectItem(item)">
<div :style = "transform">
<!-- 如果item没有孩子 -->
<i class = "el-icon-caret-right" v-if = "item.childrenMenus && item.childrenMenus.length === 0" style="opacity:0"></i>
<!-- 如果item有孩子且item.show为false,那么图标为折叠图标 -->
<i class = "el-icon-caret-right" v-if = "item.childrenMenus && item.childrenMenus.length > 0 && !item.show" ></i>
<!-- 如果item有孩子且item.show为true,那么图标为展开图标 -->
<i class = "el-icon-caret-bottom" v-if = "item.childrenMenus && item.childrenMenus.length > 0 && item.show"></i>
<!-- 如果item的selected为true,也就是里面有值的话就是勾选状态,否则就是不勾选状态 -->
<i class = "selectBox" :class = "{'checkName ':item.selected}" v-if="showCheckbox" @click.stop = "checkItem(item)">
<i></i>
</i>
{{item.menuName}}
</div>
</div>
<el-collapse-transition>
<!-- 递归组件就是自己调用自己,这里是在自己的组件内再次调用自己,但是务必要和调用使用的一模一样才可以,否则树不会生效 -->
<Tree v-if = "item.childrenMenus && item.childrenMenus.length > 0 && item.show" :menus = "item.childrenMenus" :depth = "depth+2" :actId = "actId" :showCheckbox="showCheckbox" @selectItem = "selectItem" @checkItem = "checkItem"></Tree>
</el-collapse-transition>
</li>
</ul>
</template>
<script>
export default {
name: 'Tree',
props: {
menus: {type: Array, default () { return [] }},
depth: {type: [Number, String], default: 0},
actId: {type: [Number, String], default: ''},
showCheckbox: {type: Boolean, default: false}
},
data () {
return {
}
},
methods: {
// 将selectItem方法暴露出去
selectItem (item) {
this.$emit('selectItem', item)
},
// 将checkItem方法暴露出去
checkItem (item) {
this.$emit('checkItem', item)
}
},
computed: {
// 通过传过来的depth计算下级目录的偏移量,这里我用的transform
transform () {
return 'transform:translateX(' + this.depth * 10 + 'px)'
}
}
}
</script>
<style lang = "scss" scoped>
.menu-tree{
li{
.itemTree{
height: 40px;
line-height: 40px;
width: 100%;
padding-left:10px;
position: relative;
font-size: 14px;
&:hover{
background:#6eb2eb;
color:#fff;
}
.selectBox{
display: inline-block;
width: 16px;
height:16px;
border:1px solid #ccc;
border-radius: 3px;
position: relative;
background: #fff;
top:2px;
}
.checkName{
background: #6FD202;
border-color: #6FD202;
i{
position: absolute;
left: 0;
top: -1px;
display: inline-block;
width: 14px;
height:10px;
border:2px solid #ffffff;
border-right: none;
border-top: none;
transform: rotate(-50deg);
}
}
}
.active{
background:#4E8EFF;
color:#fff;
}
}
}
</style>
最后就是模拟的数据
[
{
"menuId": 11000000000297,
"parentMenuId": null,
"menuName": "Call车",
"menuTitle": "Call车",
"childrenMenus": [
{
"menuId": 11000000000299,
"parentMenuId": 11000000000297,
"menuName": "需求管理",
"menuTitle": "需求管理",
"childrenMenus": [
{
"menuId": 11000000000300,
"parentMenuId": 11000000000299,
"menuName": "查看",
"menuTitle": "查看",
"childrenMenus": [],
"selected": true
},
{
"menuId": 11000000000301,
"parentMenuId": 11000000000299,
"menuName": "需求Call车",
"menuTitle": "需求Call车",
"childrenMenus": [],
"selected": true
}
],
"selected": true
},
{
"menuId": 11000000000304,
"parentMenuId": 11000000000297,
"menuName": "需求分配",
"menuTitle": "需求分配",
"childrenMenus": [],
"selected": true
}
],
"selected": true
},
{
"menuId": 11000000000312,
"parentMenuId": null,
"menuName": "财务相关",
"menuTitle": "财务相关",
"childrenMenus": [
{
"menuId": 11000000000313,
"parentMenuId": 11000000000312,
"menuName": "奖金",
"menuTitle": "奖金",
"childrenMenus": [
{
"menuId": 11000000000314,
"parentMenuId": 11000000000313,
"menuName": "奖金查询",
"menuTitle": "奖金查询",
"childrenMenus": [],
"selected": true
},
{
"menuId": 11000000000315,
"parentMenuId": 11000000000313,
"menuName": "奖金上传",
"menuTitle": "奖金上传",
"childrenMenus": [],
"selected": false
},
{
"menuId": 11000000000316,
"parentMenuId": 11000000000313,
"menuName": "奖金审核",
"menuTitle": "奖金审核",
"childrenMenus": [],
"selected": true
}
],
"selected": true
},
{
"menuId": 11000000000317,
"parentMenuId": 11000000000312,
"menuName": "资金",
"menuTitle": "资金",
"childrenMenus": [
{
"menuId": 11000000000318,
"parentMenuId": 11000000000317,
"menuName": "资金查询",
"menuTitle": "资金查询",
"childrenMenus": [],
"selected": true
},
{
"menuId": 11000000000319,
"parentMenuId": 11000000000317,
"menuName": "延期付款申请/提交",
"menuTitle": "延期付款申请/提交",
"childrenMenus": [],
"selected": true
},
{
"menuId": 11000000000321,
"parentMenuId": 11000000000317,
"menuName": "延期付款查询",
"menuTitle": "延期付款查询",
"childrenMenus": [],
"selected": true
},
{
"menuId": 11000000000322,
"parentMenuId": 11000000000317,
"menuName": "延期付款备案",
"menuTitle": "延期付款备案",
"childrenMenus": [],
"selected": true
}
],
"selected": true
},
{
"menuId": 11000000000323,
"parentMenuId": 11000000000312,
"menuName": "折扣",
"menuTitle": "折扣",
"childrenMenus": [
{
"menuId": 11000000000324,
"parentMenuId": 11000000000323,
"menuName": "折扣录入",
"menuTitle": "折扣录入",
"childrenMenus": [],
"selected": true
},
{
"menuId": 11000000000325,
"parentMenuId": 11000000000323,
"menuName": "折扣提交",
"menuTitle": "折扣提交",
"childrenMenus": [],
"selected": true
},
{
"menuId": 11000000000328,
"parentMenuId": 11000000000323,
"menuName": "折扣申请查询",
"menuTitle": "折扣申请查询",
"childrenMenus": [],
"selected": true
}
],
"selected": true
}
],
"selected": true
},
{
"menuId": 11000000000342,
"parentMenuId": null,
"menuName": "信息上传",
"menuTitle": "信息上传",
"childrenMenus": [
{
"menuId": 11000000000343,
"parentMenuId": 11000000000342,
"menuName": "PDI验收",
"menuTitle": "PDI验收",
"childrenMenus": [],
"selected": false
},
{
"menuId": 11000000000344,
"parentMenuId": 11000000000342,
"menuName": "终端销售提报",
"menuTitle": "终端销售提报",
"childrenMenus": [],
"selected": false
}
],
"selected": false
}
]
至此,一个树形组件外加多选框就做好了
下面看下效果图
第一次写博客,不足之处还望大家见谅,嘿嘿嘿~~~
更多推荐
已为社区贡献1条内容
所有评论(0)