// [z-paging]工具类 import zLocalConfig from '../config/index' import c from './z-paging-constant' const storageKey = 'Z-PAGING-REFRESHER-TIME-STORAGE-KEY'; let config = null; let configLoaded = false; let cachedSystemInfo = null; const timeoutMap = {}; // 获取默认配置信息 function gc(key, defaultValue) { // 这里return一个函数以解决在vue3+appvue中,props默认配置读取在main.js之前执行导致uni.$zp全局配置无效的问题。相当于props的default中传入一个带有返回值的函数 return () => { // 处理z-paging全局配置 _handleDefaultConfig(); // 如果全局配置不存在,则返回默认值 if (!config) return defaultValue; const value = config[key]; // 如果全局配置存在但对应的配置项不存在,则返回默认值;反之返回配置项 return value === undefined ? defaultValue : value; }; } // 获取最终的touch位置 function getTouch(e) { let touch = null; if (e.touches && e.touches.length) { touch = e.touches[0]; } else if (e.changedTouches && e.changedTouches.length) { touch = e.changedTouches[0]; } else if (e.datail && e.datail != {}) { touch = e.datail; } else { return { touchX: 0, touchY: 0 } } return { touchX: touch.clientX, touchY: touch.clientY }; } // 判断当前手势是否在z-paging内触发 function getTouchFromZPaging(target) { if (target && target.tagName && target.tagName !== 'BODY' && target.tagName !== 'UNI-PAGE-BODY') { const classList = target.classList; if (classList && classList.contains('z-paging-content')) { // 此处额外记录当前z-paging是否是页面滚动、是否滚动到了顶部、是否是聊天记录模式以传给renderjs。避免不同z-paging组件renderjs内部判断数据互相影响导致的各种问题 return { isFromZp: true, isPageScroll: classList.contains('z-paging-content-page'), isReachedTop: classList.contains('z-paging-reached-top'), isUseChatRecordMode: classList.contains('z-paging-use-chat-record-mode') }; } else { return getTouchFromZPaging(target.parentNode); } } else { return { isFromZp: false }; } } // 递归获取z-paging所在的parent,如果查找不到则返回null function getParent(parent) { if (!parent) return null; if (parent.$refs.paging) return parent; return getParent(parent.$parent); } // 打印错误信息 function consoleErr(err) { console.error(`[z-paging]${err}`); } // 延时操作,如果key存在,调用时清除对应key之前的延时操作 function delay(callback, ms = c.delayTime, key) { const timeout = setTimeout(callback, ms);; if (!!key) { timeoutMap[key] && clearTimeout(timeoutMap[key]); timeoutMap[key] = timeout; } return timeout; } // 设置下拉刷新时间 function setRefesrherTime(time, key) { const datas = getRefesrherTime() || {}; datas[key] = time; uni.setStorageSync(storageKey, datas); } // 获取下拉刷新时间 function getRefesrherTime() { return uni.getStorageSync(storageKey); } // 通过下拉刷新标识key获取下拉刷新时间 function getRefesrherTimeByKey(key) { const datas = getRefesrherTime(); return datas && datas[key] ? datas[key] : null; } // 通过下拉刷新标识key获取下拉刷新时间(格式化之后) function getRefesrherFormatTimeByKey(key, textMap) { const time = getRefesrherTimeByKey(key); const timeText = time ? _timeFormat(time, textMap) : textMap.none; return `${textMap.title}${timeText}`; } // 将文本的px或者rpx转为px的值 function convertToPx(text) { const dataType = Object.prototype.toString.call(text); if (dataType === '[object Number]') return text; let isRpx = false; if (text.indexOf('rpx') !== -1 || text.indexOf('upx') !== -1) { text = text.replace('rpx', '').replace('upx', ''); isRpx = true; } else if (text.indexOf('px') !== -1) { text = text.replace('px', ''); } if (!isNaN(text)) { if (isRpx) return Number(rpx2px(text)); return Number(text); } return 0; } // rpx => px,预留的兼容处理 function rpx2px(rpx) { return uni.upx2px(rpx); } // 同步获取系统信息,兼容不同平台 function getSystemInfoSync(useCache = false) { if (useCache && cachedSystemInfo) { return cachedSystemInfo; } // 目前只用到了deviceInfo、appBaseInfo和windowInfo中的信息,因此仅整合这两个信息数据 const infoTypes = ['DeviceInfo', 'AppBaseInfo', 'WindowInfo']; const { deviceInfo, appBaseInfo, windowInfo } = infoTypes.reduce((acc, key) => { const method = `get${key}`; if (uni[method] && uni.canIUse(method)) { acc[key.charAt(0).toLowerCase() + key.slice(1)] = uni[method](); } return acc; }, {}); // 如果deviceInfo、appBaseInfo和windowInfo都可以从各自专属的api中获取,则整合它们的数据 if (deviceInfo && appBaseInfo && windowInfo) { cachedSystemInfo = { ...deviceInfo, ...appBaseInfo, ...windowInfo }; } else { // 使用uni.getSystemInfoSync兜底,确保能获取到最终的系统信息 cachedSystemInfo = uni.getSystemInfoSync(); } return cachedSystemInfo; } // 获取当前时间 function getTime() { return (new Date()).getTime(); } // 获取z-paging实例id,随机生成10位数字+字母 function getInstanceId() { const s = []; const hexDigits = "0123456789abcdef"; for (let i = 0; i < 10; i++) { s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1); } return s.join('') + getTime(); } // 等待一段时间 function wait(ms) { return new Promise(resolve => { setTimeout(resolve, ms); }); } // 是否是promise function isPromise(func) { return Object.prototype.toString.call(func) === '[object Promise]'; } // 添加单位 function addUnit(value, unit) { if (Object.prototype.toString.call(value) === '[object String]') { let tempValue = value; tempValue = tempValue.replace('rpx', '').replace('upx', '').replace('px', ''); if (value.indexOf('rpx') === -1 && value.indexOf('upx') === -1 && value.indexOf('px') !== -1) { tempValue = parseFloat(tempValue) * 2; } value = tempValue; } return unit === 'rpx' ? value + 'rpx' : (value / 2) + 'px'; } // 深拷贝 function deepCopy(obj) { if (typeof obj !== 'object' || obj === null) return obj; let newObj = Array.isArray(obj) ? [] : {}; for (let key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = deepCopy(obj[key]); } } return newObj; } // ------------------ 私有方法 ------------------------ // 处理全局配置 function _handleDefaultConfig() { // 确保只加载一次全局配置 if (configLoaded) return; // 优先从config.js中读取 if (zLocalConfig && Object.keys(zLocalConfig).length) { config = zLocalConfig; } // 如果在config.js中读取不到,则尝试到uni.$zp读取 if (!config && uni.$zp) { config = uni.$zp.config; } // 将config中的短横线写法全部转为驼峰写法,使得读取配置时可以直接通过key去匹配,而非读取每个配置时候再去转,减少不必要的性能开支 config = config ? Object.keys(config).reduce((result, key) => { result[_toCamelCase(key)] = config[key]; return result; }, {}) : null; configLoaded = true; } // 时间格式化 function _timeFormat(time, textMap) { const date = new Date(time); const currentDate = new Date(); // 设置time对应的天,去除时分秒,使得可以直接比较日期 const dateDay = new Date(time).setHours(0, 0, 0, 0); // 设置当前的天,去除时分秒,使得可以直接比较日期 const currentDateDay = new Date().setHours(0, 0, 0, 0); const disTime = dateDay - currentDateDay; let dayStr = ''; const timeStr = _dateTimeFormat(date); if (disTime === 0) { dayStr = textMap.today; } else if (disTime === -86400000) { dayStr = textMap.yesterday; } else { dayStr = _dateDayFormat(date, date.getFullYear() !== currentDate.getFullYear()); } return `${dayStr} ${timeStr}`; } // date格式化为年月日 function _dateDayFormat(date, showYear = true) { const year = date.getFullYear(); const month = date.getMonth() + 1; const day = date.getDate(); return showYear ? `${year}-${_fullZeroToTwo(month)}-${_fullZeroToTwo(day)}` : `${_fullZeroToTwo(month)}-${_fullZeroToTwo(day)}`; } // data格式化为时分 function _dateTimeFormat(date) { const hour = date.getHours(); const minute = date.getMinutes(); return `${_fullZeroToTwo(hour)}:${_fullZeroToTwo(minute)}`; } // 不满2位在前面填充0 function _fullZeroToTwo(str) { str = str.toString(); return str.length === 1 ? '0' + str : str; } // 驼峰转短横线 function _toKebab(value) { return value.replace(/([A-Z])/g, "-$1").toLowerCase(); } // 短横线转驼峰 function _toCamelCase(value) { return value.replace(/-([a-z])/g, (_, group1) => group1.toUpperCase()); } export default { gc, setRefesrherTime, getRefesrherFormatTimeByKey, getTouch, getTouchFromZPaging, getParent, convertToPx, getTime, getInstanceId, consoleErr, delay, wait, isPromise, addUnit, deepCopy, rpx2px, getSystemInfoSync };