// [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
|
};
|