摘取uView1.x源码里好用的工具函数

102 阅读2分钟

防抖

let timeout = null;

/**
 * 防抖原理:一定时间内,只有最后一次操作,再过wait毫秒后才执行函数
 * 
 * @param {Function} func 要执行的回调函数 
 * @param {Number} wait 延时的时间
 * @param {Boolean} immediate 是否立即执行 
 * @return null
 */
function debounce(func, wait = 500, immediate = false) {
    // 清除定时器
    if (timeout !== null) clearTimeout(timeout);
    // 立即执行,此类情况一般用不到
    if (immediate) {
        var callNow = !timeout;
        timeout = setTimeout(function() {
                timeout = null;
        }, wait);
        if (callNow) typeof func === 'function' && func();
    } else {
        // 设置定时器,当最后一次操作后,timeout不会再被清除,所以在延时wait毫秒后执行func回调方法
        timeout = setTimeout(function() {
                typeof func === 'function' && func();
        }, wait);
    }
}

export default debounce

节流

let timer, flag;
/**
 * 节流原理:在一定时间内,只能触发一次
 * 
 * @param {Function} func 要执行的回调函数 
 * @param {Number} wait 延时的时间
 * @param {Boolean} immediate 是否立即执行
 * @return null
 */
function throttle(func, wait = 500, immediate = true) {
    if (immediate) {
        if (!flag) {
            flag = true;
            // 如果是立即执行,则在wait毫秒内开始时执行
            typeof func === 'function' && func();
            timer = setTimeout(() => {
                    flag = false;
            }, wait);
        }
    } else {
        if (!flag) {
            flag = true
            // 如果是非立即执行,则在wait毫秒内的结束处执行
            timer = setTimeout(() => {
                    flag = false
                    typeof func === 'function' && func();
            }, wait);
        }

    }
};
export default throttle

获取父元素

// 获取父组件的参数,因为支付宝小程序不支持provide/inject的写法
// this.$parent在非H5中,可以准确获取到父组件,但是在H5中,需要多次this.$parent.$parent.xxx
// 这里默认值等于undefined有它的含义,因为最顶层元素(组件)的$parent就是undefined,意味着不传name
// 值(默认为undefined),就是查找最顶层的$parent
export default function $parent(name = undefined) {
    let parent = this.$parent;
    // 通过while历遍,这里主要是为了H5需要多层解析的问题
    while (parent) {
        // 父组件
        if (parent.$options && parent.$options.name !== name) {
            // 如果组件的name不相等,继续上一级寻找
            parent = parent.$parent;
        } else {
            return parent;
        }
    }
    return false;
}

总结:

  • $parent(); // 没写name默认是获取到App.vue的实例对象
  • $parent('Pay'); // 返回name为'Pay'的实例对象

获取祖先元素的参数值

// 获取父组件的参数,因为支付宝小程序不支持provide/inject的写法
// this.$parent在非H5中,可以准确获取到父组件,但是在H5中,需要多次this.$parent.$parent.xxx
export default function getParent(name, keys) {
    let parent = this.$parent;
    // 通过while历遍,这里主要是为了H5需要多层解析的问题
    while (parent) {
        // 父组件
        if (parent.$options.name !== name) {
            // 如果组件的name不相等,继续上一级寻找
            parent = parent.$parent;
        } else {
            let data = {};
            // 判断keys是否数组,如果传过来的是一个数组,那么直接使用数组元素值当做键值去父组件寻找
            if(Array.isArray(keys)) {
                keys.map(val => {
                    data[val] = parent[val] ? parent[val] : '';
                })
            } else {
                // 历遍传过来的对象参数
                for(let i in keys) {
                    // 如果子组件有此值则用,无此值则用父组件的值
                    // 判断是否空数组,如果是,则用父组件的值,否则用子组件的值
                    if(Array.isArray(keys[i])) {
                        if(keys[i].length) {
                                data[i] = keys[i];
                        } else {
                                data[i] = parent[i];
                        }
                    } else if(keys[i].constructor === Object) {
                        // 判断是否对象,如果是对象,且有属性,那么使用子组件的值,否则使用父组件的值
                        if(Object.keys(keys[i]).length) {
                                data[i] = keys[i];
                        } else {
                                data[i] = parent[i];
                        }
                    } else {
                        // 只要子组件有传值,即使是false值,也是“传值”了,也需要覆盖父组件的同名参数
                        data[i] = (keys[i] || keys[i] === false) ? keys[i] : parent[i];
                    }
                }
            }
            return data;
        }
    }
    return {};
}

总结:

  • getParent(undefined, ['abc', 'tmp']); // undefined默认是获取到App.vue,返回一个对象{ abc: '123', tmp: '456' }
  • getParent('Pay', ['abc']); // 获取到name为Pay的组件,返回一个对象{ abc: '123' }
  • getParent('Pay', { abc: '' }); // 返回{ abc: 123 }
  • getParent('Pay', { abc: false }); // 返回{ abc: false } - 但App.vue的abc不会被覆盖
  • getParent('Pay', { abc: 456 }); // 返回{ abc: 456 } - 但App.vue的abc不会被覆盖