Skip to content

Commit

Permalink
test: 增加测试代码
Browse files Browse the repository at this point in the history
  • Loading branch information
Lionad-Morotar committed Dec 18, 2023
1 parent 04c2c98 commit 6c0c542
Show file tree
Hide file tree
Showing 5 changed files with 223 additions and 26 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"vue-demi": "^0.14.6"
},
"devDependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@commitlint/cli": "^17.8.1",
"@commitlint/config-conventional": "^17.8.1",
"@types/node": "^17.0.45",
Expand All @@ -48,6 +49,7 @@
"less": "^4.2.0",
"lint-staged": "^13.3.0",
"mitt": "^3.0.1",
"nativebird": "^1.2.11",
"overlayscrollbars": "^2.4.4",
"overlayscrollbars-vue": "^0.5.6",
"postcss": "^8.4.31",
Expand Down
105 changes: 98 additions & 7 deletions play/src/vxe-table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
<h4>## VXETable with Virtual Scrollbars {{ isHover ? ' - Hovered' : '' }}</h4>
<el-checkbox v-model="states.isVirtualScroll">表格虚拟滚动</el-checkbox>
<el-checkbox v-model="states.isVirtualScrollbar">表格虚拟滚动条</el-checkbox>
<el-button type="primary" @click="measure">测试滚动性能</el-button>
<el-button type="primary" @click="refresh">刷新</el-button>
<el-button type="primary" @click="addMore">+{{ listCount }}条数据</el-button>
</div>
<vxe-table-virtual-scrollbar
v-model:tableRef="vxeTableRef"
border
stripe
:enable="states.isVirtualScrollbar"
Expand All @@ -17,32 +19,107 @@
:row-config="{isHover: true}"
:checkbox-config="{labelField: 'id', highlight: true}"
:data="states.tableData"
:scroll-x="{ enabled: states.isVirtualScroll }"
:scroll-y="{ enabled: states.isVirtualScroll }"
:scroll-x="{ enabled: states.isVirtualScroll, oSize: 0 }"
:scroll-y="{ enabled: states.isVirtualScroll, oSize: 0 }"
>
<vxe-column type="seq" :width="180" fixed="left" tree-node></vxe-column>
<vxe-column type="checkbox" title="ID" :width="140"></vxe-column>
<vxe-column field="name" title="Name" :width="140"></vxe-column>
<vxe-column field="sex" title="Sex" :formatter="formatterSex" :width="140"></vxe-column>
<vxe-column field="age" title="Age" :width="120"></vxe-column>
<vxe-column field="address" title="Address" show-overflow :min-width="300"></vxe-column>
<vxe-column field="age" title="Age" :width="120"></vxe-column>
<vxe-column field="sex" title="Sex" :formatter="formatterSex" :width="140"></vxe-column>
<vxe-column field="age" title="Age" :width="120"></vxe-column>
<vxe-column field="sex" title="Sex" :formatter="formatterSex" :width="140"></vxe-column>
<vxe-column field="age" title="Age" :width="120"></vxe-column>
<vxe-column field="sex" title="Sex" :formatter="formatterSex" :width="140"></vxe-column>
<vxe-column field="age" title="Age" :width="120"></vxe-column>
<vxe-column field="sex" title="Sex" :formatter="formatterSex" :width="140"></vxe-column>
<vxe-column field="age" title="Age" :width="120"></vxe-column>
<vxe-column field="sex" title="Sex" :formatter="formatterSex" :width="140"></vxe-column>
<vxe-column field="age" title="Age" :width="120"></vxe-column>
<vxe-column field="sex" title="Sex" :formatter="formatterSex" :width="140"></vxe-column>
<vxe-column field="age" title="Age" :width="120"></vxe-column>
<vxe-column field="sex" title="Sex" :formatter="formatterSex" :width="140"></vxe-column>
<vxe-column field="age" title="Age" :width="120"></vxe-column>
<vxe-column field="sex" title="Sex" :formatter="formatterSex" :width="140"></vxe-column>
<vxe-column field="age" title="Age" :width="120"></vxe-column>
<vxe-column field="sex" title="Sex" :formatter="formatterSex" :width="140"></vxe-column>
<vxe-column field="age" title="Age" :width="120"></vxe-column>
<vxe-column field="sex" title="Sex" :formatter="formatterSex" :width="140"></vxe-column>
<vxe-column field="age" title="Age" :width="120"></vxe-column>
<vxe-column field="sex" title="Sex" :formatter="formatterSex" :width="140"></vxe-column>
<vxe-column field="age" title="Age" :width="120"></vxe-column>
<vxe-column field="sex" title="Sex" :formatter="formatterSex" :width="140"></vxe-column>
<vxe-column field="age" title="Age" :width="120"></vxe-column>
<vxe-column field="sex" title="Sex" :formatter="formatterSex" :width="140"></vxe-column>
<vxe-column field="age" title="Age" :width="120"></vxe-column>
<vxe-column field="sex" title="Sex" :formatter="formatterSex" :width="140"></vxe-column>
<vxe-column field="age" title="Age" :width="120"></vxe-column>
<vxe-column field="sex" title="Sex" :formatter="formatterSex" :width="140"></vxe-column>
<vxe-column field="age" title="Age" :width="120"></vxe-column>
<vxe-column field="sex" title="Sex" :formatter="formatterSex" :width="140"></vxe-column>
<vxe-column field="age" title="Age" :width="120"></vxe-column>
<vxe-column field="sex" title="Sex" :formatter="formatterSex" :width="140"></vxe-column>
<vxe-column field="age" title="Age" :width="120"></vxe-column>
<vxe-column field="sex" title="Sex" :formatter="formatterSex" :width="140"></vxe-column>
<vxe-column field="age" title="Age" :width="120"></vxe-column>
<vxe-column field="sex" title="Sex" :formatter="formatterSex" :width="140"></vxe-column>
<vxe-column field="age" title="Age" :width="120"></vxe-column>
<vxe-column field="sex" title="Sex" :formatter="formatterSex" :width="140"></vxe-column>
<vxe-column field="age" title="Age" :width="120"></vxe-column>
<vxe-column field="address" title="Address Another" :width="1000"></vxe-column>
<vxe-column field="address" title="Address Another" :width="1000"></vxe-column>
<vxe-column field="address" title="Address Another" :width="1000"></vxe-column>
<vxe-column type="seq" :width="60" fixed="right"></vxe-column>
<vxe-column width="500" fixed="right">
<el-button size="small" type="text">
Upload<el-icon class="el-icon--right"><Upload /></el-icon>
</el-button>
<el-button size="small" type="text">
Upload<el-icon class="el-icon--right"><Upload /></el-icon>
</el-button>
<el-button size="small" type="text">
Upload<el-icon class="el-icon--right"><Upload /></el-icon>
</el-button>
<el-button size="small" type="text">
Upload<el-icon class="el-icon--right"><Upload /></el-icon>
</el-button>
<el-button size="small" type="text">
Upload<el-icon class="el-icon--right"><Upload /></el-icon>
</el-button>
<el-button size="small" type="text">
Upload<el-icon class="el-icon--right"><Upload /></el-icon>
</el-button>
<el-button size="small" type="text">
Upload<el-icon class="el-icon--right"><Upload /></el-icon>
</el-button>
<el-button size="small" type="text">
Upload<el-icon class="el-icon--right"><Upload /></el-icon>
</el-button>
<el-button size="small" type="text">
Upload<el-icon class="el-icon--right"><Upload /></el-icon>
</el-button>
<el-button size="small" type="text">
Upload<el-icon class="el-icon--right"><Upload /></el-icon>
</el-button>
</vxe-column>
</vxe-table-virtual-scrollbar>
</div>
</template>

