zoukankan      html  css  js  c++  java
  • 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,这样会让我开心很长时间,我也会在第一时间认真解决您的问题

    最后,感谢您阅读至此。

  • 相关阅读:
    BZOJ3670:[NOI2014]动物园(KMP)
    415. [HAOI2009] 旅行
    U10223 Cx大帝远征埃及
    U10206 Cx的治疗
    2741. [济南集训 2017] 掰巧克力
    复习题目汇总 over
    7-20 表达式转换(25 分)
    7-19 求链式线性表的倒数第K项(20 分)(单链表定义与尾插法)
    7-18 银行业务队列简单模拟(25 分)
    7-17 汉诺塔的非递归实现(25 分)(有待改进)
  • 原文地址:https://www.cnblogs.com/bbbiu/p/9002915.html
Copyright © 2011-2022 走看看