移动端下拉刷新,兼容vue

1,162 阅读1分钟

开发目的,使下拉动作和数据反馈执行分离,目前各组件库都需要loading负值阻断弹回,造成页面显示阻塞。

初始化

new Touch("#app",{option}).then()  //应当在#app 元素生成后执行
  • 在入口页面添加#app,{option},then 都为非必填
  • vue页面在 methods 中增加?onTouch 方法,在拉取下拉刷新后回掉
/**
 * @name 下拉刷新
 * @template new Touch("#app",{option}).then()
 * @param {arguments[0]} String 非必填(建议填如id),下拉动态负载,默认body
 * @param {option} Object  非必填
 * @param {lazy} Number  {lazy:100} 下拉响应惰性值默认 100 
 * @param {time} Number  {time:1000} 数据防抖惰性值默认 1000 
 * @returns then Function  xxx.then(arg=>arg) //下拉刷新后回掉
 * @name vue页面注入
 * @template { methods: {?onTouch }}
 */
import Vue,{callHook} from "vue";
let setT,$event = new Vue();

class Touch {
    constructor(id,opt={ }){
        this.main();
        this.createElement(id);
        this.generators=new Set();
        this.next = null;
        this.status={};
        this.opt = Object.assign({
            lazy:100 ,//下拉取惰性
            time:1000,//数据防抖动值
        },opt)
    
        return this;
    }
    main(){
        this.options = {
            start:0,
            move:0,
            end:0,
            isTrue:false,//是否拖动到有效值

         }

       
    }
    then(fun){
       this.generators.add(fun);
       return this;
    }
    createElement(id){
       const doc = (document.documentElement||document.body);
        this.self =  id? document.querySelector(id):doc;
        this.parent  = this.self==doc? this.self:this.self.parentNode;
        this.element = document.createElement("div");
        Object.assign(this.element.style,{
            "textAlign":"center","height":"0","transform":"translateY(50%)","position":"fixed",
            "top":"0","left":"0","width":"100%","zIndex":"1","overflow":"hidden"
        })
        this.arrow = document.createElement("span");
        Object.assign(this.arrow.style,{
            display:"inline-block",
            borderRadius:"50%",
            border:"#c00 solid 2px",
            borderTop:"none",
            width:"50px",
            height:"50px",
            transform:"translate3d(0,0,0),rotate(0deg)",

        })
        this.element.appendChild(this.arrow);
        let first = this.parent.children[0];
        this.parent.insertBefore(this.element,first);
        this.addEvent();
    }
    //事件绑定
    addEvent(){
        
       // window.addEventListener("scroll",this.scrollEvent.bind(this),false);
        window.addEventListener("touchstart",this.touchstart.bind(this),false);
        window.addEventListener("touchmove",this.touchmove.bind(this),false);
        window.addEventListener("touchend",this.touchend.bind(this),false)
    }
    scrollEvent(event){
     //   console.log(this.parent)
      //  console.log(self.scrollTop);
    }
    touchstart(event){
       //console.log(event)
       this.touchend();
        let {pageX,pageY} = event.targetTouches[0];
       // console.log(this.parent)
      //  console.log(pageY,this.parent.scrollTop)
      //  console.log(this.parent.scrollTop)
        if(this.parent.scrollTop<=0){
           
            Object.assign(this.options,{
                start:pageY,
                touchs:true
            })
            
        }
        
        //console.log("start",event.targetTouches)
    }
    touchmove(event){
        let {pageX,pageY} = event.targetTouches[0];
        if(!this.options.touchs){ 
            this.options.isTrue=false;
            return
        }
      
        
        this.options.move = pageY; 
       // console.log("move",event.changedTouches)
        let height = pageY-this.options.start;
        if(height<0){
           // console.log(height);
           this.options.isTrue=false;
            this.touchend();
            return
        }
        if(height>100){ 
            let _height = height-this.opt.lazy;
            this.options.isTrue=true;
            this.setTransform(_height);
           
        }

        //指针归位
        this.next = this.generators.values();
        
    }
    touchend(event){
 
       this.setTransform(0); //位置复位

       if(setT){ clearTimeout(setT)}
      
       setT = setTimeout(()=>{
            
            event&&  //用户事件
            this.options.isTrue&&  //有效拖动
            this.runNext();  //执行回掉
           
        },this.opt.time);

        //复位
        Object.assign(this.options,{
            start:0,
            move:0,
            end:0,
            touchs:false
        })
       
    }
    runNext(item=this.next,...res){
            this.options.isTrue=false;
            let next = item.next();
            if(!next.done){
                let fun = next.value(res); //执行
                if(/Promise/ig.test(Object.prototype.toString.call(fun))){
                    fun.then((params)=>{
                        this.runNext(item,params);
                    });//处理promise
                }else{
                    this.runNext(item,fun);//处理普通事件
                }

            }else{
                 $event.$emit("?onTouch",res);//发送事件给组件
                 //指针归位 
                this.next = this.generators.values();
            }
            
    }
    setTransform(height){
       
        Object.assign(this.self.style,{
            transform:`translateY(${height}px)`
        })
        Object.assign(this.element.style,{
            height:height>=100? "100px":"0"
          // height:height+"px"
        })
        Object.assign(this.arrow.style,{
            transform:`rotate(${height}deg)`
        })
        
    }
}
export function install (vue,options){
    console.log(callHook);
    vue.mixin({
       beforeCreate() {
           let self = this;
          $event.$on("?onTouch",(arg)=>{
              //this.$mount(arg)
              this["?onTouch"]&&this.?onTouch(arg);
          })
          
       }
    })
}
Vue.use(install)
export default Touch;