mirror of
https://github.com/vbenjs/gf-vben-admin.git
synced 2025-01-23 11:50:20 +08:00
fix(modal): height calc error #161
This commit is contained in:
parent
8d7d0835ad
commit
144ab577da
@ -13,6 +13,7 @@
|
||||
- 恢复 table 的`isTreeTable`属性
|
||||
- 修复表格内存溢出问题
|
||||
- 修复`layout` 收缩展开功能在分割模式下失效
|
||||
- 修复 modal 高度计算错误
|
||||
|
||||
## 2.0.0-rc.15 (2020-12-31)
|
||||
|
||||
|
@ -256,8 +256,8 @@ yarn clean:lib # 删除node_modules,兼容window系统
|
||||
|
||||
如果这些插件对你有帮助,可以给一个 star 支持下
|
||||
|
||||
- [vite-plugin-mock](https://github.com/anncwb/vite-plugin-mock)
|
||||
- [vite-plugin-html](https://github.com/anncwb/vite-plugin-html)
|
||||
- [vite-plugin-mock](https://github.com/vbenjs/vite-plugin-mock)
|
||||
- [vite-plugin-html](https://github.com/vbenjs/vite-plugin-html)
|
||||
|
||||
## 加入我们
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
export default defineComponent({
|
||||
name: 'BasicArrow',
|
||||
inheritAttrs: false,
|
||||
components: { RightOutlined },
|
||||
props: {
|
||||
// Expand contract, expand by default
|
||||
|
@ -12,6 +12,7 @@
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
export default defineComponent({
|
||||
name: 'BasicHelp',
|
||||
inheritAttrs: false,
|
||||
components: { Tooltip },
|
||||
props: {
|
||||
// max-width
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
export default defineComponent({
|
||||
name: 'BasicTitle',
|
||||
inheritAttrs: false,
|
||||
components: { BasicHelp },
|
||||
props: {
|
||||
helpMessage: {
|
||||
|
@ -35,6 +35,7 @@
|
||||
|
||||
export default defineComponent({
|
||||
name: 'LazyContainer',
|
||||
inheritAttrs: false,
|
||||
components: { Skeleton },
|
||||
props: {
|
||||
// Waiting time, if the time is specified, whether visible or not, it will be automatically loaded after the specified time
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ScrollContainer',
|
||||
inheritAttrs: false,
|
||||
components: { Scrollbar },
|
||||
setup() {
|
||||
const scrollbarRef = ref<Nullable<ScrollbarType>>(null);
|
||||
|
@ -8,19 +8,23 @@
|
||||
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { useLocale } from '/@/hooks/web/useLocale';
|
||||
import { useModalContext } from '../../Modal';
|
||||
|
||||
type Lang = 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' | undefined;
|
||||
export default defineComponent({
|
||||
emits: ['change'],
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
height: propTypes.number.def(360),
|
||||
value: propTypes.string.def(''),
|
||||
},
|
||||
emits: ['change', 'get'],
|
||||
setup(props, { attrs, emit }) {
|
||||
const wrapRef = ref<ElRef>(null);
|
||||
const vditorRef = ref<Nullable<Vditor>>(null);
|
||||
const initedRef = ref(false);
|
||||
|
||||
const modalFn = useModalContext();
|
||||
|
||||
const lang = ref<Lang>();
|
||||
|
||||
const { getLang } = useLocale();
|
||||
@ -66,10 +70,19 @@
|
||||
initedRef.value = true;
|
||||
}
|
||||
|
||||
const instance = {
|
||||
getVditor: (): Vditor => vditorRef.value!,
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
init();
|
||||
setTimeout(() => {
|
||||
modalFn?.redoModalHeight?.();
|
||||
}, 200);
|
||||
});
|
||||
|
||||
emit('get', instance);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
@ -82,7 +95,7 @@
|
||||
|
||||
return {
|
||||
wrapRef,
|
||||
getVditor: (): Vditor => vditorRef.value!,
|
||||
...instance,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
@ -27,7 +27,7 @@
|
||||
:height="getProps.height"
|
||||
:visible="visibleRef"
|
||||
:modalFooterHeight="footer !== undefined && !footer ? 0 : undefined"
|
||||
v-bind="omit(getProps.wrapperProps, 'visible')"
|
||||
v-bind="omit(getProps.wrapperProps, 'visible', 'height')"
|
||||
@ext-height="handleExtHeight"
|
||||
@height-change="handleHeightChange"
|
||||
>
|
||||
@ -51,6 +51,7 @@
|
||||
watchEffect,
|
||||
toRef,
|
||||
getCurrentInstance,
|
||||
nextTick,
|
||||
} from 'vue';
|
||||
|
||||
import Modal from './components/Modal';
|
||||
@ -67,6 +68,7 @@
|
||||
import { omit } from 'lodash-es';
|
||||
export default defineComponent({
|
||||
name: 'BasicModal',
|
||||
inheritAttrs: false,
|
||||
components: { Modal, ModalWrapper, ModalClose, ModalFooter, ModalHeader },
|
||||
props: basicProps,
|
||||
emits: ['visible-change', 'height-change', 'cancel', 'ok', 'register'],
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ModalWrapper',
|
||||
inheritAttrs: false,
|
||||
components: { Spin, ScrollContainer },
|
||||
props: {
|
||||
loading: propTypes.bool,
|
||||
@ -51,6 +52,8 @@
|
||||
const realHeightRef = ref(0);
|
||||
const minRealHeightRef = ref(0);
|
||||
|
||||
let realHeight = 0;
|
||||
|
||||
let stopElResizeFn: Fn = () => {};
|
||||
|
||||
useWindowSizeFn(setModalHeight);
|
||||
@ -137,8 +140,9 @@
|
||||
|
||||
if (!spinEl) return;
|
||||
|
||||
const realHeight = spinEl.scrollHeight;
|
||||
|
||||
if (!realHeight) {
|
||||
realHeight = spinEl.scrollHeight;
|
||||
}
|
||||
if (props.fullScreen) {
|
||||
realHeightRef.value =
|
||||
window.innerHeight - props.modalFooterHeight - props.modalHeaderHeight;
|
||||
@ -147,7 +151,7 @@
|
||||
? props.height
|
||||
: realHeight > maxHeight
|
||||
? maxHeight
|
||||
: realHeight + 16 + 30;
|
||||
: realHeight + 46;
|
||||
}
|
||||
emit('height-change', unref(realHeightRef));
|
||||
} catch (error) {
|
||||
|
@ -33,6 +33,7 @@
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Scrollbar',
|
||||
inheritAttrs: false,
|
||||
components: { Bar },
|
||||
props: {
|
||||
native: {
|
||||
@ -91,12 +92,18 @@
|
||||
onMounted(() => {
|
||||
if (props.native) return;
|
||||
nextTick(update);
|
||||
!props.noresize && addResizeListener(resize.value, update);
|
||||
if (!props.noresize) {
|
||||
addResizeListener(resize.value, update);
|
||||
addResizeListener(wrap.value, update);
|
||||
}
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (props.native) return;
|
||||
!props.noresize && removeResizeListener(resize.value, update);
|
||||
if (!props.noresize) {
|
||||
removeResizeListener(resize.value, update);
|
||||
removeResizeListener(wrap.value, update);
|
||||
}
|
||||
});
|
||||
const style = computed(() => {
|
||||
let style: any = props.wrapStyle;
|
||||
@ -127,7 +134,7 @@
|
||||
|
||||
&__wrap {
|
||||
height: 100%;
|
||||
overflow: scroll;
|
||||
overflow: auto;
|
||||
|
||||
&--hidden-default {
|
||||
scrollbar-width: none;
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Tinymce',
|
||||
inheritAttrs: false,
|
||||
props: basicProps,
|
||||
emits: ['change', 'update:modelValue'],
|
||||
setup(props, { emit, attrs }) {
|
||||
|
@ -15,6 +15,7 @@ import { extendSlots } from '/@/utils/helper/tsxHelper';
|
||||
import { basicProps } from './props';
|
||||
import { useTree } from './useTree';
|
||||
import { useExpose } from '/@/hooks/core/useExpose';
|
||||
import { onMounted } from 'vue';
|
||||
|
||||
interface State {
|
||||
expandedKeys: Keys;
|
||||
@ -25,7 +26,7 @@ const prefixCls = 'basic-tree';
|
||||
export default defineComponent({
|
||||
name: 'BasicTree',
|
||||
props: basicProps,
|
||||
emits: ['update:expandedKeys', 'update:selectedKeys', 'update:value'],
|
||||
emits: ['update:expandedKeys', 'update:selectedKeys', 'update:value', 'get'],
|
||||
setup(props, { attrs, slots, emit }) {
|
||||
const state = reactive<State>({
|
||||
expandedKeys: props.expandedKeys || [],
|
||||
@ -182,7 +183,7 @@ export default defineComponent({
|
||||
state.checkedKeys = props.checkedKeys;
|
||||
});
|
||||
|
||||
useExpose<TreeActionType>({
|
||||
const instance: TreeActionType = {
|
||||
setExpandedKeys,
|
||||
getExpandedKeys,
|
||||
setSelectedKeys,
|
||||
@ -195,6 +196,12 @@ export default defineComponent({
|
||||
filterByLevel: (level: number) => {
|
||||
state.expandedKeys = filterByLevel(level);
|
||||
},
|
||||
};
|
||||
|
||||
useExpose<TreeActionType>(instance);
|
||||
|
||||
onMounted(() => {
|
||||
emit('get', instance);
|
||||
});
|
||||
|
||||
return () => {
|
||||
|
@ -1,8 +1,6 @@
|
||||
import type { InjectionKey, ComputedRef, Ref } from 'vue';
|
||||
import { createContext, useContext } from '/@/hooks/core/useContext';
|
||||
|
||||
import {} from 'vue';
|
||||
|
||||
export interface PageContextProps {
|
||||
contentHeight: ComputedRef<number>;
|
||||
pageHeight: Ref<number>;
|
||||
|
@ -113,7 +113,6 @@
|
||||
const activePath = ref('');
|
||||
const chilrenMenus = ref<Menu[]>([]);
|
||||
const openMenu = ref(false);
|
||||
const isInit = ref(false);
|
||||
const dragBarRef = ref<ElRef>(null);
|
||||
const sideRef = ref<ElRef>(null);
|
||||
const currentRoute = ref<Nullable<RouteLocationNormalized>>(null);
|
||||
@ -251,8 +250,8 @@
|
||||
}
|
||||
|
||||
function handleClickOutside() {
|
||||
setActive(true);
|
||||
closeMenu();
|
||||
setActive();
|
||||
}
|
||||
|
||||
function getItemEvents(item: Menu) {
|
||||
|
@ -75,7 +75,7 @@ export function isOperaFn() {
|
||||
* set page Title
|
||||
* @param {*} title :page Title
|
||||
*/
|
||||
const setDocumentTitle = (title: string) => {
|
||||
function setDocumentTitle(title: string) {
|
||||
document.title = title;
|
||||
const ua = navigator.userAgent;
|
||||
const regex = /\bMicroMessenger\/([\d.]+)/;
|
||||
@ -91,7 +91,7 @@ const setDocumentTitle = (title: string) => {
|
||||
};
|
||||
document.body.appendChild(i);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function setTitle(title: string, appTitle?: string) {
|
||||
if (title) {
|
||||
|
@ -5,10 +5,10 @@
|
||||
* @param String color 十六进制颜色值
|
||||
* @return Boolean
|
||||
*/
|
||||
export const isHexColor = function (color: string) {
|
||||
export function isHexColor(color: string) {
|
||||
const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
|
||||
return reg.test(color);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB 颜色值转换为 十六进制颜色值.
|
||||
@ -19,18 +19,18 @@ export const isHexColor = function (color: string) {
|
||||
* @param g
|
||||
* @param b
|
||||
*/
|
||||
export const rgbToHex = function (r: number, g: number, b: number) {
|
||||
export function rgbToHex(r: number, g: number, b: number) {
|
||||
// tslint:disable-next-line:no-bitwise
|
||||
const hex = ((r << 16) | (g << 8) | b).toString(16);
|
||||
return '#' + new Array(Math.abs(hex.length - 7)).join('0') + hex;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a HEX color to its RGB representation
|
||||
* @param {string} hex The color to transform
|
||||
* @returns The RGB representation of the passed color
|
||||
*/
|
||||
export const hexToRGB = function (hex: string) {
|
||||
export function hexToRGB(hex: string) {
|
||||
let sHex = hex.toLowerCase();
|
||||
if (isHexColor(hex)) {
|
||||
if (sHex.length === 4) {
|
||||
@ -47,16 +47,16 @@ export const hexToRGB = function (hex: string) {
|
||||
return 'RGB(' + sColorChange.join(',') + ')';
|
||||
}
|
||||
return sHex;
|
||||
};
|
||||
}
|
||||
|
||||
export const colorIsDark = (color: string) => {
|
||||
export function colorIsDark(color: string) {
|
||||
if (!isHexColor(color)) return;
|
||||
const [r, g, b] = hexToRGB(color)
|
||||
.replace(/(?:\(|\)|rgb|RGB)*/g, '')
|
||||
.split(',')
|
||||
.map((item) => Number(item));
|
||||
return r * 0.299 + g * 0.578 + b * 0.114 < 192;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Darkens a HEX color given the passed percentage
|
||||
@ -64,14 +64,14 @@ export const colorIsDark = (color: string) => {
|
||||
* @param {number} amount The amount to change the color by
|
||||
* @returns {string} The HEX representation of the processed color
|
||||
*/
|
||||
export const darken = (color: string, amount: number) => {
|
||||
export function darken(color: string, amount: number) {
|
||||
color = color.indexOf('#') >= 0 ? color.substring(1, color.length) : color;
|
||||
amount = Math.trunc((255 * amount) / 100);
|
||||
return `#${subtractLight(color.substring(0, 2), amount)}${subtractLight(
|
||||
color.substring(2, 4),
|
||||
amount
|
||||
)}${subtractLight(color.substring(4, 6), amount)}`;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Lightens a 6 char HEX color according to the passed percentage
|
||||
@ -79,14 +79,14 @@ export const darken = (color: string, amount: number) => {
|
||||
* @param {number} amount The amount to change the color by
|
||||
* @returns {string} The processed color represented as HEX
|
||||
*/
|
||||
export const lighten = (color: string, amount: number) => {
|
||||
export function lighten(color: string, amount: number) {
|
||||
color = color.indexOf('#') >= 0 ? color.substring(1, color.length) : color;
|
||||
amount = Math.trunc((255 * amount) / 100);
|
||||
return `#${addLight(color.substring(0, 2), amount)}${addLight(
|
||||
color.substring(2, 4),
|
||||
amount
|
||||
)}${addLight(color.substring(4, 6), amount)}`;
|
||||
};
|
||||
}
|
||||
|
||||
/* Suma el porcentaje indicado a un color (RR, GG o BB) hexadecimal para aclararlo */
|
||||
/**
|
||||
@ -95,11 +95,11 @@ export const lighten = (color: string, amount: number) => {
|
||||
* @param {number} amount The amount to change the color by
|
||||
* @returns {string} The processed part of the color
|
||||
*/
|
||||
const addLight = (color: string, amount: number) => {
|
||||
function addLight(color: string, amount: number) {
|
||||
const cc = parseInt(color, 16) + amount;
|
||||
const c = cc > 255 ? 255 : cc;
|
||||
return c.toString(16).length > 1 ? c.toString(16) : `0${c.toString(16)}`;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates luminance of an rgb color
|
||||
@ -107,33 +107,36 @@ const addLight = (color: string, amount: number) => {
|
||||
* @param {number} g green
|
||||
* @param {number} b blue
|
||||
*/
|
||||
const luminanace = (r: number, g: number, b: number) => {
|
||||
function luminanace(r: number, g: number, b: number) {
|
||||
const a = [r, g, b].map((v) => {
|
||||
v /= 255;
|
||||
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
|
||||
});
|
||||
return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates contrast between two rgb colors
|
||||
* @param {string} rgb1 rgb color 1
|
||||
* @param {string} rgb2 rgb color 2
|
||||
*/
|
||||
const contrast = (rgb1: string[], rgb2: number[]) =>
|
||||
(luminanace(~~rgb1[0], ~~rgb1[1], ~~rgb1[2]) + 0.05) /
|
||||
(luminanace(rgb2[0], rgb2[1], rgb2[2]) + 0.05);
|
||||
function contrast(rgb1: string[], rgb2: number[]) {
|
||||
return (
|
||||
(luminanace(~~rgb1[0], ~~rgb1[1], ~~rgb1[2]) + 0.05) /
|
||||
(luminanace(rgb2[0], rgb2[1], rgb2[2]) + 0.05)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines what the best text color is (black or white) based con the contrast with the background
|
||||
* @param hexColor - Last selected color by the user
|
||||
*/
|
||||
export const calculateBestTextColor = (hexColor: string) => {
|
||||
export function calculateBestTextColor(hexColor: string) {
|
||||
const rgbColor = hexToRGB(hexColor.substring(1));
|
||||
const contrastWithBlack = contrast(rgbColor.split(','), [0, 0, 0]);
|
||||
|
||||
return contrastWithBlack >= 12 ? '#000000' : '#FFFFFF';
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts the indicated percentage to the R, G or B of a HEX color
|
||||
@ -141,8 +144,8 @@ export const calculateBestTextColor = (hexColor: string) => {
|
||||
* @param {number} amount The amount to change the color by
|
||||
* @returns {string} The processed part of the color
|
||||
*/
|
||||
const subtractLight = (color: string, amount: number) => {
|
||||
function subtractLight(color: string, amount: number) {
|
||||
const cc = parseInt(color, 16) - amount;
|
||||
const c = cc < 0 ? 0 : cc;
|
||||
return c.toString(16).length > 1 ? c.toString(16) : `0${c.toString(16)}`;
|
||||
};
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ export function formatToDate(date: moment.MomentInput = null, format = DATE_FORM
|
||||
return moment(date).format(format);
|
||||
}
|
||||
|
||||
export const formatAgo = (str: string | number) => {
|
||||
export function formatAgo(str: string | number) {
|
||||
if (!str) return '';
|
||||
const date = new Date(Number(str));
|
||||
const time = new Date().getTime() - date.getTime(); // 现在的时间-传入的时间 = 相差的时间(单位 = 毫秒)
|
||||
@ -35,6 +35,6 @@ export const formatAgo = (str: string | number) => {
|
||||
} else {
|
||||
return parseInt(String(time / 31536000000)) + '年前';
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const dateUtil = moment;
|
||||
|
@ -132,7 +132,7 @@ export function hackCss(attr: string, value: string) {
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
export const on = function (
|
||||
export function on(
|
||||
element: Element | HTMLElement | Document | Window,
|
||||
event: string,
|
||||
handler: EventListenerOrEventListenerObject
|
||||
@ -140,10 +140,10 @@ export const on = function (
|
||||
if (element && event && handler) {
|
||||
element.addEventListener(event, handler, false);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
export const off = function (
|
||||
export function off(
|
||||
element: Element | HTMLElement | Document | Window,
|
||||
event: string,
|
||||
handler: Fn
|
||||
@ -151,10 +151,10 @@ export const off = function (
|
||||
if (element && event && handler) {
|
||||
element.removeEventListener(event, handler, false);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
export const once = function (el: HTMLElement, event: string, fn: EventListener): void {
|
||||
export function once(el: HTMLElement, event: string, fn: EventListener): void {
|
||||
const listener = function (this: any, ...args: unknown[]) {
|
||||
if (fn) {
|
||||
fn.apply(this, args);
|
||||
@ -162,4 +162,4 @@ export const once = function (el: HTMLElement, event: string, fn: EventListener)
|
||||
off(el, event, listener);
|
||||
};
|
||||
on(el, event, listener);
|
||||
};
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
import type { GlobEnvConfig } from '/@/types/config';
|
||||
|
||||
export const getGlobEnvConfig = (): GlobEnvConfig => {
|
||||
export function getGlobEnvConfig(): GlobEnvConfig {
|
||||
const env = import.meta.env;
|
||||
return (env as unknown) as GlobEnvConfig;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 开发模式
|
||||
@ -20,25 +20,33 @@ export const prodMode = 'production';
|
||||
* @returns:
|
||||
* @example:
|
||||
*/
|
||||
export const getEnv = (): string => import.meta.env.MODE;
|
||||
export function getEnv(): string {
|
||||
return import.meta.env.MODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 是否是开发模式
|
||||
* @returns:
|
||||
* @example:
|
||||
*/
|
||||
export const isDevMode = (): boolean => import.meta.env.DEV;
|
||||
export function isDevMode(): boolean {
|
||||
return import.meta.env.DEV;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 是否是生产模式模式
|
||||
* @returns:
|
||||
* @example:
|
||||
*/
|
||||
export const isProdMode = (): boolean => import.meta.env.PROD;
|
||||
export function isProdMode(): boolean {
|
||||
return import.meta.env.PROD;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 是否开启mock
|
||||
* @returns:
|
||||
* @example:
|
||||
*/
|
||||
export const isUseMock = (): boolean => import.meta.env.VITE_USE_MOCK === 'true';
|
||||
export function isUseMock(): boolean {
|
||||
return import.meta.env.VITE_USE_MOCK === 'true';
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import ResizeObserver from 'resize-observer-polyfill';
|
||||
const isServer = typeof window === 'undefined';
|
||||
|
||||
/* istanbul ignore next */
|
||||
const resizeHandler = function (entries: any[]) {
|
||||
function resizeHandler(entries: any[]) {
|
||||
for (const entry of entries) {
|
||||
const listeners = entry.target.__resizeListeners__ || [];
|
||||
if (listeners.length) {
|
||||
@ -12,10 +12,10 @@ const resizeHandler = function (entries: any[]) {
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
export const addResizeListener = function (element: any, fn: () => any) {
|
||||
export function addResizeListener(element: any, fn: () => any) {
|
||||
if (isServer) return;
|
||||
if (!element.__resizeListeners__) {
|
||||
element.__resizeListeners__ = [];
|
||||
@ -23,13 +23,13 @@ export const addResizeListener = function (element: any, fn: () => any) {
|
||||
element.__ro__.observe(element);
|
||||
}
|
||||
element.__resizeListeners__.push(fn);
|
||||
};
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
export const removeResizeListener = function (element: any, fn: () => any) {
|
||||
export function removeResizeListener(element: any, fn: () => any) {
|
||||
if (!element || !element.__resizeListeners__) return;
|
||||
element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
|
||||
if (!element.__resizeListeners__.length) {
|
||||
element.__ro__.disconnect();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -4,6 +4,6 @@
|
||||
export function triggerWindowResize() {
|
||||
const event = document.createEvent('HTMLEvents');
|
||||
event.initEvent('resize', true, true);
|
||||
(event as ChangeEvent).eventType = 'message';
|
||||
(event as any).eventType = 'message';
|
||||
window.dispatchEvent(event);
|
||||
}
|
||||
|
@ -4,6 +4,6 @@ import pkg from '../../../package.json';
|
||||
const globSetting = useGlobSetting();
|
||||
|
||||
// Generate cache key according to version
|
||||
export const getStorageShortName = () => {
|
||||
export function getStorageShortName() {
|
||||
return `${globSetting.shortName}__${getEnv()}${`__${pkg.version}`}__`.toUpperCase();
|
||||
};
|
||||
}
|
||||
|
@ -85,3 +85,17 @@ export function getDynamicProps<T, U>(props: T): Partial<U> {
|
||||
|
||||
return ret as Partial<U>;
|
||||
}
|
||||
|
||||
export function getLastItem<T extends any>(list: T) {
|
||||
if (Array.isArray(list)) {
|
||||
return list.slice(-1)[0];
|
||||
}
|
||||
|
||||
if (list instanceof Set) {
|
||||
return Array.from(list).slice(-1)[0];
|
||||
}
|
||||
|
||||
if (list instanceof Map) {
|
||||
return Array.from(list.values()).slice(-1)[0];
|
||||
}
|
||||
}
|
||||
|
@ -4,17 +4,33 @@ export function is(val: unknown, type: string) {
|
||||
return toString.call(val) === `[object ${type}]`;
|
||||
}
|
||||
|
||||
export const isDef = <T = unknown>(val?: T): val is T => {
|
||||
export function isDef<T = unknown>(val?: T): val is T {
|
||||
return typeof val !== 'undefined';
|
||||
};
|
||||
}
|
||||
|
||||
export const isUnDef = <T = unknown>(val?: T): val is T => {
|
||||
export function isUnDef<T = unknown>(val?: T): val is T {
|
||||
return !isDef(val);
|
||||
};
|
||||
}
|
||||
|
||||
export const isObject = (val: any): val is Record<any, any> => {
|
||||
export function isObject(val: any): val is Record<any, any> {
|
||||
return val !== null && is(val, 'Object');
|
||||
};
|
||||
}
|
||||
|
||||
export function isEmpty<T = unknown>(val: T): val is T {
|
||||
if (isArray(val) || isString(val)) {
|
||||
return val.length === 0;
|
||||
}
|
||||
|
||||
if (val instanceof Map || val instanceof Set) {
|
||||
return val.size === 0;
|
||||
}
|
||||
|
||||
if (isObject(val)) {
|
||||
return Object.keys(val).length === 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isDate(val: unknown): val is Date {
|
||||
return is(val, 'Date');
|
||||
@ -40,7 +56,9 @@ export function isString(val: unknown): val is string {
|
||||
return is(val, 'String');
|
||||
}
|
||||
|
||||
export const isFunction = (val: unknown): val is Function => typeof val === 'function';
|
||||
export function isFunction(val: unknown): val is Function {
|
||||
return typeof val === 'function';
|
||||
}
|
||||
|
||||
export function isBoolean(val: unknown): val is boolean {
|
||||
return is(val, 'Boolean');
|
||||
@ -54,13 +72,13 @@ export function isArray(val: any): val is Array<any> {
|
||||
return val && Array.isArray(val);
|
||||
}
|
||||
|
||||
export const isWindow = (val: any): val is Window => {
|
||||
export function isWindow(val: any): val is Window {
|
||||
return typeof window !== 'undefined' && is(val, 'Window');
|
||||
};
|
||||
}
|
||||
|
||||
export const isElement = (val: unknown): val is Element => {
|
||||
export function isElement(val: unknown): val is Element {
|
||||
return isObject(val) && !!val.tagName;
|
||||
};
|
||||
}
|
||||
|
||||
export const isServer = typeof window === 'undefined';
|
||||
|
||||
@ -70,17 +88,17 @@ export function isImageDom(o: Element) {
|
||||
return o && ['IMAGE', 'IMG'].includes(o.tagName);
|
||||
}
|
||||
|
||||
export const isTextarea = (element: Element | null): element is HTMLTextAreaElement => {
|
||||
export function isTextarea(element: Element | null): element is HTMLTextAreaElement {
|
||||
return element !== null && element.tagName.toLowerCase() === 'textarea';
|
||||
};
|
||||
}
|
||||
|
||||
export const isMobile = (): boolean => {
|
||||
export function isMobile(): boolean {
|
||||
return !!navigator.userAgent.match(
|
||||
/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export const isUrl = (path: string): boolean => {
|
||||
export function isUrl(path: string): boolean {
|
||||
const reg = /(((^https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/;
|
||||
return reg.test(path);
|
||||
};
|
||||
}
|
||||
|
@ -1,30 +0,0 @@
|
||||
import { isWindow } from '/@/utils/is';
|
||||
|
||||
let scrollBarWidth: number;
|
||||
|
||||
export default function (): number {
|
||||
if (!isWindow) return 0;
|
||||
if (scrollBarWidth !== undefined) return scrollBarWidth;
|
||||
|
||||
const outer = document.createElement('div');
|
||||
outer.className = 'scrollbar__wrap';
|
||||
outer.style.visibility = 'hidden';
|
||||
outer.style.width = '100px';
|
||||
outer.style.position = 'absolute';
|
||||
outer.style.top = '-9999px';
|
||||
document.body.appendChild(outer);
|
||||
|
||||
const widthNoScroll = outer.offsetWidth;
|
||||
outer.style.overflow = 'scroll';
|
||||
|
||||
const inner = document.createElement('div');
|
||||
inner.style.width = '100%';
|
||||
outer.appendChild(inner);
|
||||
|
||||
const widthWithScroll = inner.offsetWidth;
|
||||
const parentNode = outer.parentNode;
|
||||
parentNode && parentNode.removeChild(outer);
|
||||
scrollBarWidth = widthNoScroll - widthWithScroll;
|
||||
|
||||
return scrollBarWidth;
|
||||
}
|
Loading…
Reference in New Issue
Block a user