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;
        }
    }
}
相关推荐
肥肥呀呀呀33 分钟前
在Flutter上如何实现按钮的拖拽效果
前端·javascript·flutter
Zero1017131 小时前
【React的useMemo钩子详解】
前端·react.js·前端框架
养军博客1 小时前
spring boot3.0自定义校验注解:文章状态校验示例
java·前端·spring boot
uperficialyu1 小时前
2025年01月10日浙江鑫越系统科技前端面试
前端·科技·面试
付朝鲜1 小时前
用自写的jQuery库+Ajax实现了省市联动
java·前端·javascript·ajax·jquery
coderYYY2 小时前
多个el-form-item两列布局排齐且el-select/el-input组件宽度撑满
前端·javascript·vue.js·elementui·前端框架
荔枝吖2 小时前
项目中会出现的css样式
前端·css·html
Dontla2 小时前
何时需要import css文件?怎么知道需要导入哪些css文件?为什么webpack不提示CSS导入?(导入css导入规则、css导入规范)
前端·css·webpack
小堃学编程2 小时前
前端学习(2)—— CSS详解与使用
前端·css·学习
蓝婷儿2 小时前
第一章:HTML基石·现实的骨架
前端·html