这是一个多选下拉框的组件,简单弄了一个样式,后续有时间可以会加一下动画效果啥的,现在将就着用先。
通过父组件传入数据可以实现多数据多页面的复用。
子组件:
html部分:
<template>
<div class="select_wrap">
<div class="content" @click.stop="togglePanel">
<div class="selected_item">
<div>{{ defaultValue }}</div>
</div>
</div>
<div v-if="panelShow" class="checkbox_content">
<div class="checkbox_list">
<div :class="['select_item', { 'select_item_active': isAll }]" @click.stop="handleAll">全部</div>
<div v-for="item in courseData" :key="item.id" :class="['select_item', { 'select_item_active': item.checkType }]" @click.stop="toggleItem(item)">
<input type="checkbox" v-model="item.checkType">
<span>{{ item.text }}</span>
</div>
</div>
</div>
</div>
</template>
js部分:
<script>
export default {
name: "Select",
props: {
courseData: {
type: Array,
required: true,
default:{}
}
},
data() {
return {
selectData: [],
panelShow: false,
isAll: false
};
},
computed: {
defaultValue() {
if (this.isAll) {
return '全部';
} else if (this.selectData.length > 0) {
return this.selectData.map(item => item.text).join(', ');
} else {
return this.courseData.length ? this.courseData[0].text : null;
}
}
},
watch: {
courseData: {
immediate: true,
handler() {
this.resetSelections();
}
}
},
methods: {
togglePanel() {
this.panelShow = !this.panelShow;
if (this.panelShow) {
document.addEventListener("click", this.closeList);
} else {
document.removeEventListener("click", this.closeList);
this.validateSelections();
}
},
toggleItem(item) {
item.checkType = !item.checkType;
this.updateSelections();
},
handleAll() {
this.isAll = !this.isAll;
if (this.isAll) {
this.courseData.forEach(item => {
item.checkType = true;
});
this.selectData = [...this.courseData];
} else {
this.courseData.forEach(item => {
item.checkType = false;
});
this.selectData = [];
}
this.$emit("change", this.selectData);
},
updateSelections() {
this.selectData = this.courseData.filter(item => item.checkType);
this.isAll = this.selectData.length === this.courseData.length;
this.$emit("change", this.selectData);
},
validateSelections() {
if (!this.selectData.length) {
this.courseData[0].checkType = true;
this.selectData = [this.courseData[0]];
this.isAll = false;
}
},
resetSelections() {
this.selectData = this.courseData.filter(item => item.checkType);
this.isAll = this.selectData.length === this.courseData.length;
},
closeList() {
this.panelShow = false;
}
}
};
</script>
css部分:
<style lang="scss" scoped>
/* 多选显示区 */
.select_wrap {
position: relative;
width: 120px;
.content {
display: flex;
align-items: center;
border-radius: 2px;
border: 1px solid rgba(0, 0, 0, 0.3);
.selected_item {
display: flex;
align-items: center;
border-radius: 2px;
padding: 0 10px;
}
}
.checkbox_content {
position: absolute;
left: 0;
top: 30px;
width: 100%;
.checkbox_list {
position: absolute;
border: 1px solid rgba(0, 0, 0, 0.3);
left: 0;
top: 0;
right: 0;
height: 100px;
background-color: #fff;
padding: 10px 0;
z-index: 99;
text-align: left;
overflow: hidden;
overflow-y: auto;
/* 滚动条样式 */
&::-webkit-scrollbar {
width: 6px; /* 设置纵轴(y轴)轴滚动条 */
height: 6px; /* 设置横轴(x轴)轴滚动条 */
}
/* 滚动条滑块(里面小方块) */
&::-webkit-scrollbar-thumb {
border-radius: 10px;
background: #fff;
}
/* 滚动条轨道 */
&::-webkit-scrollbar-track {
border-radius: 0;
box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
background: transparent;
}
.select_item {
display: flex;
align-items: center;
justify-content: center;
height: 25px;
padding: 0 5px;
cursor: pointer;
&:hover {
background: orange;
}
}
.select_item_active {
background: orange;
}
input {
height: 16px;
width: 16px;
border: 1px solid rgba(0, 0, 0, 0.3);
}
}
}
}
</style>
父组件就直接来了
<template>
<div class="home">
<HelloWorld :courseData="courseData" />
</div>
</template>
<script>
import HelloWorld from '@/components/HelloWorld.vue'
export default {
name: 'HomeView',
components: {
HelloWorld
},
data() {
return {
courseData: [
{ id: "1", text: "理想", checkType: true },
{ id: "2", text: "蔚来", checkType: false },
{ id: "3", text: "小米", checkType: false },
],
}
}
}
</script>
<style>
.home{
padding: 50px;
}
</style>
感兴趣的可以直接跑一下。