基於vue封裝的橫向滾動tab欄組件
知識點:1,父子組件傳值 ,2,vue如何獲取dom元素(ref,$refs),3,點擊高亮,4,獲取屏幕寬度(window.innerWidth),5,左偏移量(offsetLeft),6,當前元素寬度(offsetWidth),7,左滾動(scrollLeft);
有兩種寫法:一,邏輯代碼在父組件中實現(本篇);二,邏輯代碼在子組件中實現(第二篇博客中); 如果一個項目中多次使用,建議采用第二種。
界面效果 (可橫向滑動)

父組件
<template>
<div class="home">
<header-tab
:listArray="list"
:current="current"
@change="changeTab"
ref="tab"
>
<img :src="imgSrc" alt="" slot="header_tab_img" />
</header-tab>
</div>
</template>
<script>
import HeaderTab from "../components/HeaderTab";
export default {
name: "home",
components: {
HeaderTab,
},
data() {
return {
list:[],
current: 1,
imgSrc: "",
};
},
created() {
this.getlist();
this.imgSrc = require("../assets/img/search.png");
},
methods: {
getlist() {
this.list = [
{ id: 1, name: "關注" },
{ id: 2, name: "推薦" },
{ id: 3, name: "科技" },
{ id: 4, name: "財經" },
{ id: 5, name: "生活" },
{ id: 6, name: "職場" },
{ id: 7, name: "時尚" },
{ id: 8, name: "汽車" },
{ id: 9, name: "娛樂" },
];
},
changeTab(index, e) {
this.current = index; // 高亮當前
let tab = this.$refs.tab.$refs.headertab; // 包裹 ul的 div
let tabitem = this.$refs.tab.$refs.tabitem; // 包裹 li的 ul
let winWidth = window.innerWidth; // 當前屏幕的寬度
let liList = e.target; // 當前點擊的li
if (liList) { // 當前li左偏移, li的寬度, 中間值(當前屏幕的寬度 - li的寬度) /2, 目標值 (中間值 - 當前li左偏移), 整個ul的寬度
let liLeft = liList.offsetLeft,
liWidth = liList.offsetWidth,
liCenter = (winWidth - liWidth) / 2,
liTarget = liLeft - liCenter;
let ulWidth = tabitem.offsetWidth;
if (liTarget < 0) {
tab.scrollLeft = 0;
return;
}
// winWidth(375) - ulWidth(436) = -61
if (liTarget < winWidth - ulWidth) {
tab.scrollLeft = -(winWidth - ulWidth) + liWidth;
return;
}
tab.scrollLeft = liTarget;
}
},
},
};
</script>
<style lang="less"></style>
子組件
<template>
<div class="header">
<div class="header_tab" ref="headertab">
<ul ref="tabitem">
<li
v-for="(item, index) in listArray"
:key="index"
:class="index == current ? 'activeheader' : ''"
@click="getTab(index, $event)"
>
{{ item.name }}
</li>
</ul>
</div>
<div class="header_search">
<slot name="header_tab_img"></slot>
</div>
</div>
</template>
<script>
export default {
name: "HeaderTab",
props: {
listArray: {
type: Array,
},
current:{
type:Number,
default:1,
}
},
data() {
return {
};
},
methods: {
getTab(index, e) {
this.$emit('change',index,e)
},
},
};
</script>
<style lang="less">
.header {
width: 100%;
height: 45px;
background-color: #fff;
display: flex;
}
.header_tab {
width: 90%;
height: 45px;
display: flex;
flex-wrap: nowrap;
overflow: scroll;
}
.header_tab::-webkit-scrollbar {
display: none;
}
ul {
display: inline-block;
white-space: nowrap;
}
li {
display: inline-block;
line-height: 45px;
padding: 0px 10px;
font-size: 14px;
color: #333;
// 點擊高亮某一項時,將原來的字體變大,會導致沒有高亮的元素距離上面有空隙,會出現縱向滾動條
margin-top: -1px;
}
.activeheader {
font-size: 16px;
font-weight: 700;
position: relative;
}
.activeheader:after {
position: absolute;
content: "";
width: 35%;
height: 2px;
bottom: 0;
left: 15px;
background-color: #333;
border-radius: 50px;
}
.header_search {
width: 10%;
height: 45px;
position: relative;
}
.header_search img {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
}
</style>
