本文只给出子组件的源代码,可以来我的主页看我封装的其他组件。
封装树组件,父子级不关联,并为树组件添加右键功能。
<template>
<div>
<el-tree
:data="data"
:props='props'
:highlight-current='highlight_current'
:expand-on-click-node="expand_on_click_node"
:default-expanded-keys='default_expanded_keys'
:filter-node-method="filterNodeMethod"
:node-key="node_key"
@node-click="nodeClick"
:ref="tree_ref"
:show-checkbox='show_checkbox'
:check-strictly='check_strictly'
:default-expand-all='default_expand_all'
:default-checked-keys='default_checked_keys'
@check='check'
@node-contextmenu="nodeContextmenu"
></el-tree>
<div class='rightMenu' @mouseleave="rightNav=false" ref="rightNav" v-show="rightNav">
<div @click="checkAll">勾选全部</div>
<div @click="checkAllCancel">取消全部</div>
<div @click="checkSelfOrChild">勾选本级及下级</div>
<div @click="checkSelfOrChildCancel">取消本级及下级</div>
</div>
</div>
</template>
<script>
export default {
name: 'tree',
data () {
return {
rightNav:false,//控制右键菜单显示与隐藏
}
},
props:{
data:{
//展示数据,必传,数组格式。
type:Array,
require:true,
default(){
return []
}
},
props:{
//配置选项,必传,对象格式。
type:Object,
require:true,
default(){
return {
label: '',
value: '',
children: '',
disabledRightMenu: false,//控制右键菜单是否启用,默认启用
}
}
},
tree_ref:{
//相当于整颗树的ID,字符串类型,非必传。
type:String,
require:false,
default:'tree'
},
expand_on_click_node:{
//是否在点击节点的时候展开或者收缩节点, 默认值为 true,如果为 false,则只有点箭头图标的时候才会展开或者收缩节点。
type:Boolean,
require:false,
default:true
},
highlight_current:{
//是否高亮当前选中节点,默认值是 true。
type:Boolean,
require:false,
default:true
},
default_expanded_keys:{
//默认展开的节点的 key 的数组,数组格式。
type:Array,
require:false,
default(){
return []
}
},
default_checked_keys:{
//默认勾选的节点的 key 的数组,数组格式。
type:Array,
require:false,
default(){
return []
}
},
node_key:{
//每个树节点用来作为唯一标识的属性,整棵树应该是唯一的。
type:String,
require:false,
default:null
},
show_checkbox:{
//节点是否可被选择,即是否显示多选框,默认不显示多选框。
type:Boolean,
require:false,
default:false
},
check_strictly:{
//在显示复选框的情况下,是否严格的遵循父子不互相关联的做法,默认为 false。
type:Boolean,
require:false,
default:false
},
default_expand_all:{
//是否默认展开所有节点,默认为 false。
type:Boolean,
require:false,
default:false
},
},
methods:{
/* 节点被点击时触发 */
nodeClick(val) {
console.log('nodeClick',val)
//触发父组件事件
this.$emit('node-click',val);//父组件事件名@node-click
},
/* 对树节点进行筛选时执行的方法,返回 true 表示这个节点可以显示,返回 false 则表示这个节点会被隐藏。 */
filterNodeMethod(value, data, node){
if (!value) return true;
return data[this.props.label].includes(value);
},
/* 把树的ref传给父组件 */
getTreeRef(){
console.log('getTreeRef',this.tree_ref,this.$refs[this.tree_ref])
//在勾选树的多选框时有用,在父组件中利用子组件的ref获取勾选后的node-key数组。
this.$emit('get-tree-ref',this.$refs[this.tree_ref])//父组件事件名:get-tree-ref
},
/* 当复选框被点击的时候触发 */
check(node,obj){
// 共两个参数,依次为:传递给 data 属性的数组中该节点所对应的对象、树目前的选中状态对象,包含 checkedNodes、checkedKeys、halfCheckedNodes、halfCheckedKeys 四个属性
console.log('check',node,obj)
this.$emit('check',node,obj)//父组件事件名:check
},
/* 当单击鼠标右键时触发 */
nodeContextmenu(event,obj,node,self){
//如果没有多选框 或 禁用右键菜单
if(!this.show_checkbox||this.props.disabledRightMenu){
return;//右键不显示菜单。
}
//共四个参数,依次为:event、传递给 data 属性的数组中该节点所对应的对象、节点对应的 Node、节点组件本身。
this.$emit('node-contextmenu',event,obj,node,self)//右键时触发父组件事件@right-menu-data,获取值
this.nodeContextmenuObj = obj;
var ev = ev || event;
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
this.rightNav = true;
this.$refs.rightNav.style.left = ev.clientX + "px";
//当滑动滚动条时也能准确获取菜单位置
this.$refs.rightNav.style.top = ev.clientY + scrollTop + "px";
},
//右键勾选递归
getTreeCheck(dataAll,data,childrenName,code){
if(data && data.length > 0){
for(let i=0; i<data.length; i++){
if(this.checkedKeys.indexOf(data[i][code]) === -1){
this.checkedKeys.push(data[i][code]);
}
if(data[i][childrenName] && data[i][childrenName].length > 0){
this.getTreeCheck(dataAll,data[i][childrenName],childrenName,code);
}
this.$refs[this.tree_ref].setCheckedKeys(this.checkedKeys);
}
}
},
//右键取消勾选递归
getTreeCheckCancel(dataAll,data,childrenName,code){
if(data && data.length > 0){
for(let i=0; i<data.length; i++){
if(this.checkedKeys.indexOf(data[i][code]) > -1){
this.checkedKeys.splice(this.checkedKeys.indexOf(data[i][code]),1);
}
if(data[i][childrenName] && data[i][childrenName].length > 0){
this.getTreeCheckCancel(dataAll,data[i][childrenName],childrenName,code);
}
this.$refs[this.tree_ref].setCheckedKeys(this.checkedKeys);
}
}
},
//勾选所有
checkAll(){
//判断是数组类型
this.checkedKeys = [];
this.getTreeCheck(this.data,this.data,this.props.children,this.node_key);
//把勾选树的node-key返给父组件
this.$emit('get-check-data',this.$refs[this.tree_ref].getCheckedKeys(),this.tree_ref)//触发父组件事件@get-check-data
this.rightNav = false;
window.event.stopPropagation();
},
//勾选本级及下集
checkSelfOrChild(){
this.checkedKeys = this.$refs[this.tree_ref].getCheckedKeys();
if(this.checkedKeys.indexOf(this.nodeContextmenuObj[this.node_key]) === -1){
this.checkedKeys.push(this.nodeContextmenuObj[this.node_key]);
}
this.getTreeCheck(this.data,this.nodeContextmenuObj[this.props.children],this.props.children,this.node_key);
this.$emit('get-check-data',this.$refs[this.tree_ref].getCheckedKeys(),this.tree_ref)//触发父组件事件@get-check-data
this.rightNav = false;
window.event.stopPropagation();
},
//取消勾选所有
checkAllCancel(){
this.checkedKeys = [];
this.$refs[this.tree_ref].setCheckedKeys(this.checkedKeys);
//把勾选树的node-key返给父组件--未勾选所以是空数组
this.$emit('get-check-data',this.$refs[this.tree_ref].getCheckedKeys(),this.tree_ref)//触发父组件事件@get-check-data
this.rightNav = false;
window.event.stopPropagation();
},
//取消勾选本级及下级
checkSelfOrChildCancel(){
this.checkedKeys = this.$refs[this.tree_ref].getCheckedKeys();
if(this.checkedKeys.indexOf(this.nodeContextmenuObj[this.node_key]) > -1){
this.checkedKeys.splice(this.checkedKeys.indexOf(this.nodeContextmenuObj[this.node_key]),1);
}
this.getTreeCheckCancel(this.data,this.nodeContextmenuObj[this.props.children],this.props.children,this.node_key);
this.$emit('get-check-data',this.$refs[this.tree_ref].getCheckedKeys(),this.tree_ref)//触发父组件事件@get-check-data
this.rightNav = false;
window.event.stopPropagation();
},
},
created(){
},
mounted(){
this.getTreeRef()
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>
/*右键菜单*/
.rightMenu {
position: fixed;
left:0;
top: 0;
background: #fff;
border: 1px solid #a9a9a9;
z-index: 9999;
padding-top: 2px;
padding-bottom: 2px;
font-size: 12px;
color: #2c3e50!important;
}
.rightMenu div {
cursor: pointer;
height:24px;
line-height: 24px;
padding: 0 80px 0 20px;
}
.rightMenu div:hover {
background: #eee!important;
color: #2c3e50!important;
}
</style>