Skip to content

Commit

Permalink
feat: ✨添加展示数据的逻辑
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremyjone committed Apr 17, 2023
1 parent 223e936 commit 625e862
Show file tree
Hide file tree
Showing 14 changed files with 248 additions and 51 deletions.
2 changes: 1 addition & 1 deletion demo/demo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ let id = 0;
const ganttData = reactive<any>([]);
for (let i = 0; i < 50; i++) {
for (let i = 0; i < 500; i++) {
onAdd();
}
Expand Down
45 changes: 35 additions & 10 deletions src/components/column/index.vue
Original file line number Diff line number Diff line change
@@ -1,19 +1,40 @@
<template>
<td v-if="colspan > 0" class="xg-table-cell" :colspan="colspan">
<!-- <td v-if="colspan > 0" class="xg-table-cell" :colspan="colspan">
<div class="cell">
<slot v-if="slots.default" v-bind="props.data?.data" />
<template v-else-if="props.prop">{{
props.data?.data?.[props.prop]
}}</template>
</div>
</td>
</td> -->

<div
class="xg-table-cell"
:style="{
width: getColumnWidth(props?.width ?? Variables.default.tableColumnWidth),
...$styleBox.getBorderColor()
}"
>
<div
class="cell"
:style="{ lineHeight: `${rowHeight}px`, height: `${rowHeight}px` }"
>
<slot v-if="slots.default" v-bind="props.data?.data" />

<template v-else-if="props.prop">{{
props.data?.data?.[props.prop]
}}</template>
</div>
</div>
</template>

<script lang="ts">
import Variables from '@/constants/vars';
import columnProps from './props';
import { defineComponent, ref, useSlots } from 'vue';
import { defineComponent, useSlots } from 'vue';
import { getColumnWidth } from './util';
import useStyle from '@/composables/useStyle';
export default defineComponent({
name: Variables.name.column
Expand All @@ -24,24 +45,28 @@ export default defineComponent({
const props = defineProps(columnProps);
const slots = useSlots();
const { $styleBox, rowHeight } = useStyle();
// TODO: 合并列通过这个实现
const colspan = ref(1);
// const colspan = ref(1);
</script>

<style lang="scss" scoped>
.xg-table-cell {
box-sizing: border-box;
height: 100%;
display: inline-block;
position: relative;
vertical-align: middle;
text-overflow: ellipsis;
box-sizing: border-box;
border-right: 1px solid;
.cell {
width: calc(100% - 12px);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: 20px;
height: 20px;
font-size: 14px;
vertical-align: middle;
text-overflow: ellipsis;
padding: 0 6px;
}
}
</style>
28 changes: 18 additions & 10 deletions src/components/common/GanttBody.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,44 @@
class="xg-gantt-body"
:style="{ height: bodyHeight, width: `${ganttWidth}px` }"
>
<div v-for="d in $data.flatData" :key="d.uuid" class="xg-gantt-row">
<div
v-for="d in inView"
:key="d.uuid"
class="xg-gantt-row"
:style="{
top: `${d.flatIndex * rowHeight}px`,
height: `${rowHeight}px`,
...$styleBox.getBorderColor()
}"
>
<component :is="$slotsBox.slider" :data="d" />
</div>
</div>
</template>

<script lang="ts" setup>
import useData from '@/composables/useData';
import useGanttWidth from '@/composables/useGanttWidth';
import useInView from '@/composables/useInView';
import useSlotsBox from '@/composables/useSlotsBox';
import useStyle from '@/composables/useStyle';
const { $slotsBox } = useSlotsBox();
const { $data } = useData();
const { bodyHeight } = useStyle();
const { $slotsBox } = useSlotsBox();
const { bodyHeight, $styleBox, rowHeight } = useStyle();
const { ganttWidth } = useGanttWidth();
const { inView } = useInView();
</script>

<style lang="scss" scoped>
.xg-gantt-body {
background-color: darksalmon;
position: relative;
.xg-gantt-row {
width: 100%;
height: 20px;
background-color: darkkhaki;
position: relative;
position: absolute;
overflow: hidden;
border-bottom: 1px solid;
box-sizing: border-box;
}
}
</style>
60 changes: 49 additions & 11 deletions src/components/common/TableBody.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<table
<!-- <table
class="xg-table-body"
:style="{ height: bodyHeight }"
cellspacing="0"
Expand All @@ -16,37 +16,75 @@
</template>
</colgroup>
<tbody>
<tr v-for="d in $data.flatData" :key="d.uuid" class="xg-table-row">
<tr
v-for="d in inView"
:key="d.uuid"
class="xg-table-row"
:style="{
top: `${d.flatIndex * rowHeight}px`,
height: `${rowHeight}px`
}"
>
<template v-for="(c, i) in $slotsBox.cols" :key="i">
<component :is="c" :data="d" />
</template>
</tr>
</tbody>
</table>
</table> -->

<div class="xg-table-body" :style="{ height: bodyHeight }">
<div
v-for="d in inView"
:key="d.uuid"
class="xg-table-row"
:style="{
top: `${d.flatIndex * rowHeight}px`,
height: `${rowHeight}px`,
...$styleBox.getBorderColor()
}"
>
<template v-for="(c, i) in $slotsBox.cols" :key="i">
<component :is="c" :data="d" />
</template>
</div>

<div
:style="{
height: `${props.gap}px`,
width: '100%',
position: 'absolute',
top: `${rowHeight * $data.flatData.length}px`
}"
/>
</div>
</template>

