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,18 +14,17 @@
14 } from 'vue'; 14 } from 'vue';
15 import Vditor from 'vditor'; 15 import Vditor from 'vditor';
16 import 'vditor/dist/index.css'; 16 import 'vditor/dist/index.css';
17 -  
18 - import { propTypes } from '/@/utils/propTypes';  
19 import { useLocale } from '/@/locales/useLocale'; 17 import { useLocale } from '/@/locales/useLocale';
20 import { useModalContext } from '../../Modal'; 18 import { useModalContext } from '../../Modal';
21 import { useRootSetting } from '/@/hooks/setting/useRootSetting'; 19 import { useRootSetting } from '/@/hooks/setting/useRootSetting';
22 20
23 type Lang = 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' | undefined; 21 type Lang = 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' | undefined;
  22 +
24 export default defineComponent({ 23 export default defineComponent({
25 inheritAttrs: false, 24 inheritAttrs: false,
26 props: { 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 emits: ['change', 'get'], 29 emits: ['change', 'get'],
31 setup(props, { attrs, emit }) { 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,10 +20,7 @@
20 20
21 <script lang="ts"> 21 <script lang="ts">
22 import { defineComponent, computed, ref, watch, unref, watchEffect } from 'vue'; 22 import { defineComponent, computed, ref, watch, unref, watchEffect } from 'vue';
23 -  
24 import { Input } from 'ant-design-vue'; 23 import { Input } from 'ant-design-vue';
25 -  
26 - // @ts-ignore  
27 import { zxcvbn } from '@zxcvbn-ts/core'; 24 import { zxcvbn } from '@zxcvbn-ts/core';
28 import { useDesign } from '/@/hooks/web/useDesign'; 25 import { useDesign } from '/@/hooks/web/useDesign';
29 import { propTypes } from '/@/utils/propTypes'; 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,10 +3,8 @@
3 </template> 3 </template>
4 <script lang="ts"> 4 <script lang="ts">
5 import { defineComponent, ref, watch } from 'vue'; 5 import { defineComponent, ref, watch } from 'vue';
6 -  
7 import { useI18n } from '/@/hooks/web/useI18n'; 6 import { useI18n } from '/@/hooks/web/useI18n';
8 import { useIntervalFn } from '@vueuse/core'; 7 import { useIntervalFn } from '@vueuse/core';
9 -  
10 import { formatToDateTime, formatToDate, dateUtil } from '/@/utils/dateUtil'; 8 import { formatToDateTime, formatToDate, dateUtil } from '/@/utils/dateUtil';
11 import { isNumber, isObject, isString } from '/@/utils/is'; 9 import { isNumber, isObject, isString } from '/@/utils/is';
12 import { propTypes } from '/@/utils/propTypes'; 10 import { propTypes } from '/@/utils/propTypes';
@@ -15,6 +13,7 @@ @@ -15,6 +13,7 @@
15 const ONE_MINUTES = ONE_SECONDS * 60; 13 const ONE_MINUTES = ONE_SECONDS * 60;
16 const ONE_HOUR = ONE_MINUTES * 60; 14 const ONE_HOUR = ONE_MINUTES * 60;
17 const ONE_DAY = ONE_HOUR * 24; 15 const ONE_DAY = ONE_HOUR * 24;
  16 +
18 export default defineComponent({ 17 export default defineComponent({
19 name: 'Time', 18 name: 'Time',
20 props: { 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,7 +16,6 @@
16 import type { RawEditorSettings } from 'tinymce'; 16 import type { RawEditorSettings } from 'tinymce';
17 import tinymce from 'tinymce/tinymce'; 17 import tinymce from 'tinymce/tinymce';
18 import 'tinymce/themes/silver'; 18 import 'tinymce/themes/silver';
19 -  
20 import 'tinymce/icons/default/icons'; 19 import 'tinymce/icons/default/icons';
21 import 'tinymce/plugins/advlist'; 20 import 'tinymce/plugins/advlist';
22 import 'tinymce/plugins/anchor'; 21 import 'tinymce/plugins/anchor';
@@ -58,11 +57,8 @@ @@ -58,11 +57,8 @@
58 onUnmounted, 57 onUnmounted,
59 onDeactivated, 58 onDeactivated,
60 } from 'vue'; 59 } from 'vue';
61 -  
62 import ImgUpload from './ImgUpload.vue'; 60 import ImgUpload from './ImgUpload.vue';
63 -  
64 import { toolbar, plugins } from './tinymce'; 61 import { toolbar, plugins } from './tinymce';
65 -  
66 import { buildShortUUID } from '/@/utils/uuid'; 62 import { buildShortUUID } from '/@/utils/uuid';
67 import { bindHandlers } from './helper'; 63 import { bindHandlers } from './helper';
68 import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated'; 64 import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated';
@@ -96,7 +92,6 @@ @@ -96,7 +92,6 @@
96 required: false, 92 required: false,
97 default: 400, 93 default: 400,
98 }, 94 },
99 -  
100 width: { 95 width: {
101 type: [Number, String] as PropType<string | number>, 96 type: [Number, String] as PropType<string | number>,
102 required: false, 97 required: false,
src/components/Tinymce/src/ImgUpload.vue
@@ -52,9 +52,9 @@ @@ -52,9 +52,9 @@
52 function handleChange(info: Recordable) { 52 function handleChange(info: Recordable) {
53 const file = info.file; 53 const file = info.file;
54 const status = file?.status; 54 const status = file?.status;
55 -  
56 const url = file?.response?.url; 55 const url = file?.response?.url;
57 const name = file?.name; 56 const name = file?.name;
  57 +
58 if (status === 'uploading') { 58 if (status === 'uploading') {
59 if (!uploading) { 59 if (!uploading) {
60 emit('uploading', name); 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 const wrapEl = unref(wrapElRef); 121 const wrapEl = unref(wrapElRef);
129 if (!wrapEl) { 122 if (!wrapEl) {
130 return; 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 </div> 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,7 +11,7 @@ import { App } from &#39;vue&#39;;
11 const compList = [Icon, AntButton.Group]; 11 const compList = [Icon, AntButton.Group];
12 12
13 export function registerGlobComp(app: App) { 13 export function registerGlobComp(app: App) {
14 - compList.forEach((comp: any) => { 14 + compList.forEach((comp) => {
15 app.component(comp.name || comp.displayName, comp); 15 app.component(comp.name || comp.displayName, comp);
16 }); 16 });
17 17