可移动的下划线选中效果

851 阅读3分钟

可移动的选中效果的tag下划线

先看效果

activeTag.gif

首先把tag样式和点击事件写好

<script setup>
import { ref } from "vue";
const tagList = [
    "123123",
    "15135",
    "5435413541",
    "354354135",
    "534354135",
    "564564564656465",
    "4564564564",
    "564564564654654654564",
]; // tag数据
const activeTag = ref(null); // 当前选中的tag下标
</script>

<template>
    <!-- tag的盒子 -->
    <view class="tag-box">
        <!-- 每一个tag -->
        <view
            class="tag"
            v-for="(item, index) in tagList"
            :key="index"
            :class="activeTag == index ? 'tag--active' : ''"
            @click="activeTag = index"
            >{{ item }}</view
        >
    </view>
</template>

<style scoped lang="scss">
.tag-box {
    width: 750rpx;
    height: 100rpx;
    background-color: #777676;
    display: flex;
    align-items: center;
    overflow: scroll; // 超出滚动

    .tag {
        margin: 0 10rpx;

        // 这样写也可以
        // &--active {
        //     color: brown;
        // }
    }
    .tag--active {
        color: brown;
    }
}
</style>

此时效果

taglist.gif

前置工作准备完成,接下来先把下划线写出来

<template>
    <!-- tag的盒子 -->
    <view class="tag-box">
        <!-- 每一个tag -->
        <!-- ..... -->
        <!-- 下滑线 -->
        <view class="xian"></view>
    </view>
</template>

<style scoped lang="scss">
.tag-box {
    width: 750rpx;
    height: 100rpx;
    background-color: #777676;
    display: flex;
    align-items: center;
    overflow: scroll; // 超出滚动
    position: relative; // 相对定位

    .tag {
        margin: 0 10rpx;
    }
    .tag--active {
        color: brown;
    }
    // 下划线的样式
    .xian {
        background-color: #f5b501;
        width: 50rpx;
        height: 10rpx;
        border-radius: 9999rpx;
        position: absolute;
        left: 0;
        bottom: 15rpx;
    }
}
</style>

现在的效果

image.png

现在就会想到下划线的宽度以及定位的left需要动态改变,

  1. 宽度为当前选中tag的宽度
  2. left为当前选中tag在页面中的left

那么就需要获取节点的位置信息,

  1. 打开uniapp的官网
  2. 搜索这个API uni.createSelectorQuery
  3. 直接复制示例代码

image.png

然后再稍稍修改一下

import { ref, getCurrentInstance } from "vue";
import { onReady } from "@dcloudio/uni-app";

const tagXYList = ref([]); // 所有tag节点位置信息的数组
onReady(() => {
    const instance = getCurrentInstance();
    const query = uni.createSelectorQuery().in(instance.proxy);
    query
        // .select("#id") // 选中id='id'节点
        .selectAll(".tag") // 选中所有class='tag'节点
        .boundingClientRect((data) => {
            console.log(data); // 这里就是所有节点的坐标信息数组
            tagXYList.value = data; // 保存起来
        })
        .exec();
    activeTag.value = 0;
});

这个时候每个tag元素的宽度以及left已经被保存起来了 接下来只需要把当前选中的tag的宽度以及left给下划线赋值上就可以了(所有位置信息的单位都是px)

        <view
            class="xian"
            v-if="tagXYList.length"
            :style="{ width: tagXYList[activeTag].width + 'px', left: tagXYList[activeTag].left + 'px' }"
        ></view>

现在下划线的宽度和left就是当前选中tag的宽度和left了。 实现的核心就是使用uni.createSelectorQuery()获取节点的位置信息

完整代码

<script setup>
import { ref, getCurrentInstance } from "vue";
import { onReady } from "@dcloudio/uni-app";
const tagList = [
    "123123",
    "15135",
    "5435413541",
    "354354135",
    "534354135",
    "564564564656465",
    "4564564564",
    "564564564654654654564",
];

const tagXYList = ref([]);
const activeTag = ref(null);

onReady(() => {
    const instance = getCurrentInstance();

    const query = uni.createSelectorQuery().in(instance.proxy);
    query
        // .select("#id") // 选中id='id'节点
        .selectAll(".tag") // 选中所有class='tag'节点
        .boundingClientRect((data) => {
            console.log(data); // 这里就是所有节点的坐标信息数组
            tagXYList.value = data;
        })
        .exec();
    activeTag.value = 0; // 把下划线的初始位置设置到第一个
});
</script>

<template>
    <!-- tag的盒子 -->
    <view class="tag-box">
        <!-- 每一个tag -->
        <view
            class="tag"
            v-for="(item, index) in tagList"
            :key="index"
            :class="activeTag == index ? 'tag--active' : ''"
            @click="activeTag = index"
            >{{ item }}</view
        >
        <!-- 下滑线 -->
        <view
            class="xian"
            v-if="tagXYList.length"
            :style="{ width: tagXYList[activeTag].width + 'px', left: tagXYList[activeTag].left + 'px' }"
        ></view>
    </view>
</template>

<style scoped lang="scss">
.tag-box {
    width: 750rpx;
    height: 100rpx;
    background-color: #777676;
    display: flex;
    align-items: center;
    overflow: scroll; // 超出滚动
    position: relative;

    .tag {
        margin: 0 10rpx;

        // 这样写也可以
        // &--active {
        //     color: brown;
        // }
    }
    .tag--active {
        color: brown;
    }
    .xian {
        background-color: #f5b501;
        width: 50rpx;
        height: 10rpx;
        border-radius: 9999rpx;
        position: absolute;
        left: 0;
        bottom: 15rpx;
        transition: all 0.3s; // 加上过度效果
    }
}
</style>