使用el-select二次封裝tree下拉多選框

<!--

????/**

?????*?樹形下拉選擇組件,下拉框展示樹形結(jié)構(gòu),提供選擇某節(jié)點(diǎn)功能,方便其他模塊調(diào)用

?????*?@author?wz

?????*?@date?2020-06-09

?????*?調(diào)用示例:

?????*?<tree-select?:height="400"?//?下拉框中樹形高度

?????*??????????????:width="200"?//?下拉框中樹形寬度?不填寫自適應(yīng)el-select?input框大小

?????*??????????????size="small"??//?輸入框的尺寸:?medium/small/mini

?????*??????????????:data="data"?//?樹結(jié)構(gòu)的數(shù)據(jù)或者普通包含主鍵,父主鍵的普通集合

????????????????????:obj="{}"????//可自定義字段,字段映射如下

?????*??????????????multiple???//?多選

????????????????????//默認(rèn)值:單選可傳入數(shù)字,字符串,對象;多選傳入【數(shù)字|字符|對象】數(shù)組,其他非法

????????????????????:default-key="..."

?????*??????????????clearable???//?可清空選擇

?????*??????????????collapseTags???//?多選時將選中值按文字的形式展示

????????????????????expand-click-node???//點(diǎn)擊節(jié)點(diǎn)自動展開。多選有效

????????????????????check-click-node?//?是否點(diǎn)擊節(jié)點(diǎn)是選中?多選生效

?????*??????????????checkStrictly?//?多選時,嚴(yán)格遵循父子不互相關(guān)聯(lián)?效果參考elementui?對應(yīng)屬性效果

?????*??????????????@getValue="父組件獲取值方法">?//?事件有兩個參數(shù):第一個是所有選中的節(jié)點(diǎn)ID,第二個是所有選中的節(jié)點(diǎn)數(shù)據(jù)

?????*??????????????</tree-select>

??????<select-tree

?????obj?字段映射如下,值填寫你實(shí)際字段,可拓展字段。最終返回主鍵以及選擇對象【全部字段】

????????????????????????id:'id',//可改成自己對應(yīng)主鍵【改值】

????????????????????????label:?'name',//?顯示名稱

????????????????????????children:?'children',?//子級字段名

????????????????????????path:'path',//路徑

????????????????????????content:'content',//描述

????????????????????????pid:'pid',//父id

?????*/

-->

<template>

??<div?id="treeSelect">

????<div?class="mask"

?????????v-show="isShowSelect"></div>

????<el-popover?placement="top-start"

????????????????title=""

????????????????trigger="manual"

????????????????v-model="isShowSelect"

????????????????@hide="popoverHide">

??????<div?class="mrb10">

????????<el-input?placeholder="輸入關(guān)鍵字進(jìn)行過濾"

??????????????????v-model="filterText"

??????????????????size="small">

????????</el-input>

??????</div>

??????<el-tree?class="common-tree"

???????????????width="width"

???????????????style="height:300px"

???????????????ref="tree"

???????????????:data="data"

???????????????:props="obj"

???????????????:show-checkbox="multiple"

???????????????:node-key="obj.id"

???????????????:check-strictly="checkStrictly"

???????????????:default-expanded-keys="defaultKey"

???????????????:default-checked-keys="checkKeys"

???????????????:expand-on-click-node="multiple&&expandClickNode"

???????????????:check-on-click-node="checkClickNode"

???????????????:highlight-current="true"

???????????????@check-change="nodeClick"

???????????????:filter-node-method="filterNode"

???????????????@node-click="nodeClick"></el-tree>

??????<el-select?slot="reference"

?????????????????ref="select"

?????????????????:size="size"

?????????????????popper-class="operateDropOption"

?????????????????:popper-append-to-body="true"

?????????????????style="width:?300px"

?????????????????v-model="returnDataKeys"

?????????????????:multiple="multiple"

?????????????????:clearable="clearable"

?????????????????:collapse-tags="collapseTags"

?????????????????@click.native="selectClick"

?????????????????@remove-tag="removeTag"

?????????????????@clear="clean"

