0


Element-UI实现的下拉搜索树组件(el-select、el-input、el-tree组合使用)

一、效果图

在这里插入图片描述

二、代码(此代码是基于自己项目更改,根据各自项目进行调整)

1、子组件封装
注意使用:正常使用

// 在el-tree触发@check-change="checkChange" 事件,方法如下:checkChange(){// 节点选中状态更改// 获取选中的node节点let selectedArray =this.getCheckedNodes();// 设置select展示的labelthis.selectShowLabel = selectedArray.map(node=> node[this.defaultProps.label]);// 更新model绑定值let selectValueArray = selectedArray.map(node=> node[this.defaultProps.value]);this.$emit("changeChecked", selectValueArray)},
正常使用的情况下可以不需要这些,个人需求需要
  useData:{type: Array,default:()=>[]},item:{type: Object,default:()=>{}},initData:{type: Object,default:()=>{}},// 因项目需求不一致,故使用了@check="checkChange(useData, item,initData)" @check-change="onSetCheckedNodes"两种

// 子组件使用

<template><div class="root"><el-select v-model="selectShowLabel":clearable="clearable":placeholder="placeholder"multiple:collapse-tags="collapseTags":popper-append-to-body="false" @blur="handleBlur" @visible-change="visibleChange" @change="changeHandle" @clear="clear" @remove-tag="removeTag"><el-option :value="selectShowLabel"disabled:style="'margin:5px'"><el-input v-model="filterText" size="small" prefix-icon="el-icon-search" clearable placeholder="输入关键字进行查找"></el-input></el-option><el-tree ref="tree":data="treeData":expand-on-click-node="false" check-on-click-node check-strictly show-checkbox :node-key="defaultProps.value":props="defaultProps":default-expand-all="expandAll":filter-node-method="filterNode" @check="checkChange(useData, item,initData)" @check-change="onSetCheckedNodes"></el-tree></el-select></div></template><script>import CircularJSON from'circular-json';exportdefault{model:{prop:'checkedArray',// 把父组件传过来的值重命名为checkedArrayevent:'changeChecked'// 把父组件传过来的方法重命名为changeChecked 其实就是 input},props:{// 选中节点的值checkedArray:{type: Array,default:()=>{return[];}},// 树数据treeData:{type: Array,required:true},useData:{type: Array,default:()=>[]},item:{type: Object,default:()=>{}},initData:{type: Object,default:()=>{}},// 设置指定的label,value,childrennodeConfig:{type: Object,default:()=>{return{value:'code',label:'name',children:'childrenList'};}}},data(){return{// 用于下拉列表展示selectShowLabel:'',// 筛选输入框绑定值filterText:'',placeholder:'请选择',clearable:true,// 开启下拉框一键清空collapseTags:true,// 下拉框tag是否折叠expandAll:false,// 是否展开所有节点modelData:[],modelList:[],modelListData:[],filtraArr:[],filterMessage:''};},computed:{defaultProps(){return Object.assign({value:'code',label:'name',children:'childrenList'},this.nodeConfig
      );}},watch:{// 设置回显checkedArray:{handler(val){if(val && val.length >0){this.setCheckedNodes(val);}},// 监听第一次数据更改immediate:true},// 筛选符合条件选项filterText(val){this.$refs.tree.filter(val);this.getFilterData();}},methods:{onSetCheckedNodes(data){this.filtraArr =[data.code];},visibleChange($event){if(!$event){this.filterText ='';}},// el-select失去焦点后校验handleBlur(val){this.$emit('blur', val.target.value);this.dispatch('ElFormItem','el.form.blur',[this.checkedArray]);},// el-select清空树选择的内容clear(){this.$emit('changeChecked',[]);this.$refs.tree.setCheckedKeys([]);},// el-select选择值发生改变后校验changeHandle(){this.dispatch('ElFormItem','el.form.change',[this.checkedArray]);},// select移除选中标签removeTag(label){// 选中项的valuelet selectedValueArray =this.$refs.tree
        .getCheckedNodes().filter((o)=> o[this.defaultProps.label]!== label).map((o)=> o[this.defaultProps.value]);// 移除的节点let removeNode =this.$refs.tree
        .getCheckedNodes().filter((o)=> o[this.defaultProps.label]=== label);// 更新树选中节点
      removeNode.forEach((o)=>{this.$refs.tree.setChecked(o,false,true);});// 更新父组件绑定值this.$emit('changeChecked', selectedValueArray);},// 树节点过滤方法filterNode(value, data){if(!value)returntrue;return data[this.defaultProps.label].indexOf(value)!==-1;},getFilterData(){if(this.filterText){const rootData =this.$refs.tree.root;if(rootData.visible){const childNodesStr = CircularJSON.stringify(rootData.childNodes);const childNodes = CircularJSON.parse(childNodesStr);this.filterData =this.recursionNodes(childNodes);this.filterMessage ='';}else{this.filterMessage ='暂无数据';}}},// 这里解释一下为什么要用CircularJSON这个插件,因为element tree 这node数据存在一个对象里的子项存在循环引用,存在循环引用的对象recursionNodes(childNodes){const nodes = childNodes;const result =[];for(const item of nodes){if(item.visible){
          result.push(item.data);}if(item.childNodes && item.childNodes.length){const tempResult =this.recursionNodes(item.childNodes);
          item.data.children = tempResult;}}return result;},// 获取选中节点getCheckedNodes(){let onlyLeaf =true;returnthis.$refs.tree.getCheckedNodes(onlyLeaf).map((node)=>({[this.defaultProps.label]: node[this.defaultProps.label],[this.defaultProps.value]: node[this.defaultProps.value]}));},// 设置选中节点asyncsetCheckedNodes(selectedArray){if(!selectedArray || selectedArray.length ===0){this.clear();return;}// 外层"this.$nextTick"处理第一次回显dom可能未加载导致setCheckedKeys报错this.$nextTick(()=>{this.$refs.tree.setCheckedKeys(selectedArray);});},// 过滤出当前点击得codefiltrationArr(arr, arr1){const tempArr =[];
      arr.forEach((item)=>{const itemStr = item.toString();let flag =false;
        arr1.forEach((item1)=>{const itemStr1 = item1.toString();if(itemStr === itemStr1){
            flag =true;}});if(!flag){
          tempArr.push(item);}});return tempArr;},// 数据将属性结构扁平化treeArr(data, parentCode, res =[]){
      data.forEach((item)=>{const{ code, name, level, childrenList }= item;
        res.push({code: code,parentCode: parentCode,name: name,level: level
        });if(childrenList && childrenList.length){this.treeArr(childrenList, code, res);}});return res;},// 节点选中状态更改checkChange(model, item, initData){let filtraArr =null;// 1、树结构扁平化处理数组放到vuexthis.$store.commit('cascaderData',this.treeArr(item.options));// 2、记录点击选中与上一次得数据if(this.modelData.length ===0){this.modelData =[...this.$refs.tree.getCheckedNodes()];}else{this.modelListData =[...this.modelList];this.modelList =[...this.modelData];this.modelData =[...this.$refs.tree.getCheckedNodes()];}// 3、过滤出当前选中得数据(判断选中数据大于等2是且记录数据不为0,并且选中数据大于记录数据)if(this.modelData.length >=1&&this.modelList.length !==0){let modelData =[];let modelList =[];let modelListData =[];this.modelData.forEach((item)=>{
          modelData.push(item.code);});this.modelList.forEach((item)=>{
          modelList.push(item.code);});this.modelListData.forEach((item)=>{
          modelListData.push(item.code);});
        filtraArr =this.filtraArr;}// 4、根据选中得值跟 扁平化数据对比if(filtraArr !==undefined&& filtraArr !==null){let flatData =this.$store.state.user.cascaderData;// 扁平数据let currentValue = filtraArr[0];let currentNode = flatData.filter((item)=> item.code === currentValue
        )[0];let parent = flatData.filter((item)=> item.code === currentNode.parentCode
        )[0];let count =1;const deleteCodes =[];if(parent !==undefined){
          deleteCodes.push(parent.code);// 往上寻找while(parent.level !=='1'&& count <10){
            parent = flatData.filter((item)=> item.code === parent.parentCode
            )[0];
            deleteCodes.push(parent.code);
            count++;}}let childrenNodes = flatData.filter((item)=> item.parentCode === currentValue
        );let childrenCodes =[];
        childrenNodes.forEach((item)=>{
          childrenCodes.push(item.code);});while(childrenCodes.length >0){const code = childrenCodes.shift();
          deleteCodes.push(code);const children = flatData.filter((item)=> item.parentCode === code);if(children.length >0){
            children.forEach((item)=>{
              childrenCodes.push(item.code);});}}const modelArr =[];const modelAller =[];this.modelData.forEach((item)=>{
          modelAller.push(item.code);});
        modelAller.forEach((item)=>{let deleteState = deleteCodes.indexOf(item);if(deleteState ===-1){if(filtraArr[0]=== item){
              modelArr.unshift(item);}else{
              modelArr.push(item);}}});let modelArrData =[];
        modelArr.forEach((items)=>{let tree = flatData.filter((item)=> item.code === items);
          modelArrData.push({code: tree[0].code,name: tree[0].name
          });});// // 设置select展示的labelthis.selectShowLabel = modelArrData.map((node)=> node[this.defaultProps.label]);// // // 更新model绑定值let selectValueArray = modelArrData.map((node)=> node[this.defaultProps.value]);this.$emit('changeChecked', selectValueArray);}elseif(this.modelData.length ===1){this.selectShowLabel =this.modelData.map((node)=> node[this.defaultProps.label]);// // // 更新model绑定值let selectValueArray =this.modelData.map((node)=> node[this.defaultProps.value]);this.$emit('changeChecked', selectValueArray);}},// 提供表单校验dispatch(componentName, eventName, params){var parent =this.$parent ||this.$root;var name = parent.$options.componentName;while(parent &&(!name || name !== componentName)){
        parent = parent.$parent;if(parent){
          name = parent.$options.componentName;}}if(parent){
        parent.$emit.apply(parent,[eventName].concat(params));}}}};</script><style lang="scss" scoped>::v-deep .el-input .el-input__inner {height: 34px;
  line-height: 34px;}</style>

父组件调用

<template><div id="app"><selectTree v-model="address" placeholder="请选择地址":tree-data="mockData"/></div></template><script>import selectTree from'./components/selectTree.vue'exportdefault{name:'App',components:{
    selectTree
  },data(){return{address:[],
    mockData:[],// 树形结构数据}}}</script>
标签: javascript vue.js

本文转载自: https://blog.csdn.net/weixin_44979432/article/details/129835086
版权归原作者 你说的誓言°变失言 所有, 如有侵权,请联系我们删除。

“Element-UI实现的下拉搜索树组件(el-select、el-input、el-tree组合使用)”的评论:

还没有评论