better-scroll在vue中的使用


一、介紹

  關於better-scroll的原文詳細介紹請參考,這里只做總結

    黃老師的文章當 better-scroll 遇見 Vue》的詳細介紹

    better-scroll的api:點擊

  better-scroll的滾動原理

<div class="wrapper">
  <ul class="content">
    <li>...</li>
    <li>...</li>
    ...
  </ul>
</div>    

      

     綠色部分為 wrapper,也就是父容器,它會有固定的高度。黃色部分為 content,它是父容器的第一個子元素,它的高度會隨着內容的大小而撐高。那么,當 content 的高度不超過父容器的高度,是不能滾動的,而它一旦超過了父容器的高度,我們就可以滾動內容區了,這就是 better-scroll 的滾動原理。
     better-scroll 的初始化時機很重要,因為它在初始化的時候,會計算父元素和子元素的高度和寬度,來決定是否可以縱向和橫向滾動。因此,我們在初始化它的時候,必須確保父元素和子元素的內容已經正確渲染了。如果子元素或者父元素 DOM 結構發生改變的時候,必須重新調用 scroll.refresh() 方法重新計算來確保滾動效果的正常。

 

二、better-scroll在vue中的使用

  Vue.js 提供了我們一個獲取 DOM 對象的接口—— vm.$refs。在這里,我們通過了 this.$refs.wrapper 訪問到了這個 DOM 對象,並且我們在 mounted 這個鈎子函數里,this.$nextTick 的回調函數中初始化 better-scroll 。因為這個時候,wrapper 的 DOM 已經渲染了,我們可以正確計算它以及它內層 content 的高度,以確保滾動正常。

  這里的 this.$nextTick 是一個異步函數,為了確保 DOM 已經渲染,感興趣的同學可以了解一下它的內部實現細節,底層用到了 MutationObserver 或者是 setTimeout(fn, 0)。其實我們在這里把 this.$nextTick 替換成 setTimeout(fn, 20) 也是可以的(20 ms 是一個經驗值,每一個 Tick 約為 17 ms),對用戶體驗而言都是無感知的。

  

  這里從今日頭條截取獲取后台數據鏈接,用vue-jsonp來異步獲取數據。

  安裝vue-jsonp

npm install vue-jsonp --save-dev

  在組件單獨使用

import Vue from 'vue'
import VueJsonp from 'vue-jsonp'
Vue.use(VueJsonp)

  詳細請參考 vue-jsonp的npm地址:點擊

<template>
  <div>
     <nav class="nav">
      <ul>
        <li>推薦</li>
      </ul>
    </nav>
    <div class="wrapper" ref="wrapper">
      <div class="content" >
        <section class="has_action" v-for="item in data">
          <div class="item-detail">
            <h3 class="dotdot">{{item.title}}</h3>
            <div class="item-info">
              <div>
                <span class="stick_label space">{{item.label}}</span>
                <span class="src space">{{item.media_name}}</span>
                <span class="cmt space">評論{{item.comment_count}}</span>
                <span class="time space" title="2018-11-05 19:23">{{item.datetime}}</span>
              </div>
            </div>
          </div>
        </section>
      </div>
    </div>
  </div>
</template>

  

<script>
  import Vue from 'vue'
  import VueJsonp from 'vue-jsonp'
  import BScroll from 'better-scroll'
  Vue.use(VueJsonp)
  export default {
    name: 'myscroll',
    data() {
      return {
        data: []
      }
    },
    created() {
      this._getData().then(json => {
        this.data = json.data
        this.$nextTick(() => {
          this.scroll = new BScroll(this.$refs.wrapper,{})
        })
        
      })
    },
    methods: {
      // 或者頁面數據,調用今日頭條數據接口
      _getData() {
        return this.$jsonp('https://m.toutiao.com/list',{
          tag: '__all__',
          ac: 'wap',
          count: 20,
          format: 'json_raw',
          as: 'A1B57B7E600F6A7',
          cp: '5BE0AFC5FDAEAE1',
          min_behot_time: 1541469897,
          _signature: 'A6d5hAAAWEyp4NHR.YRHRAOneZ',
          i: 1541469650
        })
      }
    }
  }
