需求背景
需要再下拉框中加上搜索框和树形选择,看下图就很明显了。
解决方法就是在 el-select 中加上 el-input 和 el-tree,我这个版本是组件化的,支持 v-model 双向绑定值,可以帮助快速开发并在不同页面中使用,同时也方便优化维护,如有问题私信我,有帮助点点赞就可以啦。
代码如下:
vue2代码
<template>
<div class="about">
<el-select
v-model="selectVal"
placeholder="请选择"
size="mini"
clearable
ref="selectRef"
class="select"
collapse-tags
multiple
@clear="clear"
@remove-tag="removeTag"
value-key="code"
popper-class="eloption"
:popper-append-to-body="true"
>
<!-- 防止无数据时显示无数据 -->
<el-option
key="id"
value="1"
label="1"
style="position: fixed; top: -100%; z-index: -11; opacity: 0"
>
</el-option>
<el-input
class="input"
placeholder="请输入搜索内容"
prefix-icon="el-icon-search"
v-model="treeFilter"
size="mini"
clearable
></el-input>
<div style="margin-top: 50px">
<el-tree
:data="treeData"
:props="defaultProps"
@node-click="handleNodeClick"
ref="tree"
node-key="code"
:filter-node-method="filterNode"
show-checkbox
@change="change"
>
</el-tree>
</div>
</el-select>
</div>
</template>
<script>
/**
* 搜索组件 (自定义下拉框内容)
* 引入:import selectCustom from '@/components/select-custom/index.vue';
* 使用:<selectCustom v-model="value"></selectCustom>
* v-model 绑定所需要的值
*/
export default {
name: "selectCustom",
props: {
modelValue: {
type: String,
default: "",
},
},
data() {
return {
selectVal: "", // select框的绑定值
selectName: "", // select框显示的name
treeFilter: "", // 搜索框绑定值,用作过滤
// 展示的 porps
defaultProps: {
label: "label",
children: "children",
},
// 树形控件数据
treeData: [
{
code: "1",
label: "根节点1",
children: [
{
code: "1-1",
label: "子节点1",
children: [
{ code: "1-1", label: "孙子节点1" },
{ code: "1-2", label: "孙子节点2" },
],
},
{
code: "1-2",
label: "子节点2",
children: [
{ code: "1-2-1", label: "孙子节点4" },
{ code: "1-2-2", label: "孙子节点3" },
],
},
],
},
{
code: "2",
label: "根节点2",
children: [
{
code: "2-1",
label: "子节点2-1",
children: [
{ code: "2-1-1", label: "孙子节点2-1-1" },
{ code: "2-1-2", label: "孙子节点2-1-2" },
],
},
{
code: "2-2",
label: "子节点2",
children: [
{ code: "2-2-1", label: "孙子节点2-2-1" },
{ code: "2-2-2", label: "孙子节点2-2-2" },
],
},
],
},
],
};
},
watch: {
// 搜索过滤,监听input搜索框绑定的treeFilter
treeFilter(val) {
this.$refs.tree.filter(val);
// 当搜索框键入值改变时,将该值作为入参执行树形控件的过滤事件filterNode
},
modelValue(newV, oldV) {
if (!newV) {
this.selectVal = [];
this.selectName = "";
this.$refs.tree.setCheckedKeys([]);
}
},
},
methods: {
/** 移除标签 */
removeTag(val) {
// 设置删除的值选中为false
this.$refs.tree.setChecked(val.code, false);
// 过滤空数据
const list = this.$refs.tree.getCheckedKeys().filter((item) => {
return item;
});
this.$emit("update:modelValue", list);
},
/** 获取数结构 */
getTreeData() {
/* 获取数据 */
// treeData.value = [];在此处获取所需要的数据
},
// 模糊查询(搜索过滤),实质为筛选出树形控件中符合输入条件的选项,过滤掉其他选项
filterNode(value, data) {
if (!value) return true;
const filterRes = data.label.indexOf(value) !== -1;
return filterRes;
},
// 改变选中
change() {
const arr = []; // 选中的列表数据
const list = []; // 选中的code列表
this.$refs.tree.getCheckedNodes().forEach((item) => {
// 只获取第三级的数据
if (!item.children) {
arr.push(item);
list.push(item.code);
}
});
this.selectVal = arr;
this.$emit("update:modelValue", list);
},
// 清空选中
clear() {
this.$refs.tree.setCheckedKeys([]);
this.$emit("update:modelValue", []);
},
},
mounted() {
this.getTreeData(); // 获取职位类型数据并渲染到树形控件中
},
};
</script>
<style scoped lang="scss">
.input {
width: 100%;
position: absolute;
top: 0px;
z-index: 1;
padding: 10px 4% 10px 4%;
background: #fff;
}
/** 防止滑动时复选框可以看见 */
:deep(.el-tree-node__content) {
.el-checkbox {
z-index: 0;
}
}
.select {
width: 350px;
}
</style>
<style>
.eloption .el-select-dropdown__wrap {
// max-height: 350px !important; // 最大高度限制
}
</style>
树形结构数据可以在 getTreeData 方法中自己获取数据,并对数据进行相应的转换。
Vue3代码
<template>
<div class="about">
<el-select
v-model="selectVal"
placeholder="请选择"
size="mini"
clearable
ref="selectRef"
collapse-tags
multiple
@clear="clear"
@remove-tag="removeTag"
value-key="code"
popper-class="eloption"
:popper-append-to-body="true"
style="width: 100%"
>
<!-- 防止无数据时显示无数据 -->
<el-option
key="id"
value="1"
label="1"
style="position: fixed; top: -100%; z-index: -11; opacity: 0"
>
</el-option>
<el-input
class="input"
placeholder="请输入搜索内容"
prefix-icon="el-icon-search"
v-model="treeFilter"
size="mini"
clearable
></el-input>
<div style="margin-top: 50px">
<el-tree
:data="treeData"
:props="defaultProps"
@node-click="handleNodeClick"
ref="treeRef"
node-key="code"
:filter-node-method="filterNode"
show-checkbox
@change="change"
>
</el-tree>
</div>
</el-select>
</div>
</template>
<script setup>
/**
* 搜索组件 (自定义下拉框内容)
* 引入:import selectCustom from '@/components/select-custom/index.vue';
* 使用:<selectCustom v-model="value"></selectCustom>
* v-model 绑定所需要的值
*/
import { ref, watch, onMounted } from "vue";
const props = defineProps({
modelValue: {
type: String,
default: "",
},
});
const selectVal = ref(""); // select框的绑定值
const selectName = ref(""); // select框显示的name
const treeFilter = ref(""); // 搜索框绑定值,用作过滤
// 展示的 porps
const defaultProps = ref({
label: "label",
children: "children",
});
const treeRef = ref(); // el-tree
const emit = defineEmits(["update:modelValue"]);
// 树形控件数据
const treeData = ref([
{
code: "1",
label: "根节点1",
children: [
{
code: "1-1",
label: "子节点1",
children: [
{ code: "1-1", label: "孙子节点1" },
{ code: "1-2", label: "孙子节点2" },
],
},
{
code: "1-2",
label: "子节点2",
children: [
{ code: "1-2-1", label: "孙子节点4" },
{ code: "1-2-2", label: "孙子节点3" },
],
},
],
},
{
code: "2",
label: "根节点2",
children: [
{
code: "2-1",
label: "子节点2-1",
children: [
{ code: "2-1-1", label: "孙子节点2-1-1" },
{ code: "2-1-2", label: "孙子节点2-1-2" },
],
},
{
code: "2-2",
label: "子节点2",
children: [
{ code: "2-2-1", label: "孙子节点2-2-1" },
{ code: "2-2-2", label: "孙子节点2-2-2" },
],
},
],
},
]);
watch(treeFilter, (val) => {
treeRef.value.filter(val);
// 当搜索框键入值改变时,将该值作为入参执行树形控件的过滤事件filterNode
});
watch(props.modelValue, (newV, oldV) => {
if (!newV) {
selectVal.value = [];
selectName.value = "";
treeRef.value.setCheckedKeys([]);
}
});
/** 移除标签 */
const removeTag = (val) => {
// 设置删除的值选中为false
treeRef.value.setChecked(val.code, false);
// 过滤空数据
const list = treeRef.value.getCheckedKeys().filter((item) => {
return item;
});
emit("update:modelValue", list);
};
/** 获取数结构 */
const getTreeData = () => {
/* 获取数据 */
// treeData.value = [];在此处获取所需要的数据
};
// 模糊查询(搜索过滤),实质为筛选出树形控件中符合输入条件的选项,过滤掉其他选项
const filterNode = (value, data) => {
if (!value) return true;
const filterRes = data.label.indexOf(value) !== -1;
return filterRes;
};
// 改变选中
const change = () => {
const arr = []; // 选中的列表数据
const list = []; // 选中的code列表
treeRef.value.getCheckedNodes().forEach((item) => {
// 只获取第三级的数据
if (!item.children) {
arr.push(item);
list.push(item.code);
}
});
selectVal.value = arr;
emit("update:modelValue", list);
};
// 清空选中
const clear = () => {
treeRef.value.setCheckedKeys([]);
emit("update:modelValue", []);
};
onMounted(() => {
getTreeData(); // 获取职位类型数据并渲染到树形控件中
});
</script>
<style scoped lang="scss">
.input {
width: 100%;
position: absolute;
top: 0px;
z-index: 1;
padding: 10px 4% 10px 4%;
background: #fff;
}
/** 防止滑动时复选框可以看见 */
:deep(.el-tree-node__content) {
.el-checkbox {
z-index: 0;
}
}
</style>
<style>
.eloption .el-select-dropdown__wrap {
max-height: 350px !important;
}
</style>
树形结构数据可以在 getTreeData 方法中自己获取数据,并对数据进行相应的转换。
解决最大高度限制
如果下拉框内容较多,显示区域较小,就无法一次性看到更多内容,如下图
解决方案:
在 el-select 中添加自定义样式,在 css 中改变样式
<el-select
***
popper-class="eloption"
:popper-append-to-body="true"
>
</el-select>
<style>
.eloption .el-select-dropdown__wrap {
max-height: 350px !important;
}
</style>
修改后
在上面代码css中就有这条注释代码,可根据需要自己调
感谢观看,有问题可以联系我。