实现如图的一个滑块效果:
先讲思路:
整体的思路就是,两个图层上面一个是标题列表图层、下面一个是滑块的图层,当点击事件发生的时候滑块移动到对应标题下面
这里面有2个问题,我们怎么知道滑块应该移动到的对应文字的距离,还有就是怎么知道滑块的宽度的大小
实现步骤:
- 用v-for渲染出标题List
- 选中item的下标
- 所有的item元素
- ul的横向滚动偏移量
- 最后点击事件发生改变时候,获取循环列表的下标元素的left和width,以及来计算滑块位置和宽度
1、构建dom结构(注意!我这里是tailwindCss来构建css样式)
<div class="bg-white sticky top-0 left-0 z-10">
<ul
ref="ulTarget" //获取ul的dom结构后面来计算偏移量
class="relative flex overflow-auto p-2 pr-10 text-md text-zinc-800"
>
//背景滑块
<li
:style="sliderStyle" //动态绑定滑块的样式(用来设置滑块的动态宽度和过度平移位置)
class="h-[24px] top-2.5 rounded-3xl transition absolute bg-black duration-400"
></li>
//循环出标题列表
<li
:ref="sliderTarget"
v-for="(item, index) in home.categoryList"
:key="index"
class="shrink-0 px-2 py-0.5 z-10 mx-2 cursor-default"
@click="changeAction(index)"//点击事件用来确定点击的是那个标签
:class="action === index ? 'text-white duration-500' : ' '"//标签激活状态
>
{{ item.title }}
</li>
</ul>
</div>
2、用js来控制变化
//设置active当点击事件changeAction触发的时候,渲染对应的样式
let action = ref(0);
const changeAction = (index) => {
action.value = index;
};
//初始化滑块的样式
const sliderStyle = ref({
transform: "translateX(2px)",
width: "60px",
});
//存储将li存储到一个空数组里面
let itemRef = [];
const sliderTarget = (el) => {
if (el) {
itemRef.push(el);
}
};
onBeforeUpdate(() => {
itemRef = [];
});
const ulTarget = ref(null);
//可以获取ul标签的滚动偏移量位置,
//这个useScroll函数是vueuse的一个hook可以多学习一下很有效率
const { x } = useScroll(ulTarget);
//监听action变化
watch(action, (val) => {
//getBoundingClientRect方法返回一个 [`DOMRect`]对象,其提供了元素的大小及其相对于[视口]的位置。
const { left, width } = itemRef[val].getBoundingClientRect();
const res = itemRef[val].getBoundingClientRect();
sliderStyle.value = {
transform: `translateX(${x.value + left - 14}px)`,//计算偏移量
width: `${width + 12}px`,//计算宽度
};
});