首先记录js的导航条点击居中,下划线跟随滚动。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>导航条点击居中,且下划线跟随滚动</title>
<script>
window.onload = function() {
var tabs = document.querySelector('.tabs')
var tab, position, liWidth
for (let i = 1; i <= 25; i++) {
tab = document.createElement('li')
tab.innerHTML = i
tabs.appendChild(tab)
tab.onclick = function(e) {
ulWidth = e.path[1].offsetWidth // 得到ul的宽度
position = e.path[0].offsetLeft // 得到被点击li的offsetLeft
liWidth = e.path[0].offsetWidth // 得到被点击li的offsetWidth
// 点击的目标li居中
tabs.scrollLeft = position - (ulWidth - liWidth) / 2
e.path[0].className = 'active'
// 下划线跟随滚动效果
var underline = document.querySelector('.underline')
underline.style.left = e.currentTarget.offsetLeft + 'px'
// e.target 是指当前点击的元素
// e.currentTarget 是指绑定事件的元素
}
}
}
</script>
</head>
<body>
<div class="tabs-box">
<ul class="tabs">
<li class="underline"></span>
</ul>
</div>
</body>
<style>
* {
margin: 0;
padding: 0;
}
.tabs-box {
height: 50px;
width: 100%;
}
.tabs {
overflow-x: auto;
height: 100%;
display: flex;
position: relative;
}
.tabs::-webkit-scrollbar {
width: 0;
height: 0;
}
li {
flex-basis: 100%;
padding: 0 10px;
height: 100%;
line-height: 50px;
list-style: none;
text-align: center;
}
.underline {
height: 1px;
width: 10px;
background: blue;
position: absolute;
bottom: 0;
}
</style>
</html>
在vue框架下导航条横线滑动,点击居中,记录位置防刷新。
<template>
<div class="my-channels">
<ul class="channels" ref="channels">
<li
class="channel"
v-for="(value, index) in channels"
:key="index"
@click.stop="openChannelDetail(value.id, index, $event)"
>
<div class="channel-name" :ref="`channel${index}`">
{{ value.name }}
</div>
</li>
<li class="channel-underLine" ref="channel-underLine"></li>
</ul>
</div>
</template>
<script>
import { getChannels } from '../api/index'
import { mapState, mapActions } from 'vuex'
import { getLocalStorage } from '../tools/index'
export default {
name: 'Tab',
data () {
return {
channels: [],
channelID: NaN
}
},
computed: {
...mapState(['user'])
},
created () {
if (this.user) {
// 登陆状态,请求获取线上用户的频道列表
getChannels()
.then(data => {
this.channels = data.data.channels
this.setMyChannels(data.data.channels)
this.channelID =
Number(sessionStorage.getItem('channelID')) || this.channels[0].id
})
.catch(function (error) {
console.log(error)
})
} else {
// 没有登陆,判断是否有本地存储的频道列表数据
if (getLocalStorage('user-channels')) {
this.channels = getLocalStorage('user-channels')
} else {
// 用户未登录,也没有本地存储的频道列表数据,那就请求获取默认推荐的频道列表
getChannels()
.then(data => {
this.channels = data.data.channels
this.setMyChannels(data.data.channels)
this.channelID =
Number(sessionStorage.getItem('channelID')) || this.channels[0].id
})
.catch(function (error) {
console.log(error)
})
}
}
},
updated () { // 记录位置,刷新位置不动
for (let i = 0; i < this.channels.length; i++) { // 记录位置防刷新
if (this.channelID === this.channels[i].id) {
this.openChannelDetail(this.channels[i].id, i)
}
}
},
methods: {
...mapActions(['setMyChannels']),
// 设置导航底部滚动条的位置
openChannelDetail (id, index, $event) {
// 设置导航条底部滚动条的位置
// var position = $event.path[1].offsetLeft
// var position = $event.path[0].offsetLeft // 获取被点击的li的offsetLeft
var position
if ($event) {
position = $event.path[0].offsetLeft // 获取被点击的li的offsetLeft
} else {
position = this.$refs[`channel${index}`][0].offsetLeft
// console.log(position)
}
// console.log(position, this.$refs[`channel${index}`][0].offsetWidth, this.$refs[`channel${index}`][0].offsetWidth)
// 获取li宽度的方式一
var liWidth = this.$refs[`channel${index}`][0].offsetWidth
// 获取li宽度的方式二
// const childNodes = this.$refs.channels.childNodes
// const liWidth = childNodes[index].clientWidth
// var ulLeft = this.$refs.channels.scrollLeft
var ulWidth = this.$refs.channels.offsetWidth
this.$refs.channels.scrollLeft = position - ulWidth / 2 + liWidth / 2
const activeChannelLeft = this.$refs[`channel${index}`][0].offsetLeft
// this.$refs['channel-underLine'].style.width = liWidth + 'px'
this.$refs['channel-underLine'].style.left =
activeChannelLeft +
(liWidth - this.$refs['channel-underLine'].offsetWidth) / 2 +
'px'
// 给Channels组件传递不同的数据
this.channelID = id
}
}
}
</script>
<style lang="less" scoped>
.my-channels {
width: 100%;
position: relative;
margin-bottom: 10px;
.channels {
overflow-x: auto;
height: 45px;
line-height: 45px;
position: relative;
display: flex;
&::-webkit-scrollbar {
display: none;
}
.channel {
display: inline-block;
background: white;
padding: 0 10px;
box-sizing: border-box;
border-bottom: 1px solid #ccc;
flex-basis: percentage(100%);
&:not(:first-child) {
border-left: 1px solid #ccc;
}
.channel-name {
min-width: 80px;
font-size: 15px;
color: #333;
text-align: center;
}
}
.channel-underLine {
position: absolute;
left: 10px;
bottom: 5px;
width: 20px;
height: 2px;
background: #1989fa;
transition: all 0.2s linear 0s;
border: none;
}
}
}
</style>