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="{width: 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: {
          //寬度
          width: 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: [],
        width: '80px',
        index: 1
      },
      options1: {
        container: 'mySlide2',
        slideData: [],
        width: '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,這樣會讓我開心很長時間,我也會在第一時間認真解決您的問題

最后,感謝您閱讀至此。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM