使用vue2封装树形结构的组件,用于下拉选择,结构如下:
父组件---->封装的树形组件----->回显input组件 & tree组件
封装的树形结构组件代码如下:
<template>
<div>
<div @click="openTree">
<el-input v-model="deptName" placeholder="请选择部门" @keyup.enter.native="handleQuery">
<i slot="suffix" class="el-input__icon " :class="showTree?'el-icon-caret-bottom':'el-icon-caret-left'"
style="position: relative;">
<div @click.stop="changeTreeShow" style="width: 100%;height: 100%;position: absolute;top: 0;z-index: 9999"></div>
</i>
</el-input>
</div>
<div style="" class="myScrollbar treeBox" v-show="showTree">
<dept-tree ref="deptTree" :default-dept-id="defaultDeptId" :refresh="showTree" @node-click="nodeClick"/>
</div>
</div>
</template>
<script>
import DeptTree from "@/views/system/dept/components/deptTree";
import {getDept} from "@/api/system/dept";
export default {
name: "deptSelect",
components: {DeptTree},
props: {
defaultDeptId: {//默认回显的部门id
type: String
}
},
data() {
return {
deptName: '',//用于显示的部门名称
showTree: false//是否显示下拉的树形组件
}
},
watch: {
defaultDeptId: {
handler(val, oldVal) {
if (val !== oldVal) {
this.getDeptName(val);//监听默认部门id变化,实时查询对应的部门名称进行回显
}
},
immediate: true
}
},
methods: {
changeTreeShow() {
setTimeout(() => {
this.$nextTick(() => {//动态切换树形组件的显示与否
this.showTree = !this.showTree
})
});
},
handleQuery() {//实现通过部门名称进行部门找的功能
this.$refs.deptTree.queryDeptByDeptName(this.deptName);
},
getDeptName(deptId) {//通过部门id查询部门名称
if (deptId) {
//TODO 此处异步查询接口根据实际情况需要自定义
getDept(deptId).then(res => {
this.deptName = res.data.deptName;
});
}
},
openTree() {
//打开下拉的树形结构
this.showTree = true;
},
nodeClick(node) {
//用户选择了树节点后的回调
this.showTree = false //关闭树组件
this.deptName = node.label//设置选中的部门名称
this.$emit('setDept', node);//回传选中的节点给父组件
}
}
}
</script>
<style scoped>
.treeBox {
max-height: 300px;
overflow: auto;
position: absolute;
z-index: 999;
width: 100%;
border-radius: 0 0 8px 8px;
border: 1px solid #e0e3e9;
border-top: 0;
margin-top: -4px;
}
</style>
树形组件代码:
<template>
<div>
<!-- 部门树-->
<el-tree
:data="deptTree"//显示的树形结构数据,使用懒加载的时候可以用于初始化,不需要的话可以去除
:props="defaultProps"//树形组件配置项,根据需要进行修改
:expand-on-click-node="false"//点击节点的时候是否展开,因为点击节点的时候业务逻辑为选中,所以此处设置为不展开
ref="tree"
lazy //启用懒加载机制
node-key="id"
:load="getDeptTree"//懒加载调用的方法
:highlight-current="true"//高亮当前行
@node-click="handleNodeClick"//点击节点后回调的方法
/>
</div>
</template>
<script>
//TODO 引用的api接口均需自己重新写
import {getUserProfile} from "@/api/system/user";//获取当前登录用户信息
import {getDept, getDeptByParentId, getDeptRootTree, listDept} from "@/api/system/dept";
export default {
name: "deptTree",
props: {
defaultDeptId: {//默认的部门id
type: String
},
refresh: {//是否需要刷新
type: Boolean,
default: false
}
},
watch: {
defaultDeptId(val, oldVal) {//默认的部门id
if (val !== oldVal) {
//同步给选中的部门id
this.choosedDeptId = val;
}
},
refresh(val, oldVal) {
if (val !== oldVal) {
//获取根部门
this.getRootDept()
}
}
},
data() {
return {
deptTree: [],//部门tree
userInfo: {},//当前用户信息
choosedDeptId: this.defaultDeptId,//选中的部门id
defaultProps: {//部门树配置
children: 'children',
label: 'label'
},
}
},
methods: {
getDeptTree(node, resolve) {//部门树懒加载调用方法
getUserProfile().then(response => {//先获取当前登录人的信息
this.userInfo = response.data
if (node.level === 0) {//如果是第一次加载,即加载的是第一层的
//首次加载,根据角色进行初始化,不同的角色看到的根节点不一样
getDept(this.userInfo.deptId).then(response => {//根据当前登录人的部门id获取根部门,实现不同的用户只能看见本部门及其下属部门的功能
let deptInfo = response.data
let tmp = []
tmp.push({label: deptInfo.deptName, id: deptInfo.deptId, leaf: false})
resolve(tmp)//添加获取的部门数据到树上
this.deptTree = tmp;//保存树数据
})
} else {
//加载子节点
getDeptByParentId(node.data.id).then(response => {
let tmp = []
response.data.forEach(deptInfo => {
tmp.push({label: deptInfo.deptName, id: deptInfo.deptId, leaf: false})
})
resolve(tmp)//添加获取的部门数据到树上
})
}
})
},
getRootDept() {
//根据当前登录人的部门id获取根部门,实现不同的用户只能看见本部门及其下属部门的功能
getDept(this.userInfo.deptId).then(response => {
let deptInfo = response.data
let tmp = []
tmp.push({label: deptInfo.deptName, id: deptInfo.deptId, leaf: false})
this.deptTree = tmp;
})
},
queryDeptByDeptName(deptName) {
//根据部门名称查询部门列表
if (!deptName) {
this.getRootDept()
} else {
//查询部门列表
listDept({deptName: deptName, deptIdScope: this.userInfo.deptId}).then(response => {
let tmp = []
response.data.forEach(deptInfo => {
tmp.push({label: deptInfo.deptName, id: deptInfo.deptId, leaf: false})
})
this.deptTree = tmp;//直接赋值,不使用懒加载的机制
})
}
},
handleNodeClick(data) {
//点击节点后的回传点击的数据给上级组件
this.$emit('node-click', data)
}
}
}
</script>
<style scoped>
</style>
封装的组件调用:
ui部分:
<dept-select :default-dept-id="deptId" placeholder="请选择归属部门" @setDept="setDept"/>
js部分:
setDept(dept) {
this.deptId = dept.id
}