<script lang="ts" setup>
import useData from '@/composables/useData';
import useInView from '@/composables/useInView';
import useSlotsBox from '@/composables/useSlotsBox';
import useStyle from '@/composables/useStyle';
import Variables from '@/constants/vars';
import { getColumnWidth } from '../column/util';
const { $slotsBox } = useSlotsBox();
const props = defineProps<{ gap: number }>();
const { $slotsBox } = useSlotsBox();
const { bodyHeight, rowHeight, $styleBox } = useStyle();
const { inView } = useInView();
const { $data } = useData();
const { bodyHeight } = useStyle();
</script>

<style lang="scss" scoped>
.xg-table-body {
width: 100%;
table-layout: fixed;
border-collapse: separate;
position: relative;
.xg-table-row {
background-color: darksalmon;
width: 100%;
position: absolute;
background-color: darkkhaki;
overflow: hidden;
border-bottom: 1px solid;
box-sizing: border-box;
}
}
</style>
5 changes: 5 additions & 0 deletions src/components/container/SyncScrollContainer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// This component idea from https://github.com/metawin-m/vue-scroll-sync
import useBus from '@/composables/useBus';
import { uuid } from '@/utils/common';
import useInView from '@/composables/useInView';
import { onMounted, reactive, ref } from 'vue';
const props = defineProps({
Expand Down Expand Up @@ -59,6 +60,8 @@ function scrollFunc(e: any) {
scrollAction.y = e.target.scrollTop;
}
const { setTop } = useInView();
function handleScroll(e: any) {
// 禁用条件
if (props.disableHorizontal && ['left', 'right'].includes(direction.value)) {
Expand Down Expand Up @@ -127,6 +130,8 @@ onMounted(() => {
container!.scrollTop = props.proportional
? (paneHeight * data.scrollTop) / scrollTopOffset
: data.scrollTop;
setTop(container!.scrollTop);
}
if (
!data.disableHorizontal &&
Expand Down
19 changes: 12 additions & 7 deletions src/components/root/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,7 @@
<TableHeader />

<!-- 表内容 -->
<TableBody />

<div
:style="{
height: `${scrollGapSize}px`
}"
/>
<TableBody :gap="scrollGapSize" />
</sync-scroll-container>

<div class="mid-separate-line" />
Expand Down Expand Up @@ -59,6 +53,7 @@ import { getCurrentInstance, onMounted, onUpdated, ref, toRefs } from 'vue';
import rootProps from './rootProps';
import useData from '@/composables/useData';
import useStyle from '@/composables/useStyle';
import useInView from '@/composables/useInView';
import { useResizeObserver } from '@vueuse/core';
const containerId = uuid(10);
Expand All @@ -83,6 +78,15 @@ onMounted(getScrollGapSize);
onUpdated(getScrollGapSize);
// #endregion
// #region 得到组件高度,并保存
const { setRootHeight } = useInView();
onMounted(() => {
setRootHeight(
Math.max(ganttRef.value.$el.offsetHeight, ganttRef.value.$el.clientHeight)
);
});
// #endregion
// #region 处理样式参数
const { setStyles, $styleBox } = useStyle();
setStyles(props);
Expand Down Expand Up @@ -124,6 +128,7 @@ console.log('.....root', getCurrentInstance());
.table-container {
height: 100%;
display: inline-block;
position: relative;
}
.mid-separate-line {
Expand Down
64 changes: 64 additions & 0 deletions src/composables/useInView.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import useStore from '@/store';
import { computed, reactive, watch } from 'vue';
import useStyle from './useStyle';
import type RowItem from '@/models/data/row';

export default () => {
const store = useStore();

const currentTop = computed(() => store.$param.currentTop);
function setTop(t: number) {
store.$param.currentTop = t;
}

const rootHeight = computed(() => store.$param.rootHeight);
function setRootHeight(h: number) {
store.$param.rootHeight = h;
}

const { rowHeight } = useStyle();

// 预加载条数
const preload = 5;

// 数据展示最上面的 index
const top = computed(() => {
const index = Math.ceil(currentTop.value / rowHeight.value);
return Math.max(index - preload, 0);
});

// 数据展示最下面的 index
const bottom = computed(() => {
const count = Math.ceil(rootHeight.value / rowHeight.value);
const t = Math.ceil(currentTop.value / rowHeight.value) + count + preload;
return Math.min(t, store.$data.length);
});

// 切出要展示的数据
const inView = reactive<RowItem[]>([]);
watch(
() => [top.value, bottom.value],
() => {
for (let i = inView.length - 1; i >= 0; i--) {
if (
inView[i].flatIndex < top.value ||
inView[i].flatIndex > bottom.value
) {
inView.splice(i, 1);
}
}

for (let i = top.value; i < bottom.value; i++) {
if (!~inView.findIndex(v => v.flatIndex === i)) {
inView.push(store.$data.flatData[i]);
}
}
}
);

return {
inView,
setRootHeight,
setTop
};
};
Loading

0 comments on commit 625e862

Please sign in to comment.