Commit 3b2c40bec818238bde165656dc17e885f242aa81
1 parent
1c1755cf
refactor(virtual-scroll): refactor virtualScroll component
Showing
15 changed files
with
200 additions
and
203 deletions
src/components/Markdown/index.ts
1 | -import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; | |
2 | -export const MarkDown = createAsyncComponent(() => import('./src/Markdown.vue')); | |
1 | +import { withInstall } from '/@/utils'; | |
2 | +import markDown from './src/Markdown.vue'; | |
3 | 3 | |
4 | -export * from './src/types'; | |
4 | +export const MarkDown = withInstall(markDown); | |
5 | +export * from './src/typing'; | ... | ... |
src/components/Markdown/src/Markdown.vue
... | ... | @@ -14,18 +14,17 @@ |
14 | 14 | } from 'vue'; |
15 | 15 | import Vditor from 'vditor'; |
16 | 16 | import 'vditor/dist/index.css'; |
17 | - | |
18 | - import { propTypes } from '/@/utils/propTypes'; | |
19 | 17 | import { useLocale } from '/@/locales/useLocale'; |
20 | 18 | import { useModalContext } from '../../Modal'; |
21 | 19 | import { useRootSetting } from '/@/hooks/setting/useRootSetting'; |
22 | 20 | |
23 | 21 | type Lang = 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' | undefined; |
22 | + | |
24 | 23 | export default defineComponent({ |
25 | 24 | inheritAttrs: false, |
26 | 25 | props: { |
27 | - height: propTypes.number.def(360), | |
28 | - value: propTypes.string.def(''), | |
26 | + height: { type: Number, default: 360 }, | |
27 | + value: { type: String, default: '' }, | |
29 | 28 | }, |
30 | 29 | emits: ['change', 'get'], |
31 | 30 | setup(props, { attrs, emit }) { | ... | ... |
src/components/Markdown/src/types.ts renamed to src/components/Markdown/src/typing.ts
src/components/StrengthMeter/index.ts
src/components/StrengthMeter/src/StrengthMeter.vue
... | ... | @@ -20,10 +20,7 @@ |
20 | 20 | |
21 | 21 | <script lang="ts"> |
22 | 22 | import { defineComponent, computed, ref, watch, unref, watchEffect } from 'vue'; |
23 | - | |
24 | 23 | import { Input } from 'ant-design-vue'; |
25 | - | |
26 | - // @ts-ignore | |
27 | 24 | import { zxcvbn } from '@zxcvbn-ts/core'; |
28 | 25 | import { useDesign } from '/@/hooks/web/useDesign'; |
29 | 26 | import { propTypes } from '/@/utils/propTypes'; | ... | ... |
src/components/Time/index.ts
src/components/Time/src/Time.vue
... | ... | @@ -3,10 +3,8 @@ |
3 | 3 | </template> |
4 | 4 | <script lang="ts"> |
5 | 5 | import { defineComponent, ref, watch } from 'vue'; |
6 | - | |
7 | 6 | import { useI18n } from '/@/hooks/web/useI18n'; |
8 | 7 | import { useIntervalFn } from '@vueuse/core'; |
9 | - | |
10 | 8 | import { formatToDateTime, formatToDate, dateUtil } from '/@/utils/dateUtil'; |
11 | 9 | import { isNumber, isObject, isString } from '/@/utils/is'; |
12 | 10 | import { propTypes } from '/@/utils/propTypes'; |
... | ... | @@ -15,6 +13,7 @@ |
15 | 13 | const ONE_MINUTES = ONE_SECONDS * 60; |
16 | 14 | const ONE_HOUR = ONE_MINUTES * 60; |
17 | 15 | const ONE_DAY = ONE_HOUR * 24; |
16 | + | |
18 | 17 | export default defineComponent({ |
19 | 18 | name: 'Time', |
20 | 19 | props: { | ... | ... |
src/components/Tinymce/index.ts
src/components/Tinymce/src/Editor.vue
... | ... | @@ -16,7 +16,6 @@ |
16 | 16 | import type { RawEditorSettings } from 'tinymce'; |
17 | 17 | import tinymce from 'tinymce/tinymce'; |
18 | 18 | import 'tinymce/themes/silver'; |
19 | - | |
20 | 19 | import 'tinymce/icons/default/icons'; |
21 | 20 | import 'tinymce/plugins/advlist'; |
22 | 21 | import 'tinymce/plugins/anchor'; |
... | ... | @@ -58,11 +57,8 @@ |
58 | 57 | onUnmounted, |
59 | 58 | onDeactivated, |
60 | 59 | } from 'vue'; |
61 | - | |
62 | 60 | import ImgUpload from './ImgUpload.vue'; |
63 | - | |
64 | 61 | import { toolbar, plugins } from './tinymce'; |
65 | - | |
66 | 62 | import { buildShortUUID } from '/@/utils/uuid'; |
67 | 63 | import { bindHandlers } from './helper'; |
68 | 64 | import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated'; |
... | ... | @@ -96,7 +92,6 @@ |
96 | 92 | required: false, |
97 | 93 | default: 400, |
98 | 94 | }, |
99 | - | |
100 | 95 | width: { |
101 | 96 | type: [Number, String] as PropType<string | number>, |
102 | 97 | required: false, | ... | ... |
src/components/Tinymce/src/ImgUpload.vue
... | ... | @@ -52,9 +52,9 @@ |
52 | 52 | function handleChange(info: Recordable) { |
53 | 53 | const file = info.file; |
54 | 54 | const status = file?.status; |
55 | - | |
56 | 55 | const url = file?.response?.url; |
57 | 56 | const name = file?.name; |
57 | + | |
58 | 58 | if (status === 'uploading') { |
59 | 59 | if (!uploading) { |
60 | 60 | emit('uploading', name); | ... | ... |
src/components/VirtualScroll/index.ts
1 | -import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; | |
1 | +import { withInstall } from '/@/utils/index'; | |
2 | +import vScroll from './src/VirtualScroll.vue'; | |
2 | 3 | |
3 | -export const VScroll = createAsyncComponent(() => import('./src/VirtualScroll')); | |
4 | +export const VScroll = withInstall(vScroll); | ... | ... |
src/components/VirtualScroll/src/VirtualScroll.tsx renamed to src/components/VirtualScroll/src/VirtualScroll.vue
1 | -import { | |
2 | - defineComponent, | |
3 | - computed, | |
4 | - ref, | |
5 | - unref, | |
6 | - reactive, | |
7 | - onMounted, | |
8 | - watch, | |
9 | - nextTick, | |
10 | - CSSProperties, | |
11 | -} from 'vue'; | |
12 | -import { useEventListener } from '/@/hooks/event/useEventListener'; | |
13 | - | |
14 | -import { props as basicProps } from './props'; | |
15 | -import { getSlot } from '/@/utils/helper/tsxHelper'; | |
16 | -import './index.less'; | |
17 | - | |
18 | -const prefixCls = 'virtual-scroll'; | |
19 | - | |
20 | -function convertToUnit(str: string | number | null | undefined, unit = 'px'): string | undefined { | |
21 | - if (str == null || str === '') { | |
22 | - return undefined; | |
23 | - } else if (isNaN(+str!)) { | |
24 | - return String(str); | |
25 | - } else { | |
26 | - return `${Number(str)}${unit}`; | |
1 | +<script lang="tsx"> | |
2 | + import { | |
3 | + defineComponent, | |
4 | + computed, | |
5 | + ref, | |
6 | + unref, | |
7 | + reactive, | |
8 | + onMounted, | |
9 | + watch, | |
10 | + nextTick, | |
11 | + CSSProperties, | |
12 | + } from 'vue'; | |
13 | + import { useEventListener } from '/@/hooks/event/useEventListener'; | |
14 | + import { getSlot } from '/@/utils/helper/tsxHelper'; | |
15 | + | |
16 | + type NumberOrNumberString = PropType<string | number | undefined>; | |
17 | + | |
18 | + const props = { | |
19 | + height: [Number, String] as NumberOrNumberString, | |
20 | + maxHeight: [Number, String] as NumberOrNumberString, | |
21 | + maxWidth: [Number, String] as NumberOrNumberString, | |
22 | + minHeight: [Number, String] as NumberOrNumberString, | |
23 | + minWidth: [Number, String] as NumberOrNumberString, | |
24 | + width: [Number, String] as NumberOrNumberString, | |
25 | + bench: { | |
26 | + type: [Number, String] as NumberOrNumberString, | |
27 | + default: 0, | |
28 | + }, | |
29 | + itemHeight: { | |
30 | + type: [Number, String] as NumberOrNumberString, | |
31 | + required: true, | |
32 | + }, | |
33 | + items: { | |
34 | + type: Array as PropType<any[]>, | |
35 | + default: () => [], | |
36 | + }, | |
37 | + }; | |
38 | + | |
39 | + const prefixCls = 'virtual-scroll'; | |
40 | + | |
41 | + function convertToUnit(str: string | number | null | undefined, unit = 'px'): string | undefined { | |
42 | + if (str == null || str === '') { | |
43 | + return undefined; | |
44 | + } else if (isNaN(+str!)) { | |
45 | + return String(str); | |
46 | + } else { | |
47 | + return `${Number(str)}${unit}`; | |
48 | + } | |
27 | 49 | } |
28 | -} | |
29 | - | |
30 | -export default defineComponent({ | |
31 | - name: 'VirtualScroll', | |
32 | - props: basicProps, | |
33 | - setup(props, { slots }) { | |
34 | - const wrapElRef = ref<HTMLDivElement | null>(null); | |
35 | - const state = reactive({ | |
36 | - first: 0, | |
37 | - last: 0, | |
38 | - scrollTop: 0, | |
39 | - }); | |
40 | - | |
41 | - const getBenchRef = computed(() => { | |
42 | - return parseInt(props.bench as string, 10); | |
43 | - }); | |
44 | - | |
45 | - const getItemHeightRef = computed(() => { | |
46 | - return parseInt(props.itemHeight as string, 10); | |
47 | - }); | |
48 | - | |
49 | - const getFirstToRenderRef = computed(() => { | |
50 | - return Math.max(0, state.first - unref(getBenchRef)); | |
51 | - }); | |
52 | - | |
53 | - const getLastToRenderRef = computed(() => { | |
54 | - return Math.min((props.items || []).length, state.last + unref(getBenchRef)); | |
55 | - }); | |
56 | - | |
57 | - const getContainerStyleRef = computed((): CSSProperties => { | |
58 | - return { | |
59 | - height: convertToUnit((props.items || []).length * unref(getItemHeightRef)), | |
60 | - }; | |
61 | - }); | |
62 | - | |
63 | - const getWrapStyleRef = computed((): CSSProperties => { | |
64 | - const styles: Recordable<string> = {}; | |
65 | - const height = convertToUnit(props.height); | |
66 | - const minHeight = convertToUnit(props.minHeight); | |
67 | - const minWidth = convertToUnit(props.minWidth); | |
68 | - const maxHeight = convertToUnit(props.maxHeight); | |
69 | - const maxWidth = convertToUnit(props.maxWidth); | |
70 | - const width = convertToUnit(props.width); | |
71 | - | |
72 | - if (height) styles.height = height; | |
73 | - if (minHeight) styles.minHeight = minHeight; | |
74 | - if (minWidth) styles.minWidth = minWidth; | |
75 | - if (maxHeight) styles.maxHeight = maxHeight; | |
76 | - if (maxWidth) styles.maxWidth = maxWidth; | |
77 | - if (width) styles.width = width; | |
78 | - return styles; | |
79 | - }); | |
80 | - | |
81 | - watch([() => props.itemHeight, () => props.height], () => { | |
82 | - onScroll(); | |
83 | - }); | |
84 | - | |
85 | - function getLast(first: number): number { | |
86 | - const wrapEl = unref(wrapElRef); | |
87 | - if (!wrapEl) { | |
88 | - return 0; | |
89 | - } | |
90 | - const height = parseInt(props.height || 0, 10) || wrapEl.clientHeight; | |
91 | 50 | |
92 | - return first + Math.ceil(height / unref(getItemHeightRef)); | |
93 | - } | |
51 | + export default defineComponent({ | |
52 | + name: 'VirtualScroll', | |
53 | + props, | |
54 | + setup(props, { slots }) { | |
55 | + const wrapElRef = ref<HTMLDivElement | null>(null); | |
56 | + const state = reactive({ | |
57 | + first: 0, | |
58 | + last: 0, | |
59 | + scrollTop: 0, | |
60 | + }); | |
94 | 61 | |
95 | - function getFirst(): number { | |
96 | - return Math.floor(state.scrollTop / unref(getItemHeightRef)); | |
97 | - } | |
62 | + const getBenchRef = computed(() => { | |
63 | + return parseInt(props.bench as string, 10); | |
64 | + }); | |
98 | 65 | |
99 | - function onScroll() { | |
100 | - const wrapEl = unref(wrapElRef); | |
101 | - if (!wrapEl) { | |
102 | - return; | |
103 | - } | |
104 | - state.scrollTop = wrapEl.scrollTop; | |
105 | - state.first = getFirst(); | |
106 | - state.last = getLast(state.first); | |
107 | - } | |
66 | + const getItemHeightRef = computed(() => { | |
67 | + return parseInt(props.itemHeight as string, 10); | |
68 | + }); | |
108 | 69 | |
109 | - function renderChildren() { | |
110 | - const { items = [] } = props; | |
111 | - return items.slice(unref(getFirstToRenderRef), unref(getLastToRenderRef)).map(genChild); | |
112 | - } | |
70 | + const getFirstToRenderRef = computed(() => { | |
71 | + return Math.max(0, state.first - unref(getBenchRef)); | |
72 | + }); | |
113 | 73 | |
114 | - function genChild(item: any, index: number) { | |
115 | - index += unref(getFirstToRenderRef); | |
74 | + const getLastToRenderRef = computed(() => { | |
75 | + return Math.min((props.items || []).length, state.last + unref(getBenchRef)); | |
76 | + }); | |
116 | 77 | |
117 | - const top = convertToUnit(index * unref(getItemHeightRef)); | |
118 | - return ( | |
119 | - <div class={`${prefixCls}__item`} style={{ top }} key={index}> | |
120 | - {getSlot(slots, 'default', { index, item })} | |
121 | - </div> | |
122 | - ); | |
123 | - } | |
78 | + const getContainerStyleRef = computed((): CSSProperties => { | |
79 | + return { | |
80 | + height: convertToUnit((props.items || []).length * unref(getItemHeightRef)), | |
81 | + }; | |
82 | + }); | |
83 | + | |
84 | + const getWrapStyleRef = computed((): CSSProperties => { | |
85 | + const styles: Recordable<string> = {}; | |
86 | + const height = convertToUnit(props.height); | |
87 | + const minHeight = convertToUnit(props.minHeight); | |
88 | + const minWidth = convertToUnit(props.minWidth); | |
89 | + const maxHeight = convertToUnit(props.maxHeight); | |
90 | + const maxWidth = convertToUnit(props.maxWidth); | |
91 | + const width = convertToUnit(props.width); | |
92 | + | |
93 | + if (height) styles.height = height; | |
94 | + if (minHeight) styles.minHeight = minHeight; | |
95 | + if (minWidth) styles.minWidth = minWidth; | |
96 | + if (maxHeight) styles.maxHeight = maxHeight; | |
97 | + if (maxWidth) styles.maxWidth = maxWidth; | |
98 | + if (width) styles.width = width; | |
99 | + return styles; | |
100 | + }); | |
101 | + | |
102 | + watch([() => props.itemHeight, () => props.height], () => { | |
103 | + onScroll(); | |
104 | + }); | |
124 | 105 | |
125 | - onMounted(() => { | |
126 | - state.last = getLast(0); | |
127 | - nextTick(() => { | |
106 | + function getLast(first: number): number { | |
107 | + const wrapEl = unref(wrapElRef); | |
108 | + if (!wrapEl) { | |
109 | + return 0; | |
110 | + } | |
111 | + const height = parseInt(props.height || 0, 10) || wrapEl.clientHeight; | |
112 | + | |
113 | + return first + Math.ceil(height / unref(getItemHeightRef)); | |
114 | + } | |
115 | + | |
116 | + function getFirst(): number { | |
117 | + return Math.floor(state.scrollTop / unref(getItemHeightRef)); | |
118 | + } | |
119 | + | |
120 | + function onScroll() { | |
128 | 121 | const wrapEl = unref(wrapElRef); |
129 | 122 | if (!wrapEl) { |
130 | 123 | return; |
131 | 124 | } |
132 | - useEventListener({ | |
133 | - el: wrapEl, | |
134 | - name: 'scroll', | |
135 | - listener: onScroll, | |
136 | - wait: 0, | |
125 | + state.scrollTop = wrapEl.scrollTop; | |
126 | + state.first = getFirst(); | |
127 | + state.last = getLast(state.first); | |
128 | + } | |
129 | + | |
130 | + function renderChildren() { | |
131 | + const { items = [] } = props; | |
132 | + return items.slice(unref(getFirstToRenderRef), unref(getLastToRenderRef)).map(genChild); | |
133 | + } | |
134 | + | |
135 | + function genChild(item: any, index: number) { | |
136 | + index += unref(getFirstToRenderRef); | |
137 | + const top = convertToUnit(index * unref(getItemHeightRef)); | |
138 | + return ( | |
139 | + <div class={`${prefixCls}__item`} style={{ top }} key={index}> | |
140 | + {getSlot(slots, 'default', { index, item })} | |
141 | + </div> | |
142 | + ); | |
143 | + } | |
144 | + | |
145 | + onMounted(() => { | |
146 | + state.last = getLast(0); | |
147 | + nextTick(() => { | |
148 | + const wrapEl = unref(wrapElRef); | |
149 | + if (!wrapEl) { | |
150 | + return; | |
151 | + } | |
152 | + useEventListener({ | |
153 | + el: wrapEl, | |
154 | + name: 'scroll', | |
155 | + listener: onScroll, | |
156 | + wait: 0, | |
157 | + }); | |
137 | 158 | }); |
138 | 159 | }); |
139 | - }); | |
140 | - return () => ( | |
141 | - <div class={prefixCls} style={unref(getWrapStyleRef)} ref={wrapElRef}> | |
142 | - <div class={`${prefixCls}__container`} style={unref(getContainerStyleRef)}> | |
143 | - {renderChildren()} | |
160 | + | |
161 | + return () => ( | |
162 | + <div class={prefixCls} style={unref(getWrapStyleRef)} ref={wrapElRef}> | |
163 | + <div class={`${prefixCls}__container`} style={unref(getContainerStyleRef)}> | |
164 | + {renderChildren()} | |
165 | + </div> | |
144 | 166 | </div> |
145 | - </div> | |
146 | - ); | |
147 | - }, | |
148 | -}); | |
167 | + ); | |
168 | + }, | |
169 | + }); | |
170 | +</script> | |
171 | +<style scoped lang="less"> | |
172 | + .virtual-scroll { | |
173 | + position: relative; | |
174 | + display: block; | |
175 | + width: 100%; | |
176 | + max-width: 100%; | |
177 | + overflow: auto; | |
178 | + flex: 1 1 auto; | |
179 | + | |
180 | + &__container { | |
181 | + display: block; | |
182 | + } | |
183 | + | |
184 | + &__item { | |
185 | + position: absolute; | |
186 | + right: 0; | |
187 | + left: 0; | |
188 | + } | |
189 | + } | |
190 | +</style> | ... | ... |
src/components/VirtualScroll/src/index.less deleted
100644 → 0
src/components/VirtualScroll/src/props.ts deleted
100644 → 0
1 | -// Helpers | |
2 | - | |
3 | -import type { PropType } from 'vue'; | |
4 | -// Types | |
5 | - | |
6 | -export type NumberOrNumberString = PropType<string | number | undefined>; | |
7 | - | |
8 | -export const props = { | |
9 | - height: [Number, String] as NumberOrNumberString, | |
10 | - maxHeight: [Number, String] as NumberOrNumberString, | |
11 | - maxWidth: [Number, String] as NumberOrNumberString, | |
12 | - minHeight: [Number, String] as NumberOrNumberString, | |
13 | - minWidth: [Number, String] as NumberOrNumberString, | |
14 | - width: [Number, String] as NumberOrNumberString, | |
15 | - bench: { | |
16 | - type: [Number, String] as NumberOrNumberString, | |
17 | - default: 0, | |
18 | - }, | |
19 | - itemHeight: { | |
20 | - type: [Number, String] as NumberOrNumberString, | |
21 | - required: true, | |
22 | - }, | |
23 | - items: { | |
24 | - type: Array as PropType<any[]>, | |
25 | - default: () => [], | |
26 | - }, | |
27 | -}; |
src/components/registerGlobComp.ts
... | ... | @@ -11,7 +11,7 @@ import { App } from 'vue'; |
11 | 11 | const compList = [Icon, AntButton.Group]; |
12 | 12 | |
13 | 13 | export function registerGlobComp(app: App) { |
14 | - compList.forEach((comp: any) => { | |
14 | + compList.forEach((comp) => { | |
15 | 15 | app.component(comp.name || comp.displayName, comp); |
16 | 16 | }); |
17 | 17 | ... | ... |