import {Component, Mixins, Ref} from "vue-property-decorator"; import {emitNames} from '../enum/emit'; import ScrollApi from '../api/scroll'; import ScrollStatus from './status'; import { Config, EventTypes, ListenerEventTarget, ScrollConfig, ScrollXConfig, ScrollYConfig } from "../types/on"; @Component({ created(this:ScrollViewConfig){ this._config = {}; this._scrollConfig = { look:false, stipitate:undefined, x:{ x:0, width:0, actualWidth:0, maxScroll:0 }, y:{ y:0, height:0, actualHeight:0, maxScroll:0 } }; }, mounted(this:ScrollViewConfig){ // 执行安装 return this.installScroll(); }, // 释放组件的时候触发 beforeDestroy(this:ScrollViewConfig){ this._scrollApi && this._scrollApi.destroy(); this._scrollConfig.stipitate&&clearTimeout(this._scrollConfig.stipitate); this._scrollApi = undefined; this.scrollEl && this._config.scrollUnique && this.removeEventListener(this.scrollEl,'scroll',this._config.scrollUnique); } }) export default class ScrollViewConfig extends Mixins(ScrollStatus) { // 滚动标签实例 @Ref('scroll') scrollEl:HTMLElement | undefined; // 滚动包容标签实例 @Ref('scrollTake') scrollTakeEl:HTMLElement | undefined; // 运行时的 scrollApi _scrollApi:ScrollApi | undefined; // 运行时参数 _config:Config={}; // 滚动系列参数配置 _scrollConfig:ScrollConfig={ look:false, stipitate:undefined, x:{ x:0, width:0, actualWidth:0, maxScroll:0 }, y:{ y:0, height:0, actualHeight:0, maxScroll:0 } }; // 配置滚动系列参数 setScrollConfig(){ if (this._scrollConfig.look) return; // 设置锁 this._scrollConfig.look = true; // 配置 x 轴 this.scrollX && this.setScrollAxisConfig('x'); // 配置 y 轴 this.scrollY && this.setScrollAxisConfig('y'); // 帧频率不允许重复 this._scrollConfig.stipitate = setTimeout(()=>{ this._scrollConfig.stipitate = undefined; this._scrollConfig.look = false; },16.66); }; // 配置单独轴系列参数 setScrollAxisConfig(axis:'x' | 'y'){ if (this.scrollEl === undefined || this.scrollTakeEl === undefined) return; let sizeKey: 'width' | 'height' = axis === 'x' ? 'width':'height'; let actualKey : 'actualWidth' | 'actualHeight' = axis === 'x' ? 'actualWidth' :'actualHeight'; let scrollAxis: 'scrollLeft' | 'scrollTop' = axis === 'x'? 'scrollLeft' :'scrollTop'; let elSizeKey:'offsetWidth' | 'offsetHeight' = axis === 'x' ? 'offsetWidth' :'offsetHeight'; // 设置配置文件 // @ts-ignore this._scrollConfig[axis] = { [sizeKey]: this.scrollEl[elSizeKey] || 0, [axis]: this.scrollEl[scrollAxis] || 0, [actualKey]: this.scrollTakeEl[elSizeKey] || 0, maxScroll:0 }; // // // 设置最大滚动 // @ts-ignore (this._scrollConfig[axis] as ScrollYConfig | ScrollXConfig).maxScroll = Math.max(0,this._scrollConfig[axis][actualKey] - this._scrollConfig[axis][sizeKey]); }; // 安装 installScroll(){ // 设置当前的配置文件 this.setScrollConfig(); // 创建滚动Api if (this.scrollEl !== undefined) { this._scrollApi = new ScrollApi(this._scrollConfig,this.scrollEl); } // 如果存在此三种的任何一种 事件开启监听 if ( (this.$listeners[emitNames.onScroll] || this.$listeners[emitNames.onScrollLower] || this.$listeners[emitNames.onScrollUpper]) && this.scrollEl !== undefined ) { // 获取存储的唯一标识 this._config.scrollUnique = this.addEventListener(this.scrollEl,'scroll',()=> this.onScroll()); } } // 滚动时触发 onScroll(){ if (this.scrollEl) { // 设置配置 this.setScrollConfig(); if (this.$listeners[emitNames.onScrollUpper] || this.$listeners[emitNames.onScrollLower]) { if (this.scrollY) { if ( this.$listeners[emitNames.onScrollLower] && this.testScrollDistance('y','lowerThreshold','_lowerThresholdYStatus')) { this.emitScrollLower('y'); } else if (this.$listeners[emitNames.onScrollUpper] && this.testScrollDistance('y','upperThreshold','_upperThresholdYStatus')) { this.emitScrollUpper('y'); } } if (this.scrollX) { if ( this.$listeners[emitNames.onScrollLower] && this.testScrollDistance('x','lowerThreshold','_lowerThresholdXStatus')) { this.emitScrollLower('x'); } else if (this.$listeners[emitNames.onScrollUpper] && this.testScrollDistance('x','upperThreshold','_upperThresholdXStatus')) { this.emitScrollUpper('x'); } } } if(this.$listeners[emitNames.onScroll]) { return this.emitScroll(this._scrollConfig); } } } // 校验是否满足条件 testScrollDistance(axis:'x' | 'y',key:'lowerThreshold' | 'upperThreshold',testKey:'_lowerThresholdXStatus'|'_lowerThresholdYStatus'|'_upperThresholdXStatus'|'_upperThresholdYStatus'){ if ( this[key] !== undefined && // @ts-ignore key === 'upperThreshold' ? this._scrollConfig[axis][axis] <= this[key] : this._scrollConfig[axis].maxScroll - this._scrollConfig[axis][axis] <= this[key] ) { if (!this[testKey]) { this[testKey] = true; return true; } } else { this[testKey] = false; } return false; } // 监听器对象 _listeners: { [key:string]:ListenerEventTarget } | undefined = undefined; // 添加监听 addEventListener(el:HTMLElement,event:T,target:ListenerEventTarget){ // 如果没有监听器对象创建 if (this._listeners === undefined) { this._listeners = {}; } let unique:string = this.getUnique(event); this._listeners[unique] = target; if (window.addEventListener !== undefined) { el.addEventListener(event,target,{ passive:true }); } else { // @ts-ignore 兼容策略 el.attachEvent('on'+event,target,{ passive:true }); } return unique; } // 移除兼容 removeEventListener(el:HTMLElement,event:K,unique:string){ if (this._listeners !== undefined && this._listeners[unique] !== undefined) { if (window.removeEventListener !== undefined) { el.removeEventListener(event, this._listeners[unique]); } else { // @ts-ignore 兼容策略 el.detachEvent('on' + event, this._listeners[unique]); } return true; } else { return false; } } // 获取唯一值 getUnique(value:string=''):string{ return new Date().getTime() + value + Math.floor(Math.random() * 10000) ; } }