diff --git a/locales/en.yaml b/locales/en.yaml index 7ed5381f7..9841faebe 100644 --- a/locales/en.yaml +++ b/locales/en.yaml @@ -82,5 +82,6 @@ menus: hsQrcode: Qrcode hsCascader: Area Cascader hsSwiper: Swiper Plugin + hsVirtualList: Virtual List status: hsLoad: Loading... diff --git a/locales/zh-CN.yaml b/locales/zh-CN.yaml index 84b82ff44..9dc4b4aba 100644 --- a/locales/zh-CN.yaml +++ b/locales/zh-CN.yaml @@ -82,5 +82,6 @@ menus: hsQrcode: 二维码 hsCascader: 区域级联选择器 hsSwiper: Swiper插件 + hsVirtualList: 虚拟列表 status: hsLoad: 加载中... diff --git a/package.json b/package.json index 6cee4cc7a..acb27844a 100644 --- a/package.json +++ b/package.json @@ -70,6 +70,7 @@ "vue-json-pretty": "^2.0.2", "vue-router": "^4.0.15", "vue-types": "^4.1.1", + "vue-virtual-scroller": "^2.0.0-alpha.1", "vuedraggable": "4.1.0", "vxe-table": "^4.2.3", "xe-utils": "^3.5.4", @@ -78,6 +79,7 @@ "devDependencies": { "@commitlint/cli": "13.1.0", "@commitlint/config-conventional": "13.1.0", + "@faker-js/faker": "^6.3.1", "@iconify-icons/carbon": "^1.2.4", "@iconify-icons/ep": "^1.2.4", "@iconify-icons/fa": "^1.2.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 40ea26545..4e8d67398 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,6 +5,7 @@ specifiers: "@commitlint/cli": 13.1.0 "@commitlint/config-conventional": 13.1.0 "@ctrl/tinycolor": ^3.4.1 + "@faker-js/faker": ^6.3.1 "@iconify-icons/carbon": ^1.2.4 "@iconify-icons/ep": ^1.2.4 "@iconify-icons/fa": ^1.2.2 @@ -105,6 +106,7 @@ specifiers: vue-json-pretty: ^2.0.2 vue-router: ^4.0.15 vue-types: ^4.1.1 + vue-virtual-scroller: ^2.0.0-alpha.1 vuedraggable: 4.1.0 vxe-table: ^4.2.3 xe-utils: ^3.5.4 @@ -154,6 +156,7 @@ dependencies: vue-json-pretty: 2.0.6_vue@3.2.33 vue-router: 4.0.15_vue@3.2.33 vue-types: 4.1.1_vue@3.2.33 + vue-virtual-scroller: 2.0.0-alpha.1_vue@3.2.33 vuedraggable: 4.1.0_vue@3.2.33 vxe-table: 4.2.3_vue@3.2.33+xe-utils@3.5.4 xe-utils: 3.5.4 @@ -162,6 +165,7 @@ dependencies: devDependencies: "@commitlint/cli": 13.1.0 "@commitlint/config-conventional": 13.1.0 + "@faker-js/faker": 6.3.1 "@iconify-icons/carbon": 1.2.5 "@iconify-icons/ep": 1.2.4 "@iconify-icons/fa": 1.2.2 @@ -938,6 +942,14 @@ packages: - supports-color dev: true + /@faker-js/faker/6.3.1: + resolution: + { + integrity: sha512-8YXBE2ZcU/pImVOHX7MWrSR/X5up7t6rPWZlk34RwZEcdr3ua6X+32pSd6XuOQRN+vbuvYNfA6iey8NbrjuMFQ== + } + engines: { node: ">=14.0.0", npm: ">=6.0.0" } + dev: true + /@floating-ui/core/0.6.2: resolution: { @@ -5989,6 +6001,13 @@ packages: kind-of: 6.0.3 dev: true + /mitt/2.1.0: + resolution: + { + integrity: sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg== + } + dev: false + /mitt/3.0.0: resolution: { @@ -8471,6 +8490,28 @@ packages: vue: 3.2.33 dev: false + /vue-observe-visibility/2.0.0-alpha.1_vue@3.2.33: + resolution: + { + integrity: sha512-flFbp/gs9pZniXR6fans8smv1kDScJ8RS7rEpMjhVabiKeq7Qz3D9+eGsypncjfIyyU84saU88XZ0zjbD6Gq/g== + } + peerDependencies: + vue: ^3.0.0 + dependencies: + vue: 3.2.33 + dev: false + + /vue-resize/2.0.0-alpha.1_vue@3.2.33: + resolution: + { + integrity: sha512-7+iqOueLU7uc9NrMfrzbG8hwMqchfVfSzpVlCMeJQe4pyibqyoifDNbKTZvwxZKDvGkB+PdFeKvnGZMoEb8esg== + } + peerDependencies: + vue: ^3.0.0 + dependencies: + vue: 3.2.33 + dev: false + /vue-router/4.0.15_vue@3.2.33: resolution: { @@ -8509,6 +8550,20 @@ packages: vue: 3.2.33 dev: false + /vue-virtual-scroller/2.0.0-alpha.1_vue@3.2.33: + resolution: + { + integrity: sha512-Mn5w3Qe06t7c3Imm2RHD43RACab1CCWplpdgzq+/FWJcpQtcGKd5vDep8i+nIwFtzFLsWAqEK0RzM7KrfAcBng== + } + peerDependencies: + vue: ^3.0.11 + dependencies: + mitt: 2.1.0 + vue: 3.2.33 + vue-observe-visibility: 2.0.0-alpha.1_vue@3.2.33 + vue-resize: 2.0.0-alpha.1_vue@3.2.33 + dev: false + /vue/3.2.33: resolution: { diff --git a/src/main.ts b/src/main.ts index f812f1898..66c8d6f48 100644 --- a/src/main.ts +++ b/src/main.ts @@ -6,6 +6,7 @@ import { getServerConfig } from "./config"; import { createApp, Directive } from "vue"; import { useI18n } from "../src/plugins/i18n"; import { MotionPlugin } from "@vueuse/motion"; +import VirtualScroller from "vue-virtual-scroller"; import { useTable } from "../src/plugins/vxe-table"; import { injectResponsiveStorage } from "/@/utils/storage/responsive"; @@ -22,6 +23,7 @@ import "@pureadmin/components/dist/theme.css"; import "./assets/iconfont/iconfont.js"; import "./assets/iconfont/iconfont.css"; import "v-contextmenu/dist/themes/default.css"; +import "vue-virtual-scroller/dist/vue-virtual-scroller.css"; const app = createApp(App); @@ -46,6 +48,11 @@ getServerConfig(app).then(async config => { await router.isReady(); injectResponsiveStorage(app, config); setupStore(app); - app.use(MotionPlugin).use(useI18n).use(ElementPlus).use(useTable); + app + .use(MotionPlugin) + .use(useI18n) + .use(ElementPlus) + .use(useTable) + .use(VirtualScroller); app.mount("#app"); }); diff --git a/src/router/modules/able.ts b/src/router/modules/able.ts index 18a55e763..8c3123169 100644 --- a/src/router/modules/able.ts +++ b/src/router/modules/able.ts @@ -122,6 +122,14 @@ const ableRouter = { meta: { title: $t("menus.hsSwiper") } + }, + { + path: "/able/virtualList", + name: "reVirtualList", + component: () => import("/@/views/able/virtual-list/index.vue"), + meta: { + title: $t("menus.hsVirtualList") + } } ] }; diff --git a/src/views/able/virtual-list/data.ts b/src/views/able/virtual-list/data.ts new file mode 100644 index 000000000..3904dd39d --- /dev/null +++ b/src/views/able/virtual-list/data.ts @@ -0,0 +1,70 @@ +import { faker } from "@faker-js/faker"; + +let uid = 0; + +function generateItem() { + return { + name: faker.name.findName(), + avatar: faker.internet.avatar() + }; +} + +export function getData(count, letters) { + const raw = {}; + + const alphabet = "abcdefghijklmnopqrstuvwxyz".split(""); + + for (const l of alphabet) { + raw[l] = []; + } + + for (let i = 0; i < count; i++) { + const item = generateItem(); + const letter = item.name.charAt(0).toLowerCase(); + raw[letter].push(item); + } + + const list = []; + let index = 1; + + for (const l of alphabet) { + raw[l] = raw[l].sort((a, b) => (a.name < b.name ? -1 : 1)); + if (letters) { + list.push({ + id: uid++, + index: index++, + type: "letter", + value: l, + height: 200 + }); + } + for (const item of raw[l]) { + list.push({ + id: uid++, + index: index++, + type: "person", + value: item, + height: 50 + }); + } + } + + return list; +} + +export function addItem(list) { + list.push({ + id: uid++, + index: list.length + 1, + type: "person", + value: generateItem(), + height: 50 + }); +} + +export function generateMessage() { + return { + avatar: faker.internet.avatar(), + message: faker.lorem.text() + }; +} diff --git a/src/views/able/virtual-list/horizontal.vue b/src/views/able/virtual-list/horizontal.vue new file mode 100644 index 000000000..44bb84570 --- /dev/null +++ b/src/views/able/virtual-list/horizontal.vue @@ -0,0 +1,138 @@ + + + + + diff --git a/src/views/able/virtual-list/index.vue b/src/views/able/virtual-list/index.vue new file mode 100644 index 000000000..e7c02f9e0 --- /dev/null +++ b/src/views/able/virtual-list/index.vue @@ -0,0 +1,26 @@ + + + diff --git a/src/views/able/virtual-list/vertical.vue b/src/views/able/virtual-list/vertical.vue new file mode 100644 index 000000000..97d410c81 --- /dev/null +++ b/src/views/able/virtual-list/vertical.vue @@ -0,0 +1,124 @@ + + + + + diff --git a/tsconfig.json b/tsconfig.json index e980c7225..a29d95ee9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "target": "esnext", "module": "esnext", - "moduleResolution": "node", + "moduleResolution": "Node", "strict": false, "jsx": "preserve", "importHelpers": true,