Files
mini-yu/uni_modules/tdesign-uniapp/components/common/utils.js
lingxiao865 c5af079d8c first commit
2026-02-10 08:05:03 +08:00

359 lines
8.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { prefix } from './config';
import { isString, isNumeric, isDef, isBoolean, isObject } from './validator';
import { getWindowInfo, getAppBaseInfo, getDeviceInfo } from './wechat';
export { getWindowInfo };
export const systemInfo = getWindowInfo();
export const appBaseInfo = getAppBaseInfo();
export const deviceInfo = getDeviceInfo();
/**
* 多参数空值合并函数
* @param {...any} args - 任意数量的参数
* @returns {any} 第一个非null/undefined的参数值
*/
export function coalesce(...args) {
// 遍历所有参数
for (let i = 0; i < args.length; i += 1) {
// 返回第一个非null且非undefined的值
if (args[i] !== null && args[i] !== undefined) {
return args[i];
}
}
// 如果所有参数都是null/undefined返回最后一个参数
return args[args.length - 1];
}
export const debounce = function (func, wait = 500) {
let timerId;
return function (...rest) {
if (timerId) {
clearTimeout(timerId);
}
timerId = setTimeout(() => {
func.apply(this, rest);
}, wait);
};
};
export const throttle = (func, wait = 100, options = null) => {
let previous = 0;
let timerid = null;
if (!options) {
options = {
leading: true,
};
}
return function (...args) {
const now = Date.now();
if (!previous && !options.leading) previous = now;
const remaining = wait - (now - previous);
const context = this;
if (remaining <= 0) {
if (timerid) {
clearTimeout(timerid);
timerid = null;
}
previous = now;
func.apply(context, args);
}
};
};
export const classNames = function (...args) {
const hasOwn = {}.hasOwnProperty;
const classes = [];
args.forEach((arg) => {
// for (let i = 0; i < args.length; i++) {
// eslint-disable-next-line
// const arg = args[i]
if (!arg) return;
const argType = typeof arg;
if (argType === 'string' || argType === 'number') {
classes.push(arg);
} else if (Array.isArray(arg) && arg.length) {
const inner = classNames(...arg);
if (inner) {
classes.push(inner);
}
} else if (argType === 'object') {
// eslint-disable-next-line
for (const key in arg) {
if (hasOwn.call(arg, key) && arg[key]) {
classes.push(key);
}
}
}
});
return classes.join(' ');
};
export const styles = function (styleObj) {
return Object.keys(styleObj)
.map(styleKey => `${styleKey}: ${styleObj[styleKey]}`)
.join('; ');
};
export const getAnimationFrame = function (context, cb) {
return uni
.createSelectorQuery()
.in(context)
.selectViewport()
.boundingClientRect()
.exec(() => {
cb();
});
};
export const getRect = function (context, selector, needAll = false, useH5Origin = false) {
let result;
// #ifdef H5
if (useH5Origin) {
result = document[needAll ? 'querySelectorAll' : 'querySelector'](selector)?.getBoundingClientRect();
}
// #endif
if (result) {
return result;
}
return new Promise((resolve, reject) => {
uni
.createSelectorQuery()
.in(context)
// eslint-disable-next-line no-unexpected-multiline
[needAll ? 'selectAll' : 'select'](selector)
.boundingClientRect((rect) => {
if (rect) {
resolve(rect);
} else {
reject(rect);
}
})
.exec();
});
};
export const getTreeDepth = (tree, key) => tree.reduce((maxDepth, node) => {
const keyName = coalesce(key, 'children');
if (node[keyName] && node[keyName].length > 0) {
return Math.max(maxDepth, getTreeDepth(node[keyName], key) + 1);
}
return Math.max(maxDepth, 1);
}, 0);
export const isIOS = function () {
return !!(deviceInfo?.system?.toLowerCase().search('ios') + 1);
};
/**
* 判断是否是为企微环境
* 企微环境 wx.getSystemInfoSync() 接口会额外返回 environment 字段(微信中不返回)
* https://developer.work.weixin.qq.com/document/path/91511
*/
export const isWxWork = deviceInfo?.environment === 'wxwork';
export const isPC = ['mac', 'windows'].includes(deviceInfo?.platform);
export const addUnit = function (value) {
if (!isDef(value)) {
return undefined;
}
value = String(value);
return isNumeric(value) ? `${value}px` : value;
};
/**
* 计算字符串字符的长度并可以截取字符串。
* @param char 传入字符串maxcharacter条件下一个汉字表示两个字符
* @param max 规定最大字符串长度
* @returns 当没有传入maxCharacter/maxLength 时返回字符串字符长度当传入maxCharacter/maxLength时返回截取之后的字符串和长度。
*/
export const getCharacterLength = (type, char, max) => {
const str = String(coalesce(char, ''));
if (str.length === 0) {
return {
length: 0,
characters: '',
};
}
if (type === 'maxcharacter') {
let len = 0;
for (let i = 0; i < str.length; i += 1) {
let currentStringLength = 0;
if (str.charCodeAt(i) > 127 || str.charCodeAt(i) === 94) {
currentStringLength = 2;
} else {
currentStringLength = 1;
}
if (len + currentStringLength > max) {
return {
length: len,
characters: str.slice(0, i),
};
}
len += currentStringLength;
}
return {
length: len,
characters: str,
};
}
if (type === 'maxlength') {
const length = str.length > max ? max : str.length;
return {
length,
characters: str.slice(0, length),
};
}
return {
length: str.length,
characters: str,
};
};
export const chunk = (arr, size) => Array.from({ length: Math.ceil(arr.length / size) }, (v, i) => arr.slice(i * size, i * size + size));
const getPageContext = () => {
const pages = getCurrentPages();
const page = pages[pages.length - 1];
return (page).$$basePage || page;
};
const findInstance = (context, pageContext, pureSelector) => {
if (context && context.$refs[pureSelector]) {
return context.$refs[pureSelector];
}
if (pageContext && pageContext.$refs[pureSelector]) {
return pageContext.$refs[pureSelector];
}
return null;
};
export const getInstance = function (context, selector) {
const pageContext = getPageContext();
const pureSelector = /^[.#]/.test(selector) ? selector.slice(1) : selector;
const instance = findInstance(context, pageContext, pureSelector);
if (!instance) {
console.warn('未找到组件,请检查 selector 是否正确');
return null;
}
return instance;
};
export const unitConvert = (value) => {
if (typeof value === 'string') {
if (value.includes('rpx')) {
return (parseInt(value, 10) * (coalesce(systemInfo?.screenWidth, 750))) / 750;
}
return parseInt(value, 10);
}
return coalesce(value, 0);
};
export const setIcon = (iconName, icon, defaultIcon) => {
if (icon) {
if (typeof icon === 'string') {
return {
[`${iconName}Name`]: icon,
[`${iconName}Data`]: {},
};
}
if (typeof icon === 'object') {
return {
[`${iconName}Name`]: '',
[`${iconName}Data`]: icon,
};
}
return {
[`${iconName}Name`]: defaultIcon,
[`${iconName}Data`]: {},
};
}
return {
[`${iconName}Name`]: '',
[`${iconName}Data`]: {},
};
};
export const toCamel = str => str.replace(/-(\w)/g, (match, m1) => m1.toUpperCase());
export const toPascal = name => name
.split('-')
.map(part => part.charAt(0).toUpperCase() + part.slice(1))
.join('');
export function hyphenate(str) {
const hyphenateRE = /\B([A-Z])/g;
return str.replace(hyphenateRE, '-$1').toLowerCase();
}
export const getCurrentPage = function () {
const pages = getCurrentPages();
return pages[pages.length - 1];
};
export const uniqueFactory = (compName) => {
let number = 0;
return () => {
const uniqueId = `${prefix}_${compName}_${number}`;
number += 1;
return uniqueId;
};
};
export const calcIcon = (icon, defaultIcon) => {
if (icon && ((isBoolean(icon) && defaultIcon) || isString(icon))) {
return { name: isBoolean(icon) ? defaultIcon : icon };
}
if (isObject(icon)) {
return icon;
}
return null;
};
export const isOverSize = (size, sizeLimit) => {
if (!sizeLimit) return false;
const base = 1000;
const unitMap = {
B: 1,
KB: base,
MB: base * base,
GB: base * base * base,
};
const computedSize = typeof sizeLimit === 'number'
? sizeLimit * base
: sizeLimit?.size * unitMap[coalesce(sizeLimit?.unit, 'KB')]; // 单位 KB
return size > computedSize;
};
export const rpx2px = rpx => Math.floor((systemInfo.windowWidth * rpx) / 750);
export const nextTick = () => new Promise((resolve) => {
setTimeout(() => {
resolve();
}, 33);
});