| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- <template>
- <view class="display-flex__ac channel-type__selector">
- <view
- v-for="(item, index) in list"
- :key="index"
- class="channel-type__tag text-center font-bold"
- :class="{ active: sltVal == item.value }"
- @click="tabClick(item)"
- >
- {{ item.name }}
- </view>
- <view
- class="channel-type__block backgroundCustom"
- :style="{
- width: blockWidth,
- transform: `translateX(${blockTranslateX})`
- }"
- ></view>
- </view>
- </template>
- <script setup lang="ts">
- import { computed, toRefs } from 'vue';
- const props = defineProps({
- config: {
- type: Object,
- default: () => ({
- name: "name",
- value: "value",
- })
- },
- tabList: {
- type: Array,
- default: () => []
- },
- value: {
- type: [String, Number],
- default: ""
- }
- });
- const emit = defineEmits(['tabClick', 'update:value']);
- // Use props directly or computed to normalize list based on config if needed.
- // However, the original code assigned `tabList` to `list` data.
- // And it accessed `item.value` and `item.name` in the template directly,
- // but the JS `tabClick` method used `this.properties.config.value` to find index.
- // The WXML used `item.value` directly in `data-value` and `sltVal == item.value`.
- // This implies the input `tabList` objects MUST have 'value' and 'name' properties,
- // OR the original WXML was relying on the fact that `item.value` worked.
- // Wait, looking at WXML: `{{item.name}}` and `data-value="{{item.value}}"`.
- // But `config` prop defaults to `{name: "name", value: "value"}`.
- // If the user passes a config with different keys, the WXML `item.name` might fail if not handled?
- // Actually, in the original JS `observer`, it just sets `list: val`.
- // So the original WXML assumes `item.name` and `item.value` exist on the objects in `tabList`.
- // BUT, the `config` prop suggests dynamic keys.
- // If `config` is used, we should probably map the list to standard keys or use the config keys in template.
- // The original WXML: `<view ...>{{item.name}}</view>`
- // This looks like it ignores `config.name` in the template rendering?
- // Let's check `tabClick` in JS:
- // `index: list.findIndex((item) => item[this.properties.config.value] == value)`
- // So logic USES config, but template uses hardcoded `name` and `value`.
- // This might be a bug or limitation in the original code, OR the `tabList` passed in always has `name`/`value` OR the `config` is rarely changed from default.
- // However, to be safe and "strict", I should probably respect `config` if possible, OR just reproduce the original behavior.
- // The original behavior: Template uses `.name` and `.value`. Logic uses `config`.
- // If I change template to use `item[config.name]`, it might break if `config` isn't passed correctly but data has `name`.
- // I will reproduce the original behavior:
- // 1. Template uses `item.name` and `item.value` (assuming data structure matches).
- // 2. Logic uses `config.value` for finding index.
- // Actually, looking at `tabClick` in JS: `const { value } = e.currentTarget.dataset;` -> comes from `data-value="{{item.value}}"`.
- // So `value` is definitely taken from `.value` property of item.
- // Then `list.findIndex((item) => item[this.properties.config.value] == value)`.
- // If `config.value` is "id", then it looks for `item.id == item.value`.
- // This implies `item.value` MUST be the value we are looking for.
- // I'll stick to the original WXML structure which accesses `.name` and `.value`.
- const { tabList: list, value: sltVal } = toRefs(props);
- const blockWidth = computed(() => {
- const len = list.value.length || 1;
- return `${100 / len}%`;
- });
- const blockTranslateX = computed(() => {
- const len = list.value.length || 1;
- const keyName = props.config.value || 'value'; // Default to 'value' if not set, though default prop handles it.
- const val = sltVal.value;
-
- if (len <= 0) return '100%';
-
- let idx = 0;
- for (let i = 0; i < len; i++) {
- // Original logic: list[i][keyName] == value
- // Note: original WXML passed `item.value` to dataset, so `value` is `item.value`.
- // But finding index uses `item[config.value]`.
- // This implies `item.value` and `item[config.value]` should be consistent.
- if (list.value[i][keyName] == val) {
- idx = i;
- break;
- }
- }
-
- // (idx * preWidth * (list.length || 1)) + '%'
- // preWidth = 100 / len
- // result = idx * (100/len) * len = idx * 100
- return `${idx * 100}%`;
- });
- const tabClick = (item: any) => {
- const val = item.value; // Corresponds to data-value="{{item.value}}"
- const keyName = props.config.value || 'value';
-
- const data = {
- config: props.config,
- list: list.value,
- value: val,
- index: list.value.findIndex((it: any) => it[keyName] == val),
- };
-
- emit('tabClick', data);
- emit('update:value', val);
- };
- </script>
- <style scoped lang="scss">
- .channel-type__selector {
- position: relative;
- height: 100upx;
- line-height: 100upx;
- overflow: hidden;
- display: flex;
- align-items: center;
- width: 100%;
- min-height: 80upx;
- height: fit-content;
- background-color: #fff;
- border-radius: 24upx;
- }
- .channel-type__tag {
- height: inherit;
- line-height: inherit;
- font-size: 32upx;
- flex: 1 0 0;
- z-index: 9;
- transition: all .3s ease-in-out;
- }
- .channel-type__tag.active {
- color: #fff;
- }
- .channel-type__block {
- position: absolute;
- height: 100%;
- z-index: 1;
- border-radius: 24upx;
- transition: all .3s ease-in-out;
- }
- .no-padding {
- padding: 0 !important;
- }
- .text-center {
- text-align: center;
- }
- .font-bold {
- font-weight: bold;
- }
- .backgroundCustom {
- background: var(--dominantColor) !important;
- color: #fff !important;
- }
- </style>
|