最终效果图:
用的是vue2写法,喜欢用vue3的同学可以自行修改下。
需求要求:
- 实现el-select功能复用;
- 支持单选或者多选功能;
- 支持全拼或者简拼搜索功能;
直接上代码:
pinyin.js文件文章来源:https://www.toymoban.com/news/detail-523895.html
import PinYin from "pinyin";
/**
*
* @param { String } q - 翻译的全拼key值
* @param { String } j - 翻译的简拼key值
* @return { Object }
*/
export default function(str, q, j) {
q = q || "q";
j = j || "j";
let obj = {
[q]: "",
[j]: ""
};
if (str) {
obj[q] =
PinYin(str, {
style: PinYin.STYLE_NORMAL
}).join("") || "";
obj[j] =
PinYin(str, {
style: PinYin.STYLE_FIRST_LETTER
}).join("") || "";
}
return obj;
}
// 注册全局汉字转拼音方法
import pinyin from "@/utils/pinyin";
Vue.prototype.$pinyin = pinyin;
父组件
<select-multiple
:id.sync="form.shop"
:list="initData.shops"
name="适用门店"
placeholder="请选择适用门店"
type="Array"
></select-multiple>
子组件
<template>
<el-select
v-model="data_id"
:placeholder="placeholder || `请选择${name}`"
@change="changeData"
clearable
filterable
collapse-tags
:no-data-text="`未搜索到${name}`"
loading-text="搜索中"
:filter-method="remoteMethod"
:loading="loading"
:multiple="multiple"
@visible-change="visibleChange"
:default-first-option="true"
:disabled="disabled"
>
<div style="text-align: center; margin-bottom: 10px" v-show="multiple && isShowCheck">
<el-checkbox v-model="checked" @change="dataSelectAll">全选</el-checkbox>
</div>
<el-option
v-for="item in options"
:key="item[value] + Math.random()"
:label="item[label]"
:value="item[value]"
>
</el-option>
</el-select>
</template>
<script>
export default {
props: {
// 搜索placeholder
placeholder: {
type: String,
default: ""
},
// 搜索名称
name: {
type: String,
default: "门店"
},
// option选项的value键名
value: {
type: String,
default: "id"
},
// option选项的label键名
label: {
type: String,
default: "name"
},
// 传进来的选中数据
id: [String, Number, Array],
// 筛选项数据
list: Array,
// 多选数据分隔符
separator: {
type: String,
default: "_"
},
// 是否多选
multiple: {
type: Boolean,
default: true
},
// 传值类型 string、array
type: {
type: String,
default: "String"
},
// 是否禁用
disabled: {
type: Boolean,
default: false
},
// 全拼的键名,默认为q
q: {
type: String,
default: "q"
},
// 简拼的键名,默认为j
j: {
type: String,
default: "j"
}
},
data() {
return {
// 选中数据ID
data_id: [],
// 搜索数据加载状态
loading: false,
// 简拼搜索添加防抖
methodTimer: null,
// 获取到全部的数据
allOptions: [],
// 展示的数据
options: [],
// 全选、反选
checked: false,
// 是否显示全选按钮
isShowCheck: true
};
},
methods: {
// 监听选择值变化
changeData(val) {
if (this.multiple) {
if (val.length === this.allOptions.length) {
this.checked = true;
} else {
this.checked = false;
}
if (this.type === "String") {
this.$emit("update:id", val.join(this.separator));
this.$emit("change", val.join(this.separator));
} else if (this.type === "Array") {
this.$emit("update:id", val);
this.$emit("change", val);
}
} else {
this.$emit("update:id", val);
this.$emit("change", val);
}
},
// 搜索输入字符监控
remoteMethod(query) {
if (this.methodTimer) {
clearTimeout(this.methodTimer);
}
if (query !== "") {
this.isShowCheck = false;
this.loading = true;
if (this.methodTimer) {
clearTimeout(this.methodTimer);
}
query = query.toLowerCase();
this.methodTimer = setTimeout(() => {
this.options = this.allOptions.filter(i => {
return (
(i[this.q] && i[this.q].indexOf(query) !== -1) ||
(i[this.j] && i[this.j].indexOf(query) !== -1) ||
(i[this.label] && i[this.label].indexOf(query) !== -1)
);
});
this.loading = false;
clearTimeout(this.methodTimer);
}, 500);
} else {
this.loading = false;
this.isShowCheck = true;
this.computedOptions();
}
},
// 给可选项赋值全部数据
computedOptions() {
this.options = JSON.parse(JSON.stringify(this.allOptions));
},
// 下拉框显示隐藏事件
visibleChange(val) {
if (val) {
this.computedOptions();
}
},
// 选择门店全选&&反选
dataSelectAll() {
this.data_id = [];
if (this.checked) {
this.data_id = this.allOptions.map(item => {
return item[this.value];
});
}
this.changeData(this.data_id);
}
},
watch: {
// 监听门店数据变化
list: {
handler(val) {
if (val.length) {
const options = JSON.parse(JSON.stringify(val));
this.allOptions = options.map(i => {
return Object.assign(i, this.$pinyin(i[this.label], this.q, this.j));
});
this.computedOptions();
} else {
this.allOptions = [];
this.options = [];
}
},
deep: true,
immediate: true
},
id: {
handler(val) {
if (this.multiple) {
let isTrue = false;
if (this.type === "String") {
isTrue = this.data_id.join(this.separator) != val;
} else {
isTrue = this.data_id.join(this.separator) != val.join(this.separator);
}
if (isTrue) {
if (!val) {
this.checked = false;
this.data_id = [];
} else {
if (this.type === "String") {
this.data_id = val.split(this.separator);
} else {
this.data_id = val;
}
this.computedOptions();
}
}
} else {
this.data_id = val;
this.computedOptions();
}
},
deep: true,
immediate: true
}
}
};
</script>
<style lang="scss" scoped>
::v-deep.el-select {
width: 100%;
}
::v-deep.el-select .el-select__tags {
.el-tag {
max-width: 100px;
overflow: hidden;
text-overflow: ellipsis;
}
}
</style>
希望对大家有帮助哟!文章来源地址https://www.toymoban.com/news/detail-523895.html
到了这里,关于vue+elememt-ui el-select组件封装的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!