perf: 首屏优化,减少 1.5MB 资源

This commit is contained in:
xiaoxian521
2022-11-29 19:30:33 +08:00
parent a22bc8622e
commit d2b1bd5b44
17 changed files with 1842 additions and 4612 deletions

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import { ref } from "vue";
import { IconSelect } from "@/components/ReIcon";
import IconSelect from "@/components/ReIcon/src/Select.vue";
defineOptions({
name: "IconSelect"

View File

@@ -1,70 +0,0 @@
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()
};
}

View File

@@ -1,33 +1,27 @@
<script setup lang="ts">
import { ref, computed } from "vue";
import { generateMessage } from "./data";
import { DynamicScroller, DynamicScrollerItem } from "vue-virtual-scroller";
const items = ref([]);
const search = ref("");
for (let i = 0; i < 10000; i++) {
for (let i = 0; i < 800; i++) {
items.value.push({
id: i,
...generateMessage()
id: i
});
}
const filteredItems = computed(() => {
if (!search.value) return items.value;
const lowerCaseSearch = search.value.toLowerCase();
return items.value.filter(i =>
i.message.toLowerCase().includes(lowerCaseSearch)
);
const lowerCaseSearch = search.value;
return items.value.filter(i => i.id == lowerCaseSearch);
});
function changeMessage(message) {
Object.assign(message, generateMessage());
}
</script>
<template>
<div class="dynamic-scroller-demo">
<div class="flex justify-around mb-4">
<div class="flex-ac mb-4 shadow-2xl">
水平模式 horizontal
<el-input
class="mr-2 !w-[1/1.5]"
clearable
@@ -35,7 +29,6 @@ function changeMessage(message) {
placeholder="Filter..."
style="width: 300px"
/>
<el-tag effect="dark">水平模式horizontal</el-tag>
</div>
<DynamicScroller
@@ -48,31 +41,21 @@ function changeMessage(message) {
<DynamicScrollerItem
:item="item"
:active="active"
:size-dependencies="[item.message]"
:size-dependencies="[item.id]"
:data-index="index"
:data-active="active"
:title="`Click to change message ${index}`"
:style="{
width: `${Math.max(
130,
Math.round((item.message.length / 20) * 20)
)}px`
width: `${Math.max(130, Math.round((item.id?.length / 20) * 20))}px`
}"
class="message"
@click="changeMessage(item)"
>
<div class="avatar">
<div>
<IconifyIconOnline
icon="openmoji:beaming-face-with-smiling-eyes"
width="40"
/>
</div>
<div class="text">
{{ item.message }}
</div>
<div class="index">
<span>{{ item.id }} (id)</span>
<span>{{ index }} (index)</span>
<p class="text-center">{{ item.id }}</p>
</div>
</DynamicScrollerItem>
</template>
@@ -104,35 +87,4 @@ function changeMessage(message) {
padding: 12px;
box-sizing: border-box;
}
.avatar {
flex: auto 0 0;
width: 32px;
height: 32px;
border-radius: 50%;
margin-bottom: 12px;
}
.avatar .image {
max-width: 100%;
max-height: 100%;
border-radius: 50%;
}
.index,
.text {
flex: 1;
}
.text {
margin-bottom: 12px;
}
.index {
opacity: 0.5;
}
.index span {
display: block;
}
</style>

View File

@@ -1,6 +1,7 @@
<script setup lang="ts">
import verticalList from "./vertical.vue";
import horizontalList from "./horizontal.vue";
import "vue-virtual-scroller/dist/vue-virtual-scroller.css";
defineOptions({
name: "VirtualList"

View File

@@ -1,75 +1,56 @@
<script setup lang="ts">
import { ref, computed } from "vue";
import { generateMessage } from "./data";
import { DynamicScroller, DynamicScrollerItem } from "vue-virtual-scroller";
const items = ref([]);
const search = ref("");
for (let i = 0; i < 10000; i++) {
for (let i = 0; i < 800; i++) {
items.value.push({
id: i,
...generateMessage()
id: i
});
}
const filteredItems = computed(() => {
if (!search.value) return items.value;
const lowerCaseSearch = search.value.toLowerCase();
return items.value.filter(i =>
i.message.toLowerCase().includes(lowerCaseSearch)
);
const lowerCaseSearch = search.value;
return items.value.filter(i => i.id == lowerCaseSearch);
});
function changeMessage(message) {
Object.assign(message, generateMessage());
}
function onResize() {
console.log("resize");
}
</script>
<template>
<div class="dynamic-scroller-demo">
<div class="flex justify-around mb-4">
<div class="flex-ac mb-4 shadow-2xl">
垂直模式 vertical
<el-input
class="mr-2 !w-[1/1.5]"
class="!w-[350px]"
clearable
v-model="search"
placeholder="Filter..."
/>
<el-tag effect="dark">垂直模式vertical</el-tag>
</div>
<DynamicScroller
:items="filteredItems"
:min-item-size="54"
class="scroller"
@resize="onResize"
>
<template #default="{ item, index, active }">
<DynamicScrollerItem
:item="item"
:active="active"
:size-dependencies="[item.message]"
:size-dependencies="[item.id]"
:data-index="index"
:data-active="active"
:title="`Click to change message ${index}`"
class="message"
@click="changeMessage(item)"
>
<div class="avatar">
<div class="flex items-center">
<IconifyIconOnline
icon="openmoji:beaming-face-with-smiling-eyes"
width="40"
/>
</div>
<div class="text">
{{ item.message }}
</div>
<div class="index">
<span>{{ item.id }} (id)</span>
<span>{{ index }} (index)</span>
<span>{{ item.id }}</span>
</div>
</DynamicScrollerItem>
</template>
@@ -94,31 +75,4 @@ function onResize() {
padding: 12px;
box-sizing: border-box;
}
.avatar {
flex: auto 0 0;
width: 32px;
height: 32px;
border-radius: 50%;
margin-right: 12px;
}
.index,
.text {
flex: 1;
}
.text {
max-width: 400px;
}
.index {
opacity: 0.5;
}
.index span {
display: inline-block;
width: 160px;
text-align: right;
}
</style>

View File

@@ -2,6 +2,7 @@
import basic from "./basic.vue";
import menuGroup from "./menuGroup.vue";
import menuDynamic from "./menuDynamic.vue";
import "v-contextmenu/dist/themes/default.css";
defineOptions({
name: "ContextMenu"

View File

@@ -195,7 +195,7 @@ onUnmounted(() => {
>
<TypeIt
:className="'type-it2'"
:values="['Pure-Admin 版本日志']"
:values="['PureAdmin 版本日志']"
:cursor="false"
:speed="80"
/>