87 lines
1.8 KiB
Vue
87 lines
1.8 KiB
Vue
<script setup lang="ts">
|
|
import { computed } from "vue";
|
|
|
|
const props = withDefaults(
|
|
defineProps<{
|
|
items?: string[];
|
|
modelValue?: number;
|
|
}>(),
|
|
{
|
|
items: () => [],
|
|
modelValue: 0,
|
|
}
|
|
);
|
|
const emit = defineEmits<{
|
|
(e: "update:modelValue", index: number): void;
|
|
(e: "onChange", target: { currentIndex: number }): void;
|
|
}>();
|
|
|
|
const activeStyle = computed(() => {
|
|
const x = 60 * props.modelValue;
|
|
return {
|
|
transform: `translate3d(${x}px, 0, 0)`,
|
|
};
|
|
});
|
|
|
|
const segmentedWidth = computed(() => {
|
|
return { width: `${props.items.length * 60}px` };
|
|
});
|
|
|
|
function segmentedItem(index: number) {
|
|
if (props.modelValue === index) return;
|
|
emit("update:modelValue", index);
|
|
emit("onChange", {
|
|
currentIndex: index,
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<view class="segmentedes" :style="segmentedWidth">
|
|
<view
|
|
class="segmented-item"
|
|
v-for="(item, index) in items"
|
|
:key="item"
|
|
:class="{ active: modelValue === index }"
|
|
@click="segmentedItem(index)"
|
|
>
|
|
<text>{{ item }}</text>
|
|
</view>
|
|
<div class="active-bar" :style="activeStyle"></div>
|
|
</view>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
.segmentedes {
|
|
display: flex;
|
|
position: relative;
|
|
align-items: center;
|
|
margin: 0 auto;
|
|
border: 1px solid $color-highlight-background;
|
|
border-radius: 5px;
|
|
.segmented-item {
|
|
position: relative;
|
|
z-index: 10;
|
|
flex: 1;
|
|
height: 30px;
|
|
line-height: 30px;
|
|
text-align: center;
|
|
font-size: $font-size-medium;
|
|
color: $color-text-d;
|
|
&.active {
|
|
color: $color-text;
|
|
}
|
|
}
|
|
.active-bar {
|
|
position: absolute;
|
|
left: 0;
|
|
top: 0;
|
|
width: 60px;
|
|
height: 30px;
|
|
transition: transform 0.3s;
|
|
border-radius: 5px;
|
|
background: $color-highlight-background;
|
|
}
|
|
}
|
|
</style>
|