針對一些 HTML Element 的共用 CSS Style,Vue 並不鼓勵使用 Global CSS,而是建議這些 HTML Element 包成 Component,然後各 page 都使用此 Component,此時可在 Component 使用 v-model
,讓使用體驗與原生 HTML Element 無異。
Version
Vue 3.4
Common Style
- 為了風格統一,整個網站的 Select 都要使用此 style
app.vue
<template>
<select v-model="selected" class="minimal">
<option disabled value="">Please select one</option>
<option v-for="(item, i) in options" :value="item.value" :key="i">
{{ item.text }}
</option>
</select>
{{ selected }}
</template>
<script setup>
import { ref } from 'vue'
let selected = ref('')
let options = ref([
{ text: 'Apple', value: '0' },
{ text: 'Google', value: '1' },
{ text: 'Microsoft', value: '2' }
])
</script>
<style scoped>
select {
/* styling */
background-color: white;
border: thin solid blue;
border-radius: 4px;
display: inline-block;
font: inherit;
line-height: 1.5em;
padding: 0.5em 3.5em 0.5em 1em;
/* reset */
margin: 0;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
-webkit-appearance: none;
-moz-appearance: none;
}
select.minimal {
background-image: linear-gradient(45deg, transparent 50%, gray 50%),
linear-gradient(135deg, gray 50%, transparent 50%), linear-gradient(to right, #ccc, #ccc);
background-position:
calc(100% - 20px) calc(1em + 2px),
calc(100% - 15px) calc(1em + 2px),
calc(100% - 2.5em) 0.5em;
background-size:
5px 5px,
5px 5px,
1px 1.5em;
background-repeat: no-repeat;
}
select.minimal:focus {
background-image: linear-gradient(45deg, green 50%, transparent 50%),
linear-gradient(135deg, transparent 50%, green 50%), linear-gradient(to right, #ccc, #ccc);
background-position:
calc(100% - 15px) 1em,
calc(100% - 20px) 1em,
calc(100% - 2.5em) 0.5em;
background-size:
5px 5px,
5px 5px,
1px 1.5em;
background-repeat: no-repeat;
border-color: green;
outline: 0;
}
select:-moz-focusring {
color: transparent;
text-shadow: 0 0 0 #000;
}
</style>
Line 2
<select v-model="selected" class="minimal">
<option disabled value="">Please select one</option>
<option v-for="(item, i) in options" :value="item.value" :key="i">
{{ item.text }}
</option>
</select>
<select>
使用minimal
CSS class 重新定義其 style,並且希望整個網站的<select>
都使用minimal
CSS class
MySelect
App.vue
<template>
<MySelect v-model="selected" :options />
{{ selected }}
</template>
<script setup>
import { ref } from 'vue'
import MySelect from '@/components/MySelect.vue'
let selected = ref('')
let options = ref([
{ text: 'Apple', value: '0' },
{ text: 'Google', value: '1' },
{ text: 'Microsoft', value: '2' }
])
</script>
Line 2
<MySelect v-model="selected" :options />
- 將
minimal
CSS class 包進MySelect
component,將資料以options
prop 傳進去,原本的selected
仍搭配v-model
MySelect.vue
<template>
<select v-model="selected" class="minimal">
<option disabled value="">Please select one</option>
<option v-for="(item, i) in props.options" :value="item.value" :key="i">
{{ item.text }}
</option>
</select>
{{ selected }}
</template>
<script setup>
let selected = defineModel()
let props = defineProps({ options: Array })
</script>
<style scoped>
select {
/* styling */
background-color: white;
border: thin solid blue;
border-radius: 4px;
display: inline-block;
font: inherit;
line-height: 1.5em;
padding: 0.5em 3.5em 0.5em 1em;
/* reset */
margin: 0;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
-webkit-appearance: none;
-moz-appearance: none;
}
select.minimal {
background-image: linear-gradient(45deg, transparent 50%, gray 50%),
linear-gradient(135deg, gray 50%, transparent 50%), linear-gradient(to right, #ccc, #ccc);
background-position:
calc(100% - 20px) calc(1em + 2px),
calc(100% - 15px) calc(1em + 2px),
calc(100% - 2.5em) 0.5em;
background-size:
5px 5px,
5px 5px,
1px 1.5em;
background-repeat: no-repeat;
}
select.minimal:focus {
background-image: linear-gradient(45deg, green 50%, transparent 50%),
linear-gradient(135deg, transparent 50%, green 50%), linear-gradient(to right, #ccc, #ccc);
background-position:
calc(100% - 15px) 1em,
calc(100% - 20px) 1em,
calc(100% - 2.5em) 0.5em;
background-size:
5px 5px,
5px 5px,
1px 1.5em;
background-repeat: no-repeat;
border-color: green;
outline: 0;
}
select:-moz-focusring {
color: transparent;
text-shadow: 0 0 0 #000;
}
</style>
Line 12
let selected = defineModel()
let props = defineProps({ options: Array })
- 使用
defineModel()
定義selected
v-model - 使用
defineProps()
定義props
prop
Conclusion
v-model
特別適合將原本 HTML element 包成 component,因為 HTML element 也使用v-model
,包成 component 改變的代碼不多