vitepress-theme-base-teek
Version:
查看 [使用说明](https://vp.xiaoying.org.cn/pages/9d746f)
255 lines (222 loc) • 6.31 kB
text/typescript
/**
* 是否为合法的 URL 前缀
*/
export const isExternal = (path: string) => /^(http?:|https?:|mailto:|tel:)/.test(path);
/**
* 是否是有效的 URL
*/
export const isValidURL = (url: string) => {
try {
new URL(url);
return true;
} catch {
return false;
}
};
/**
* 判断数据类型
* @param {Any} val 需要判断类型的数据
* @return string
*/
export const isType = (val: any) => {
if (val === null) return "null";
if (typeof val !== "object") return typeof val;
else return Object.prototype.toString.call(val).slice(8, -1).toLocaleLowerCase();
};
/**
* 判断值是否未某个类型
*/
export const is = (val: unknown, type: string) => {
return Object.prototype.toString.call(val) === `[object ${type}]`;
};
/**
* 是否为函数
*/
export const isFunction = <T = Function>(val: unknown): val is T => {
return is(val, "Function");
};
/**
* 是否已定义
*/
export const isDef = <T = unknown>(val?: T): val is T => {
return typeof val !== "undefined";
};
/**
* 是否为未定义
*/
export const isUnDef = <T = unknown>(val?: T): val is T => {
return !isDef(val);
};
/**
* 是否为对象
*/
export const isObject = (val: any): val is Record<any, any> => {
return val !== null && is(val, "Object");
};
/**
* 是否为时间
*/
export const isDate = (val: unknown): val is Date => {
return is(val, "Date");
};
/**
* 是否是有效的数字(包含正负整数,0 以及正负浮点数)
*/
export const isNumber = (val: unknown): val is number => {
const regPos = /^\d+(\.\d+)?$/; // 非负浮点数
const regNeg = /^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$/; // 负浮点数
if (regPos.test(val as string) || regNeg.test(val as string)) {
return true;
} else {
return false;
}
};
/**
* 是否为字符串数字
*/
export const isStringNumber = (val: string): boolean => {
if (!isString(val)) return false;
return !Number.isNaN(Number(val));
};
/**
* 是否为 AsyncFunction
*/
export const isAsyncFunction = <T = any>(val: unknown): val is Promise<T> => {
return is(val, "AsyncFunction");
};
/**
* 是否为 promise
*/
export const isPromise = <T = any>(val: unknown): val is Promise<T> => {
return is(val, "Promise") && isObject(val) && isFunction(val.then) && isFunction(val.catch);
};
/**
* 是否为字符串
*/
export const isString = (val: unknown): val is string => {
return is(val, "String");
};
/**
* 是否为boolean类型
*/
export const isBoolean = (val: unknown): val is boolean => {
return is(val, "Boolean");
};
/**
* 是否为数组
*/
export const isArray = (arg: any) => {
if (typeof Array.isArray === "undefined") {
return Object.prototype.toString.call(arg) === "[object Array]";
}
return Array.isArray(arg);
};
/**
* 是否客户端
*/
export const isClient = typeof window !== "undefined" && typeof document !== "undefined";
/**
* 是否为服务器
*/
export const isServer = !isClient;
/**
* 是否在浏览器中
*/
export const inBrowser = isClient;
/**
* 是否为元素节点
*/
export const isElement = (val: unknown): val is Element => {
if (typeof Element === "undefined") return false;
return val instanceof Element;
};
// 是否为图片节点
export const isImageDom = (o: Element) => {
return o && ["IMAGE", "IMG"].includes(o.tagName);
};
/**
* 是否为 null
*/
export const isNull = (val: unknown): val is null => {
return val === null;
};
/**
* 是否为 null 且未定义
*/
export const isNullAndUnDef = (val: unknown): val is null | undefined => {
return isUnDef(val) && isNull(val);
};
/**
* 是否为 null 或未定义
*/
export const isNullOrUnDef = (val: unknown): val is null | undefined => {
return isUnDef(val) || isNull(val);
};
/**
* 是否为手机号
*/
export const isPhone = (val: string) => {
return /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/.test(val);
};
/**
* 是否是图片链接
*/
export const isImgPath = (path: string): boolean => {
return /(https?:\/\/|data:image\/).*?\.(png|jpg|jpeg|gif|svg|webp|ico)/gi.test(path);
};
export const isIOS = () => {
return (
isClient &&
window?.navigator?.userAgent &&
(/iP(?:ad|hone|od)/.test(window.navigator.userAgent) ||
(window?.navigator?.maxTouchPoints > 2 && /iPad|Macintosh/.test(window?.navigator.userAgent)))
);
};
/**
* 是否为空值项(包含数组、对象判断)
*
* @param checkFull 是否检查数组、对象是否为空。默认 true
*/
export const isEmpty = (val: any, checkFull = true): boolean => {
// NaN 的检查
if (isNumber(val) && isNaN(val)) return true;
// 检查空字符串、null 和 undefined
if (val === "" || val === null || val === undefined) return true;
if (!checkFull) return false;
// 检查是不是数组并且长度为 0
if (isArray(val) && val.length === 0) return true;
// 检查是不是对象并且没有自身可枚举属性
if (isObject(val) && Object.keys(val).length === 0) return true;
// 如果以上都不是,则不为空
return false;
};
/**
* 确定目标元素是否可聚焦
*
* @param element HTML 元素
*/
export const isFocusable = (element: HTMLElement): boolean => {
if (element.tabIndex > 0 || (element.tabIndex === 0 && element.getAttribute("tabIndex") !== null)) {
return true;
}
if (element.tabIndex < 0 || element.hasAttribute("disabled") || element.getAttribute("aria-disabled") === "true") {
return false;
}
switch (element.nodeName) {
case "A": {
// casting current element to Specific HTMLElement in order to be more type precise
return !!(element as HTMLAnchorElement).href && (element as HTMLAnchorElement).rel !== "ignore";
}
case "INPUT": {
return !((element as HTMLInputElement).type === "hidden" || (element as HTMLInputElement).type === "file");
}
case "BUTTON":
case "SELECT":
case "TEXTAREA": {
return true;
}
default: {
return false;
}
}
};