Vue 简单自定义标签

Vue 简单自定义标签

思路:

1、计算每个项离父级左侧宽 left

2、计算当前滑块的宽,绝对定位

3、下一个项的宽/2-滑块的宽/2+下一项离父级左侧的宽 left

4、使用定位left(性能较差一点) 或 translate 移动距离

html 复制代码
<template>
    <div class="tab-list">
        <!--菜单-->
        <div class="tab-list-main">
            <div class="tab-list-main-item"
                 v-for="(item,index) in list"
                 :key="item.component"
                 :class="{ 'tab-list-main-active': index === currentIndex }"
                 @click="changeItem(index)"
            >
                {{item.title}}
            </div>
            <!--滑块-->
            <div class="tab-list-main-slider" id="lineSlider"></div>
        </div>
    </div>
</template>
js 复制代码
export default {
    name: "oil-tabs",
	props: {
	    list: { // 菜单
	        type: Array,
	        default: () => []
	    },
	    duration: { // 滑动所需时间 单位ms
	        type: Number,
	        default: () => 300
	    },
	    activeColor: { // 选中项颜色
	        type: String,
	        default: () => ''
	    }
	},
	data() {
	    return {
	        currentIndex: 0,// 当前的下标
	        itemObj: {} // 菜单项的位置
	    }
	},
	watch: {
	    list: {
	        handler(val) {
	            this.itemObj = {}
	            this.list = val
	            if (val && val.length > 0) {
	                this.$nextTick(() => {
	                    this.handleSlider()
	                })
	            }
	        }, immediate: true
	    }
	},
	methods: {
	    /**
	     * 点击tab项
	     * */
	    changeItem(index) {
	        if (this.currentIndex === index) {
	            return;
	        }
	        this.currentIndex = index
	        this.handleSlider()
	        let item = this.list[index]
	        this.$emit('change', item)
	    },
	    /**
	     * 计算菜单项的位置
	     * */
	    async handleItem() {
	        let obj = {}
	        this.itemObj = {}
	        let itemList = document.getElementsByClassName('tab-list-main-item');
	
	        if (itemList.length > 0) {
	            for (let o = 0; o < itemList.length; o++) {
	                obj[o] = itemList[o].getBoundingClientRect()
	                obj[o].offsetLeft = itemList[o].offsetLeft
	            }
	            this.itemObj = obj
	        }
	    },
	    /**
	     * 计算滑块当前位置
	     * */
	    async handleSlider() {
	        if (Object.keys(this.itemObj).length === 0) {
	            await this.handleItem()
	        }
	        let currentTab = this.itemObj[this.currentIndex]
	        if (!currentTab) {
	            return;
	        }
	        // 滑块
	        let lineSlider = document.getElementById('lineSlider');
	        if (!lineSlider) {
	            return;
	        }
	        // 滑块宽
	        let { width: currentWidth } = lineSlider.getBoundingClientRect();
			// 下一个菜单的宽及距父级左侧left
			let { offsetLeft, width } = currentTab;
			// 滑块位置
			// lineSlider.style.left = width / 2 - currentWidth / 2 + offsetLeft + 'px';
			lineSlider.style.transform = `translateX(${width / 2 - currentWidth / 2 + offsetLeft}px)`;
	    }
	}
}
css 复制代码
.tab-list {
    width: 100%;
    min-height: 28px;

    &-main {
        display: flex;
        flex-wrap: nowrap;
        white-space: nowrap;
        overflow: auto hidden;
        color: #ccc;
        position: relative;
        padding-bottom: 5px;

        &-item {
            margin-right: 24px;
            font-size: 14px;
            font-weight: 500;

            &:last-child {
                margin-right: 0;
            }
        }

        &-active {
            color: blue;
            font-weight: 800;
        }

        &-slider {
            margin-top: 2px;
            height: 3px;
            width: 28px;
            border-radius: 2px;
            background-color: blue;
            position: absolute;
            bottom: 0;
            left: 0;
            transform: translateX(0);
            will-change: left;
            transition: all .1s linear;
        }
    }
}
相关推荐
JieE2127 分钟前
LeetCode 226. 翻转二叉树|JS 递归超详细拆解,二叉树入门经典题
javascript·算法
JieE21223 分钟前
LeetCode 104. 二叉树的最大深度|递归思路超详细拆解
javascript·算法
爱勇宝1 小时前
鸿蒙生态的下半场:开发者不只要能开发,还要能赚钱
android·前端·程序员
IT_陈寒4 小时前
SpringBoot这个自动配置坑我跳了三次
前端·人工智能·后端
kyriewen4 小时前
我用 AI 一周写完了整个项目,上线第一天就崩了——这是我踩过最贵的 5 个坑
前端·javascript·ai编程
Larcher5 小时前
AI Loop:让AI像人一样自主完成任务的核心机制
javascript·人工智能·设计模式
默_笙5 小时前
🃏 JS 只有 8 种数据类型,但我花了 2 天才搞懂 null 和 undefined 的区别
javascript
牧艺5 小时前
从零到协同:构建类飞书在线文档系统的五个技术重难点
前端·人工智能
jump_jump5 小时前
流式 HTML:从 htmx 片段装配到浏览器原生增量渲染
javascript·性能优化·前端工程化
红尘散仙5 小时前
想写一个像样的终端 App?试试把 React 的开发体验搬进 Rust TUI
前端·rust