vue+element 多选下拉选项树状列表

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>
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
element-ui是一套基于Vue.js的UI组件库,提供了丰富的组件和工具,方便开发者进行项目开发。其中,下拉多选树状图是element-ui中的一个常用组件之一。 使用element-ui的下拉多选树状图组件,可以实现用户通过下拉选择来选择多个选项,并且这些选项还以树状图的形式展示。这在处理包含层级关系的数据时尤其有用。 首先,在Vue组件中引入element-ui的下拉多选树状图组件,即el-select组件。然后,在组件中定义一个变量来存储用户选中的值,例如selectedOptions。接着,在挂载到DOM之前设置el-select组件的placeholder属性,如:请选择。 接下来,通过调用element-ui提供的API,将需要展示的选项作为树节点传递给el-select组件。可以使用element-ui的el-tree组件来支持树状结构,通过配置tree-props属性来指定树节点的显示字段,例如label和children。在数据源中,可以为每个节点设置一个唯一的key属性。 然后,在el-select组件的v-model属性中绑定selectedOptions变量,以实现选中值的双向绑定。此时,用户可以通过下拉选择多个选项,选中的选项会自动存储在selectedOptions变量中。 最后,在Vue组件的template中使用el-select组件来展示下拉多选树状图。设置el-select的filterable属性为true,可以让用户通过输入关键字来筛选选项。使用el-option组件来表示每一个下拉选项。为el-select组件设置多选属性multiple,并通过el-tree组件的子节点slot来显示树状结构。 通过以上步骤,我们就可以使用element-ui快速实现下拉多选树状图。使用这个组件,可以方便地展示具有层级关系的数据,并让用户灵活选择多个选项
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值