</script>

注意:nav和wrapper這兩個class的css定位屬性

<style scoped lang="stylus">
  .nav
    z-index: 999
    position: fixed
    display: block
    box-sizing: border-box
    height: 74px
    width: 100%
    text-align: center
    line-height: 74px
    font-size: 20px
    color: #f85959
    background: #f4f5f6
  .wrapper
    position: fixed
    top: 74px
    left: 0
    bottom: 0
    right: 0
    overflow: hidden
    .content
      list-style: none
      .has_action
        position: relative
        margin: 0 30px
        border-bottom: 1px solid rgba(221, 221, 221, 0.6)
        .item-detail
          padding: 32px 0px;
          .dotdot
            overflow: hidden
            text-overflow: ellipsis
            line-height: 42px
            font-size: 34px
            font-weight: normal
            color: #222
          .item-info
            margin-top: 12px
            overflow: hidden
            font-size: 0
            color: #999
            .space
              display: inline-block
              margin-right: 10px
              vertical-align: middle
              line-height: 30px
              font-size: 28px
            .stick_label
              border-radius: 4px
              border: 1PX solid rgba(248,89,89,.5)
              width: 60px
              text-align: center
              color: #f85959
</style>
View Code

 

  

   結果如下:

   

 三、scroll 組件的抽象和封裝

  在components下面新建一個scroll文件夾->scroll.vue

  1 <template>
  2   <div ref="wrapper">
  3     <slot></slot>
  4   </div>
  5 </template>
  6 <script type="text/ecmascript-6">
  7   import BScroll from 'better-scroll'
  8   export default {
  9     props: {
 10       /**
 11        * 1 滾動的時候會派發scroll事件,會截流。
 12        * 2 滾動的時候實時派發scroll事件,不會截流。
 13        * 3 除了實時派發scroll事件,在swipe的情況下仍然能實時派發scroll事件
 14        */
 15       probeType: {
 16         type: Number,
 17         default: 1
 18       },
 19       /**
 20        * 點擊列表是否派發click事件
 21        */
 22       click: {
 23         type: Boolean,
 24         default: true
 25       },
 26       /**
 27        * 是否開啟橫向滾動
 28        */
 29       scrollX: {
 30         type: Boolean,
 31         default: false
 32       },
 33       /**
 34        * 是否派發滾動事件
 35        */
 36       listenScroll: {
 37         type: Boolean,
 38         default: false
 39       },
 40       /**
 41        * 列表的數據
 42        */
 43       data: {
 44         type: Array,
 45         default: null
 46       },
 47       /**
 48        * 是否派發滾動到底部的事件,用於上拉加載
 49        */
 50       pullup: {
 51         type: Boolean,
 52         default: false
 53       },
 54       /**
 55        * 是否派發頂部下拉的事件,用於下拉刷新
 56        */
 57       pulldown: {
 58         type: Boolean,
 59         default: false
 60       },
 61       /**
 62        * 是否派發列表滾動開始的事件
 63        */
 64       beforeScroll: {
 65         type: Boolean,
 66         default: false
 67       },
 68       /**
 69        * 當數據更新后,刷新scroll的延時。
 70        */
 71       refreshDelay: {
 72         type: Number,
 73         default: 20
 74       }
 75     },
 76     mounted() {
 77       // 保證在DOM渲染完畢后初始化better-scroll
 78       setTimeout(() => {
 79         this._initScroll()
 80       }, 20)
 81     },
 82     methods: {
 83       _initScroll() {
 84         if (!this.$refs.wrapper) {
 85           return
 86         }
 87         // better-scroll的初始化
 88         this.scroll = new BScroll(this.$refs.wrapper, {
 89           probeType: this.probeType,
 90           click: this.click,
 91           scrollX: this.scrollX
 92         })
 93 
 94         // 是否派發滾動事件
 95         if (this.listenScroll) {
 96           let me = this
 97           this.scroll.on('scroll', (pos) => {
 98             me.$emit('scroll', pos)
 99           })
100         }
101 
102         // 是否派發滾動到底部事件,用於上拉加載
103         if (this.pullup) {
104           this.scroll.on('scrollEnd', () => {
105             // 滾動到底部
106             if (this.scroll.y <= (this.scroll.maxScrollY + 50)) {
107               this.$emit('scrollToEnd')
108             }
109           })
110         }
111 
112         // 是否派發頂部下拉事件,用於下拉刷新
113         if (this.pulldown) {
114           this.scroll.on('touchend', (pos) => {
115             // 下拉動作
116             if (pos.y > 50) {
117               this.$emit('pulldown')
118             }
119           })
120         }
121 
122         // 是否派發列表滾動開始的事件
123         if (this.beforeScroll) {
124           this.scroll.on('beforeScrollStart', () => {
125             this.$emit('beforeScroll')
126           })
127         }
128       },
129       disable() {
130         // 代理better-scroll的disable方法
131         this.scroll && this.scroll.disable()
132       },
133       enable() {
134         // 代理better-scroll的enable方法
135         this.scroll && this.scroll.enable()
136       },
137       refresh() {
138         // 代理better-scroll的refresh方法
139         this.scroll && this.scroll.refresh()
140       },
141       scrollTo() {
142         // 代理better-scroll的scrollTo方法
143         this.scroll && this.scroll.scrollTo.apply(this.scroll, arguments)
144       },
145       scrollToElement() {
146         // 代理better-scroll的scrollToElement方法
147         this.scroll && this.scroll.scrollToElement.apply(this.scroll, arguments)
148       }
149     },
150     watch: {
151       // 監聽數據的變化,延時refreshDelay時間后調用refresh方法重新計算,保證滾動效果正常
152       data() {
153         setTimeout(() => {
154           this.refresh()
155         }, this.refreshDelay)
156       }
157     }
158   }
159 </script>
View Code

  在my-scroll中使用scroll組件

