下拉选择树,可过滤搜索、单选及多选,基于 vue2 element-ui 封装
根据实际开发需要,基于 vue2 element-ui 封装了一个下拉选择树,支持过滤搜索,单选,多选
·
下拉选择树,可过滤搜索、单选及多选,基于 vue2 element-ui 封装
半吊子前端水平,根据实际开发需要,基于 vue2 element-ui 封装了一个下拉选择树,支持过滤搜索,单选,多选,现为初版,欢迎提 bug
如下,依赖 lodash 的两个方法,若不想依赖的话,请改写
// npm i --save lodash
// main.js 文件中全局引入 lodash
import _ from 'lodash'
Vue.prototype._ = _
// 使用到的方法
this._.isEmpty(val) // 判空
this._.findIndex(this.checkedArray, data) // 查询索引值
效果图如下,敏感数据打马
1. 组件 SelectTree.vue
代码如下:
<template>
<!-- 单选的时候,value绑定id,多选的时候绑定展示名称字符串数组 -->
<el-select
:title="multiple? optionData.label : ''"
ref="select"
:value="multiple ? optionData.label : value"
placeholder="请选择"
:size="size"
clearable
:filterable="filterable"
:filter-method="filterMethod"
:disabled="disabled"
:multiple="multiple"
:collapse-tags="collapseTags"
@remove-tag="removeTag"
@clear="clear"
@visible-change="visibleChange"
@focus="focus"
>
<!-- 单选的时候,label绑定展示名称,多选的时候绑定空字符串 -->
<el-option
ref="option"
class="tree-select__option"
:value="optionData.id"
:label="multiple ? '' : optionData.label"
>
<el-tree
ref="tree"
class="tree-select__tree"
:class="`tree-select__tree--${multiple ? 'checked' : 'radio'}`"
:node-key="nodeKey"
:data="data"
:props="props"
v-bind="treeAttr"
:highlight-current="!multiple"
:show-checkbox="multiple"
:check-strictly="checkStrictly"
:expand-on-click-node="multiple"
:filter-node-method="filterNode"
@node-click="handleNodeClick"
@current-change="handleCurrentChange"
@check-change="handleCheckChange"
></el-tree>
</el-option>
</el-select>
</template>
<script>
export default {
name: 'SelectTree',
props: {
size: {
type: String,
default: 'small'
},
// v-model绑定
value: {
type: [String, Number, Array],
default: ''
},
// 树形的数据
data: {
type: Array,
default: function () {
return []
}
},
// 每个树节点用来作为唯一标识的属性
nodeKey: {
type: [String, Number],
default: 'id'
},
filterable: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
multiple: {
type: Boolean,
default: false
},
collapseTags: {
type: Boolean,
default: false
},
checkStrictly: {
type: Boolean,
default: false
},
// tree的props配置
props: {
type: Object,
default: function () {
return {
label: 'label',
children: 'children'
}
}
}
},
data() {
return {
optionData: {
id: '',
name: ''
},
filterFlag: false,
checkedArray: []
}
},
computed: {
treeAttr() {
if (this.value) {
return {
defaultExpandedKeys: [this.value]
}
} else {
// 考虑 value 可能为 null
return {}
}
}
},
watch: {
value: {
handler(val) {
if (!this.isEmpty(this.data)) {
this.init(val)
}
},
immediate: true
},
data: function (val) {
if (!this.isEmpty(val)) {
this.init(this.value)
}
}
},
methods: {
// 是否为空
isEmpty(val) {
return this._.isEmpty(val)
},
handleNodeClick(data) {
if (this.multiple) {
return
}
if (data.disabled) {
// 若节点 disabled === true,则取消选中
this.$refs.tree.setCurrentKey(null)
return
}
this.$emit('input', data[this.nodeKey])
this.$emit('setLayer', data['layer'])
this.$emit('selectNode', data[this.nodeKey])
this.$refs.select.visible = false
},
handleCurrentChange(data) {
if (this.multiple) {
return
}
this.$emit('change', false)
},
handleCheckChange(data, checked, childrenChecked) {
if (checked) {
this.checkedArray.push(data)
} else {
let checkIndex = this._.findIndex(this.checkedArray, data)
this.checkedArray.splice(checkIndex, 1)
}
// 多选绑定的值是数组
this.optionData.id = this.checkedArray
.map(item => item[this.nodeKey])
// 多选展示的 label 是字符串数组
const label = this.props.label || 'name'
this.optionData[label] = this.checkedArray
.map(item => item[label])
this.$emit('input', this.optionData.id)
this.$emit('selectNode', this.optionData.id)
},
init(val) {
// 多选
if (this.multiple) {
if (val) {
const arr = val.toString().split(',')
this.$nextTick(() => {
this.$refs.tree.setCheckedKeys(arr)
const nodes = this.$refs.tree.getCheckedNodes()
this.optionData.id = val
// 多选展示的 label 是字符串数组
const label = this.props.label || 'name'
this.optionData[label] = nodes
.map(item => item[label])
})
} else {
this.$refs.tree.setCheckedKeys([])
}
} else {
// 单选
val = val === '' ? null : val
this.$nextTick(() => {
this.$refs.tree.setCurrentKey(val)
if (!val) {
return
}
const label = this.props.label || 'name'
const node = this.$refs.tree.getNode(val)
this.optionData.id = val
this.optionData[label] = node.label
})
}
},
removeTag(tag) {
// this.handleCheckChange({ id: tag }, false)
},
visibleChange(e) {
if (e) {
const tree = this.$refs.tree
this.filterFlag && tree.filter('')
this.filterFlag = false
let selectDom = null
if (this.multiple) {
selectDom = tree.$el.querySelector('.el-tree-node.is-checked')
} else {
selectDom = tree.$el.querySelector('.is-current')
}
setTimeout(() => {
this.$refs.select.scrollToOption({ $el: selectDom })
}, 0)
}
},
focus(e) {
this.$emit('focus')
},
clear() {
this.$emit('input', null)
},
filterMethod(val) {
this.filterFlag = true
this.$refs.tree.filter(val)
},
filterNode(value, data) {
if (!value) return true
const label = this.props.label || 'name'
return data[label].indexOf(value) !== -1
}
}
}
</script>
<style lang="scss" scoped>
.tree-select__option {
height: auto;
line-height: 1;
padding: 0;
background-color: #fff;
&.el-select-dropdown__item {
height: auto;
line-height: 1;
padding: 0;
background-color: #fff;
}
}
.tree-select__tree {
padding: 4px 20px;
font-weight: 400;
&.tree-select__tree--radio {
::v-deep .el-tree-node.is-current > .el-tree-node__content {
color: #409eff;
font-weight: 700;
}
}
/*::v-deep .el-tree-node.is-current > .el-tree-node__content {
color: #409eff;
font-weight: 700;
}*/
::v-deep .el-tree-node:focus > .el-tree-node__content {
background-color: #ffffff;
}
}
/* 禁止通过 tag 取消选中 */
::v-deep .el-tag.el-tag--info .el-tag__close {
display: none;
}
</style>
2. 使用方法
import SelectTree from "XXXXXX/TreeSelect" // 根据实际路径引入
<select-tree
v-model="value"
:data="options"
filterable
multiple
/>
Attributes
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
size | 尺寸 | string | medium / small / mini | small |
value | v-model 绑定值,单选是 String, Number;多选是 Array | String, Number, Array | — | — |
data | 树形结构数据,参考 element-ui tree 对数据格式的要求 | Array | — | — |
nodeKey | 每个树节点用来作为唯一标识的属性,整棵树应该是唯一的 | String | — | id |
filterable | 是否可搜索 | boolean | — | false |
disabled | 是否禁用 | boolean | — | false |
multiple | 是否可多选 | boolean | — | false |
collapse-tags | 多选时是否将选中值按文字的形式展示 | boolean | — | false |
check-strictly | 在显示复选框的情况下,是否严格的遵循父子不互相关联的做法,默认为 false | boolean | — | false |
props | 配置选项,具体看下表 | object | — | — |
props
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
label | 指定节点标签为节点对象的某个属性值 | string, function(data, node) | — | — |
children | 指定子树为节点对象的某个属性值 | string | — | — |
disabled | 指定节点选择框是否禁用为节点对象的某个属性值 | boolean, function(data, node) | — | — |
isLeaf | 指定节点是否为叶子节点,仅在指定了 lazy 属性的情况下生效 | boolean, function(data, node) | — | — |
Methods
参考源代码及 element-ui 文档,有时间补充
Events
参考源代码及 element-ui 文档,有时间补充
更多推荐
已为社区贡献2条内容
所有评论(0)