?????????????????class="tree-select">

????????<el-option?v-for="item?in?options"

???????????????????:key="item.value"

???????????????????:label="item.label"

???????????????????:value="item.value"></el-option>

??????</el-select>

??????<el-row>

????????<!--?<el-button?v-if="multiple"

???????????????????class="ok"

???????????????????@click="isShowSelect=false"

???????????????????size="mini"

???????????????????type="text">確定</el-button>?-->

??????</el-row>

????</el-popover>

??</div>

</template>


<script>

export?default?{

??name:?"tree-select",

??props:?{

????//?樹結(jié)構(gòu)數(shù)據(jù)

????data:?{

??????type:?Array,

??????default()?{

????????return?[];

??????}

????},

????obj:?{

??????type:?Object,

??????required:?false,

??????default:?()?=>?{

????????return?{

??????????id:?'value',//?ID

??????????label:?'label',//?顯示名稱

??????????children:?'children',?//子級字段名

??????????path:?'path',//路徑

??????????content:?'content',//描述

??????????pid:?'pid',//父id

????????}

??????}

????},

????//?配置是否可多選

????multiple:?{

??????type:?Boolean,

??????default()?{

????????return?true;

??????}

????},

????//?配置是否可清空選擇

????clearable:?{

??????type:?Boolean,

??????default()?{

????????return?false;

??????}

????},

????//?配置多選時是否將選中值按文字的形式展示

????collapseTags:?{

??????type:?Boolean,

??????default()?{

????????return?false;

??????}

????},

????//?顯示復(fù)選框情況下,是否嚴(yán)格遵循父子不互相關(guān)聯(lián)

????checkStrictly:?{

??????type:?Boolean,

??????default()?{

????????return?false;

??????}

????},

????//多選是設(shè)置點(diǎn)擊節(jié)點(diǎn)是否可以選中

????checkClickNode:?{

??????type:?Boolean,

??????default()?{

????????return?false;

??????}

????},

????//多選時:點(diǎn)擊節(jié)點(diǎn)展開還是點(diǎn)三角標(biāo)

????expandClickNode:?{

??????type:?Boolean,

??????default()?{

????????return?false;

??????}

????},

????//?默認(rèn)選中的節(jié)點(diǎn)key

????defaultKey:?{

??????type:?[Number,?String,?Array,?Object],

??????default()?{

????????return?[''];

??????}

????},

????checkKeys:?{

??????type:?[Number,?String,?Array,?Object],

??????default()?{

????????return?[''];

??????}

????},

????size:?{

??????type:?String,

??????default()?{

????????return?'small';

??????}

????},

????width:?{

??????type:?String,

??????default()?{

????????return?'100%';

??????}

????},

????height:?{

??????type:?String,

??????default()?{

????????return?'100%';

??????}

????},

??},

??data()?{

????return?{

??????filterText:?'',

??????popoverWidth:?"300px",//下拉框大小

??????isShowSelect:?false,?//?是否顯示樹狀選擇器

??????options:?[],//select?option選項(xiàng)

??????returnDatas:?[],//返回給父組件數(shù)組對象

??????returnDataKeys:?[],//返回父組件數(shù)組主鍵值

????};

??},

??computed:?{

????//?treeData()?{?//?若非樹狀結(jié)構(gòu),則轉(zhuǎn)化為樹狀結(jié)構(gòu)數(shù)據(jù)

????//???return?JSON.stringify(this.data).indexOf(this.obj.children)?!==?-1???this.data?:?this.switchTree();

????//?},

??},

??mounted()?{

????this.nodeClick()

????addEventListener('click',?(val)?=>?{

??????this.isShowSelect?=?false

????})

??},

??deactivated()?{

????this.clean()

??},

??methods:?{

????init()?{

??????//?eslint-disable-next-line?no-undef,no-debugger

??????//?debugger

??????if?(this.defaultKey?!=?undefined?&&?this.defaultKey.length?>?0)?{

????????if?(this.multiple)?{

??????????//?多選

??????????if?(Object.prototype.toString.call(this.defaultKey).indexOf("Array")?!=?-1)?{

????????????if?(Object.prototype.toString.call(this.defaultKey[0]).indexOf("Object")?!=?-1)?{//對象

??????????????this.setDatas(this.defaultKey);

????????????}?else?if?(Object.prototype.toString.call(this.defaultKey[0]).indexOf("Number")?!=?-1

??????????????||?Object.prototype.toString.call(this.defaultKey[0]).indexOf("String")?!=?-1)?{

??????????????this.setKeys(this.defaultKey);

????????????}?else?{

??????????????//?console.log("多選:傳入?yún)?shù)類型不匹配");

??????????????return;

????????????}

??????????}?else?{

????????????//?console.log("多選:傳入?yún)?shù)類型不匹配");

????????????return;

??????????}

????????}?else?{

??????????//?單選

??????????if?(Object.prototype.toString.call(this.defaultKey).indexOf("Number")?!=?-1

????????????||?Object.prototype.toString.call(this.defaultKey).indexOf("String")?!=?-1

????????????||?Object.prototype.toString.call(this.defaultKey).indexOf("Object")?!=?-1)?{

????????????this.setKey(this.defaultKey);

??????????}?else?{

????????????//?console.log("單選:傳入?yún)?shù)類型不匹配");

????????????return;

??????????}

????????}

??????}

????},

????//下拉框select點(diǎn)擊[入口]

????selectClick()?{

??????this.$nextTick(function?()?{//設(shè)置下拉框自適應(yīng)寬度

????????this.popoverWidth?=?this.$refs.select.$el.clientWidth?-?26;

??????})

??????//顯示下拉框

??????return?this.isShowSelect?=?!this.isShowSelect

????},

????//單選:?樹點(diǎn)擊方法

????nodeClick(data,?node)?{

??????if?(!this.multiple)?{//單選

????????this.isShowSelect?=?false;

????????this.setKey(node.key);

??????}?else?{//多選

????????var?checkedNodes?=?this.$refs.tree.getCheckedNodes(true,?false);?//?所有被選中的節(jié)點(diǎn)

????????var?t?=?[];

????????//?數(shù)組去重

????????const?map?=?new?Map()

????????checkedNodes.forEach((item)?=>?{

??????????if?(!map.has(item['id']))?{

????????????map.set(item['id'],?item)

??????????}

????????})

????????const?newCheckedNodes?=?[...map.values()]

????????var?checkedKeys?=?newCheckedNodes.map(item?=>?item.id)?//?所有被選中的節(jié)點(diǎn)的?key?所組成的數(shù)組數(shù)據(jù)

????????this.options?=?checkedKeys.map((item)?=>?{//設(shè)置option選項(xiàng)

??????????var?node?=?this.$refs.tree.getNode(item);?//?所有被選中的節(jié)點(diǎn)對應(yīng)的node

??????????t.push(node.data);

??????????return?{?label:?node.label,?value:?node.key?};

????????});

????????this.returnDataKeys?=?this.options.map((item)?=>?{

??????????return?item.value;

????????});

????????this.$emit('change',?this.returnDataKeys)

????????this.returnDatas?=?t;

??????}

????},

????filterNode(value,?data)?{

??????if?(!value)?return?true;

??????return?data.label.indexOf(value)?!==?-1;

????},

????//單選:清空選中

????clean()?{

??????this.$refs.tree.setCurrentKey(null);//清除樹選中key

??????this.returnDatas?=?null;?this.returnDataKeys?=?'';

??????this.popoverHide();

??????this.isShowSelect?=?false;

??????this.$refs.tree.setCheckedKeys([]);

??????this.$refs.tree.setChecked([]);

??????//折疊全部節(jié)點(diǎn)

??????for?(let?i?=?0;?i?<?this.$refs.tree.store._getAllNodes().length;?i++)?{

????????this.$refs.tree.store._getAllNodes()[i].expanded?=?false;

??????}

????},

????//單選:設(shè)置、初始化值?key

????setKey(thisKey)?{

??????this.$refs.tree.setCurrentKey(thisKey);

??????var?node?=?this.$refs.tree.getNode(thisKey);

??????this.setData(node.data);

????},

????//單選:設(shè)置、初始化對象

????setData(data)?{

??????this.options?=?[];

??????this.options.push({?label:?data[this.obj.label],?value:?data[this.obj.id]?});

??????this.returnDatas?=?data;

??????this.returnDataKeys?=?data[this.obj.id]

????},

????//多選:設(shè)置、初始化值?keys

????setKeys(thisKeys)?{

??????this.$refs.tree.setCheckedKeys(thisKeys);

??????this.returnDataKeys?=?thisKeys;

??????var?t?=?[];

??????thisKeys.map((item)?=>?{//設(shè)置option選項(xiàng)

????????var?node?=?this.$refs.tree.getNode(item);?//?所有被選中的節(jié)點(diǎn)對應(yīng)的node

????????t.push(node.data);

????????return?{?label:?node.label,?value:?node.key?};

??????});

??????this.returnDatas?=?t;

??????this.popoverHide()

????},

????//多選:設(shè)置、初始化對象

????setDatas(data)?{

??????this.$refs.tree.setCheckedNodes(data);

??????this.returnDatas?=?data;

??????var?t?=?[];

??????data.map((item)?=>?{//設(shè)置option選項(xiàng)

????????t.push(item[this.obj.id]);

??????});

??????this.returnDataKeys?=?t;

??????this.popoverHide()

????},

????//?多選,刪除任一select選項(xiàng)的回調(diào)

????removeTag(val)?{

??????this.$refs.tree.setChecked(val,?false);//設(shè)置為未選中

??????var?node?=?this.$refs.tree.getNode(val);//獲取節(jié)點(diǎn)

??????if?(!this.checkStrictly?&&?node.childNodes.length?>?0)?{

????????this.treeToList(node).map(item?=>?{

??????????if?(item.childNodes.length?<=?0)?{

????????????this.$refs.tree.setChecked(item,?false);

??????????}

????????});

??????}

??????this.nodeClick();

??????this.popoverHide();

????},

????//下拉框關(guān)閉執(zhí)行

????popoverHide()?{

??????this.$emit('getValue',?this.returnDataKeys,?this.returnDatas);

????},

????//?多選,清空所有勾選

????clearSelectedNodes()?{

??????var?checkedKeys?=?this.$refs.tree.getCheckedKeys();?//?所有被選中的節(jié)點(diǎn)的?key?所組成的數(shù)組數(shù)據(jù)

??????for?(let?i?=?0;?i?<?checkedKeys.length;?i++)?{

????????this.$refs.tree.setChecked(checkedKeys[i],?false);

??????}

????},

????//樹形轉(zhuǎn)為集合

????treeToList(tree)?{

??????var?queen?=?[];

??????var?out?=?[];

??????queen?=?queen.concat(tree);

??????while?(queen.length)?{

????????var?first?=?queen.shift();

????????if?(first.childNodes)?{

??????????queen?=?queen.concat(first.childNodes);

????????}

????????out.push(first);

??????}

??????return?out;

????},

????//?switchTree()?{

????//???return?this.buildTree(this.data,?this.defaultValue);

????//?},

????//?將一維的扁平數(shù)組轉(zhuǎn)換為多層級對象

????//?buildTree(data,?id)?{

????//???const?fa?=?(id)?=>?{

????//?????const?temp?=?[];

????//?????for?(let?i?=?0;?i?<?data.length;?i++)?{

????//???????const?n?=?data[i];

????//???????if?(n[this.obj.pid]?===?id)?{

????//?????????n[this.obj.children]?=?fa(n[this.obj.id]);

????//?????????temp.push(n);

????//???????}

????//?????}

????//?????return?temp;

????//???};

????//???return?fa(id);

????//?},

??},

??watch:?{

????//?eslint-disable-next-line?no-unused-vars

????isShowSelect(val)?{

??????//?隱藏select自帶的下拉框

??????if?(!val)?{

????????this.$refs.select.blur();

??????}

????},

????checkKeys:?{

??????handler(newValue,?oldValue)?{

????????this.returnDataKeys?=?newValue;

??????},

??????deep:?true,

??????immediate:?true

????},

????//?treeData()?{//監(jiān)聽tree數(shù)據(jù)

????//???this.$nextTick(()?=>?{

????//?????this.init();

????//???})

????//?},

????filterText(val)?{

??????this.$nextTick(()?=>?{

????????this.$refs.tree.filter(val);

??????})

????}

??}

};

