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;
        }
    }
}
相关推荐
忧郁的蛋~16 分钟前
HTML表格导出为Excel文件的实现方案
前端·html·excel
小彭努力中17 分钟前
141.在 Vue 3 中使用 OpenLayers Link 交互:把地图中心点 / 缩放级别 / 旋转角度实时写进 URL,并同步解析显示
前端·javascript·vue.js·交互
然我37 分钟前
别再只用 base64!HTML5 的 Blob 才是二进制处理的王者,面试常考
前端·面试·html
NanLing39 分钟前
【纯前端推理】纯端侧 AI 对象检测:用浏览器就能跑的深度学习模型
前端
呆呆的心41 分钟前
前端必学:从盒模型到定位,一篇搞定页面布局核心 🧩
前端·css
小飞悟41 分钟前
前端高手才知道的秘密:Blob 居然这么强大!
前端·javascript·html
小old弟42 分钟前
用Sass循环实现炫彩文字跑马灯效果
前端
code_YuJun42 分钟前
Promise 基础使用
前端·javascript·promise
Codebee42 分钟前
OneCode自主UI设计体系:架构解析与核心实现
前端·javascript·前端框架
GIS之路1 小时前
GIS 空间关系:九交模型
前端