仿element实现可选择的树形控件
组件套组件的方式实现循环嵌套
html:
<div class="box">
<Tree :data="list" />
</div>
js:
import Tree from '@/components/tree.vue'//树形控件组件
export default {
name: 'treet',
data() {
return {
//循环列表
list: [
{
id: 1,
label: '一级 1',
children: [
{
id: 4,
label: '二级 1-1',
children: [
{
id: 9,
label: '三级 1-1-1'
},
{
id: 10,
label: '三级 1-1-2'
}
]
},
{
id: 5,
label: '二级 1-2',
children: [
{
id: 9,
label: '三级 1-2-1'
},
{
id: 10,
label: '三级 1-2-2'
}
]
}
]
},
{
id: 2,
label: '一级 2',
children: [
{
id: 5,
label: '二级 2-1',
children: [
{
id: 11,
label: '三级 2-1-1'
},
{
id: 12,
label: '三级 2-1-2'
}
]
},
{
id: 6,
label: '二级 2-2'
}
]
},
{
id: 3,
label: '一级 3',
children: [
{
id: 7,
label: '二级 3-1'
},
{
id: 8,
label: '二级 3-2'
}
]
}
]
}
},
components: {
Tree
},
mounted() {},
methods: {}
}
css:
.box{
padding-top: 20px;
}
以上是引入树形控件的文件内容
以下是树形控件本身
html:
<div>
<div v-for="item in data" :key="item.id">
<div class="flex">
<a v-if='item.children' :class="item.open?'transicon':''" @click="open(item)"></a>
<button @click="select(item)" :class="item.select=='1'?'active':item.select=='2'?'actives':''"></button>
<div>{{item.label}}</div>
</div>
<div class="children" v-show="item.children&&item.open">
<!-- 就是这个标签名 -->
<tree :data='item.children' />
</div>
</div>
</div>
这里划重点呐 集美们!!html引入的组件是本身这个vue文件!所以!vue文件的name要和引入组件的标签名保持一致啊,要不报错了可别怪我没提醒你!!
js:
export default {
name: 'tree',//就是这个name
props: {
data: {
type: Array //上边那个父组件传过来的循环列表
}
},
data() {
return {}
},
mounted() {},
computed: {},
methods: {
select(item) {
//==1是全选了显示对号 ==2是没全选显示横岗 剩下的就是没选的状态
if (item.select == '1' || item.select == '2') {
this.$set(item, 'select', '0')
} else {
this.$set(item, 'select', '1')
}
this.forLiat(item)//这个是你点击了的框的孩子们要做的事
this.parentList(this.$parent)//这是他的祖宗们要做的
},
parentList(item) {
if (!item.data) return//如果没上级了 那就啥也不干
if (item.$children) {
item.$children.map((element, index) => {
let a = 0//选中状态有几个
let b = 0//没被选择的有几个
if (element.data) {
element.data.map(elements => {
if (elements.select == '1') {
a++//子集有被选中的就++
}
if (elements.select != '1' && elements.select != '2') {
b++//同理
}
})
if (element.data.length == a) {//子集全部被选中了 这个父级也标记为选中状态
this.$set(item.data[index], 'select', '1')
} else if (element.data.length == b) {//子集全部没被选 这个父级被标记为没选状态
this.$set(item.data[index], 'select', '0')
} else {//啥也不是的就是横岗状态
this.$set(item.data[index], 'select', '2')
}
}
})
this.parentList(item.$parent)//一直找上级 直到没上级了
}
},
forLiat(item) {//item的子元素继承父元素的选中状态
if (item.children) {
item.children.forEach(element => {
this.$set(element, 'select', item.select)
if (element.children) {
this.forLiat(element)//反复循环直到没子元素了
}
})
}
},
open(item) {
this.$set(item, 'open', !item.open)
}
}
}
css:
.children {
padding-left: 15px;
}
.childrenhide {
display: none;
}
.flex {
display: flex;
align-items: center;
padding-left: 20px;
position: relative;
margin: 5px 0;
}
.flex > a {
position: absolute;
left: 0px;
width: 0;
height: 0;
border-left: 6px solid black;
border-top: 6px solid transparent;
border-bottom: 6px solid transparent;
margin-left: 10px;
margin-right: 10px;
transform: rotate(0deg);
transition: transform 0.3s ease-in-out;
}
.transicon {
transform: rotate(90deg) !important;
}
button {
margin: 0 5px;
outline: 0;
line-height: 1;
display: inline-block;
position: relative;
border: 2px solid #212121;
border-radius: 2px;
width: 16px;
height: 16px;
background-color: #fff;
z-index: 1;
-webkit-transition: border-color 0.15s ease-in, background-color 0.15s ease-in;
transition: border-color 0.15s ease-in, background-color 0.15s ease-in;
}
/* 对号 */
.active {
background-color: #2196f3;
border-color: #2196f3;
}
.active::after {
-webkit-box-sizing: content-box;
box-sizing: content-box;
content: '';
border: 2px solid #fff;
border-left: 0;
border-top: 0;
height: 6px;
left: 4px;
position: absolute;
top: 1px;
width: 3px;
-webkit-transition: -webkit-transform 0.15s
cubic-bezier(0.71, -0.46, 0.88, 0.6) 0.05s;
transition: -webkit-transform 0.15s cubic-bezier(0.71, -0.46, 0.88, 0.6) 0.05s;
transition: transform 0.15s cubic-bezier(0.71, -0.46, 0.88, 0.6) 0.05s;
transition: transform 0.15s cubic-bezier(0.71, -0.46, 0.88, 0.6) 0.05s,
-webkit-transform 0.15s cubic-bezier(0.71, -0.46, 0.88, 0.6) 0.05s;
-webkit-transform-origin: center;
transform-origin: center;
-webkit-transform: rotate(45deg) scaleY(1);
transform: rotate(45deg) scaleY(1);
}
/* 横杠 */
.actives {
background-color: #2196f3;
border-color: #2196f3;
}
.actives::before {
content: '';
position: absolute;
display: block;
border-top: 2px solid #fff;
left: 3px;
right: 3px;
top: 50%;
-webkit-transform: translateY(-1px);
transform: translateY(-1px);
}