tab切换时是项目中经常用到的,把这个功能记录下来,共享
<!-- 思路: 1,右侧3个tab导航名称。注意:2种样式,未选中的样式,选中的那个改变样式 2. 左侧对应tab的内容。 注意:数据格式,循环出来的 [ title: '导航', subtitle: '线性图标', icons: [ { url: '../../a.svg', name: '张' }, { url: '../../a.svg', name: '张' } ], title: '装饰', subtitle: '线性图标', icons: [ { url: '../../b.svg', name: '张' }, ] ] 3. 加滚动事件 注意:可以选择原生,可以引用插件vue-scrollto;通过ref获取标题节点和滚动的区域大小 4. 加点击监听事件,获取id,把id这个div上加scrollIntoView这个事件 知识点: 滚动事件 cnblogs.com/97z4moon/p/14566564.html window.addEventListener('scroll',this.handleScroll,true) // 添加滚动监听 -- 第一个参数是事件类型,第二个事件是函数,第三个参数true防止监听事件无效 document.documentElement.scrollTop; // 获取滚动条位置;要获取当前页面的滚动条纵坐标位置;documentElement对应的是html document.body.scrollTop; // 对应的是body标签,上面的更准确 window.pageYOffset; // 返回文档在窗口左上角垂直方向的滚动像素 点击事件 document.getElementById: 获取id Element.scrollIntoView方法让当前的元素滚动到浏览器窗口的可视区域内 默认为true: 滚动到顶部 false:滚动到底部 behavior: 属性定义动画过度效果 block:垂直方向的对齐 inline:水平方向的对齐 element.getBoundingClientRect():https://developer.mozilla.org/zh-CN/docs/Web/API/Element/getBoundingClientRect 滚动页面: 有时也可以用offsettop和scrolltop -->
代码如下:
<template>
<div>
<div class="wrapper">
<!-- 左侧内容 -->
<div class="wrapper-left">
<!-- id dom节点,是为了样式 -->
<div
class="icons"
v-for="(item,index) in iconList"
:id="`tab-${index+1}`"
:key="index">
<div class="icons-title" :ref="`tab${index + 1}`">{{item.title}}</div>
<div class="icons-subtitle">{{item.subtitle}}</div>
<div class="icons-icon">
<div
class="block"
v-for="(itemChild,index) in item.icons"
:key="index">
<img :src="itemChild.url" id="girlImg" >
<div class="name">{{ itemChild.name }}</div>
</div>
</div>
</div>
</div>
<!-- 右侧tab -->
<div class="wrapper-right">
<div class="tab">
<ul>
<li id="nav1" :class="{'select-tab': active === 1}" @click="setTab(1)">导航图标</li>
<li id="nav2" :class="{'select-tab': active === 2}" @click="setTab(2)">操作图标</li>
<li id="nav3" :class="{'select-tab': active === 3}" @click="setTab(3)">装饰图标</li>
</ul>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "Tab",
data(){
return {
active: 1,// 选中tab
cancelScroll: false,
iconList: [
{
title: '导航图标',
subtitle: '线性图标',
icons: [
{
url: require('../../../src/assets/icon/icon_1.1.1.2首页02.svg'),
name: '首页'
},
{
url: require('../../../src/assets/icon/icon_1.1.1.3资料.svg'),
name: '资料'
}
],
},
{
title: '操作图标',
subtitle: '线性图标',
icons: [
{
url: require('../../../src/assets/icon/icon_2.1.1.1编辑.svg'),
name: '编辑'
}
]
},
{
title: '装饰图标',
subtitle: '线性图标',
icons: [
{
url: require('../../../src/assets/icon/icon_3.1.1.1word.svg'),
name: 'word'
}
],
}
]
};
},
mounted() {
window.addEventListener('scroll', this.handleScroll,true);
},
beforeDestroy () {
// 清除监听
// Cannot read property ‘getBoundingClientRect‘ of undefined
window.removeEventListener('scroll', this.handleScroll,true);
},
methods:{
/**
* 选中点击事件
* @param tab
*/
setTab(tab){
this.active = tab;
document.getElementById(`tab-${tab}`).scrollIntoView({ behavior : "smooth", block: "start" });
// 解决点击tab的时候跳到上一个tab(晃一下)问题; 也就是触发点击事件的同时也出发了滚动事件
this.cancelScroll = true;
setTimeout(() =>{
this.cancelScroll = null;
});
},
/**
* 滚动监听事件
*/
handleScroll(){
if (this.cancelScroll){
return;
}
// this.$refs 获取的是节点 不是数组
let tab1top = this.$refs['tab1'][0].getBoundingClientRect().top;
let tab2top = this.$refs['tab2'][0].getBoundingClientRect().top;
let tab3top = this.$refs['tab3'][0].getBoundingClientRect().top;
console.log(document.documentElement.scrollTop, '页面滚出');
// 86是怎么算的?也可以是0,小于0就是滚出去;(内容超出自己的高度,才会有滚动)
// 第一个tab的滚动的距离
if (tab1top < 0 && tab2top > 0){
this.active = 1;
}
// 第二个tab的滚动的距离
if (tab2top < 0 && tab3top > 0){
this.active = 2;
}
// 第三个tab的滚动的距离
if (tab3top < 0){
this.active = 3;
}
}
}
};
</script>
<style scoped lang="scss">
.wrapper{
width: 100%;
height: 100%;
margin: 20px 50px;
display: flex;
flex-direction: row;
&-left{
flex: 1;
.icons{
&-title{
font-size: 20px;
color: #09102B;
letter-spacing: 0;
margin: 44px 0 36px;
display: flex;
align-items: center;
}
&-subtitle{
font-size: 13px;
color: #667186;
letter-spacing: 0;
line-height: 22px;
margin-top: 10px;
}
&-icon{
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin-top: 30px;
.block{
border: 1px solid #F0F0F0;
width: 117px;
height: 128px;
margin-right: 36px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
margin-bottom: 24px;
.name{
padding-top: 20px;
}
}
}
}
}
&-right{
width: 300px;
.tab{
position: fixed;
ul{
list-style: none;
// 未选中情况下的样色
li{
padding:0;
background: #EEF1F6;
border-radius: 3px 100px 100px 98px;
cursor:pointer;
text-align:center;
text-decoration:none;
width:100px;
font-size:12px;
height:30px;
line-height:30px;
margin:10px 0px 10px 0;
position:relative;
color: #ADB1C3;
}
// 选中的样式
.select-tab{
background: #0F59BA;
border-bottom-color:#fff;
cursor:default;
font-weight:bold;
font-size: 12px;
height:30px;
line-height:30px;
color: #FFFFFF;
text-align: center;
}
}
}
}
}
</style>