Vue 仿B站滑动导航

仿照B站制作的滑动导航功能,进行了部分优化,例如可定制默认选中元素,并将选中元素居中显示,可动态更改数据,可定制回调函数取的下标和选中元素内容,可根据需求制作N级联动

已开发成插件,使用方法与源码请前往github------传送门

注:此项目依托于swiper

vue-tabbar-slide.vue

template:

<div class="tabbar-slide-wrapper">
  <div class="swiper-container" :class="options.container">
    <div class="swiper-wrapper">
      <div :style="[slideStyle, {'color': (index == slideOptions.slideIndex) ? slideStyle.checkedColor : slideStyle.color}]" :class="[index == slideOptions.slideIndex ? 'swiper-slide-checked' : '', 'swiper-slide']" v-for="(item, index) in options.slideData" :key="index">{{item}}</div>
      <!-- 下划线 -->
      <div :style="{ slideStyle.width, height: downLineStyle.downLineHeight, background: downLineStyle.downLineColor}" ref="slideDownLine" class="slide-down-line"></div>
    </div>
  </div>
  <div class="tabbar-slide-container"></div>
</div>

script:

import Swiper from 'swiper'
import '../../node_modules/swiper/dist/css/swiper.min.css'

  export default {
    name: 'vueTabbarSlide',
    props: ['options'],
    data () {
      return {
        mySwiper: null,
        //数据
        slideArr: this.options.slideData || ['slide1', 'slide2', 'slide3', 'slide4', 'slide5', 'slide6', 'slide7', 'slide8', 'slide9', 'slide10', 'slide11', 'slide12', 'slide13'],
        //样式
        slideStyle: {
          //宽度
           this.options.width || '80px',
          //高度
          height: this.options.height || '40px',
          //垂直高度
          lineHeight: this.options.height || '40px',
          //文本排列方式
          textAlign: this.options.textAlign || 'center',
          //字体大小
          fontSize: this.options.fontSize || '14px',
          //字体格式
          fontFamily: this.options.fontFamily || 'Microsoft YaHei',
          //默认字体颜色
          color: this.options.color || '#333',
          //选中字体颜色
          checkedColor: this.options.checkedColor || '#00a0e9'
        },
        downLineStyle: {
           //下划线高度
          downLineHeight: this.options.downLineHeight || '2px',
          //下划线颜色
          downLineColor: this.options.downLineColor || '#00a0e9',
        },
        //选项
        slideOptions: {
          slideIndex: this.options.index || 0
        },
        //下划线
        slideDownLine: null
      }
    },
    watch: {
      options: {
        //此处不要用箭头函数,this会跑偏 ^_^
        handler: function(newValue, oldValue) {
          if (this.mySwiper) {
            this.mySwiper.destroy(true, false)
          }
          this.mySwiper = new Swiper(`.${this.options.container}`, {
            slidesPerView: "auto",
            freeMode: true,
            freeModeMomentumRatio: 0.5,
            observer: true,
            observeParents: false,
            on: {
              init: () => {
                //默认选中
                this.slideOptions.slideIndex = this.options.index || 0
                //下划线
                this.$refs.slideDownLine.style.transform = `translateX(${this.slideOptions.slideIndex*parseInt(this.slideStyle.width)}px)`
                //回调函数
                this.$emit("callback", event, this.slideOptions.slideIndex, this.options.slideData[this.slideOptions.slideIndex])
              },
              tap: () => {
                //滑动时间
                this.mySwiper.setTransition(300)
                //滑动
                this.slide(swiperWidth, maxTranslate, maxWidth)
                //更改class
                this.slideOptions.slideIndex = this.mySwiper.clickedIndex
                //下划线
                this.$refs.slideDownLine.style.transform = `translateX(${this.slideOptions.slideIndex*parseInt(this.slideStyle.width)}px)`
                //回调函数
                this.$emit("callback", event, this.mySwiper.clickedIndex, event.target.innerText)
              }
            }
          });
          //swiper可视宽度
          const swiperWidth = this.mySwiper.width
          //swiper最大移动距离
          const maxTranslate = swiperWidth - (parseInt(this.options.width) * this.options.slideData.length)
          //
          const maxWidth = -maxTranslate + swiperWidth / 2
     },
     deep: true
      }
    },
    methods: {
      slide(swiperWidth, maxTranslate, maxWidth) {
        //点击的slide
        const slide = this.mySwiper.slides[this.mySwiper.clickedIndex]
        //点击的slide offsetLeft距离浏览器左边距离
        const slideLeft = slide.offsetLeft
        //点击的slide的可视宽度
        const slideWidth = slide.clientWidth
        // 被点击slide的中心点
        const slideCenter = slideLeft + slideWidth / 2
        //当中心点距离少于一半宽度时
        if (slideCenter < swiperWidth / 2) {

          this.mySwiper.setTranslate(0)

        } else if (slideCenter > maxWidth) {

          this.mySwiper.setTranslate(maxTranslate)

        } else {

          const nowTlanslate = slideCenter - swiperWidth / 2

          this.mySwiper.setTranslate(-nowTlanslate)

        }
        //选中颜色
        slide.style.color = this.downLineStyle.downLineColor
      }
    }
  }

App.vue

template:

<div id="app">
  <vue-tabbar-slide :options="options" @callback="callback"></vue-tabbar-slide>
  <vue-tabbar-slide1 :options="options1" @callback="callback1"></vue-tabbar-slide1>

  <div @click="getData">点击获取数据</div>
  <div>第一行下标及数据{{callbackHtml}},<br>第二行下标及数据{{callbackHtml1}}</div>
</div>

script:

import vueTabbarSlide from './lib/vueTabbarSlide'

export default {
  name: 'app',
  data () {
    return {
      options: {
        container: 'mySlide1',
        slideData: [],
         '80px',
        index: 1
      },
      options1: {
        container: 'mySlide2',
        slideData: [],
         '80px',
        index: 1
      },
      callbackHtml: '',
      callbackHtml1: ''
    }
  },
  components: {
    vueTabbarSlide: vueTabbarSlide,
    vueTabbarSlide1: vueTabbarSlide
  },
  methods: {
    getData () {
      this.options.slideData = ['data1', 'data2', 'data3', 'data4', 'data5', 'data6', 'data7', 'data8', 'data9', 'data10']
      this.options1.slideData = ['data11', 'data21', 'data31', 'data41', 'data51', 'data61']
    },
    callback (event, index, val) {
      this.callbackHtml = index + ';' + val
    },
    callback1 (event, index, val) {
      this.callbackHtml1 = index + ';' + val
    },
  }
}

在使用中有问题请先去github中查看是否更新到最新版本

如果在新版本中未解决,欢迎您在此或github中给我issure,这样会让我开心很长时间,我也会在第一时间认真解决您的问题

最后,感谢您阅读至此。

原文地址:https://www.cnblogs.com/bbbiu/p/9002915.html