vue横向滑动导航条点击居中,下划线跟随移动,记录位置防刷新

首先记录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>

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值