zoukankan      html  css  js  c++  java
  • vue版app上下拉加载

    首先把基本的样式写好,这里就略过了,然后引入better-scroll库

    import BScroll from 'better-scroll'

     

    其次,在mounted生命周期实例化scroll,可以获取完数据后再new,也可以先new后,获取完数据调用refresh。

    //是否开启下拉刷新,可传入true或者false,如果需要更多配置可以传入一个对象
     
    pullDownRefresh:{
      threshold:80,
      stop:40
    }
    //是否开启上拉加载,同上,上拉无stop参数,这里需要注意是负数
    pullUpLoad:{
      threshold:-80,
    }
    /**
     *
     * @param threshold 触发事件的阀值,即滑动多少距离触发
     * @param stop 下拉刷新后回滚距离顶部的距离(为了给loading留出一点空间)
     */
     

    对于不同缩放程度的屏幕,还需要乘以对应的缩放比。

    淘宝flexible.js里面其实已经有这个获取屏幕缩放比方法,这里直接从里面拿:

    //在util.js里面加一个方法
    export function getDeviceRatio(){
      var isAndroid = window.navigator.appVersion.match(/android/gi);
      var isIPhone = window.navigator.appVersion.match(/iphone/gi);
      var devicePixelRatio = window.devicePixelRatio;
      var dpr;
      if (isIPhone) {
        // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
        if (devicePixelRatio >= 3) {       
          dpr = 3;
        } else if (devicePixelRatio >= 2){
          dpr = 2;
        } else {
          dpr = 1;
        }
      } else {
        // 其他设备下,仍旧使用1倍的方案
        dpr = 1;
      }
      return dpr
    }
     
    import{ DEVICE_RATIO} from '../base/js/api.js'
    /*获取当前缩放比*/
    const DEVICE_RATIO=getDeviceRatio();
     
     
     /*下拉配置*/
    const DOWN_CONFIG={
     threshold:80*DEVICE_RATIO,
     stop:40*DEVICE_RATIO
    }
    /*上拉配置*/
    const UP_CONFIG={
     threshold:-80*DEVICE_RATIO,
    }
     
    this.scroller = new BScroll(scrollWrap,{
     click:true,
     probeType:3,
     pullDownRefresh:DOWN_CONFIG,
     pullUpLoad:UP_CONFIG
    });
     
    实例化后,接下来就是监听上拉和下拉事件了。betterScroll新增了一些事件,主要的有:
     
    /*下拉事件*/
    this.scroller.on('pullingDown',()=> {});
     
    /*上拉事件*/
    this.scroller.on('pullingUp',()=>{});
     

    触发上拉或者下拉事件后,需要我们调用 this.scroller.finishPullDown() 或者 this.scroller.finishPullUp() 来通知better-scroll事件完成。

    大致的流程是这样的:

    this.scroller.on('pullingDown',()=> {
       
      <!-- 1. 发送请求获取数据 -->
       
      <!-- 2. 获取成功后,通知事件完成 -->
       
      <!-- 3. 修改data数据,在nextTick调用refresh -->
    });
    通常操作完成后都需要我们手动触发refresh方法来重新计算可滚动的距离,因此可以写一个watch监听数据的变化,这样我们只需要改变数据,不用每次操作数据后都调用refresh方法。
    watch:{
     dataList(){
      this.$nextTick(()=>{
       this.scroller.refresh();
      })
     }
    },
     
    如果你使用的版本还是旧的,那可以在on( scroll )事件的时候进行判断来实现功能
    this.scroller.on("scroll",(pos)=>{
      //获取整个滚动列表的高度
      var height=getStyle(scroller,"height");
     
      //获取滚动外层wrap的高度
      var pageHeight=getStyle(scrollWrap,"height");
     
      //触发事件需要的阀值
      var distance=80*DEVICE_RATIO;
     
      //参数pos为当前位置
     
      if(pos.y>distance){
     
        //console.log("下拉");
        //do something
        
      }else if(pos.y-pageHeight<-height-distance){
     
        //console.log("上拉");
        //do something
      }
    为了防止多次触发,需要加2个开关类的东西;
    var onPullUp=true;
    var onPullDown=true;

    每次触发事件时,將对应的开关设置为false, 等操作完成后,再重新设置为true,否则多次下拉或者上拉就会触发多次事件。通过设置开关可以保证每次只有一个事件在进行。

    最后,来封装成一个组件

    <template>
      <div ref="wrapper" class="list-wrapper">
        <div class="scroll-content">   
          <slot></slot>    
        </div>  
      </div>
    </template>

    由于每个页面需要滚动的具体内容都是不一样的,所以用了一个插槽来分发。

    组件需要的参数由父级传入,通过prop来接收并设置默认值

    export default {
     props: {
      dataList:{
       type: Array,
       default: []
      },
      probeType: {
       type: Number,
       default: 3
      },
      click: {
       type: Boolean,
       default: true
      }, 
      pullDownRefresh: {
       type: null,
       default: false
      },
      pullUpLoad: {
       type: null,
       default: false
      }, 
     }
     
    组件挂载后,在事件触发时并不直接处理事件,而是向父级发送一个事件,父级通过在模板v-on接收事件并处理后续的逻辑
    mounted() {
      this.scroll = new BScroll(this.$refs.wrapper, {
          probeType: this.probeType,
          click: this.click,   
          pullDownRefresh: this.pullDownRefresh,
          pullUpLoad: this.pullUpLoad,
        })
     
      this.scroll.on('pullingUp',()=> {
        if(this.continuePullUp){
          this.beforePullUp();
          this.$emit("onPullUp","当前状态:上拉加载");
        }
      });
     
      this.scroll.on('pullingDown',()=> {
        this.beforePullDown();
        this.$emit("onPullDown","当前状态:下拉加载更多");
      });
    }
    父组件在使用时,需要传入配置参数Props以及处理子组件发射的事件,并且用具体的内容并替换掉 slot 标签
    <Scroller
      id="scroll"
      ref="scroll"
      :dataList="filmList"
      :pullDownRefresh="DOWN_CONFIG"
      :pullUpLoad="UP_CONFIG"
      @onPullUp="pullUpHandle"
      @onPullDown="pullDownHandle"
     >
     
      <ul>
         <router-link class="film-list" v-for="(v,i) in filmList" :key="v.id" tag="li" :to='{path:"/film-detail/"+v.id}'>
            <div class="film-list__img">
               <img v-lazy="v.images.small" alt="" />       
            </div>
            <div class="film-list__detail">
              <p class="film-list__detail__title">{{v.title}}</p>
              <p class="film-list__detail__director">导演:{{filterDirectors(v.directors)}}</p>
              <p class="film-list__detail__year">年份:{{v.year}}<span>{{v.stock}}</span></p>
              <p class="film-list__detail__type">类别:{{v.genres.join(" / ")}}<span></span></p>
              <p class="film-list__detail__rank">评分:<span>{{v.rating.average}}分</span></p>
            </div>            
          </router-link>
       </ul>    
     </Scroller>
    父组件可以通过this.$refs.xxx来获取到子组件,可以调用子组件里面的方法;
    computed:{
       scrollElement(){
         return this.$refs.scroll
       }
     }
    完整的scroller组件内容如下
    <template>
      <div ref="wrapper" class="list-wrapper">
        <div class="scroll-content">   
          <slot></slot>
          <div>
            <PullingWord v-show="!inPullUp&&dataList.length>0" :loadingWord="beforePullUpWord"></PullingWord>
            <Loading v-show="inPullUp" :loadingWord='PullingUpWord'></Loading>
          </div>   
        </div>
     
        <transition name="pullDown">
          <Loading class="pullDown" v-show="inPullDown" :loadingWord='PullingDownWord'></Loading>
        </transition>
      </div>
    </template>
     
     
    <script >
     import BScroll from 'better-scroll'
     import Loading from './loading.vue'
     import PullingWord from './pulling-word'
     
     const PullingUpWord="正在拼命加载中...";
     const beforePullUpWord="上拉加载更多";
     const finishPullUpWord="加载完成";
     
     const PullingDownWord="加载中...";
     
     export default {
      props: {
       dataList:{
        type: Array,
        default: []
       },
       probeType: {
        type: Number,
        default: 3
       },
       click: {
        type: Boolean,
        default: true
       }, 
       pullDownRefresh: {
        type: null,
        default: false
       },
       pullUpLoad: {
        type: null,
        default: false
       }, 
      },
      data() {
        return {
          scroll:null,
          inPullUp:false,
          inPullDown:false,
          beforePullUpWord,
          PullingUpWord,
          PullingDownWord,
          continuePullUp:true
        }
      },
        
      mounted() {
        setTimeout(()=>{
          this.initScroll();
     
          this.scroll.on('pullingUp',()=> {
            if(this.continuePullUp){
              this.beforePullUp();
              this.$emit("onPullUp","当前状态:上拉加载");
            }
          });
     
          this.scroll.on('pullingDown',()=> {
            this.beforePullDown();
            this.$emit("onPullDown","当前状态:下拉加载更多");
          });
     
        },20)
         
      },
      methods: {
        initScroll() {
          if (!this.$refs.wrapper) {
            return
          }
          this.scroll = new BScroll(this.$refs.wrapper, {
            probeType: this.probeType,
            click: this.click,   
            pullDownRefresh: this.pullDownRefresh,
            pullUpLoad: this.pullUpLoad,
          })
        },
        beforePullUp(){
          this.PullingUpWord=PullingUpWord;
          this.inPullUp=true;
        },
        beforePullDown(){
          this.disable();
          this.inPullDown=true;
        },
        finish(type){
          this["finish"+type]();
          this.enable();
          this["in"+type]=false;
        },
        disable() {
          this.scroll && this.scroll.disable()
        },
        enable() {
          this.scroll && this.scroll.enable()
        },
        refresh() {
          this.scroll && this.scroll.refresh()
        },
        finishPullDown(){
          this.scroll&&this.scroll.finishPullDown()
        },
        finishPullUp(){
          this.scroll&&this.scroll.finishPullUp()
        },  
      },
          
      watch: {
        dataList() {       
          this.$nextTick(()=>{
            this.refresh();           
          })
        }
      },
      components: {
        Loading,
        PullingWord
      }
     }
     
    </script>
  • 相关阅读:
    Smart Client Architecture and Design Guide
    Duwamish密码分析篇, Part 3
    庆贺发文100篇
    .Net Distributed Application Design Guide
    New Introduction to ASP.NET 2.0 Web Parts Framework
    SPS toplevel Site Collection Administrators and Owners
    来自Ingo Rammer先生的Email关于《Advanced .Net Remoting》
    The newsletter published by Ingo Rammer
    深度探索.Net Remoting基础架构
    信道、接收器、接收链和信道接受提供程序
  • 原文地址:https://www.cnblogs.com/ccotk/p/8003915.html
Copyright © 2011-2022 走看看