您现在的位置是:首页 > 文章详情

VUE-ElementUI 对话框多层级树形控件,穿越框复杂业务实现

日期:2019-11-30点击:492

VUE-ElementUI 对话框多层级树形控件,穿越框复杂业务实现

请忽略css,主要是逻辑,看图,图片为子组件,左侧树形控件,中间选择框,右侧展示框

1575106275_1_
1575106412_1_

父组件

<template> <div class="box"> <div class="ad-primary choose-btn" @click="chooseOne">请选择人员</div> <div class="ad-primary choose-btn" @click="chooseTwo">请选择管理员</div> <div>选择人员{{attendanceOfficerNameList}}</div> <div>选择管理员{{attendanceOfficerNameListF}}</div> <select-officer @dialogFun="dialogOne" :post-visible="dialogVisibleOne" :post-person="kqPerson" :post-frame="kqCount" :post-user="kqCountu"></select-officer> <select-officer @dialogFun="dialogTwo" :post-visible="dialogVisibleTwo" :post-person="labelPerson" :post-frame="labelCount" :post-user="labelCountu"></select-officer> </div> </template> <script> import attendanceOfficer from "@/pages/common/attendanceOfficer" export default { name: 'attendanceAdd', components: { 'select-officer': attendanceOfficer }, data() { return { dialogVisibleOne: false, dialogVisibleTwo: false, kqPerson: [], kqCount: 0, kqCountu: 0, labelPerson: [], labelCount: 0, labelCountu: 0, attendanceOfficerIds: [], attendanceOfficerNameList: "", attendanceOfficerIdsF: [], attendanceOfficerNameListF: "", } }, created() { this.getDatas(); }, methods: { /** 考勤类型列表 */ getDatas() { function getQuery (variable) { let code = window.location.search.substring(1) //let enUrl = 'user=dev-test&pwd=11111111' //let enUrls = encodeURIComponent(enUrl) //console.log(enUrls) let codes = decodeURIComponent(code) let vars = codes.split("&"); for (let i = 0; i < vars.length; i++) { let pair = vars[i].split("="); if (pair[0] == variable) { return pair[1]; } } return (false); } let that = this; let u = getQuery('kqId'); //console.log('kq = '+u) if (u) { let params_show = { //"requestId":"4333532244114", "authToken": "12312", "userToken": "26cea5f746ae4c7fbf7c3a4018b23f28", "data": { "kqId": u } } this.http.post('www.centby.com/show', params_show).then( res => { if (res.data.kqPersons != null) { that.kqPerson = res.data.kqPersons; let j = 0; let k = 0; res.data.kqPersons.forEach(function (item) { if (nodeType == 0) { j++; } else if (nodeType == 1) { k++ } }); that.kqCount = j; that.kqCountu = k; } if (res.data.kqLiablePersons != null) { that.labelPerson = res.data.kqLiablePersons; let m = 0; let n = 0; res.data.kqLiablePersons.forEach(function (item) { if (nodeType == 0) { m++; } else if (nodeType == 1) { n++ } }); that.labelCount = m; that.labelCountu = n; } //console.log(JSON.stringify(res)) }, error => { console.log(error.message) } ) } }, chooseOne(){ this.dialogVisibleOne = true; }, chooseTwo(){ this.dialogVisibleTwo = true; }, dialogOne(data){ //console.log(data) this.dialogVisibleOne = data.emita; this.attendanceOfficerIds = data.emitb; this.attendanceOfficerNameList = data.emitc; }, dialogTwo(data){ //console.log(data) this.dialogVisibleTwo = data.emita; this.attendanceOfficerIdsF = data.emitb; this.attendanceOfficerNameListF = data.emitc; } } } </script> <style scoped> .choose-btn { width: 80px; height: 30px; line-height: 30px; padding: 0 20px; margin-bottom: 10px; font-size: 14px; font-weight: 600; border-radius: 4px; cursor: pointer; } </style> 

子组件

<template> <el-dialog title="选择人员" align="left" :visible.sync="dialogVisible" width="50%" :before-close="handleClose"> <div class="chosen-modal"> <div class="chosen-modal-left"> <div class="chosen-modal-hd"> <div class="chosen-modal-hd-search"> <i class="el-icon-search" @click="searchSelect"></i> <input type="text" class="aui-input" placeholder="搜索" v-model="searchWord" id="chosenSearch"> </div> </div> <div class="chosen-modal-bd" style="position: relative;"> <div class="chosen-left" style="width: 200px;"> <el-tree :data="treeData" :props="defaultProps" node-key="id" @node-click="handleNodeClick"> <span class="custom-tree-node" slot-scope="{ node, data }"> <i class="el-icon-folder-opened" v-show="data.nodeType == 0 ? true : false"></i> <i class="el-icon-s-custom" v-show="data.nodeType == 0 ? false : true"></i> <span>{{ node.label }}</span> </span> </el-tree> </div> <div class="chosen-right"> <el-checkbox v-model="checkAll" @change="handleCheckAllChange" :disabled="forbid">全选</el-checkbox> <div style="margin: 15px 0;"></div> <el-checkbox-group v-model="checkedCities" @change="handleCheckedCitiesChange"> <el-checkbox v-for="item in category" :label="item.id" :key="item.id" :disabled="forbid"> <i class="el-icon-folder-opened" v-show="item.nodeType == 0 ? true : false"></i> <i class="el-icon-s-custom" v-show="item.nodeType == 0 ? false : true"></i> {{item.name}} </el-checkbox> </el-checkbox-group> </div> </div> </div> <div class="chosen-modal-right"> <div class="chosen-modal-right-hd"> <p id="tipText">已选{{frameCount}}个架构,{{userCount}}名用户</p> </div> <div class="chosen-modal-right-bd"> <div class="chosen-person-org" v-for="items in selectList" :key="items.id" @click="delList(items.id)"> <i class="el-icon-folder-opened" v-show="items.nodeType == 0 ? true : false"></i> <i class="el-icon-s-custom" v-show="items.nodeType == 0 ? false : true"></i> <span class="js-chosen-rs-text">{{items.name}}</span> <i class="el-icon-close"></i> </div> </div> </div> </div> <span slot="footer" class="dialog-footer"> <el-button @click="handleClose">取 消</el-button> <el-button type="primary" class="ad-primary" @click="next">确 定</el-button> </span> </el-dialog> </template> <script> //centby.com export default { name: 'attendanceOfficer', props: { postFrame: { type: Number }, postUser: { type: Number }, postVisible: { type: Boolean }, postPerson: { type: Array, default: () => [] } }, data () { return { searchWord: "", defaultProps: { children: 'children', label: 'label' }, treeData: [],//树形渲染 category: [],//选中框渲染 selectList: [],//展示框渲染 checkAll: false,//全选按钮状态 checkedCities: [],//选中框选中的 id 列表 listId:[],//选中框所有 id 列表 parentList: [],//当前树形节点所有父级 id 列表包含自己 forbid: false,//选中框所有禁选状态,默认可选 frameCount: 0, userCount: 0, attendanceOfficerIds: [],//选中的 id 传给父组件 attendanceOfficerNameList: "",//选中字符串传给父组件,做展示 reviewData: '',//展示框请求回显数据 dialogVisible: false//对话框打开或关闭状态 } }, watch: { postFrame: { handler(newName, oldName) { this.frameCount = newName; }, immediate: true, deep: true }, postUser: { handler(newName, oldName) { this.userCount = newName; }, immediate: true, deep: true }, postPerson: { handler(newName, oldName) { this.selectList = newName; }, immediate: true, deep: true }, postVisible: { handler(newName, oldName) { this.dialogVisible = newName; }, type: Boolean } }, created(){ this.treePool(); }, methods: { handleClose(){ this.dialogVisible = false; this.$emit('dialogFun', this.dialogVisible); }, next() { let list = this.selectList; let arr = []; list.forEach(item => { this.attendanceOfficerIds.push(item.id); arr.push(item.name); }) this.attendanceOfficerNameList = arr.join(","); console.log(this.attendanceOfficerIds) console.log(this.attendanceOfficerNameList) this.dialogVisible = false; //对话框打开关闭状态,选中 id 列表,选中 name 列表返回给父组件 this.$emit('dialogFun', {emita:this.dialogVisible,emitb:this.attendanceOfficerIds,emitc:this.attendanceOfficerNameList}); }, treePool () { //展示框数据 // this.selectList = [{ // id: '7387601', // name: '科技部', // nodeType: '0' // }] //树形数据 /* [{ "id": "0", "label": "学生", "nodeType": 0, "orgType": 1, "children": [ { "id": "3736461431145987660", "label": "初中部", "nodeType": 0, "orgType": 1, "children": [ { "id": "3736461431145987661", "label": "2011级", "nodeType": 0, "orgType": 1, "children": [ { "id": "3736461431145987662", "label": "3班", "nodeType": 0, "orgType": 1, "children": [ { "id": "3736461431145987663", "label": "小牛奶", "nodeType": 1, "orgType": 1, "children": null }, { "id": "3736461431145987663", "label": "小牛奶", "nodeType": 1, "orgType": 1, "children": null } ] } ] } ] } ] }] */ let that = this; let params = { //"requestId":"4333532244114", "authToken":"12312", "userToken":"26cea5f746ae4c7fbf7c3a4018b23f28", "data":{ } } this.http.post('www.centby.com/whole', params).then( res => { that.treeData = res.data; //console.log(JSON.stringify(treeData)) }, error => { console.log(error.message) } ) }, searchSelect() { console.log(this.searchWord); let that = this; let keyWord = this.searchWord; let params = { //"requestId":"userToken1574677356105xRx1", "authToken":"666", "userToken":"666", "data":{ "keyWord": keyWord } } this.http.post('www.centby.com/word', params).then( res => { console.log(JSON.stringify(res)) that.treeData = res.data }, error => { console.log(error.message) } ) }, handleCheckAllChange(val) { let all = JSON.parse(JSON.stringify(this.listId)); //console.log("all === "+all) this.checkedCities = val ? all : []; //this.isIndeterminate = false; //console.log("list === "+this.checkedCities); let that = this; let categorys = JSON.parse(JSON.stringify(this.category)); if(val === true){ //全部展示 categorys.forEach(function(item){ categorys.find(function(s){ if(s.id === item.id){ //console.log(s) that.selectList = that.selectList.concat([s]) //放入展示框,并去重 let k = {}; that.selectList = that.selectList.reduce(function (subitem, next) { k[next.id] ? '' : k[next.id] = true && subitem.push(next); return subitem; }, []); } }) }) }else{ //取消展示 categorys.forEach(function(item){ for(let j = 0;j < that.selectList.length;j++){ if(that.selectList[j].id === item.id){ that.selectList.splice(j,1); } } }) } //计算展示框数量 let j = 0; let k = 0; that.selectList.forEach(function(item){ if(item.nodeType == 0){ j++; }else if(item.nodeType == 1){ k++ } }); that.frameCount = j; that.userCount = k; }, handleCheckedCitiesChange(value) { //console.log("sub === "+JSON.stringify(value)) /* //选中 id 列表数据示例 //checkedCities = [3736461431145987743] //选择框数据示例 category = [ { "id": "3736461431145987660", "name": "初中部", "nodeType": 0 }, { "id": "3736461431145987743", "name": "小学部", "nodeType": 0 } ] * * */ let categorys = this.category; console.log("value === " + this.checkedCities ) let checkedCount = value.length; this.checkAll = checkedCount === this.category.length; //this.isIndeterminate = checkedCount > 0 && checkedCount < this.category.length; let that = this; //console.log('list = '+this.listId) let deepCopy = JSON.stringify(this.listId); let unChecked = JSON.parse(deepCopy); //选中ID展示 value.forEach(function (item) { //console.log(item) //添加到展示框 categorys.find(function(s){ if(s.id === item){ //console.log(s) that.selectList = that.selectList.concat([s]) //放入展示框,并去重 let k = {}; that.selectList = that.selectList.reduce(function (subitem, next) { k[next.id] ? '' : k[next.id] = true && subitem.push(next); return subitem; }, []); } }) //console.log('uncheck = '+JSON.stringify(unChecked)) //获取不选中的id for(let i = 0;i < unChecked.length;i++){ // /console.log(item) if(unChecked[i] == item){ unChecked.splice(i,1); } } }) //console.log('res = '+JSON.stringify(unChecked)) //把未选中的从展示框删除 unChecked.forEach(function(item){ for(let j = 0;j < that.selectList.length;j++){ if(that.selectList[j].id == item){ that.selectList.splice(j,1); } } }) //计算展示框数量 let j = 0; let k = 0; that.selectList.forEach(function(item){ if(item.nodeType == 0){ j++; }else if(item.nodeType == 1){ k++ } }); that.frameCount = j; that.userCount = k; }, delList(val){ console.log('del '+JSON.stringify(val)) //console.log('forbid = '+ this.forbid) let that = this; //let checkedMenu = JSON.parse(JSON.stringify(this.checkedCities)); let categorys = JSON.parse(JSON.stringify(that.category)); //第一步先从展示框删除 for(let j = 0;j < that.selectList.length;j++){ if(that.selectList[j].id == val){ that.selectList.splice(j,1); } } let permission = this.forbid; if(permission === true){ //禁止选择状态 //第二步拿删除当前id后的展示框列表 和 所有树形父级 id 列表对比 let hasOne = false; let parent = JSON.parse(JSON.stringify(that.parentList)); let showList = JSON.parse(JSON.stringify(that.selectList)); console.log('after == '+ JSON.stringify(showList)) console.log('parent == '+ JSON.stringify(parent)) parent.forEach(function(item){ showList.forEach(function(show){ if(show.id == item){ hasOne = true; } }) }) //没有父级,改变禁选状态为可选,并重新渲染选择框列表 if(hasOne === false){ //改变禁选状态为可选 that.forbid = false; //从展示框删除 for(let j = 0;j < that.selectList.length;j++){ if(that.selectList[j].id == val){ that.selectList.splice(j,1); } } //重新渲染选中框 that.checkAll = false; that.checkedCities = []; that.selectList.forEach(function (item) { //console.log(item) categorys.find(function(s){ if(s.id === item.id){ //console.log(s) that.checkedCities.push(item.id) //选中等于当前所有选中框列表全选操作 if(that.checkedCities.length == categorys.length){ that.checkAll = true; } } }) }) } }else{ //非禁选状态 //重新渲染选中框 for(let j = 0;j < that.checkedCities.length;j++){ if(that.checkedCities[j] == val){ that.checkedCities.splice(j,1); that.checkAll = false; } } } //计算展示框数量 let j = 0; let k = 0; that.selectList.forEach(function(item){ if(item.nodeType == 0){ j++; }else if(item.nodeType == 1){ k++ } }); that.frameCount = j; that.userCount = k; }, handleNodeClick(data) { //点击树状列表 //console.log(data); /* //选择框数据示例 { "code": 0, "message": "调用成功", "data": { "parentIds": [], "nodes": [ { "id": "3736461431145987660", "name": "初中部", "nodeType": 0 }, { "id": "3736461431145987743", "name": "小学部", "nodeType": 0 } ] } } //选中 id 数据示例 checkedCities = [3736461431145987743] //选择框展示数据示例,展示框数据结构和选择框数据结构相同,选择框选中的列表为数组结构 id 列表 category = [ { "id": "3736461431145987660", "name": "初中部", "nodeType": 0 }, { "id": "3736461431145987743", "name": "小学部", "nodeType": 0 } ] * * */ let that = this; let idx = data.id; let types = data.orgType; let params = { //"requestId":"userToken1574677356105xRx1", "authToken":"666", "userToken":"666", "data":{ "orgId": idx, "orgType": types } } this.http.post('www.centby.com/info', params).then( res => { //console.log(res) that.category = res.data.nodes; //提取所有ID并保存 let arr = []; that.category.forEach(function(item){ //console.log(item.id) arr.push(item.id) }); that.listId = arr; //所有id保存,that.listId = ['3736461431145987600','3736461431145987601','3736461431145987602']; //初始化并保存当前所有树形父级 id 列表包含自己,展示框删除操作会调用此数据 that.parentList = JSON.parse(JSON.stringify(res.data.parentIds)); console.log('parent = '+ JSON.stringify(that.parentList)); //初始化禁选判断,禁选,全选按钮,已选中 let permission = false; that.forbid = false; that.checkAll = false; that.checkedCities = []; //使用JSON转换解决深拷贝问题 let parent = JSON.parse(JSON.stringify(that.parentList)); let showList = JSON.parse(JSON.stringify(that.selectList)); //每次点击树状列表,拿当前所有树形父级 id 列表(parentIds)包含自己,和展示框列表 id 对比,如果有,选择框展示全部全选并且禁止状态 //展示框删除动作,会取此禁选状态做展示框删除动作 parent.forEach(function(item){ showList.forEach(function(show){ if(show.id == item){ permission = true; } }) }) if(permission == true){ //禁止选择操作 that.checkedCities = that.listId; that.checkAll = true; that.forbid = true; // that.selectList.forEach(function (item) { // if(item.id == idx){ // that.checkedCities = that.listId; // that.checkAll = true; // that.forbid = true; // } // }) }else{ //不禁止状态回显渲染 that.selectList.forEach(function (item) { //console.log(item) that.category.find(function(s){ if(s.id === item.id){ //console.log(s) that.checkedCities.push(item.id) //选中等于当前所有选中框列表全选操作 if(that.checkedCities.length == that.listId.length){ that.checkAll = true; } } }) }) } }, error => { console.log(error.message) } ) }, } } </script> <style scoped lang="scss"> .box >>> .el-checkbox { display: block; } .chosen-modal { display: flex; height: 598px; padding: 15px; border-top: 1px solid #eee; border-bottom: 1px solid #eee; } .chosen-modal-left { width: 430px; } .chosen-modal-hd { padding: 20px; display: flex; border-top: 1px solid #dddee1; border-right: 1px solid #dddee1; border-left: 1px solid #dddee1; } .chosen-modal-hd .chosen-modal-hd-search { position: relative; flex: 1; } .chosen-modal-hd .chosen-modal-hd-search i { width: 32px; height: 32px; line-height: 32px; font-size: 16px; text-align: center; color: #80848f; position: absolute; right: 0; z-index: 1; cursor: pointer; } .aui-input { display: inline-block; width: 100%; height: 32px; line-height: 1.5; padding: 4px 32px 4px 7px; box-sizing: border-box; font-size: 12px; border: 1px solid #dddee1; border-radius: 4px; color: #6e7d8f; background-color: #fff; background-image: none; position: relative; cursor: text; transition: border .2s ease-in-out,background .2s ease-in-out,box-shadow .2s ease-in-out; } .chosen-modal-bd { display: flex; height: 526px; border: 1px solid #dddee1; } .chosen-left { margin-top: -1px; width: 200px; min-width: 200px; height: 525px; overflow-y: auto; position: absolute; background: #fff; z-index: 2; overflow-x: hidden; border-top: 1px solid #dddee1; border-right: 1px solid #dddee1; } .chosen-left-device { margin-top: -1px; width: 200px; min-width: 200px; height: 525px; overflow-y: auto; position: absolute; background: #fff; z-index: 2; overflow-x: hidden; border-top: 1px solid #dddee1; } .chosen-right { flex: 1; padding-left: 200px; z-index: 1; overflow-y: scroll; } .chosen-right .el-checkbox { padding: 10px 15px; color: #0cb181; } .aui-checkbox-label { align-items: center; width: 100%; white-space: normal; word-wrap: break-word; word-break: break-all; margin-bottom: 0; line-height: 1.3; } .chosen-modal-right { flex: 1; border: 1px solid #dddee1; margin-left: 20px; } .chosen-modal-right-hd { padding: 20px; } .chosen-modal-right-bd { height: 538px; overflow: auto; } .chosen-person-org { display: flex; padding: 6px 20px; height: 20px; align-items: center; } .chosen-modal-right-bd>div>i { font-size: 12px; color: #0cb181; margin-right: 5px; align-self: baseline; position: relative; top: 6px; } .chosen-modal-right-bd>div>span { flex: 1; word-wrap: break-word; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; word-break: break-all; overflow: hidden; } </style> 
原文链接:https://yq.aliyun.com/articles/734373
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章