80 lines
1.9 KiB
Vue
80 lines
1.9 KiB
Vue
<script setup>
|
|
// 接收 type 和 options props 以及 v-model
|
|
const props = defineProps({
|
|
type: {
|
|
type: String,
|
|
default: 'purple-pink', // 默认颜色渐变
|
|
},
|
|
options: {
|
|
type: Array,
|
|
required: true, // 动态传入选项
|
|
},
|
|
modelValue: {
|
|
type: String,
|
|
default: '', // v-model 绑定的值
|
|
},
|
|
})
|
|
const emit = defineEmits(['update:modelValue'])
|
|
// 选中内容绑定 v-model
|
|
const selected = ref(props.modelValue)
|
|
|
|
// 监听 v-model 的变化
|
|
watch(() => props.modelValue, (newValue) => {
|
|
selected.value = newValue
|
|
})
|
|
|
|
// 根据type动态生成分割线的类名
|
|
const lineClass = computed(() => {
|
|
// 统一使用主题色渐变
|
|
return 'bg-gradient-to-r from-red-600 via-red-500 to-red-700'
|
|
})
|
|
|
|
// 计算滑动线的位置和宽度
|
|
const slideLineStyle = computed(() => {
|
|
const index = props.options.findIndex(option => option.value === selected.value)
|
|
const buttonWidth = 100 / props.options.length
|
|
return {
|
|
width: `${buttonWidth}%`,
|
|
transform: `translateX(${index * 100}%)`,
|
|
}
|
|
})
|
|
|
|
// 选择选项函数
|
|
function selectOption(option) {
|
|
selected.value = option.value
|
|
// 触发 v-model 的更新
|
|
emit('update:modelValue', option.value)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="relative flex">
|
|
<div
|
|
v-for="(option, index) in options"
|
|
:key="index"
|
|
class="flex-1 shrink-0 cursor-pointer py-2 text-center text-size-sm font-bold transition-transform duration-200 ease-in-out"
|
|
:class="{ 'text-gray-900': selected === option.value, 'text-gray-500': selected !== option.value }"
|
|
@click="selectOption(option)"
|
|
>
|
|
{{ option.label }}
|
|
</div>
|
|
<div
|
|
class="absolute bottom-0 h-[3px] rounded transition-all duration-300"
|
|
:style="slideLineStyle"
|
|
:class="lineClass"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
/* 自定义样式 */
|
|
button {
|
|
outline: none;
|
|
border: none;
|
|
cursor: pointer;
|
|
}
|
|
button:focus {
|
|
outline: none;
|
|
}
|
|
</style>
|