58 lines
1.5 KiB
Vue
58 lines
1.5 KiB
Vue
<template>
|
|
<view
|
|
class="flex items-center relative mx-auto border-1 border-solid border-#666 bg-#333 rounded-full overflow-hidden p-1"
|
|
:style="segmentedWidth"
|
|
>
|
|
<view
|
|
class="relative z-10 flex-1 h-40rpx line-height-40rpx text-center text-xs font-500 c-#fff active:text-color-theme"
|
|
v-for="(item, index) in items"
|
|
:key="index"
|
|
:class="{ active: modelValue === index }"
|
|
@click="segmentedItem(item, index)"
|
|
>
|
|
<text>{{ item.label }}</text>
|
|
</view>
|
|
<div
|
|
class="absolute h-2/3 bg-color-theme-dark rounded-full transform duration-100"
|
|
:style="activeStyle"
|
|
></div>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed } from 'vue';
|
|
|
|
const props = withDefaults(
|
|
defineProps<{
|
|
items?: { label: string }[];
|
|
modelValue?: number | string;
|
|
}>(),
|
|
{
|
|
items: () => [],
|
|
modelValue: 0,
|
|
},
|
|
);
|
|
const emit = defineEmits<{
|
|
(e: 'update:modelValue', index: number): void;
|
|
(e: 'change', item: { label: string }, index: number): void;
|
|
}>();
|
|
|
|
const activeStyle = computed(() => {
|
|
const x = 50 * Number(props.modelValue);
|
|
return {
|
|
width: `${50}px`,
|
|
transform: `translate3d(${x}px, 0, 0)`,
|
|
};
|
|
});
|
|
|
|
const segmentedWidth = computed(() => {
|
|
return { width: `${props.items.length * 50}px` };
|
|
});
|
|
|
|
function segmentedItem(item: { label: string }, index: number) {
|
|
if (props.modelValue === index) return;
|
|
emit('update:modelValue', index);
|
|
emit('change', item, index);
|
|
}
|
|
</script>
|