vue让select的下拉列表支持层级关系(tree)
如果您发现本文排版有问题,可以先点击下面的链接切换至老版进行查看!!!
vue让select的下拉列表支持层级关系(tree)

<template>
<section class="selectTree" :class="inline ? 'inline': ''">
<div class="el-select selectTree-select"
>
<el -input v-model.trim="selectedLabel" readonly
@click.native="showList = true">
<span class="el-input__suffix" slot="suffix">
<span class="el-input__suffix-inner">
<i class="el-select__caret el-input__icon el-icon-arrow-up"
:class="{'is-reverse': showList}"></i>
</span>
</span>
</el>
</div>
</section><section class="selectTree-section" v-show="showList" :style="{top: topOffset + 'px'}">
<div class="transparent-div" @click="showList = false" :style="{height: (inputHeight + 4) + 'px' }"></div>
<div class="select-div" ref="list">
<div class="inputResult">
<el -input class="input-result"
prefix-icon="el-icon-search"
:placeholder="$t('lang.input_keyword_filter')"
v-model="inputText">
</el>
</div>
<el -tree
:data="data"
show-checkbox
:props="treeProps"
:node-key="valueProp"
ref="tree"
:filter-node-method="filterNode"
:default-checked-keys="selected"
highlight-current>
</el>
<div class="btns">
<el -button size="mini" type="text" @click="showList = false">{{$t('lang.cancel')}}</el>
<el -button size="mini" type="primary" @click="handleConfirm">{{$t('lang._save')}}</el>
</div>
</div>
</section>
</template>
<script>
export default {
name: 'selectTree',
props: {
value: {
type: Array,
default() {
return [];
}
},
visible: {
type: Boolean,
default: false,
},
data: {
type: Array,
default() {
return [];
}
},
valueProp: { // 选择标志属性
type: String,
default: 'id',
},
labelProp: { // 选择显示值
type: String,
default: 'name',
},
itemLabel: { // 选择项的描述
type: String,
},
inputHeight: { // 输入框的高度
type: Number,
default: 0,
},
topOffset: { // 列表的垂直偏移量
type: Number,
default: 0,
},
treeProps: { // el-tree的props
type: Object,
default() {
return {
label: 'name',
children: 'children'
};
}
},
containerRef: { // 部分容器,比如el-popover上面的点击事件document捕获不到,需要单独处理
// type: Object
},
inline: {
type: Boolean,
default: false,
},
},
data() {
return {
showList: this.visible,
inputText: '',
selected: this.value,
dom: '',
};
},
computed: {
dataItems() {
return this.commonscript.flattenArr([])(this.data, this.valueProp);
},
selectedArr() {
return this.dataItems.filter(item => this.selected.includes(item[this.valueProp]));
},
selectedValue() {
return this.selectedArr.map(item => item[this.valueProp]);
},
selectedLabel() {
const selectedValue = this.selectedArr.map(item => item[this.valueProp]);
const selectedLabel = this.selectedArr.map(item => item[this.labelProp]);
// this.selected = selectedValue; // 修正选中的,因为传进来的selected的部分选项可能已经不在列表里面了
// this.$emit('input', selectedValue);
return this.selectedArr.length
? `${this.$t('lang.selected')} ${this.selectedArr.length} ${this.itemLabel || this.$t('lang.item')},${selectedLabel.join(' / ')}`
: '';
},
treeSelected() {
return this.$refs.tree.getCheckedNodes().filter(item => !item.children).map(item => item[this.valueProp]);
}
},
mounted() {
document.addEventListener('click', this.handleDocumentClick);
},
destroyed() {
document.removeEventListener('click', this.handleDocumentClick);
},
methods: {
filterNode(value, data) {
if (!value) return true;
const {label} = this.treeProps;
return data[label].indexOf(value) !== -1;
},
handleConfirm() {
this.showList = false;
this.$emit('input', this.treeSelected);
},
handleDocumentClick(e) {
const list = this.$refs.list;
if (!this.$el ||
this.$el.contains(e.target) ||
!list ||
list.contains(e.target)) return;
this.showList = false;
},
},
watch: {
inputText(val) {
this.$refs.tree.filter(val);
},
value: {
immediate: true,
handler(val) {
this.selected = val || [];
},
},
containerRef(value, oldValue) {
if (oldValue) {
const oldDom = oldValue.$el || oldValue;
oldDom.removeEventListener('click', this.handleDocumentClick);
}
if (value) {
this.dom = value.$el || value;
this.dom.addEventListener('click', this.handleDocumentClick);
}
},
},
}
</script>
大家可能看到这里的containerRef
是个什么东东,完全多此一举嘛,是的。只是在某些特定的嗯情况,比如再el-popover里面,document是无法获取点击事件的,造成的影响就是,我们在点击其它地方时无法取消下拉列表了,这个也是偶然发现的,所以额外加上了这个功能。- 分类:
- Web前端
更新时间: