validate.ts
export const isDef = <T>(val: T): val is NonNullable<T> =>
val !== undefined && val !== null;
export const isFunction = (val: unknown): val is Function =>
typeof val === 'function';
export const isObject = (val: unknown): val is Record<any, any> =>
val !== null && typeof val === 'object';
export const isPromise = <T = any>(val: unknown): val is Promise<T> =>
isObject(val) && isFunction(val.then) && isFunction(val.catch);
export const isDate = (val: unknown): val is Date =>
Object.prototype.toString.call(val) === '[object Date]' &&
!Number.isNaN((val as Date).getTime());
export function isMobile(value: string): boolean {
value = value.replace(/[^-|\d]/g, '');
return (
/^((\+86)|(86))?(1)\d{10}$/.test(value) || /^0[0-9-]{10,13}$/.test(value)
);
}
export type Numeric = number | string;
export const isNumeric = (val: Numeric): val is string =>
typeof val === 'number' || /^\d+(\.\d+)?$/.test(val);
export const inBrowser = typeof window !== 'undefined';
export const isIOS = (): boolean =>
inBrowser
? /ios|iphone|ipad|ipod/.test(navigator.userAgent.toLowerCase())
: false;
basic.ts
export function get(object: any, path: string): any {
const keys = path.split('.');
let result = object;
keys.forEach((key) => {
result = isObject(result) ? result[key] ?? '' : '';
});
return result;
}
const exampleObject = {
user: {
name: {
first: 'John',
last: 'Doe'
},
age: 30,
contact: {
email: 'john.doe@example.com',
phone: '123-456-7890'
}
},
company: {
name: 'Example Corp',
address: '123 Example Street',
city: 'Anytown'
}
};
console.log(get(exampleObject, 'user.name.first'));
console.log(get(exampleObject, 'user.age'));
console.log(get(exampleObject, 'user.contact.email'));
console.log(get(exampleObject, 'user.contact.phone'));
console.log(get(exampleObject, 'company.address'));
console.log(get(exampleObject, 'company.nonExistentProperty'));
export type Writeable<T> = { -readonly [P in keyof T]: T[P] };
export function pick<T, U extends keyof T>(
obj: T,
keys: ReadonlyArray<U>,
ignoreUndefined?: boolean
) {
return keys.reduce((ret, key) => {
if (!ignoreUndefined || obj[key] !== undefined) {
ret[key] = obj[key];
}
return ret;
}, {} as Writeable<Pick<T, U>>);
}
const user = {
name: '小可爱',
info: {
address: '许昌胖东来',
}
}
const info = pick(user, ['info'])
const exampleObject = {
user: {
name: {
first: 'John',
last: 'Doe'
},
age: 30,
contact: {
email: 'john.doe@example.com',
phone: '123-456-7890'
}
},
company: {
name: 'Example Corp',
address: '123 Example Street',
city: 'Anytown'
}
};
const age = pick(exampleObj, ['user.age', 'user.contact'])
function pick2(obj, keys, ignoreUndefined) {
return keys.reduce((ret, key) => {
const value = get(obj, key);
const keyArr = key.split('.');
const lastKey = keyArr.pop();
if (!ignoreUndefined || value !== undefined) {
ret[lastKey] = value;
}
return ret;
}, {});
}
const obj = pick2(exampleObject, ['user.name.first', 'user.age', 'company.name'], true)
vant-use useRect
const isWindow = (val: unknown): val is Window => val === window;
const makeDOMRect = (width: number, height: number) =>
({
top: 0,
left: 0,
right: width,
bottom: height,
width,
height,
} as DOMRect);
export const useRect = (
elementOrRef: Element | Window | Ref<Element | Window | undefined>
) => {
const element = unref(elementOrRef);
if (isWindow(element)) {
const width = element.innerWidth;
const height = element.innerHeight;
return makeDOMRect(width, height);
}
if (element?.getBoundingClientRect) {
return element.getBoundingClientRect();
}
return makeDOMRect(0, 0);
};
export const toArray = <T>(item: T | T[]): T[] =>
Array.isArray(item) ? item : [item];
dom.ts
export function getScrollTop(el: ScrollElement): number {
const top = 'scrollTop' in el ? el.scrollTop : el.pageYOffset;
return Math.max(top, 0);
}
export function setScrollTop(el: ScrollElement, value: number) {
if ('scrollTop' in el) {
el.scrollTop = value;
} else {
el.scrollTo(el.scrollX, value);
}
}
export function getRootScrollTop(): number {
return (
window.pageYOffset ||
document.documentElement.scrollTop ||
document.body.scrollTop ||
0
);
}
export function setRootScrollTop(value: number) {
setScrollTop(window, value);
setScrollTop(document.body, value);
}
export function getElementTop(el: ScrollElement, scroller?: ScrollElement) {
if (el === window) {
return 0;
}
const scrollTop = scroller ? getScrollTop(scroller) : getRootScrollTop();
return useRect(el).top + scrollTop;
}
export function isHidden(
elementRef: HTMLElement | Ref<HTMLElement | undefined>
) {
const el = unref(elementRef);
if (!el) {
return false;
}
const style = window.getComputedStyle(el);
const hidden = style.display === 'none';
const parentHidden = el.offsetParent === null && style.position !== 'fixed';
return hidden || parentHidden;
}
<div style="display: none" id="ele" />
const isHiddenEle = isHidden(ele)
format.ts
export function addUnit(value?: Numeric): string | undefined {
if (isDef(value)) {
return isNumeric(value) ? `${value}px` : String(value);
}
return undefined;
}
const obj = {}
obj.a = addUnit('1')
obj.b = addUnit(1)
obj.c = addUnit(undefined)
obj.d = addUnit(null)
obj.e = addUnit(true)
obj.f = addUnit(false)
obj.g = addUnit(NaN)
obj.h = addUnit(Infinity)
obj.i = addUnit(1.1)
obj.j = addUnit('1.1')
obj.k = addUnit('1.1px')
export function getSizeStyle(
originSize?: Numeric | Numeric[]
): CSSProperties | undefined {
if (isDef(originSize)) {
if (Array.isArray(originSize)) {
return {
width: addUnit(originSize[0]),
height: addUnit(originSize[1]),
};
}
const size = addUnit(originSize);
return {
width: size,
height: size,
};
}
}
const obj1 = {};
obj1.a = getSizeStyle('1')
obj1.b = getSizeStyle([1, 2])
obj1.c = getSizeStyle(undefined)
obj1.d = getSizeStyle(null)
obj1.e = getSizeStyle(true)
obj1.f = getSizeStyle(false)
console.log('obj1 :>> ', obj1);
let rootFontSize: number;
function getRootFontSize() {
if (!rootFontSize) {
const doc = document.documentElement;
const fontSize =
doc.style.fontSize || window.getComputedStyle(doc).fontSize;
rootFontSize = parseFloat(fontSize);
}
return rootFontSize;
}
function convertRem(value: string) {
value = value.replace(/rem/g, '');
return +value * getRootFontSize();
}
convertRem('1rem')
convertRem('2rem')
function convertVw(value: string) {
value = value.replace(/vw/g, '');
return (+value * innnerWidth) / 100;
}
function convertVh(value: string) {
value = value.replace(/vh/g, '');
return (+value * innerHeight) / 100;
}
export function unitToPx(value: Numeric): number {
if (typeof value === 'number') {
return value;
}
if (inBrowser) {
if (value.includes('rem')) {
return convertRem(value);
}
if (value.includes('vw')) {
return convertVw(value);
}
if (value.includes('vh')) {
return convertVh(value);
}
}
return parseFloat(value);
}
const obj2 = {};
obj2.a = unitToPx('1')
obj2.b = unitToPx('1rem')
obj2.c = unitToPx('1vw')
obj2.d = unitToPx('1vh')
obj2.e = unitToPx(1)
console.log('obj2 :>> ', obj2);
const camelizeRE = /-(\w)/g;
export const camelize = (str: string): string =>
str.replace(camelizeRE, (_, c) => c.toUpperCase());
camelize('custom-comp')
export const kebabCase = (str: string) =>
str
.replace(/([A-Z])/g, '-$1')
.toLowerCase()
.replace(/^-/, '');
kebabCase('camelCase');
kebabCase('PascalCase');
kebabCase('already-kebab-case');
kebabCase('Some Mixed String');
export function padZero(num: Numeric, targetLength = 2): string {
let str = num + '';
while (str.length < targetLength) {
str = '0' + str;
}
return str;
}
padZero(1, 5)
padZero('1', 4)
padZero('111', 3)
export const clamp = (num: number, min: number, max: number): number =>
Math.min(Math.max(num, min), max);
clamp(5,10,20)
clamp(24,20, 30)
clamp(20, 10, 19)
export function addNumber(num1: number, num2: number) {
const cardinal = 10 ** 10;
return Math.round((num1 + num2) * cardinal) / cardinal;
}
export function callInterceptor(
interceptor: Interceptor | undefined,
{
args = [],
done,
canceled,
}: {
args?: unknown[];
done: () => void;
canceled?: () => void;
}
) {
if (interceptor) {
const returnVal = interceptor.apply(null, args);
if (isPromise(returnVal)) {
returnVal
.then((value) => {
if (value) {
done();
} else if (canceled) {
canceled();
}
})
.catch(noop);
} else if (returnVal) {
done();
} else if (canceled) {
canceled();
}
} else {
done();
}
}
function beforeClose() {}
callInterceptor(beforeClose, {
args: [state],
done: () => {
console.log('在beforeClose触发后触发')
}
})
with-install.ts
type EventShim = {
new (...args: any[]): {
$props: {
onClick?: (...args: any[]) => void;
};
};
};
export type WithInstall<T> = T & {
install(app: App): void;
} & EventShim;
export function withInstall<T extends Component>(options: T) {
(options as Record<string, unknown>).install = (app: App) => {
const { name } = options;
if (name) {
app.component(name, options);
app.component(camelize(`-${name}`), options);
}
};
return options as WithInstall<T>;
}
import { withInstall } from '../utils';
import _Area from './Area.tsx';
export const Area = withInstall(_Area);
export default Area;
export { areaProps } from './Area';
export type { AreaProps } from './Area';
export type { AreaList, AreaInstance } from './types';
declare module 'vue' {
export interface GlobalComponents {
VanArea: typeof Area;
}
}