文章目录
- 1、单选带搜索功能(自定义搜索)
- 2、下拉多选+远程搜索
- 3、下拉多选+有默认选项
- 4、下拉多选+默认禁用
只提供大致思路,大量玩法等你开发【doge】
1、单选带搜索功能(自定义搜索)
例如,我需要实现一个功能:搜索指定姓开头的所有名字(中文)。下面我就直接省略了表单form组件了哈(一般像这类选择框、输入框等组件都是写在el-form中的)。
官方提供了一个属性:filterable
,添加它就可以直接实现模糊查询的效果,不过我们的目的是实现查询某个姓开头的所有名字这个查询逻辑,所以要自定义一个方法,因此我们要用到官方提供的另一个属性:filter-method
,filter-method
为一个Function类型,它会在输入值发生变化时调用,参数为当前输入值。当然,在使用这个属性时,filteralbe
属性也不能丢。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- 引入vue -->
<!-- <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> -->
<!-- <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script> -->
<script src="../vue/vue.js"></script>
<!-- 引入样式 -->
<link
rel="stylesheet"
href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"
/>
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<!-- 浏览器引入mockjs文件 -->
<script src="https://cdn.bootcdn.net/ajax/libs/Mock.js/1.0.0/mock.js"></script>
<title>Document</title>
</head>
<body>
<div id="app">
<template>
<!-- 匹配指定姓的全部姓名 -->
<!-- last name是姓的意思 -->
<el-select
filterable
v-model="searchValue"
placeholder="请输入姓名中的姓(中文)"
:filter-method="getNameByLastName"
clearable
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</template>
</div>
<script>
// mock模拟数据
var Random = Mock.Random;
// 生成一个包含20个对象类型的元素的数组
let data = Mock.mock({
"list|10": [
{
"value|+1": 0,
label: () => {
return Random.cname();
},
},
],
});
console.log(data);
Vue.config.productionTip = false;
new Vue({
el: "#app",
data() {
return {
searchValue: "",
options: data.list,
};
},
methods: {
// 重新定义搜索规则:获取指定姓相关的全部姓名
getNameByLastName(val) {
this.searchValue = val;
if (val) {
this.options = data.list.filter((item) => {
console.log(item.label.split("")[0]);
return item.label.split("")[0] == val;
});
} else {
this.options = data.list;
}
},
},
});
</script>
</body>
</html>
效果如下:
2、下拉多选+远程搜索
如标题所示,我们将实现两个功能,多选+远程搜索
,多选将用到multiple
属性启用多选,此时v-model接收的是一个数组,远程搜索将用到filterable
(开启查询)属性和remote
(开启远程搜索)属性,并在使用时将两者设置为true
,同时传入一个remote-method
属性,该属性接收一个Function
,会在输入值发生变化时调用,参数表示当前输入的值。此外,如果数据比较多,那么远程搜索的展示就会很慢,所以我们需要loading
属性来显示数据未展示时的效果。
下面,我们将实现功能,不过在那之前,我们得先知道,后端传到前端的数据的格式不一定就会是options需要的形式(options[{value:xxx,lable:xxx}]), 有可能就只是一个普通的字符串数组,所以我们需要转换格式。此外,下面的方式并未调用远程接口,只是简单的对本地数据进行操作,所以会用到定时器函数模拟获取远程数据时的延迟效果。
那么,接下来,我们展示代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- 引入vue -->
<!-- <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> -->
<!-- <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script> -->
<script src="../vue/vue.js"></script>
<!-- 引入样式 -->
<link
rel="stylesheet"
href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"
/>
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<!-- 浏览器引入mockjs文件 -->
<script src="https://cdn.bootcdn.net/ajax/libs/Mock.js/1.0.0/mock.js"></script>
<title>Document</title>
</head>
<body>
<div id="app">
<template>
<el-select
multiple
filterable
remote
:remote-method="remoteMethod1"
v-model="values1"
:loading="loading1"
placeholder="请输入姓名"
clearable
no-data-text="没有这个名字哦"
>
<el-option
v-for="item in options1"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
<el-select
multiple
filterable
remote
:remote-method="remoteMethod2"
v-model="values2"
:loading="loading2"
placeholder="请输入姓名"
clearable
no-data-text="没有这个名字哦"
>
<el-option
v-for="item in options2"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</template>
</div>
<script>
// mock模拟数据
var Random = Mock.Random;
// 生成一个包含20个对象类型的元素的数组
let data1 = Mock.mock({
"list|20": [
{
"value|+1": 0,
label: "@cname",
},
],
});
// 生成一个包含20个字符串元素的数组
let data2 = Mock.mock({
"list|20": [
() => {
return Random.cname();
},
],
});
Vue.config.productionTip = false;
new Vue({
el: "#app",
data() {
return {
values1: [],
values2: [],
loading1: false,
loading2: false,
options1: [],
options2: [],
list: [],
};
},
mounted() {
this.options1 = data1.list;
console.log(this.options1, "this.options1 ===========");
// 将字符串数组转为指定对象形式的数组{value:xxx,label:xxx}
this.list = data2.list.map((item, index) => {
return { value: index, label: item };
});
this.options2 = this.list;
console.log(data2.list, "data2.list ===============");
console.log(this.options2, "this.options2 ==============");
},
methods: {
remoteMethod1(query) {
if (query !== "") {
this.loading1 = true;
setTimeout(() => {
this.loading1 = false;
// 过滤出匹配的数据
this.options1 = data1.list.filter((item) => {
return (
item.label.toLowerCase().indexOf(query.toLowerCase()) > -1
);
});
}, 2000);
} else {
this.options1 = [];
}
},
remoteMethod2(query) {
if (query !== "") {
this.loading2 = true;
setTimeout(() => {
this.loading2 = false;
// 过滤出匹配的数据
this.options2 = this.list.filter((item) => {
return (
item.label.toLowerCase().indexOf(query.toLowerCase()) > -1
);
});
}, 2000);
} else {
this.options2 = [];
}
},
},
});
</script>
</body>
</html>
补充:如果不想一开始就显示出下拉选项,那么在上述代码的mounted钩子中,你可以不对options进行赋值,这样就能达到想要的效果了。
3、下拉多选+有默认选项
例如,我们想要options.value=3的选项默认展示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- 引入vue -->
<!-- <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> -->
<!-- <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script> -->
<script src="../vue/vue.js"></script>
<!-- 引入样式 -->
<link
rel="stylesheet"
href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"
/>
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<!-- 浏览器引入mockjs文件 -->
<script src="https://cdn.bootcdn.net/ajax/libs/Mock.js/1.0.0/mock.js"></script>
<title>Document</title>
</head>
<body>
<div id="app">
<template>
<el-select
multiple
filterable
remote
:remote-method="remoteMethod"
v-model="values"
:loading="loading"
placeholder="请输入姓名"
clearable
no-data-text="没有这个名字哦"
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</template>
</div>
<script>
// mock模拟数据
var Random = Mock.Random;
// 生成一个包含20个对象类型的元素的数组
let data = Mock.mock({
"list|20": [
{
"value|+1": 0,
label: "@cname",
},
],
});
console.log(data, "data ==========");
Vue.config.productionTip = false;
new Vue({
el: "#app",
data() {
return {
values: [],
loading: false,
options: [],
};
},
mounted() {
// 什么时候需要重新置为空数组? => 如果打开某个组件,这个组件上次打开时的数据没有被清除,同时这次数据又被添加上去的时候
// this.values = [];
// this.options = [];
data.list.forEach((item) => {
if (item.value == 3) {
this.values.push(item.value);
/*
注意:一定要加下面这行代码给options赋值,
否则,到时选择项显示的将会是value的值,而不是label的值
*/
this.options.push(item);
}
});
},
methods: {
remoteMethod(query) {
if (query !== "") {
this.loading = true;
setTimeout(() => {
this.loading = false;
// 过滤出匹配的数据
this.options = data.list.filter((item) => {
return (
item.label.toLowerCase().indexOf(query.toLowerCase()) > -1
);
});
}, 1000);
} else {
this.options = [];
}
},
},
});
</script>
</body>
</html>
4、下拉多选+默认禁用
要实现的效果如图:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- 引入vue -->
<!-- <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> -->
<!-- <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script> -->
<script src="../vue/vue.js"></script>
<!-- 引入样式 -->
<link
rel="stylesheet"
href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"
/>
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<!-- 浏览器引入mockjs文件 -->
<script src="https://cdn.bootcdn.net/ajax/libs/Mock.js/1.0.0/mock.js"></script>
<title>Document</title>
<style>
/* 消除tag标签后面的x */
/* .el-select .el-select__tags i {
display: none;
} */
</style>
</head>
<body>
<div id="app">
<template>
<el-select
multiple
filterable
remote
:remote-method="remoteMethod"
v-model="values"
:loading="loading"
placeholder="请输入姓名"
clearable
no-data-text="没有这个名字哦"
@clear="clearName"
@remove-tag="removeTag"
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
:disabled="item.disabled"
>
</el-option>
</el-select>
</template>
</div>
<script>
// mock模拟数据
var Random = Mock.Random;
// 生成一个包含20个对象类型的元素的数组
let data = Mock.mock({
"list|20": [
{
"value|+1": 0,
label: "@cname",
},
],
});
console.log(data, "data ==========");
Vue.config.productionTip = false;
new Vue({
el: "#app",
data() {
return {
values: [],
loading: false,
options: [],
};
},
mounted() {
// 什么时候需要重新置为空数组?
// => 如果打开某个组件,这个组件上次打开时的数据没有被清除,
// 同时这次数据又被添加上去的时候
// this.values = [];
// this.options = [];
// 第一种方式:
data.list.forEach((item) => {
if (item.value == 3) {
this.values.push(item.value);
/*
注意:一定要加下面这行代码给options赋值,
否则,到时选择项显示的将会是value的值,而不是label的值
*/
this.options.push(item);
item.disabled = true; // 设置选项不可用
}
});
// 第二种实现方式:
// this.values = [3]; // 要禁用的选项放在数组中
// data.list.forEach((item) => {
// this.values.forEach((val) => {
// if (item.value === val) {
// item.disabled = true;
// this.options.push(item);
// }
// });
// });
},
methods: {
// 远程查询
remoteMethod(query) {
if (query !== "") {
this.loading = true;
setTimeout(() => {
this.loading = false;
// 过滤出匹配的数据
this.options = data.list.filter((item) => {
return (
item.label.toLowerCase().indexOf(query.toLowerCase()) > -1
);
});
}, 1000);
} else {
this.options = [];
}
},
// 下拉框所选数据的清除(不清除默认值)
clearName() {
// 只要让默认选项的value值一直存在即可避免被清除
this.values = [3];
},
/**
* @description: 移除tag时触发的事件
* @param item 在这里指的是所选值的value值,也就是options数组下面每一个对象的value值
*/
removeTag(item) {
// 当要删除的tag的value值不等于3时
if (item !== 3) {
console.log(item);
}
// 当要删除的tag的value等于3时,让它不能删除默认值
else {
this.values = [3];
/*
我这保留默认项(默认项不能被删除)一直没想到什么好办法,
只能让this.values重新进行赋值,让他达到看起来没被删除的效果,
有懂得大佬可以提供下思路吗
*/
}
},
},
});
</script>
</body>
</html>
其他待补充doge