Commit 3b2c40bec818238bde165656dc17e885f242aa81

Authored by Vben
1 parent 1c1755cf

refactor(virtual-scroll): refactor virtualScroll component

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
1   -export { default as StrengthMeter } from './src/StrengthMeter.vue';
  1 +import { withInstall } from '/@/utils';
  2 +import strengthMeter from './src/StrengthMeter.vue';
  3 +
  4 +export const StrengthMeter = withInstall(strengthMeter);
... ...
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
1   -export { default as Time } from './src/Time.vue';
  1 +import { withInstall } from '/@/utils/index';
  2 +import time from './src/Time.vue';
  3 +
  4 +export const Time = withInstall(time);
... ...
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
1   -import Tinymce from './src/Editor.vue';
2   -export { Tinymce };
  1 +import { withInstall } from '/@/utils/index';
  2 +import tinymce from './src/Editor.vue';
  3 +
  4 +export const Tinymce = withInstall(tinymce);
... ...
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
1   -.virtual-scroll {
2   - position: relative;
3   - display: block;
4   - width: 100%;
5   - max-width: 100%;
6   - overflow: auto;
7   - flex: 1 1 auto;
8   -
9   - &__container {
10   - display: block;
11   - }
12   -
13   - &__item {
14   - position: absolute;
15   - right: 0;
16   - left: 0;
17   - }
18   -}
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 &#39;vue&#39;;
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  
... ...