Files
Friendship-and-chat-uniapp/sheep/components/segmented/segmented.vue
T
2025-11-11 21:58:44 +08:00

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>