Commit 144ab577da06ff0bd1f258d1901b87864f232e45
1 parent
8d7d0835
fix(modal): height calc error #161
Showing
26 changed files
with
162 additions
and
112 deletions
CHANGELOG.zh_CN.md
README.md
... | ... | @@ -256,8 +256,8 @@ yarn clean:lib # 删除node_modules,兼容window系统 |
256 | 256 | |
257 | 257 | 如果这些插件对你有帮助,可以给一个 star 支持下 |
258 | 258 | |
259 | -- [vite-plugin-mock](https://github.com/anncwb/vite-plugin-mock) | |
260 | -- [vite-plugin-html](https://github.com/anncwb/vite-plugin-html) | |
259 | +- [vite-plugin-mock](https://github.com/vbenjs/vite-plugin-mock) | |
260 | +- [vite-plugin-html](https://github.com/vbenjs/vite-plugin-html) | |
261 | 261 | |
262 | 262 | ## 加入我们 |
263 | 263 | ... | ... |
src/components/Basic/src/BasicArrow.vue
src/components/Basic/src/BasicHelp.vue
src/components/Basic/src/BasicTitle.vue
src/components/Container/src/LazyContainer.vue
... | ... | @@ -35,6 +35,7 @@ |
35 | 35 | |
36 | 36 | export default defineComponent({ |
37 | 37 | name: 'LazyContainer', |
38 | + inheritAttrs: false, | |
38 | 39 | components: { Skeleton }, |
39 | 40 | props: { |
40 | 41 | // Waiting time, if the time is specified, whether visible or not, it will be automatically loaded after the specified time | ... | ... |
src/components/Container/src/ScrollContainer.vue
src/components/Markdown/src/index.vue
... | ... | @@ -8,19 +8,23 @@ |
8 | 8 | |
9 | 9 | import { propTypes } from '/@/utils/propTypes'; |
10 | 10 | import { useLocale } from '/@/hooks/web/useLocale'; |
11 | + import { useModalContext } from '../../Modal'; | |
11 | 12 | |
12 | 13 | type Lang = 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' | undefined; |
13 | 14 | export default defineComponent({ |
14 | - emits: ['change'], | |
15 | + inheritAttrs: false, | |
15 | 16 | props: { |
16 | 17 | height: propTypes.number.def(360), |
17 | 18 | value: propTypes.string.def(''), |
18 | 19 | }, |
20 | + emits: ['change', 'get'], | |
19 | 21 | setup(props, { attrs, emit }) { |
20 | 22 | const wrapRef = ref<ElRef>(null); |
21 | 23 | const vditorRef = ref<Nullable<Vditor>>(null); |
22 | 24 | const initedRef = ref(false); |
23 | 25 | |
26 | + const modalFn = useModalContext(); | |
27 | + | |
24 | 28 | const lang = ref<Lang>(); |
25 | 29 | |
26 | 30 | const { getLang } = useLocale(); |
... | ... | @@ -66,10 +70,19 @@ |
66 | 70 | initedRef.value = true; |
67 | 71 | } |
68 | 72 | |
73 | + const instance = { | |
74 | + getVditor: (): Vditor => vditorRef.value!, | |
75 | + }; | |
76 | + | |
69 | 77 | onMounted(() => { |
70 | 78 | nextTick(() => { |
71 | 79 | init(); |
80 | + setTimeout(() => { | |
81 | + modalFn?.redoModalHeight?.(); | |
82 | + }, 200); | |
72 | 83 | }); |
84 | + | |
85 | + emit('get', instance); | |
73 | 86 | }); |
74 | 87 | |
75 | 88 | onUnmounted(() => { |
... | ... | @@ -82,7 +95,7 @@ |
82 | 95 | |
83 | 96 | return { |
84 | 97 | wrapRef, |
85 | - getVditor: (): Vditor => vditorRef.value!, | |
98 | + ...instance, | |
86 | 99 | }; |
87 | 100 | }, |
88 | 101 | }); | ... | ... |
src/components/Modal/src/BasicModal.vue
... | ... | @@ -27,7 +27,7 @@ |
27 | 27 | :height="getProps.height" |
28 | 28 | :visible="visibleRef" |
29 | 29 | :modalFooterHeight="footer !== undefined && !footer ? 0 : undefined" |
30 | - v-bind="omit(getProps.wrapperProps, 'visible')" | |
30 | + v-bind="omit(getProps.wrapperProps, 'visible', 'height')" | |
31 | 31 | @ext-height="handleExtHeight" |
32 | 32 | @height-change="handleHeightChange" |
33 | 33 | > |
... | ... | @@ -51,6 +51,7 @@ |
51 | 51 | watchEffect, |
52 | 52 | toRef, |
53 | 53 | getCurrentInstance, |
54 | + nextTick, | |
54 | 55 | } from 'vue'; |
55 | 56 | |
56 | 57 | import Modal from './components/Modal'; |
... | ... | @@ -67,6 +68,7 @@ |
67 | 68 | import { omit } from 'lodash-es'; |
68 | 69 | export default defineComponent({ |
69 | 70 | name: 'BasicModal', |
71 | + inheritAttrs: false, | |
70 | 72 | components: { Modal, ModalWrapper, ModalClose, ModalFooter, ModalHeader }, |
71 | 73 | props: basicProps, |
72 | 74 | emits: ['visible-change', 'height-change', 'cancel', 'ok', 'register'], | ... | ... |
src/components/Modal/src/components/ModalWrapper.vue
... | ... | @@ -31,6 +31,7 @@ |
31 | 31 | |
32 | 32 | export default defineComponent({ |
33 | 33 | name: 'ModalWrapper', |
34 | + inheritAttrs: false, | |
34 | 35 | components: { Spin, ScrollContainer }, |
35 | 36 | props: { |
36 | 37 | loading: propTypes.bool, |
... | ... | @@ -51,6 +52,8 @@ |
51 | 52 | const realHeightRef = ref(0); |
52 | 53 | const minRealHeightRef = ref(0); |
53 | 54 | |
55 | + let realHeight = 0; | |
56 | + | |
54 | 57 | let stopElResizeFn: Fn = () => {}; |
55 | 58 | |
56 | 59 | useWindowSizeFn(setModalHeight); |
... | ... | @@ -137,8 +140,9 @@ |
137 | 140 | |
138 | 141 | if (!spinEl) return; |
139 | 142 | |
140 | - const realHeight = spinEl.scrollHeight; | |
141 | - | |
143 | + if (!realHeight) { | |
144 | + realHeight = spinEl.scrollHeight; | |
145 | + } | |
142 | 146 | if (props.fullScreen) { |
143 | 147 | realHeightRef.value = |
144 | 148 | window.innerHeight - props.modalFooterHeight - props.modalHeaderHeight; |
... | ... | @@ -147,7 +151,7 @@ |
147 | 151 | ? props.height |
148 | 152 | : realHeight > maxHeight |
149 | 153 | ? maxHeight |
150 | - : realHeight + 16 + 30; | |
154 | + : realHeight + 46; | |
151 | 155 | } |
152 | 156 | emit('height-change', unref(realHeightRef)); |
153 | 157 | } catch (error) { | ... | ... |
src/components/Scrollbar/src/index.vue
... | ... | @@ -33,6 +33,7 @@ |
33 | 33 | |
34 | 34 | export default defineComponent({ |
35 | 35 | name: 'Scrollbar', |
36 | + inheritAttrs: false, | |
36 | 37 | components: { Bar }, |
37 | 38 | props: { |
38 | 39 | native: { |
... | ... | @@ -91,12 +92,18 @@ |
91 | 92 | onMounted(() => { |
92 | 93 | if (props.native) return; |
93 | 94 | nextTick(update); |
94 | - !props.noresize && addResizeListener(resize.value, update); | |
95 | + if (!props.noresize) { | |
96 | + addResizeListener(resize.value, update); | |
97 | + addResizeListener(wrap.value, update); | |
98 | + } | |
95 | 99 | }); |
96 | 100 | |
97 | 101 | onBeforeUnmount(() => { |
98 | 102 | if (props.native) return; |
99 | - !props.noresize && removeResizeListener(resize.value, update); | |
103 | + if (!props.noresize) { | |
104 | + removeResizeListener(resize.value, update); | |
105 | + removeResizeListener(wrap.value, update); | |
106 | + } | |
100 | 107 | }); |
101 | 108 | const style = computed(() => { |
102 | 109 | let style: any = props.wrapStyle; |
... | ... | @@ -127,7 +134,7 @@ |
127 | 134 | |
128 | 135 | &__wrap { |
129 | 136 | height: 100%; |
130 | - overflow: scroll; | |
137 | + overflow: auto; | |
131 | 138 | |
132 | 139 | &--hidden-default { |
133 | 140 | scrollbar-width: none; | ... | ... |
src/components/Tinymce/src/Editor.vue
src/components/Tree/src/BasicTree.tsx
... | ... | @@ -15,6 +15,7 @@ import { extendSlots } from '/@/utils/helper/tsxHelper'; |
15 | 15 | import { basicProps } from './props'; |
16 | 16 | import { useTree } from './useTree'; |
17 | 17 | import { useExpose } from '/@/hooks/core/useExpose'; |
18 | +import { onMounted } from 'vue'; | |
18 | 19 | |
19 | 20 | interface State { |
20 | 21 | expandedKeys: Keys; |
... | ... | @@ -25,7 +26,7 @@ const prefixCls = 'basic-tree'; |
25 | 26 | export default defineComponent({ |
26 | 27 | name: 'BasicTree', |
27 | 28 | props: basicProps, |
28 | - emits: ['update:expandedKeys', 'update:selectedKeys', 'update:value'], | |
29 | + emits: ['update:expandedKeys', 'update:selectedKeys', 'update:value', 'get'], | |
29 | 30 | setup(props, { attrs, slots, emit }) { |
30 | 31 | const state = reactive<State>({ |
31 | 32 | expandedKeys: props.expandedKeys || [], |
... | ... | @@ -182,7 +183,7 @@ export default defineComponent({ |
182 | 183 | state.checkedKeys = props.checkedKeys; |
183 | 184 | }); |
184 | 185 | |
185 | - useExpose<TreeActionType>({ | |
186 | + const instance: TreeActionType = { | |
186 | 187 | setExpandedKeys, |
187 | 188 | getExpandedKeys, |
188 | 189 | setSelectedKeys, |
... | ... | @@ -195,6 +196,12 @@ export default defineComponent({ |
195 | 196 | filterByLevel: (level: number) => { |
196 | 197 | state.expandedKeys = filterByLevel(level); |
197 | 198 | }, |
199 | + }; | |
200 | + | |
201 | + useExpose<TreeActionType>(instance); | |
202 | + | |
203 | + onMounted(() => { | |
204 | + emit('get', instance); | |
198 | 205 | }); |
199 | 206 | |
200 | 207 | return () => { | ... | ... |
src/hooks/component/usePageContext.ts
src/layouts/default/sider/MixSider.vue
... | ... | @@ -113,7 +113,6 @@ |
113 | 113 | const activePath = ref(''); |
114 | 114 | const chilrenMenus = ref<Menu[]>([]); |
115 | 115 | const openMenu = ref(false); |
116 | - const isInit = ref(false); | |
117 | 116 | const dragBarRef = ref<ElRef>(null); |
118 | 117 | const sideRef = ref<ElRef>(null); |
119 | 118 | const currentRoute = ref<Nullable<RouteLocationNormalized>>(null); |
... | ... | @@ -251,8 +250,8 @@ |
251 | 250 | } |
252 | 251 | |
253 | 252 | function handleClickOutside() { |
253 | + setActive(true); | |
254 | 254 | closeMenu(); |
255 | - setActive(); | |
256 | 255 | } |
257 | 256 | |
258 | 257 | function getItemEvents(item: Menu) { | ... | ... |
src/utils/browser.ts
... | ... | @@ -75,7 +75,7 @@ export function isOperaFn() { |
75 | 75 | * set page Title |
76 | 76 | * @param {*} title :page Title |
77 | 77 | */ |
78 | -const setDocumentTitle = (title: string) => { | |
78 | +function setDocumentTitle(title: string) { | |
79 | 79 | document.title = title; |
80 | 80 | const ua = navigator.userAgent; |
81 | 81 | const regex = /\bMicroMessenger\/([\d.]+)/; |
... | ... | @@ -91,7 +91,7 @@ const setDocumentTitle = (title: string) => { |
91 | 91 | }; |
92 | 92 | document.body.appendChild(i); |
93 | 93 | } |
94 | -}; | |
94 | +} | |
95 | 95 | |
96 | 96 | export function setTitle(title: string, appTitle?: string) { |
97 | 97 | if (title) { | ... | ... |
src/utils/color.ts
... | ... | @@ -5,10 +5,10 @@ |
5 | 5 | * @param String color 十六进制颜色值 |
6 | 6 | * @return Boolean |
7 | 7 | */ |
8 | -export const isHexColor = function (color: string) { | |
8 | +export function isHexColor(color: string) { | |
9 | 9 | const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/; |
10 | 10 | return reg.test(color); |
11 | -}; | |
11 | +} | |
12 | 12 | |
13 | 13 | /** |
14 | 14 | * RGB 颜色值转换为 十六进制颜色值. |
... | ... | @@ -19,18 +19,18 @@ export const isHexColor = function (color: string) { |
19 | 19 | * @param g |
20 | 20 | * @param b |
21 | 21 | */ |
22 | -export const rgbToHex = function (r: number, g: number, b: number) { | |
22 | +export function rgbToHex(r: number, g: number, b: number) { | |
23 | 23 | // tslint:disable-next-line:no-bitwise |
24 | 24 | const hex = ((r << 16) | (g << 8) | b).toString(16); |
25 | 25 | return '#' + new Array(Math.abs(hex.length - 7)).join('0') + hex; |
26 | -}; | |
26 | +} | |
27 | 27 | |
28 | 28 | /** |
29 | 29 | * Transform a HEX color to its RGB representation |
30 | 30 | * @param {string} hex The color to transform |
31 | 31 | * @returns The RGB representation of the passed color |
32 | 32 | */ |
33 | -export const hexToRGB = function (hex: string) { | |
33 | +export function hexToRGB(hex: string) { | |
34 | 34 | let sHex = hex.toLowerCase(); |
35 | 35 | if (isHexColor(hex)) { |
36 | 36 | if (sHex.length === 4) { |
... | ... | @@ -47,16 +47,16 @@ export const hexToRGB = function (hex: string) { |
47 | 47 | return 'RGB(' + sColorChange.join(',') + ')'; |
48 | 48 | } |
49 | 49 | return sHex; |
50 | -}; | |
50 | +} | |
51 | 51 | |
52 | -export const colorIsDark = (color: string) => { | |
52 | +export function colorIsDark(color: string) { | |
53 | 53 | if (!isHexColor(color)) return; |
54 | 54 | const [r, g, b] = hexToRGB(color) |
55 | 55 | .replace(/(?:\(|\)|rgb|RGB)*/g, '') |
56 | 56 | .split(',') |
57 | 57 | .map((item) => Number(item)); |
58 | 58 | return r * 0.299 + g * 0.578 + b * 0.114 < 192; |
59 | -}; | |
59 | +} | |
60 | 60 | |
61 | 61 | /** |
62 | 62 | * Darkens a HEX color given the passed percentage |
... | ... | @@ -64,14 +64,14 @@ export const colorIsDark = (color: string) => { |
64 | 64 | * @param {number} amount The amount to change the color by |
65 | 65 | * @returns {string} The HEX representation of the processed color |
66 | 66 | */ |
67 | -export const darken = (color: string, amount: number) => { | |
67 | +export function darken(color: string, amount: number) { | |
68 | 68 | color = color.indexOf('#') >= 0 ? color.substring(1, color.length) : color; |
69 | 69 | amount = Math.trunc((255 * amount) / 100); |
70 | 70 | return `#${subtractLight(color.substring(0, 2), amount)}${subtractLight( |
71 | 71 | color.substring(2, 4), |
72 | 72 | amount |
73 | 73 | )}${subtractLight(color.substring(4, 6), amount)}`; |
74 | -}; | |
74 | +} | |
75 | 75 | |
76 | 76 | /** |
77 | 77 | * Lightens a 6 char HEX color according to the passed percentage |
... | ... | @@ -79,14 +79,14 @@ export const darken = (color: string, amount: number) => { |
79 | 79 | * @param {number} amount The amount to change the color by |
80 | 80 | * @returns {string} The processed color represented as HEX |
81 | 81 | */ |
82 | -export const lighten = (color: string, amount: number) => { | |
82 | +export function lighten(color: string, amount: number) { | |
83 | 83 | color = color.indexOf('#') >= 0 ? color.substring(1, color.length) : color; |
84 | 84 | amount = Math.trunc((255 * amount) / 100); |
85 | 85 | return `#${addLight(color.substring(0, 2), amount)}${addLight( |
86 | 86 | color.substring(2, 4), |
87 | 87 | amount |
88 | 88 | )}${addLight(color.substring(4, 6), amount)}`; |
89 | -}; | |
89 | +} | |
90 | 90 | |
91 | 91 | /* Suma el porcentaje indicado a un color (RR, GG o BB) hexadecimal para aclararlo */ |
92 | 92 | /** |
... | ... | @@ -95,11 +95,11 @@ export const lighten = (color: string, amount: number) => { |
95 | 95 | * @param {number} amount The amount to change the color by |
96 | 96 | * @returns {string} The processed part of the color |
97 | 97 | */ |
98 | -const addLight = (color: string, amount: number) => { | |
98 | +function addLight(color: string, amount: number) { | |
99 | 99 | const cc = parseInt(color, 16) + amount; |
100 | 100 | const c = cc > 255 ? 255 : cc; |
101 | 101 | return c.toString(16).length > 1 ? c.toString(16) : `0${c.toString(16)}`; |
102 | -}; | |
102 | +} | |
103 | 103 | |
104 | 104 | /** |
105 | 105 | * Calculates luminance of an rgb color |
... | ... | @@ -107,33 +107,36 @@ const addLight = (color: string, amount: number) => { |
107 | 107 | * @param {number} g green |
108 | 108 | * @param {number} b blue |
109 | 109 | */ |
110 | -const luminanace = (r: number, g: number, b: number) => { | |
110 | +function luminanace(r: number, g: number, b: number) { | |
111 | 111 | const a = [r, g, b].map((v) => { |
112 | 112 | v /= 255; |
113 | 113 | return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4); |
114 | 114 | }); |
115 | 115 | return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722; |
116 | -}; | |
116 | +} | |
117 | 117 | |
118 | 118 | /** |
119 | 119 | * Calculates contrast between two rgb colors |
120 | 120 | * @param {string} rgb1 rgb color 1 |
121 | 121 | * @param {string} rgb2 rgb color 2 |
122 | 122 | */ |
123 | -const contrast = (rgb1: string[], rgb2: number[]) => | |
124 | - (luminanace(~~rgb1[0], ~~rgb1[1], ~~rgb1[2]) + 0.05) / | |
125 | - (luminanace(rgb2[0], rgb2[1], rgb2[2]) + 0.05); | |
123 | +function contrast(rgb1: string[], rgb2: number[]) { | |
124 | + return ( | |
125 | + (luminanace(~~rgb1[0], ~~rgb1[1], ~~rgb1[2]) + 0.05) / | |
126 | + (luminanace(rgb2[0], rgb2[1], rgb2[2]) + 0.05) | |
127 | + ); | |
128 | +} | |
126 | 129 | |
127 | 130 | /** |
128 | 131 | * Determines what the best text color is (black or white) based con the contrast with the background |
129 | 132 | * @param hexColor - Last selected color by the user |
130 | 133 | */ |
131 | -export const calculateBestTextColor = (hexColor: string) => { | |
134 | +export function calculateBestTextColor(hexColor: string) { | |
132 | 135 | const rgbColor = hexToRGB(hexColor.substring(1)); |
133 | 136 | const contrastWithBlack = contrast(rgbColor.split(','), [0, 0, 0]); |
134 | 137 | |
135 | 138 | return contrastWithBlack >= 12 ? '#000000' : '#FFFFFF'; |
136 | -}; | |
139 | +} | |
137 | 140 | |
138 | 141 | /** |
139 | 142 | * Subtracts the indicated percentage to the R, G or B of a HEX color |
... | ... | @@ -141,8 +144,8 @@ export const calculateBestTextColor = (hexColor: string) => { |
141 | 144 | * @param {number} amount The amount to change the color by |
142 | 145 | * @returns {string} The processed part of the color |
143 | 146 | */ |
144 | -const subtractLight = (color: string, amount: number) => { | |
147 | +function subtractLight(color: string, amount: number) { | |
145 | 148 | const cc = parseInt(color, 16) - amount; |
146 | 149 | const c = cc < 0 ? 0 : cc; |
147 | 150 | return c.toString(16).length > 1 ? c.toString(16) : `0${c.toString(16)}`; |
148 | -}; | |
151 | +} | ... | ... |
src/utils/dateUtil.ts
... | ... | @@ -14,7 +14,7 @@ export function formatToDate(date: moment.MomentInput = null, format = DATE_FORM |
14 | 14 | return moment(date).format(format); |
15 | 15 | } |
16 | 16 | |
17 | -export const formatAgo = (str: string | number) => { | |
17 | +export function formatAgo(str: string | number) { | |
18 | 18 | if (!str) return ''; |
19 | 19 | const date = new Date(Number(str)); |
20 | 20 | const time = new Date().getTime() - date.getTime(); // 现在的时间-传入的时间 = 相差的时间(单位 = 毫秒) |
... | ... | @@ -35,6 +35,6 @@ export const formatAgo = (str: string | number) => { |
35 | 35 | } else { |
36 | 36 | return parseInt(String(time / 31536000000)) + '年前'; |
37 | 37 | } |
38 | -}; | |
38 | +} | |
39 | 39 | |
40 | 40 | export const dateUtil = moment; | ... | ... |
src/utils/domUtils.ts
... | ... | @@ -132,7 +132,7 @@ export function hackCss(attr: string, value: string) { |
132 | 132 | } |
133 | 133 | |
134 | 134 | /* istanbul ignore next */ |
135 | -export const on = function ( | |
135 | +export function on( | |
136 | 136 | element: Element | HTMLElement | Document | Window, |
137 | 137 | event: string, |
138 | 138 | handler: EventListenerOrEventListenerObject |
... | ... | @@ -140,10 +140,10 @@ export const on = function ( |
140 | 140 | if (element && event && handler) { |
141 | 141 | element.addEventListener(event, handler, false); |
142 | 142 | } |
143 | -}; | |
143 | +} | |
144 | 144 | |
145 | 145 | /* istanbul ignore next */ |
146 | -export const off = function ( | |
146 | +export function off( | |
147 | 147 | element: Element | HTMLElement | Document | Window, |
148 | 148 | event: string, |
149 | 149 | handler: Fn |
... | ... | @@ -151,10 +151,10 @@ export const off = function ( |
151 | 151 | if (element && event && handler) { |
152 | 152 | element.removeEventListener(event, handler, false); |
153 | 153 | } |
154 | -}; | |
154 | +} | |
155 | 155 | |
156 | 156 | /* istanbul ignore next */ |
157 | -export const once = function (el: HTMLElement, event: string, fn: EventListener): void { | |
157 | +export function once(el: HTMLElement, event: string, fn: EventListener): void { | |
158 | 158 | const listener = function (this: any, ...args: unknown[]) { |
159 | 159 | if (fn) { |
160 | 160 | fn.apply(this, args); |
... | ... | @@ -162,4 +162,4 @@ export const once = function (el: HTMLElement, event: string, fn: EventListener) |
162 | 162 | off(el, event, listener); |
163 | 163 | }; |
164 | 164 | on(el, event, listener); |
165 | -}; | |
165 | +} | ... | ... |
src/utils/env.ts
1 | 1 | import type { GlobEnvConfig } from '/@/types/config'; |
2 | 2 | |
3 | -export const getGlobEnvConfig = (): GlobEnvConfig => { | |
3 | +export function getGlobEnvConfig(): GlobEnvConfig { | |
4 | 4 | const env = import.meta.env; |
5 | 5 | return (env as unknown) as GlobEnvConfig; |
6 | -}; | |
6 | +} | |
7 | 7 | |
8 | 8 | /** |
9 | 9 | * @description: 开发模式 |
... | ... | @@ -20,25 +20,33 @@ export const prodMode = 'production'; |
20 | 20 | * @returns: |
21 | 21 | * @example: |
22 | 22 | */ |
23 | -export const getEnv = (): string => import.meta.env.MODE; | |
23 | +export function getEnv(): string { | |
24 | + return import.meta.env.MODE; | |
25 | +} | |
24 | 26 | |
25 | 27 | /** |
26 | 28 | * @description: 是否是开发模式 |
27 | 29 | * @returns: |
28 | 30 | * @example: |
29 | 31 | */ |
30 | -export const isDevMode = (): boolean => import.meta.env.DEV; | |
32 | +export function isDevMode(): boolean { | |
33 | + return import.meta.env.DEV; | |
34 | +} | |
31 | 35 | |
32 | 36 | /** |
33 | 37 | * @description: 是否是生产模式模式 |
34 | 38 | * @returns: |
35 | 39 | * @example: |
36 | 40 | */ |
37 | -export const isProdMode = (): boolean => import.meta.env.PROD; | |
41 | +export function isProdMode(): boolean { | |
42 | + return import.meta.env.PROD; | |
43 | +} | |
38 | 44 | |
39 | 45 | /** |
40 | 46 | * @description: 是否开启mock |
41 | 47 | * @returns: |
42 | 48 | * @example: |
43 | 49 | */ |
44 | -export const isUseMock = (): boolean => import.meta.env.VITE_USE_MOCK === 'true'; | |
50 | +export function isUseMock(): boolean { | |
51 | + return import.meta.env.VITE_USE_MOCK === 'true'; | |
52 | +} | ... | ... |
src/utils/event/resizeEvent.ts
... | ... | @@ -3,7 +3,7 @@ import ResizeObserver from 'resize-observer-polyfill'; |
3 | 3 | const isServer = typeof window === 'undefined'; |
4 | 4 | |
5 | 5 | /* istanbul ignore next */ |
6 | -const resizeHandler = function (entries: any[]) { | |
6 | +function resizeHandler(entries: any[]) { | |
7 | 7 | for (const entry of entries) { |
8 | 8 | const listeners = entry.target.__resizeListeners__ || []; |
9 | 9 | if (listeners.length) { |
... | ... | @@ -12,10 +12,10 @@ const resizeHandler = function (entries: any[]) { |
12 | 12 | }); |
13 | 13 | } |
14 | 14 | } |
15 | -}; | |
15 | +} | |
16 | 16 | |
17 | 17 | /* istanbul ignore next */ |
18 | -export const addResizeListener = function (element: any, fn: () => any) { | |
18 | +export function addResizeListener(element: any, fn: () => any) { | |
19 | 19 | if (isServer) return; |
20 | 20 | if (!element.__resizeListeners__) { |
21 | 21 | element.__resizeListeners__ = []; |
... | ... | @@ -23,13 +23,13 @@ export const addResizeListener = function (element: any, fn: () => any) { |
23 | 23 | element.__ro__.observe(element); |
24 | 24 | } |
25 | 25 | element.__resizeListeners__.push(fn); |
26 | -}; | |
26 | +} | |
27 | 27 | |
28 | 28 | /* istanbul ignore next */ |
29 | -export const removeResizeListener = function (element: any, fn: () => any) { | |
29 | +export function removeResizeListener(element: any, fn: () => any) { | |
30 | 30 | if (!element || !element.__resizeListeners__) return; |
31 | 31 | element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1); |
32 | 32 | if (!element.__resizeListeners__.length) { |
33 | 33 | element.__ro__.disconnect(); |
34 | 34 | } |
35 | -}; | |
35 | +} | ... | ... |
src/utils/event/triggerWindowResizeEvent.ts
... | ... | @@ -4,6 +4,6 @@ |
4 | 4 | export function triggerWindowResize() { |
5 | 5 | const event = document.createEvent('HTMLEvents'); |
6 | 6 | event.initEvent('resize', true, true); |
7 | - (event as ChangeEvent).eventType = 'message'; | |
7 | + (event as any).eventType = 'message'; | |
8 | 8 | window.dispatchEvent(event); |
9 | 9 | } | ... | ... |
src/utils/helper/envHelper.ts
... | ... | @@ -4,6 +4,6 @@ import pkg from '../../../package.json'; |
4 | 4 | const globSetting = useGlobSetting(); |
5 | 5 | |
6 | 6 | // Generate cache key according to version |
7 | -export const getStorageShortName = () => { | |
7 | +export function getStorageShortName() { | |
8 | 8 | return `${globSetting.shortName}__${getEnv()}${`__${pkg.version}`}__`.toUpperCase(); |
9 | -}; | |
9 | +} | ... | ... |
src/utils/index.ts
... | ... | @@ -85,3 +85,17 @@ export function getDynamicProps<T, U>(props: T): Partial<U> { |
85 | 85 | |
86 | 86 | return ret as Partial<U>; |
87 | 87 | } |
88 | + | |
89 | +export function getLastItem<T extends any>(list: T) { | |
90 | + if (Array.isArray(list)) { | |
91 | + return list.slice(-1)[0]; | |
92 | + } | |
93 | + | |
94 | + if (list instanceof Set) { | |
95 | + return Array.from(list).slice(-1)[0]; | |
96 | + } | |
97 | + | |
98 | + if (list instanceof Map) { | |
99 | + return Array.from(list.values()).slice(-1)[0]; | |
100 | + } | |
101 | +} | ... | ... |
src/utils/is.ts
... | ... | @@ -4,17 +4,33 @@ export function is(val: unknown, type: string) { |
4 | 4 | return toString.call(val) === `[object ${type}]`; |
5 | 5 | } |
6 | 6 | |
7 | -export const isDef = <T = unknown>(val?: T): val is T => { | |
7 | +export function isDef<T = unknown>(val?: T): val is T { | |
8 | 8 | return typeof val !== 'undefined'; |
9 | -}; | |
9 | +} | |
10 | 10 | |
11 | -export const isUnDef = <T = unknown>(val?: T): val is T => { | |
11 | +export function isUnDef<T = unknown>(val?: T): val is T { | |
12 | 12 | return !isDef(val); |
13 | -}; | |
13 | +} | |
14 | 14 | |
15 | -export const isObject = (val: any): val is Record<any, any> => { | |
15 | +export function isObject(val: any): val is Record<any, any> { | |
16 | 16 | return val !== null && is(val, 'Object'); |
17 | -}; | |
17 | +} | |
18 | + | |
19 | +export function isEmpty<T = unknown>(val: T): val is T { | |
20 | + if (isArray(val) || isString(val)) { | |
21 | + return val.length === 0; | |
22 | + } | |
23 | + | |
24 | + if (val instanceof Map || val instanceof Set) { | |
25 | + return val.size === 0; | |
26 | + } | |
27 | + | |
28 | + if (isObject(val)) { | |
29 | + return Object.keys(val).length === 0; | |
30 | + } | |
31 | + | |
32 | + return false; | |
33 | +} | |
18 | 34 | |
19 | 35 | export function isDate(val: unknown): val is Date { |
20 | 36 | return is(val, 'Date'); |
... | ... | @@ -40,7 +56,9 @@ export function isString(val: unknown): val is string { |
40 | 56 | return is(val, 'String'); |
41 | 57 | } |
42 | 58 | |
43 | -export const isFunction = (val: unknown): val is Function => typeof val === 'function'; | |
59 | +export function isFunction(val: unknown): val is Function { | |
60 | + return typeof val === 'function'; | |
61 | +} | |
44 | 62 | |
45 | 63 | export function isBoolean(val: unknown): val is boolean { |
46 | 64 | return is(val, 'Boolean'); |
... | ... | @@ -54,13 +72,13 @@ export function isArray(val: any): val is Array<any> { |
54 | 72 | return val && Array.isArray(val); |
55 | 73 | } |
56 | 74 | |
57 | -export const isWindow = (val: any): val is Window => { | |
75 | +export function isWindow(val: any): val is Window { | |
58 | 76 | return typeof window !== 'undefined' && is(val, 'Window'); |
59 | -}; | |
77 | +} | |
60 | 78 | |
61 | -export const isElement = (val: unknown): val is Element => { | |
79 | +export function isElement(val: unknown): val is Element { | |
62 | 80 | return isObject(val) && !!val.tagName; |
63 | -}; | |
81 | +} | |
64 | 82 | |
65 | 83 | export const isServer = typeof window === 'undefined'; |
66 | 84 | |
... | ... | @@ -70,17 +88,17 @@ export function isImageDom(o: Element) { |
70 | 88 | return o && ['IMAGE', 'IMG'].includes(o.tagName); |
71 | 89 | } |
72 | 90 | |
73 | -export const isTextarea = (element: Element | null): element is HTMLTextAreaElement => { | |
91 | +export function isTextarea(element: Element | null): element is HTMLTextAreaElement { | |
74 | 92 | return element !== null && element.tagName.toLowerCase() === 'textarea'; |
75 | -}; | |
93 | +} | |
76 | 94 | |
77 | -export const isMobile = (): boolean => { | |
95 | +export function isMobile(): boolean { | |
78 | 96 | return !!navigator.userAgent.match( |
79 | 97 | /(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i |
80 | 98 | ); |
81 | -}; | |
99 | +} | |
82 | 100 | |
83 | -export const isUrl = (path: string): boolean => { | |
101 | +export function isUrl(path: string): boolean { | |
84 | 102 | const reg = /(((^https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/; |
85 | 103 | return reg.test(path); |
86 | -}; | |
104 | +} | ... | ... |
src/utils/scrollbarWidth.ts deleted
100644 → 0
1 | -import { isWindow } from '/@/utils/is'; | |
2 | - | |
3 | -let scrollBarWidth: number; | |
4 | - | |
5 | -export default function (): number { | |
6 | - if (!isWindow) return 0; | |
7 | - if (scrollBarWidth !== undefined) return scrollBarWidth; | |
8 | - | |
9 | - const outer = document.createElement('div'); | |
10 | - outer.className = 'scrollbar__wrap'; | |
11 | - outer.style.visibility = 'hidden'; | |
12 | - outer.style.width = '100px'; | |
13 | - outer.style.position = 'absolute'; | |
14 | - outer.style.top = '-9999px'; | |
15 | - document.body.appendChild(outer); | |
16 | - | |
17 | - const widthNoScroll = outer.offsetWidth; | |
18 | - outer.style.overflow = 'scroll'; | |
19 | - | |
20 | - const inner = document.createElement('div'); | |
21 | - inner.style.width = '100%'; | |
22 | - outer.appendChild(inner); | |
23 | - | |
24 | - const widthWithScroll = inner.offsetWidth; | |
25 | - const parentNode = outer.parentNode; | |
26 | - parentNode && parentNode.removeChild(outer); | |
27 | - scrollBarWidth = widthNoScroll - widthWithScroll; | |
28 | - | |
29 | - return scrollBarWidth; | |
30 | -} |