Vue【原创】基于elementui的【分组多选下拉框group-select】

2023-08-30

效果图:

如图分为多选模式和单选模式。

group-select:

  1 <template>
2 <div>
3 <el-select
4 v-model="innerValue"
5 :placeholder="placeholder"
6 @change="changeSelect"
7 :clearable="clearable"
8 :multiple="multiple"
9 :collapse-tags="collapseTags"
10 size="small"
11 popper-class="productGroupSelector"
12 >
13 <el-option-group class="productGroupSelector-group" v-for="group in options" :key="group.label" :label="group.label">
14 <div style="display: flex; align-items: start;" v-if="multiple">
15 <div style="display: flex;align-items: center; padding-top: 8px; padding-left: 10px">
16 <el-checkbox v-model="group.checked" @change="selectAll($event, group.id)" :indeterminate="group.isIndeterminate"></el-checkbox>
17 </div>
18 <div>
19 <el-option
20 class="productGroupSelector-option"
21 v-for="item in group.options"
22 :key="item.value"
23 :label="item.label"
24 :value="item.value"
25 ></el-option>
26 </div>
27 </div>
28
29 <div v-else>
30 <el-option
31 class="productGroupSelector-option"
32 v-for="item in group.options"
33 :key="item.value"
34 :label="item.label"
35 :value="item.value"
36 ></el-option>
37 </div>
38 </el-option-group>
39 </el-select>
40 </div>
41 </template>
42 <script>
43 export default {
44 name: 'LiloGroupSelect',
45 model: {
46 prop: 'value',
47 event: 'change'
48 },
49 props: {
50 value: {
51 type: [String, Array],
52 default: ''
53 },
54 options: {
55 type: Array,
56 default() {
57 return [];
58 }
59 },
60 placeholder: {
61 type: String,
62 default: '请选择'
63 },
64 multiple: {
65 type: Boolean,
66 default: false
67 },
68 clearable: {
69 type: Boolean,
70 default: false
71 },
72 collapseTags: {
73 type: Boolean,
74 default: false
75 }
76 },
77 data() {
78 return {
79 innerValue: ''
80 };
81 },
82 mounted() {
83 this.innerValue = this.value;
84 },
85 watch: {
86 value(newVal, odlVal) {
87 this.innerValue = newVal;
88 }
89 },
90 methods: {
91 selectAll(val, id) {
92 const selectOption = this.options.find(f => f.id === id);
93 const arr = selectOption.options.map(m => m.value);
94 if (val) {
95 if((typeof this.innerValue !== 'object') || this.innerValue.constructor !== Array) {
96 this.innerValue = [];
97 }
98 arr.forEach(item => {
99 if (!this.innerValue.includes(item)) {
100 this.innerValue.push(item);
101 }
102 });
103 } else {
104 this.innerValue.forEach((item, index) => {
105 if (arr.includes(item)) {
106 this.innerValue.splice(index, 1, '');
107 }
108 });
109 }
110 this.innerValue = this.innerValue.filter(f => f !== '');
111 if (selectOption.checked) {
112 selectOption.isIndeterminate = false;
113 }
114 this.$emit('change', this.innerValue);
115 },
116 changeSelect(val) {
117 if (this.multiple) {
118 this.options.forEach(item => {
119 const arr = item.options.map(m => m.value);
120 item.isIndeterminate = arr.some(v => {
121 return val.some(s => s === v);
122 });
123 item.checked = arr.every(v => {
124 return val.some(s => s === v);
125 });
126 if (item.checked) {
127 item.isIndeterminate = false;
128 }
129 });
130 this.$emit('change', this.innerValue);
131 } else {
132 this.$emit('change', val);
133 }
134 }
135 }
136 };
137 </script>
138
139 <style>
140 .productGroupSelector {
141 min-width: initial !important;
142 width: 415px;
143 }
144 </style>
145
146 <style lang="scss" scoped>
147 ::v-deep {
148 .el-select-group {
149 width: 400px;
150 display: flex;
151 flex-wrap: wrap;
152 justify-content: start;
153 padding: 0px 10px;
154 }
155
156 .el-select-group__title {
157 padding-left: 20px;
158 font-size: 12px;
159 }
160 }
161
162 .productGroupSelector-group {
163 padding-top: 5px;
164 display: flex;
165 // align-items: center;
166 // flex-wrap: wrap;
167 // width: 400px;
168 padding-bottom: 5px;
169 flex-direction: column;
170 margin: 0 5px;
171
172 &:not(:last-child) {
173 border-bottom: 1px solid rgba($color: #000000, $alpha: 0.1);
174 }
175
176 &::after {
177 display: none;
178 }
179 }
180
181 .productGroupSelector-option {
182 display: inline-flex;
183 align-items: center;
184 flex-wrap: wrap;
185 }
186
187 // .productGroupSelector {
188 // .el-scrollbar__view .el-select-dropdown__list {
189 // display: flex;
190 // flex-wrap: wrap;
191 // justify-content: space-between;
192 // align-items: baseline;
193 // padding-top: 0;
194 // overflow-x: hidden;
195 // }
196 // .el-select-dropdown__wrap .el-scrollbar__wrap {
197 // max-height: 350px;
198 // }
199 // }
200 </style>

调用示例:

1 <el-row :gutter="20" class="mt-10">
2 <el-col :xs="12" :sm="12" :md="12" :lg="12" :xl="12">
3 <lilo-group-select :options="groupSelectOptions" @change="groupSelectChange" multiple clearable></lilo-group-select>
4 </el-col>
5 <el-col :xs="12" :sm="12" :md="12" :lg="12" :xl="12">
6 <lilo-group-select :options="groupSelectOptions2" @change="groupSelectChange" clearable></lilo-group-select>
7 </el-col>
8 </el-row>

测试数据:

  1 groupSelectOptions: [
2 {
3 id: 1,
4 label: '热门城市',
5 checked: false,
6 isIndeterminate: false,
7 options: [
8 {
9 value: 'Shanghai',
10 label: '上海'
11 },
12 {
13 value: 'Beijing',
14 label: '北京'
15 }
16 ]
17 },
18 {
19 id: 2,
20 label: '城市名',
21 checked: false,
22 isIndeterminate: false,
23 options: [
24 {
25 value: 'Chengdu',
26 label: '成都'
27 },
28 {
29 value: 'Shenzhen',
30 label: '深圳'
31 },
32 {
33 value: 'Guangzhou',
34 label: '广州'
35 },
36 {
37 value: 'Dalian',
38 label: '大连'
39 },
40 {
41 value: 'Huizhou1',
42 label: '惠州1'
43 },
44 {
45 value: 'Huizhou2',
46 label: '惠州2'
47 },
48 {
49 value: 'Huizhou3',
50 label: '惠州3'
51 },
52 {
53 value: 'Huizhou4',
54 label: '惠州4'
55 },
56 {
57 value: 'Huizhou5',
58 label: '惠州5'
59 },
60 {
61 value: 'Huizhou6',
62 label: '惠州6'
63 }
64 ]
65 }
66 ],
67 groupSelectOptions2: [
68 {
69 id: 1,
70 label: '超期',
71 options: [
72 {
73 value: 'cqwbj',
74 label: '超期未办结'
75 },
76 {
77 value: 'ycq',
78 label: '已超期'
79 }
80 ]
81 },
82 {
83 id: 2,
84 label: '按天',
85 options: [
86 {
87 value: 't1',
88 label: '1天'
89 },
90 {
91 value: 't2',
92 label: '2天'
93 },
94 {
95 value: 't3',
96 label: '3天'
97 },
98 {
99 value: 't4',
100 label: '4天'
101 },
102 {
103 value: 't5',
104 label: '5天'
105 },
106 {
107 value: 't6',
108 label: '6天'
109 },
110 {
111 value: 't7',
112 label: '7天'
113 },
114 {
115 value: 't8',
116 label: '8天'
117 },
118 {
119 value: 't9',
120 label: '9天'
121 }
122 ]
123 },
124 {
125 id: 3,
126 label: '按小时',
127 options: [
128 {
129 value: 'h1',
130 label: '1小时'
131 },
132 {
133 value: 'h2',
134 label: '2小时'
135 },
136 {
137 value: 'h3',
138 label: '3小时'
139 },
140 {
141 value: 'h4',
142 label: '4小时'
143 },
144 {
145 value: 'h5',
146 label: '5小时'
147 },
148 {
149 value: 'h6',
150 label: '6小时'
151 },
152 {
153 value: 'h7',
154 label: '7小时'
155 },
156 {
157 value: 'h8',
158 label: '8小时'
159 },
160 {
161 value: 'h9',
162 label: '9小时'
163 }
164 ]
165 }
166 ]
1 groupSelectChange(val) {
2 console.log(val);
3 }

若代码中涉及到的工具类和图片资源,请移步页面底部的gitee地址下载源码。

Vue【原创】基于elementui的【分组多选下拉框group-select】的相关教程结束。