手把手教學~基於element封裝tree樹狀下拉框
在日常專案開發中,樹狀下拉框的需求還是比較常見的,但是element並沒有這種元件以供使用。在這裡,小編就基於element如何封裝一個樹狀下拉框做個詳細的介紹。
通過這篇文章,你可以瞭解學習到一個樹狀下拉框元件是如何一步一步封裝成功的。
話不多說,先看效果圖:
封裝元件
該元件主要基於element的select元件、tree元件及input元件進行二次封裝的。
元件佈局
首先我們需要基於這幾個元件對我們的元件進行佈局,話不多說直接上程式碼:
<template> <el-select ref="select"> <el-option class="options"> <el-tree id="tree-option" ref="selectTree" > </el-tree> </el-option> </el-select> </template> <style scoped> .el-scrollbar .el-scrollbar__view .el-select-dropdown__item{ height: auto; max-height: 274px; padding: 0; overflow: hidden; overflow-y: auto; } .el-select-dropdown__item.selected{ font-weight: normal; } ul li >>>.el-tree .el-tree-node__content{ height:auto; padding: 0 20px; } .el-tree-node__label{ font-weight: normal; } .el-tree >>>.is-current .el-tree-node__label{ color: #409EFF; font-weight: 700; } .el-tree >>>.is-current .el-tree-node__children .el-tree-node__label{ color:#606266; font-weight: normal; } </style>
注:css新增scoped屬性,是為了讓css只在該元件生效,避免樣式汙染
這個時候直接使用肯定是會報錯的,因為我們元件該傳的引數還未傳遞。
元件資料完善
上面我們已經完成了佈局,接下來就是為其豐富資料了,因為我們這個元件肯定是複用的,因此我們設計資料的時候,需要把常用的資料屬性提取出來通過props傳遞接收。我提取的主要有幾下幾個資料:
props:{ /* 配置項 */ props:{ type: Object, default:()=>{ return { value:'id', // ID欄位名 label: 'title', // 顯示名稱 children: 'children' // 子級欄位名 } } }, /* 選項列表資料(樹形結構的物件陣列) */ options:{ type: Array, default: ()=>{ return [] } }, /* 初始值 */ value:{ default: ()=>{ return null } }, /* 可清空選項 */ clearable:{ type:Boolean, default:()=>{ return true } }, /* 自動收起 */ accordion:{ type:Boolean, default:()=>{ return false } }, placeholder:{ type:String, default:()=>{return "請選擇"} } },
大家可能注意到,我所有prop欄位都給了type屬性,唯獨value沒有,這是因為在實際使用中下拉框的資料value值可能是字串(String)也可能是數字(Number),為了專案開發中控制檯不報太多無意義的錯,此處就沒有規定其type。
接收到prop之後,我們就開始對元件進行資料的處理,直接上程式碼:
<template> <el-select :placeholder="placeholder" ref="select"> <el-option class="options"> <el-tree id="tree-option" ref="selectTree" :accordion="accordion" :data="options" :props="props" :node-key="props.value" :default-expanded-keys="[]" > </el-tree> </el-option> </el-select> </template>
當資料過多的時候,滾動條會出現兩條,如下所示:
處理方法如下:
// 初始化滾動條
initScroll(){
this.$nextTick(()=>{
let scrollWrap = document.querySelectorAll('.el-scrollbar .el-select-dropdown__wrap')[0]
let scrollBar = document.querySelectorAll('.el-scrollbar .el-scrollbar__bar')
scrollWrap.style.cssText = 'margin: 0px; max-height: none; overflow: hidden;'
scrollBar.forEach(ele => ele.style.width = 0)
})
},
在mounted
中呼叫該方法就可以了,效果如下:
點選選中
資料也渲染顯示出來了,這個時候我們需要實現點選資料選中功能。
思路很簡單:
- select元件繫結value值
- tree元件繫結節點點選事件
- 點選事件中獲取value和label
- 將獲取的值賦給select元件以及返回給父元件
程式碼如下:
<template>
<el-select :value="valueTitle" :placeholder="placeholder" ref="select">
<el-option :value="valueTitle" :label="valueTitle" class="options">
<el-tree id="tree-option"
ref="selectTree"
:accordion="accordion"
:data="options"
:props="props"
:node-key="props.value"
:default-expanded-keys="defaultExpandedKey"
@node-click="handleNodeClick"
>
</el-tree>
</el-option>
</el-select>
</template>
data() {
return {
valueId:this.value,// 初始值
valueTitle:'',
defaultExpandedKey:[]
}
},
// 切換選項
handleNodeClick(node){
this.valueTitle = node[this.props.label]//獲取label
this.valueId = node[this.props.value]//獲取value
this.$emit('getValue',this.valueId)//傳值給父元件
},
這樣點選選中功能就實現了,但是有個問題,點選之後,下拉框選項沒有隱藏,我們只需要再呼叫一下select元件的blur方法即可實現隱藏
資料初始化
細心的小夥伴肯定已經發現了,上面有一個初始值,並且在選擇器中,初始資料也是必不可少的。實現思路如下:
- watch監聽prop中value資料變化
- 將初始值做對應賦值
- 獲取初始值對應的label並做對應賦值
- 設定tree元件的預設選中狀態
- 設定tree元件的預設展開節點
程式碼如下:
watch: {
value(){
this.valueId = this.value
this.initHandle()
}
},
// 初始化值
initHandle(){
if(this.valueId){
// 初始化顯示label
this.valueTitle = this.$refs.selectTree.getNode(this.valueId).data[this.props.label]
this.$refs.selectTree.setCurrentKey(this.valueId)// 設定預設選中
this.defaultExpandedKey = [this.valueId]// 設定預設展開
}
},
在
mounted
中呼叫執行既可
清除選中
一般輸入框或者選擇器都有清除功能,我們的元件自然也少不了清除功能,實現思路如下:
- 給select元件設定clearable屬性
- 給select元件新增清除監聽事件
- 在監聽事件中清除tree元件選中,並清除父元件中的值
程式碼如下:
<el-select :value="valueTitle" :clearable="clearable" @clear="clearHandle" :placeholder="placeholder" ref="select">
</el-select>
// 清除選中
clearHandle(){
this.valueTitle = ''
this.valueId = null
this.defaultExpandedKey = []
this.clearSelected()
this.$emit('getValue',null)
},
/* 清空選中樣式 */
clearSelected(){
let allNode = document.querySelectorAll('#tree-option .el-tree-node')
allNode.forEach((element)=>element.classList.remove('is-current'))
},
篩選資料
當tree中資料量過大時,我們需要篩選資料,實現思路如下:
- 給tree元件新增filter-node-method方法
- 新增一個輸入框,輸入篩選的內容
- 監聽輸入內容變化,並呼叫tree元件的篩選方法
程式碼如下:
<template>
<el-select :value="valueTitle" :clearable="clearable" @clear="clearHandle" :placeholder="placeholder" ref="select">
<el-input
class="selectInput"
placeholder="檢索關鍵字"
v-model="filterText">
</el-input>
<el-option :value="valueTitle" :label="valueTitle" class="options">
<el-tree id="tree-option"
ref="selectTree"
:accordion="accordion"
:data="options"
:props="props"
:node-key="props.value"
:default-expanded-keys="defaultExpandedKey"
:filter-node-method="filterNode"
@node-click="handleNodeClick">
</el-tree>
</el-option>
</el-select>
</template>
.selectInput{
padding: 0 5px;
box-sizing: border-box;
}
filterNode(value, data) {
if (!value) return true;
return data.name.indexOf(value) !== -1;
}
watch: {
filterText(val) {
this.$refs.selectTree.filter(val);
}
},
這樣一個簡單的樹狀下拉框元件就封裝好了。
使用元件
下面給個簡單的使用示例:
<template>
<basic-container>
<treeSelect
:props="defaultProps"
:options="treeData"
:value="value"
:accordion="true"
@getValue="getValue($event)"
placeholder="請選擇所屬區域"
/>
<span>選中的id:{{value}}</span>
</basic-container>
</template>
<script>
import treeSelect from "@/components/treeSelect/treeSelect";
export default {
components: {
treeSelect,
},
data() {
return {
defaultProps: {
label: "name",
value: "id",
children: "children",
},
value:'',//選中的資料
treeData:[
{id:1,name:'monkey',children:[{id:2,name:'monkey2'},{id:3,name:'monkey3'},{id:4,name:'monkey4'}]},
{id:5,name:'小猴子的web成長之路'},
{id:6,name:'小猴子的web成長之路'},
{id:7,name:'小猴子的web成長之路'},
{id:8,name:'小猴子的web成長之路'},
{id:9,name:'小猴子的web成長之路'},
{id:10,name:'小猴子的web成長之路'},
{id:11,name:'小猴子的web成長之路'},
{id:12,name:'小猴子的web成長之路'},
{id:13,name:'小猴子的web成長之路'},
{id:14,name:'小猴子的web成長之路'},
{id:15,name:'小猴子的web成長之路'},
{id:16,name:'小猴子的web成長之路'},
{id:17,name:'小猴子的web成長之路'},
]
};
},
methods:{
// 取值
getValue(value) {
this.value = value
},
}
};
</script>
原始碼收錄在公眾號【小猴子的web成長之路】,關注公眾號回覆關鍵字【treeSelect】即可獲取