本文已参与「新人创作礼」活动,一起开启掘金创作之路。
项目中多次用到,网上也看了一些别人封装的,都不太满意,于是自己动手封装了一个,不足之处,还请大家多多指点,如果项目中能用到的话,还望点个赞,直接上代码。 1.父组件
<template>
<div id="app">
<div>{{value1}}</div>
<MultipleSelectCheckbox v-model="value1" :order="1" placeholder="请选择" collapse-tags :options="options" style="width: 30%;" @change="change">
</MultipleSelectCheckbox>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<div>{{value2}}</div>
<MultipleSelectCheckbox v-model="value2" :order="2" is-inline placeholder="请选择" collapse-tags :options="options" style="width: 50%;">
</MultipleSelectCheckbox>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<div>{{value3}}</div>
<MultipleSelectCheckbox v-model="value3" :order="3" is-inline :text-width="100" placeholder="请选择" collapse-tags :options="options"
style="width: 80%;">
</MultipleSelectCheckbox>
</div>
</template>
<script>
import MultipleSelectCheckbox from "./components/MultipleSelectCheckbox"
export default {
name: 'App',
components: {
MultipleSelectCheckbox
},
data() {
return {
value1: ["选项1"],
value2: [],
value3: [],
options: [
{
value: '选项1',
label: '黄金糕11111111111111111111111'
},
{
value: '选项2',
label: '双皮奶'
},
{
value: '选项3',
label: '蚵仔煎333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333'
},
{
value: '选项4',
label: '龙须面'
},
{
value: '选项5',
label: '北京烤鸭'
},
{
value: '选项6',
label: '武汉热干面6666666666666666666'
},
{
value: '选项7',
label: '蔡甸牛肉面7777777777777777777'
}
]
}
},
methods: {
change() {
console.log(this.value1)
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
margin-top: 60px;
padding-inline-start: 100px;
}
</style>
2.子组件
<template>
<el-select v-model="selectValues" :popper-class="'multiple_select_popper_' + order" v-bind="$attrs" v-on="$listeners" multiple
:class="'multiple_select_checkbox_' + order" @visible-change="visibleChange" @change="changeSelect">
<el-option v-if="options_.length" label="全选" value="全选">
<el-checkbox v-model="isSelectAll" @click.native.prevent>全选</el-checkbox>
</el-option>
<el-option v-for="item in options_" :key="item[props.value]" :label="item[props.label]" :value="item[props.value]">
<el-tooltip :disabled="!item.isExceed" :content="item[props.label]" placement="top" effect="light">
<el-checkbox :value="selectValues.includes(item[props.value])" @click.native.prevent>{{item[props.label]}}</el-checkbox>
</el-tooltip>
</el-option>
</el-select>
</template>
<script>
export default {
name: "MultipleSelectCheckbox",
inheritAttrs: false,// 似乎设不设置都可以
props: {
value: {
type: Array,
default: () => []
},
// 下拉选项
options: {
type: Array,
default: () => []
},
// 选项键值对
props: {
type: Object,
default: () => {
return {
label: "label",
value: "value"
}
}
},
// 选项是否独占一行
isInline: {
type: Boolean,
default: false
},
// 选项的宽度
textWidth: {
type: Number,
},
// 组件唯一标识 (避免同一个页面引用多次,发生耦合)
order: {
type: Number,
default: 0
}
},
data() {
return {
selectValues: this.value,
isSelectAll: false,
multipleSelectCheckboxMaxWidth: 0,
options_: []
}
},
mounted() {
const multipleSelectCheckbox = document.querySelector(`.multiple_select_checkbox_${this.order}.el-select`)
const elSelectDropdown = document.querySelector(`.multiple_select_popper_${this.order}.el-select-dropdown`)
const multipleSelectCheckboxMaxWidth = multipleSelectCheckbox.scrollWidth
this.multipleSelectCheckboxMaxWidth = multipleSelectCheckboxMaxWidth
elSelectDropdown.style["max-width"] = multipleSelectCheckboxMaxWidth + "px"
},
watch: {
// 监听(全选or全不选)
value: {
handler(arr) {
this.selectValues = arr
this.isSelectAll = arr.length === this.options_.length
}
},
options: {
handler(arr) {
this.options_ = JSON.parse(JSON.stringify(arr))
this.isSelectAll = this.selectValues.length === this.options_.length
},
immediate: true
}
},
methods: {
changeSelect(val) {
if (val.includes("全选")) {
// 说明已经全选了,所以全不选
if (val.length > this.options_.length) {
this.selectValues = []
}
// 反之,全选
else {
this.selectValues = this.options_.map(item => item[this.props.value])
}
}
this.$emit("input", this.selectValues)
},
// 判断元素是否溢出,溢出加上toolTip
async visibleChange(visible) {
await this.$nextTick()
if (visible) {
const maxLableWidth = this.multipleSelectCheckboxMaxWidth - 80
const labels = document.querySelectorAll(`.multiple_select_popper_${this.order}.el-select-dropdown .el-checkbox.el-tooltip .el-checkbox__label`)
labels.forEach((label, index) => {
// eslint-disable-next-line no-prototype-builtins
if (!this.options_[index].hasOwnProperty("isExceed")) {
this.$set(this.options_[index], "isExceed", label.scrollWidth - 10 > (this.textWidth || maxLableWidth))
label.style["width"] = this.textWidth + "px"
label.style["max-width"] = (this.textWidth || maxLableWidth) + "px"
label.style["vertical-align"] = "middle"
label.style["overflow"] = "hidden"
label.style["text-overflow"] = "ellipsis"
label.style["white-space"] = "nowrap"
}
})
const items = document.querySelectorAll(`.multiple_select_popper_${this.order} .el-select-dropdown__item:not(:first-child)`)
items.forEach(item => {
item.style.display = this.isInline ? "inline-block" : "block"
})
}
}
}
}
</script>
<style scoped>
[class*="multiple_select_popper"].el-select-dropdown.is-multiple .el-select-dropdown__item.selected::after {
content: "";
}
</style>