<template>
  <div>
     <nav class="nav">
      <ul>
        <li>推薦</li>
      </ul>
    </nav>
    <scroll class="wrapper" :data="data">
      <div class="content" >
        <section class="has_action" v-for="item in data">
          <div class="item-detail">
            <h3 class="dotdot">{{item.title}}</h3>
            <div class="item-info">
              <div>
                <span class="stick_label space">{{item.label}}</span>
                <span class="src space">{{item.media_name}}</span>
                <span class="cmt space">評論{{item.comment_count}}</span>
                <span class="time space" title="2018-11-05 19:23">{{item.datetime}}</span>
              </div>
            </div>
          </div>
        </section>
      </div>
    </scroll>
  </div>
</template>
View Code

 

<script>
  import Vue from 'vue'
  import VueJsonp from 'vue-jsonp'
  import BScroll from 'better-scroll'
  import scroll from 'components/scroll/scroll'
  Vue.use(VueJsonp)
  export default {
    name: 'myscroll',
    components: {
      scroll
    },
    data() {
      return {
        data: []
      }
    },
    created() {
      this._getData().then(json => {
        this.data = json.data
        this.data = this.data.concat(this.data)
      })
    },
    methods: {
      // 或者頁面數據,跳用今日頭條數據接口
      _getData() {
        return this.$jsonp('https://m.toutiao.com/list',{
          tag: '__all__',
          ac: 'wap',
          count: 20,
          format: 'json_raw',
          as: 'A1D5EB0E82E44A1',
          cp: '5BE224C46AC11E1',
          min_behot_time: 1541555213,
          _signature: '.P8dTQAApydWuLUYyYBGu.z.HV',
          i: 1541555213
        })
      }
    }
  }
</script>
View Code

 

github地址


免責聲明!

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



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