1.先上效果图
二、父组件
<template>
<div class="city-tree-wraper">
<h4>选项树状列表多选</h4>
<ElInputTag
:suffix-icon="isShowSelectTree?'el-icon-arrow-up':'el-icon-arrow-down'"
:value="checkedLabel"
:addTagOnKeys="checkedkey"
:type="'info'"
:disableTransitions="true"
:readOnly="true"
:closable="true"
@click.native.stop="isShowSelectTree=!isShowSelectTree"
@input="setCheckedName"
></ElInputTag>
<el-card class="box-card" v-show="isShowSelectTree">
<el-input
class="search-tree-list"
size="small"
prefix-icon="el-icon-search"
placeholder="输入关键词"
@click.native.stop="handleClickSearch"
v-model="filterText">
</el-input>
<el-tree
:data="date"
show-checkbox
node-key="moduldCode"
ref="tree"
:expand-on-click-node="false"
:highlight-current="true"
:check-on-click-node="true"
:default-expanded-keys="[1,3]"
:default-checked-keys="checkedkey"
:props="defaultProps"
:filter-node-method="filterNode"
@check-change="handleCheckChange"
></el-tree>
</el-card>
</div>
</template>
<script>
import ElInputTag from '../el-input-tag/index.vue';
export default {
components:{ElInputTag},
data() {
return {
isShowSelectTree:false,
checkedkey: [4,5],
checkedLabel:['三级 3-1-1','三级 3-1-2'],
defaultProps: {
children: "child",
label: "moduleName",
id:'moduldCode' //可要可不要
},
filterText:'',
date: [{
moduldCode: 1,
moduleName: '一级 2',
child: [{
moduldCode: 3,
moduleName:'二级 2-1',
child: [{
moduldCode: 4,
moduleName:'三级 3-1-1',
}, {
moduldCode: 5,
moduleName:'三级 3-1-2',
}]
}, {
moduldCode: 2,
moduleName:'二级 2-2',
child: [{
moduldCode: 6,
moduleName:'三级 3-2-1',
}, {
moduldCode: 7,
moduleName:'三级 3-2-2',
}]
}]
}],
}
},
mounted () {
//判断点击的是否是类型下拉区域
document.addEventListener('click', this.bodyCloseMenus)
},
destroyed () {
document.removeEventListener('click', this.bodyCloseMenus)
},
watch: {
filterText(val) {
this.$refs.tree.filter(val);
}
},
methods: {
// search
filterNode(value, data) {
if (!value) return true;
return data.moduleName.indexOf(value) !== -1;
},
// 通过name获取nodes
getItemNodes(name){
let childItems = []
this.date.map((item)=>{
if(item.child){
item.child.map((jtem)=>{
if(jtem.child){
jtem.child.map((ntem)=>{
if(!ntem.child){
childItems.push(ntem)
}
})
}else{
childItems.push(jtem)
}
})
}else{
childItems.push(item)
}
})
return childItems.filter((item)=>{
return name.includes(item.moduleName)
})
},
// 点击删除的回调
setCheckedName(e){
this.checkedLabel = e;
let nodes = this.getItemNodes(e)
this.$refs.tree.setCheckedNodes(nodes)
},
//页面其他区域点击关闭分类
bodyCloseMenus () {
if (this.isShowSelectTree) {
this.isShowSelectTree = false
}
},
handleClickSearch(e){
console.log(e);
},
// 树状选中
handleCheckChange() {
let data = this.$refs.tree.getCheckedNodes();
let newData = data.filter((item)=>{
return !item.child
})
let checkedkey = [],checkedLabel=[]
newData.map((item)=>{
checkedkey.push(item.moduldCode)
checkedLabel.push(item.moduleName)
})
this.checkedkey = checkedkey;
this.checkedLabel = checkedLabel;
},
},
computed:{
}
};
</script>
<style lang="scss" scoped>
.city-tree-wraper{
width: 300px;
margin: 10px;
}
.box-card{
margin-top: 5px;
}
.search-tree-list{
margin-bottom: 10px;
}
</style>
三、子组件
//el-input-tag/index.vue
<template>
<div
class="el-input-tag input-tag-wrapper"
:class="[size ? 'el-input-tag--' + size : '']"
@click="focusTagInput">
<div v-if="!isShowAllTag &&innerTags.length > 1" class="tag-wraper">
<el-tag
v-bind="$attrs"
:type="type"
:size="size"
:closable="closable"
:disable-transitions="disableTransitions"
@close="remove(0)">
{{innerTags[0]}}
</el-tag>
<el-tag
v-bind="$attrs"
:size="size"
:type="type"
:disable-transitions="disableTransitions"
>
+ {{innerTags.length-1}}
</el-tag>
</div>
<div v-else class="tag-wraper">
<el-tag
v-for="(tag, idx) in innerTags"
v-bind="$attrs"
:key="tag"
:size="size"
:type="type"
:closable="closable"
:disable-transitions="disableTransitions"
@close="remove(idx)">
{{tag}}
</el-tag>
</div>
<input
v-if="!readOnly"
class="tag-input"
:value="newTag"
@input="inputTag"
@keydown.delete.stop = "removeLastTag"
@keydown = "addNew"
@blur = "addNew"
/>
<span class="el-input__suffix">
<span class="el-input__suffix-inner">
<i :class="[suffixIcon,'el-input__icon']"></i>
</span>
</span>
</div>
</template>
<script>
export default {
name: 'ElInputTag',
props: {
value: {
type: Array,
default: () => []
},
addTagOnKeys: {
type: Array,
default: () => [6,7]
},
readOnly: {
type: Boolean,
default: false
},
disableTransitions:{
type: Boolean,
default: false
},
closable:{
type: Boolean,
default: false
},
isShowAllTag:{
type: Boolean,
default: false
},
size: String,
suffixIcon:String,
type:String,
},
data () {
return {
newTag: '',
innerTags: [...this.value]
}
},
watch: {
value () {
this.innerTags = [...this.value]
}
},
methods: {
focusTagInput () {
if (this.readOnly || !this.$el.querySelector('.tag-input')) {
return
} else {
this.$el.querySelector('.tag-input').focus()
}
},
inputTag(ev) {
this.newTag = ev.target.value
},
addNew (e) {
if (e && (!this.addTagOnKeys.includes(e.keyCode)) && (e.type !== 'blur')) {
return
}
if (e) {
e.stopPropagation()
e.preventDefault()
}
let addSuccess = false
if (this.newTag.includes(',')) {
this.newTag.split(',').forEach(item => {
if (this.addTag(item.trim())) {
addSuccess = true
}
})
} else {
if (this.addTag(this.newTag.trim())) {
addSuccess = true
}
}
if (addSuccess) {
this.tagChange()
this.newTag = ''
}
},
addTag (tag) {
tag = tag.trim()
if (tag && !this.innerTags.includes(tag)) {
this.innerTags.push(tag)
return true
}
return false
},
remove (index) {
this.innerTags.splice(index, 1)
this.tagChange()
},
removeLastTag () {
if (this.newTag) {
return
}
this.innerTags.pop()
this.tagChange()
},
tagChange () {
this.$emit('input', this.innerTags)
}
}
}
</script>
<style scoped>
.el-form-item.is-error .el-input-tag {
border-color: #f56c6c;
}
.input-tag-wrapper {
position: relative;
font-size: 14px;
background-color: #fff;
background-image: none;
border-radius: 4px;
border: 1px solid #dcdfe6;
box-sizing: border-box;
color: #666;
display: inline-block;
outline: none;
padding: 0 10px 0 5px;
transition: border-color .2s cubic-bezier(.645,.045,.355,1);
width: 100%;
}
.el-tag {
margin-right: 4px;
}
.tag-input {
background: transparent;
border: 0;
font-size: inherit;
outline: none;
padding-left: 0;
width: 100px;
}
.el-input-tag {
min-height: 42px;
line-height: 42px;
}
.el-input-tag--mini {
min-height: 28px;
line-height: 28px;
font-size: 12px;
}
.el-input-tag--small {
min-height: 32px;
line-height: 32px;
}
.el-input-tag--medium {
min-height: 36px;
line-height: 36px;
}
.tag-wraper{
display: inline-block;
}
</style>