<script lang="ts" setup>
import { ref, reactive, watch, onMounted } from "vue";
import { ElButton, ElIcon } from "element-plus"
import { Upload } from "@element-plus/icons-vue"
import { useElementHover } from "@/hooks";
import VxeTableVirtualScrollbar from "./vxe-table/index.vue";
import NativeBird from "nativebird";
const playRef = ref();
const isHover = useElementHover(playRef);
const states = reactive({
const vxeTableRef = ref();
const states = reactive({
isVirtualScroll: true,
isVirtualScrollbar: true,
isLoading: false,
Expand All @@ -66,7 +143,7 @@ const formatterSex = ({ cellValue }: any) => {
let count = 0
let parentId = 0
const listCount = 300
const listCount = 2000
const getTableData = () => {
const res = Array(listCount).fill(0).map((x) => {
const res = {
Expand All @@ -92,7 +169,7 @@ const getTableData = () => {
const refresh = async () => {
states.isLoading = true
states.tableData = []
setTimeout(() => {
setTimeout(async () => {
states.tableData = getTableData()
states.isLoading = false
}, 300)
Expand All @@ -109,4 +186,18 @@ const addMore = async () => {
onMounted(refresh)
watch(() => states.isVirtualScroll, refresh)
watch(() => states.isVirtualScrollbar, refresh)
const measure = (async () => {
if (!vxeTableRef.value) {
throw new Error('[ERR] no vxeTableRef')
}
const startTime = performance.now()
await NativeBird.mapSeries(Array.from({ length: 5 }), async (_, idx) => {
await vxeTableRef.value.scrollTo(0, idx * 30)
})
const endTime = performance.now()
console.log('[info] total time', endTime - startTime)
})
</script>
21 changes: 21 additions & 0 deletions play/src/vxe-table/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* 将 promise 转化为延迟调用,以便控制其流程
*/
export function useDefer<T = unknown>() {
let resolve: (value: T | PromiseLike<T>) => void;
let reject: (reason?: any) => void;

const promise = new Promise<T>((_resolve, _reject) => {
resolve = _resolve;
reject = _reject;
});

const states = Object.freeze({
promise,
then: promise.then.bind(promise),
resolve: resolve!,
reject: reject!,
});

return states;
}
98 changes: 86 additions & 12 deletions play/src/vxe-table/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
barStates.isScrolling.y ? 'is-scrolling-y' : '',
(!barStates.isScrolling.x && !barStates.isScrolling.y) ? 'is-no-scrolling' : '',
]"
ref="tableRef"
ref="vxeTableRef"
height="100%"
v-bind="$attrs"
>
Expand All @@ -15,30 +15,96 @@
</template>

<script setup lang="ts">
import { useSlots, nextTick, ref, watch } from "vue";
import { until } from "@vueuse/core";
import { watchEffect, useAttrs, useSlots, nextTick, ref, watch } from "vue";
import { until, eagerComputed, useVModel } from "@vueuse/core";
import { useScrollbar } from "@/hooks";
const props = defineProps<{
enable: boolean
}>();
import { useDefer } from "./hooks";
const slots = useSlots();
if (!slots.default) {
throw new Error("[ERR] no default slot");
}
const tableRef = ref<any | null>(null);
const attrs = useAttrs()
const emits = defineEmits(["update:tableRef"]);
const props = defineProps<{
enable: boolean
tableRef: any
}>();
const vxeTableRef = useVModel(props, "tableRef", emits);
const leftFixedWidth = ref(0);
const rightFixedWidth = ref(0);
watchEffect(async () => {
if (!vxeTableRef.value) {
return;
}
if (!attrs.columns) {
return;
}
await nextTick();
try {
const deferLeft = useDefer<HTMLElement>();
const tickLeft = setInterval(() => {
try {
const leftFixed = vxeTableRef.value.$el.querySelector(".vxe-table--fixed-left-wrapper");
if (leftFixed) {
deferLeft.resolve(leftFixed);
clearInterval(tickLeft);
}
} catch (err) {
clearInterval(tickLeft);
deferLeft.reject();
}
}, 17 * 5);
deferLeft.then((leftFixed: HTMLElement) => {
const width = leftFixed.clientWidth;
leftFixedWidth.value = width;
});
const deferRight = useDefer<HTMLElement>();
const tickRight = setInterval(() => {
try {
const rightFixed = vxeTableRef.value.$el.querySelector(".vxe-table--fixed-right-wrapper");
if (rightFixed) {
deferRight.resolve(rightFixed);
clearInterval(tickRight);
}
} catch (err) {
clearInterval(tickRight);
deferRight.reject();
}
}, 17 * 5);
deferRight.then((rightFixed: HTMLElement) => {
const width = rightFixed.clientWidth;
rightFixedWidth.value = width;
});
} catch (err) {
leftFixedWidth.value = 0;
rightFixedWidth.value = 0;
console.log("[ERR]", err);
}
});
const cssLeftFixedWidth = eagerComputed(() => {
console.log("[INFO] leftFixedWidth.value", leftFixedWidth.value);
return leftFixedWidth.value + "px";
});
const cssRightFixedWidth = eagerComputed(() => {
console.log("[INFO] rightFixedWidth.value", rightFixedWidth.value);
return rightFixedWidth.value + "px";
});
const barStates = useScrollbar();
console.log('[info] barStates', barStates)
watch(() => props.enable, async (enable) => {
console.log('[info] 开启虚拟滚动条', enable)
if (enable) {
await nextTick();
await until(tableRef.value).toMatch((x) => x?.$el?.parentElement);
await until(vxeTableRef.value).toMatch((x) => x?.$el?.parentElement);
try {
const $table = tableRef.value.$el;
const $table = vxeTableRef.value.$el;
const $header = $table.querySelector(".vxe-table--header-wrapper");
const $bodyWrapper = $table.querySelector(".vxe-table--body-wrapper");
const $bodyContent = $table.querySelector(".vxe-table--body");
Expand All @@ -49,12 +115,12 @@ watch(() => props.enable, async (enable) => {
barStates.setOffset({ y: { top: $header } });
barStates.init({
mount: tableRef,
mount: vxeTableRef,
content: [$bodyContent, $bodyXSpace, $bodyYSpace],
viewport: [$bodyWrapper]
});
} catch (err) {
console.error("[ERR] error when init virtual scrollbar", err, tableRef);
console.error("[ERR] error when init virtual scrollbar", err, vxeTableRef);
}
} else {
barStates.destroy()
Expand Down Expand Up @@ -94,6 +160,14 @@ watch(() => props.enable, async (enable) => {
--color-1: rgb(0 0 0 / 5%);
--color-2: rgb(0 0 0 / 3%);
--color-3: rgb(0 0 0 / 8%);
--left-col-width: v-bind(cssLeftFixedWidth);
--right-col-width: v-bind(cssRightFixedWidth);
@table-header-column-height: 50px;
@header-with-shadow-height: @table-header-column-height + 50px;
.vxe-table--header-wrapper.body--wrapper {
clip-path: polygon(var(--left-col-width, 0) 0, calc(100% - var(--right-col-width, 0)) 0%, calc(100% - var(--right-col-width, 0)) @table-header-column-height, 100% @table-header-column-height, 100% calc(100% + @header-with-shadow-height), 0 calc(100% + @header-with-shadow-height), 0 @table-header-column-height, var(--left-col-width) @table-header-column-height);
}
.vxe-table--header-wrapper {
z-index: 9;
Expand Down
Loading

0 comments on commit 6c0c542

Please sign in to comment.