</script>


<style?scoped>

.mask?{

??height:?300px;

??position:?fixed;

??top:?300px;

??left:?0;

??opacity:?0;

??z-index:?11;

}

.common-tree?{

??overflow:?auto;

}

.tree-select?{

??z-index:?111;

}

.ok?{

??float:?right;

}

.el-row?{

??padding-top:?0px?!important;

}

.checkall-box?{

??width:?100%;

??height:?40px;

??line-height:?40px;

??border-bottom:?1px?solid?#fff;

}

.el-popover?{

??min-width:?300px?!important;

}

</style>

<style?lang="less">

.el-popover?{

??min-width:?274px;

}

/*?隱藏默認(rèn)下拉?*/

.operateDropOption.el-select-dropdown__empty?{

??display:?none;

}

.operateDropOption.el-select-dropdown__list?{

??display:?none;

}

.operateDropOption.el-select-dropdown?{

??display:?none;

}

//?滾動條

::-webkit-scrollbar?{

??max-width:?12px;

??height:?8px;

??background-color:?#fff?!important;

}

::-webkit-scrollbar-thumb?{

??border-radius:?8px;

??background-color:?#d8dce0?!important;

??border-style:?solid;

??border-color:?transparent;

??border-width:?2px;

??background-clip:?padding-box;

}

