AdaptiveSelect.vue
4.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
<template>
<div class="adaptive-select-container">
<el-select
v-model="selectedValue"
:placeholder="placeholder"
:popper-class="popperClass"
:style="selectStyle"
clearable
filterable
@change="handleChange"
@visible-change="handleVisibleChange"
>
<el-option
v-for="item in options"
:key="getOptionKey(item)"
:label="getOptionLabel(item)"
:value="getOptionValue(item)"
/>
</el-select>
</div>
</template>
<script>
import {ref, computed, onMounted, onUnmounted} from 'vue';
export default {
name: 'AdaptiveSelect',
props: {
// 选项列表
options: {
type: Array,
required: true,
default: () => []
},
// 默认选中的值
modelValue: {
type: [String, Number, Array],
default: ''
},
// 占位文本
placeholder: {
type: String,
default: '请选择'
},
// 小屏幕下的宽度 (默认100%)
mobileWidth: {
type: String,
default: '100%'
},
// 中等屏幕下的宽度 (默认80%)
tabletWidth: {
type: String,
default: '80%'
},
// 大屏幕下的宽度 (默认600px)
desktopWidth: {
type: String,
default: '600px'
},
// 选项的value字段名
valueKey: {
type: String,
default: 'value'
},
// 选项的label字段名
labelKey: {
type: String,
default: 'label'
},
// 是否可多选
multiple: {
type: Boolean,
default: false
},
// 是否可搜索
filterable: {
type: Boolean,
default: true
},
// 是否可清空
clearable: {
type: Boolean,
default: true
}
},
emits: ['update:modelValue', 'change'],
setup(props, {emit}) {
const selectedValue = ref(props.modelValue);
const windowWidth = ref(window.innerWidth);
const isDropdownVisible = ref(false);
// 监听窗口大小变化
const handleResize = () => {
windowWidth.value = window.innerWidth;
};
onMounted(() => {
window.addEventListener('resize', handleResize);
});
onUnmounted(() => {
window.removeEventListener('resize', handleResize);
});
// 根据窗口宽度调整选择框样式
const selectStyle = computed(() => {
if (windowWidth.value < 768) {
return {width: props.mobileWidth};
} else if (windowWidth.value < 1024) {
return {width: props.tabletWidth};
} else {
return {width: props.desktopWidth};
}
});
// 根据窗口宽度调整下拉框类名
const popperClass = computed(() => {
return windowWidth.value < 768 ? 'mobile-dropdown' : 'desktop-dropdown';
});
// 下拉框显示/隐藏时的处理
const handleVisibleChange = (visible) => {
isDropdownVisible.value = visible;
};
// 选项变化时的处理
const handleChange = (value) => {
emit('update:modelValue', value);
emit('change', value);
};
// 获取选项的key
const getOptionKey = (item) => {
return item[props.valueKey] || item.value;
};
// 获取选项的label
const getOptionLabel = (item) => {
return item[props.labelKey] || item.label || item[props.valueKey] || item.value;
};
// 获取选项的value
const getOptionValue = (item) => {
return item[props.valueKey] || item.value;
};
return {
selectedValue,
selectStyle,
popperClass,
handleVisibleChange,
handleChange,
getOptionKey,
getOptionLabel,
getOptionValue
};
}
};
</script>
<style scoped>
.adaptive-select-container {
padding: 0;
max-width: 100%;
box-sizing: border-box;
}
</style>
<style>
/* 全局样式,用于下拉框 */
.mobile-dropdown {
width: 90vw !important;
max-width: 100% !important;
}
.desktop-dropdown {
min-width: 200px !important;
max-width: 600px !important;
}
/* 响应式调整 */
@media (max-width: 768px) {
.el-select-dropdown {
max-width: calc(100vw - 40px) !important;
}
}
</style>