Touch.js 5.08 KB
/**
 * @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: 200,//下拉取惰性
      time: 1000,//数据防抖动值
      filter: []
    }, 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("touchstart", this.touchstart.bind(this), false);
    window.addEventListener("touchmove", this.touchmove.bind(this), false);
    window.addEventListener("touchend", this.touchend.bind(this), false)
  }

  scrollEvent(event) { }

  touchstart(event) {
    this.touchend();
    let { pageX, pageY } = event.targetTouches[0];
    if (this.parent.scrollTop <= 0) {
      Object.assign(this.options, {
        start: pageY,
        touchs: true
      })
    }
  }
  touchmove(event) {

    let { pageX, pageY } = event.targetTouches[0];
    let path = location.hash.replace("#", "");
    let check = this.opt.filter.filter(item => {
      if (item.length > path.length) {
        return item.includes(path)
      } else {
        return path.includes(item)
      }

    }).length;
    if (!this.options.touchs || check) {
      this.options.isTrue = false;
      return
    }

    this.options.move = pageY;
    let height = pageY - this.options.start;
    if (height < 0) {
      this.options.isTrue = false;
      this.touchend();
      return
    }
    if (height > this.opt.lazy) {
      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(() => {
      if (
        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: height > 0 ? `translateY(${height}px)` : "none"
    })
    Object.assign(this.element.style, {
      height: height >= 100 ? "100px" : "0.1px"
      // height:height+"px"
    })

    Object.assign(this.arrow.style, {
      transform: `rotate(${height}deg)`
    })
  }
}

const listeners = {}

$event.$on("$$onTouch", (arg) => {
  for (const key in listeners) {
    listeners[key](arg)
  }
})

export function install(vue, options) {
  vue.mixin({
    mounted() {
      this.refreshInit && (listeners[this._uid] = this.refreshInit)
    },
    activated() {
      this.refreshInit && (listeners[this._uid] = this.refreshInit)
    },
    destroyed() {
      delete listeners[this._uid]
    },
    deactivated() {
      delete listeners[this._uid]
    },
  })
}
Vue.use(install)
export default Touch;