::-webkit-scrollbar-track?{

??border-radius:?12px;

??border-radius:?0?!important;

??background-color:?#fff?!important;

}

</style>



調(diào)用:

<template>

??<tree-select?:height="height"

???????????????width="width"

???????????????size="small"

???????????????:data="dataList"

???????????????:obj="obj"

???????????????multiple

???????????????:default-key="defaultKey"

???????????????:checkKeys="checkKeys"

???????????????clearable

???????????????collapseTags

???????????????expand-click-node

???????????????check-click-node

???????????????@change="change">

??</tree-select>

</template>


<script>

import?TreeSelect?from?'../tree-select/tree-select.vue';

import?{?DeviceService?}?from?"@/service";

export?default?{

??components:?{

????TreeSelect

??},

??data()?{

????return?{

??????defaultKey:?[],

??????dataList:?[],

????};

??},

??props:?{

????value:?[String,?Array],?????????//?選擇的值

????width:?{

??????type:?String,

??????default()?{

????????return?'300px';

??????}

????},

????height:?{

??????type:?String,

??????default()?{

????????return?'200px';

??????}

????},

????obj:?{

??????type:?Object,

??????required:?false,

??????default:?()?=>?{

????????return?{

??????????id:?'id',//?ID

??????????label:?'label',//?顯示名稱

??????????children:?'children',?//子級字段名

??????????path:?'path',//路徑

??????????content:?'content',//描述

??????????pid:?'pid',//父id

????????}

??????}

????},

??},

??watch:?{

????value:?{

??????handler(newValue,?oldValue)?{

????????this.checkKeys?=?newValue;

????????this.defaultKey?=?newValue;

????????this.$emit("input",?newValue);

??????},

??????deep:?true,

??????immediate:?true

????},

??},

??created()?{

????this.getDeviceGroupTree();

??},

??methods:?{

????change(val)?{

??????this.$emit("input",?val);

??????this.$emit("onChange",?val);

????},

????//?獲取機(jī)型組樹形數(shù)據(jù)

????getDeviceGroupTree()?{

??????DeviceService.getDeviceGroupTree().then(res?=>?{

????????if?(res?&&?res.data)?{

??????????this.dataList?=?res.data.data

????????}

??????})

????}

??}

};

</script>


<style??lang="less"?>

</style>

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容