useBoolean
import { ref } from 'vue';
export const useBoolean = (initValue: boolean = false) => {
const value = ref(initValue);
const on = () => {
value.value = true;
};
const off = () => {
value.value = false;
};
const toggle = () => {
value.value = !value.value;
};
return [value, { toggle, on, off }] as const;
};
useInterVal
import { onUnmounted, onUpdated, ref, watchEffect } from 'vue';
type Callback = () => void;
export const useInterVal = (callback: Callback, delaty: number | null) => {
const savedCallback = ref<Callback>(callback);
const timer = ref<NodeJS.Timeout | undefined>(undefined);
onUpdated(() => {
savedCallback.value = callback;
});
watchEffect(() => {
const tick = () => {
savedCallback.value();
};
if (delaty !== null) {
timer.value = setInterval(tick, delaty);
}
});
onUnmounted(() => {
clearInterval(timer.value);
});
};
useCountDown
import dayjs from 'dayjs';
import { useInfo } from './useInfo';
import { useInterVal } from './useInterVal';
const bw = (n: number) => {
return n > 9 ? n : '0' + n;
};
interface CountDown {
expried: boolean;
timeStr: string;
days: number;
hours: number;
minutes: number;
seconds: number;
}
export const useCountDown = (targetTime: string | number | Date) => {
const { info: timeDiff, setInfoValues: setTimeDiff } = useInfo<CountDown>({
expried: false,
timeStr: '',
days: 0,
hours: 0,
minutes: 0,
seconds: 0,
});
const time = () => {
const future = +new Date(targetTime);
const nowDate = +new Date();
const s = parseInt((future - nowDate) / 1000 + '');
const d = parseInt(s / 86400 + '');
const h = parseInt((s % 86400) / 3600 + '');
const ms = parseInt((s % 3600) / 60 + '');
const sc = parseInt((s % 60) + '');
const expried = s > 0 ? false : true;
const days = d < 0 ? -d : d;
const hours = h < 0 ? -h : h;
const minutes = ms < 0 ? -ms : ms;
const seconds = sc < 0 ? -sc : sc;
const isMoreText = expried ? '过去' : '还剩';
let target = '';
if (Object.prototype.toString.call(targetTime) === '[object Date]') {
target = dayjs(targetTime).format('YYYY-MM-DD HH:mm:ss');
} else {
target = targetTime as string;
}
const timeStr = `距离${target}${isMoreText}:${bw(d)}天-${bw(h)}小时-${bw(ms)}分钟-${bw(sc)}秒`;
setTimeDiff({
timeStr,
expried,
days,
hours,
minutes,
seconds,
});
};
useInterVal(() => {
time();
}, 1000);
return timeDiff as CountDown;
};
useFuncDebounce
import { ref, onUnmounted } from 'vue';
import _ from 'lodash';
export const useFuncDebounce = function () {
const timerRef = ref<NodeJS.Timeout | undefined>(undefined);
function debouncedCallback<T extends Function, K extends unknown, U extends unknown[]>(
callback: T,
delay: number = 500,
change: boolean = true
) {
return function (object?: K, ...args: U) {
if (timerRef.value) clearTimeout(timerRef.value);
timerRef.value = setTimeout(function () {
if (change && _.isObject(object)) {
callback.apply(object, [object, ...args]);
} else {
callback(object, ...args);
}
}, delay);
};
}
onUnmounted(() => {
clearTimeout(timerRef.value);
});
return debouncedCallback;
};
useGetList
import { reactive, ref } from 'vue';
import _ from 'lodash';
const ZERO = 0;
const DATALAYERS = 'data.data.records';
const TOTALLAYERS = 'data.data.total';
const MESSAGE = '返回为空!';
interface SetListParamsType<T> {
res: unknown;
customFunc?: (list: T) => T;
path?: string;
}
interface SetTotalParamsType {
res: unknown;
path?: string;
}
export const useGetList = <T extends any[]>() => {
const defaultList: T = [] as unknown as T;
const data = reactive<T>(defaultList);
const setData = (list: T) => {
data.length = 0;
data.push(...list);
};
const total = ref<number>(ZERO);
const setTotal = (tol: number) => {
total.value = tol;
};
const setDataAuxiliary = ({ res, customFunc, path = DATALAYERS }: SetListParamsType<T>) => {
if (res) {
if (customFunc && customFunc instanceof Function) {
setData(customFunc(_.get(res, path, defaultList)) || defaultList);
} else {
setData(_.get(res, path, defaultList) || defaultList);
}
} else {
console.error(MESSAGE);
setData(defaultList);
}
};
const setTotalAuxiliary = ({ res, path = TOTALLAYERS }: SetTotalParamsType) => {
if (res) setTotal(_.get(res, path, ZERO) || ZERO);
else {
console.error(MESSAGE);
setTotal(ZERO);
}
};
return [data, setDataAuxiliary, total, setTotalAuxiliary] as const;
};
useInfo
import { onUnmounted, reactive } from 'vue';
import _ from 'lodash';
const INFOLAWERS = 'data.data';
export const useInfo = <T extends Record<string, any>>(initValus = {} as T) => {
const info = reactive(initValus) as Record<string, any>;
const setSyncInfo = (res: unknown, path = INFOLAWERS) => {
try {
const data = _.get(res, path);
for (const key in data) {
info[key] = data[key];
}
} catch (error) {
console.log('setSyncInfo error', error);
}
};
const setInfoValues = (object: any) => {
for (const key in object) {
info[key] = object[key];
}
};
const setInfoValue = (key: string, value: any) => {
info[key] = value;
};
const clear = () => {
for (const key in info) {
info[key] = '';
}
};
onUnmounted(() => {
clear();
});
return { info, clear, setSyncInfo, setInfoValues, setInfoValue } as const;
};
useMountRef
import { onMounted, onUnmounted, ref } from 'vue';
export const useMountRef = () => {
const mountedRef = ref<boolean>(false);
onMounted(() => {
mountedRef.value = true;
});
onUnmounted(() => {
mountedRef.value = false;
});
return mountedRef;
};
useOffsetTop
import { onMounted, onUnmounted, ref } from 'vue';
interface OffsetProps {
extraHeight?: number;
id?: string;
}
interface DomAttr {
top: number;
bottom: number;
height: number;
left: number;
right: number;
width: number;
x: number;
y: number;
}
const BODYELEMENT = 'body';
const body = document.getElementsByTagName(BODYELEMENT)[0];
export const useOffsetTop = ({ extraHeight = 80, id }: OffsetProps = {}) => {
const tableRef = ref<HTMLDivElement | null>(null);
const height = ref<number>(0);
const setHeight = (h: number) => {
height.value = h;
return height.value;
};
const getOffsetTop = () => {
if (tableRef.value && tableRef.value instanceof HTMLDivElement) {
const { top } = tableRef.value?.getBoundingClientRect() as DomAttr;
id ? tableRef.value.setAttribute('data-key', id) : null;
const tableHeight = document.body.clientHeight - top - extraHeight;
return tableHeight;
}
return 0;
};
const saveHeightChange = () => {
const height = getOffsetTop() >= 0 ? getOffsetTop() : 0;
return setHeight(height);
};
const resizeObserver = new ResizeObserver(function (entry) {
saveHeightChange();
});
onMounted(() => {
resizeObserver.observe(body);
});
onUnmounted(() => {
saveHeightChange(), resizeObserver.disconnect();
});
return [tableRef, height] as const;
};
useThrottle
import { onUnmounted, ref } from 'vue';
export const useThrottle = () => {
const valid = ref<boolean>(false);
const timer = ref<NodeJS.Timeout | undefined>(undefined);
const throttleCallback = (fn: Function, delay: number = 500) => {
return (config?: unknown, ...args: unknown[]) => {
if (valid.value) return;
valid.value = true;
timer.value = setTimeout(() => {
valid.value = false;
fn.apply(config, [config, ...args]);
}, delay);
};
};
onUnmounted(() => {
clearTimeout(timer.value);
});
return throttleCallback;
};
useRequest
见前一篇文章