728x90
사용예제
코드
components/common/InfiniteTable.vue
<template>
<div
id="tableFixHeadDiv"
ref="tableContainer"
@scroll.passive="onScroll"
@mousewheel.passive="whenScrollNotExist"
>
<table id="scroll-target">
<thead>
<tr>
<th
v-for="item in headers"
:key="item.value"
:class="item.class"
:style="{ textAlign: item.align }"
>
{{ item.text }}
</th>
</tr>
</thead>
<tbody :key="items.length" class="boxShadow">
<tr v-show="isUpEnd === true || items == null || items.length == 0">
<td
:colspan="headers.length"
@mousewheel.up="throttleFetchUp"
>
시간 내 조회 결과가 존재하지 않습니다.
<v-btn @click="fetchUp" text color="blue">이어하기</v-btn>
</td>
</tr>
<tr
v-for="item in items"
:key="item.id"
:class="rowClassMethod ? `${rowClassMethod(item)}` : ''"
style="border-top: 1px solid rgb(220,220,220); border-bottom: 1px solid rgb(220,220,220);"
>
<td
v-for="prop in headerProperties"
:key="prop.value"
:style="{ [`text-align`]: prop.align }"
>
<template v-if="prop.filter">
{{ prop["filter"](item[prop.value]) }}
</template>
<template v-else>
{{ item[prop.value] }}
</template>
</td>
</tr>
<tr v-if="items === null || items.length === 0" class="bg-no-content">
<td
:colspan="headers ? headers.length : 1"
>
조회 결과가 존재하지 않습니다.
</td>
</tr>
<tr v-show="isEnd === true || items == null || items.length == 0">
<td
:colspan="headers.length"
@mousewheel.down="throttleFetchDown"
>
시간 내 조회 결과가 존재하지 않습니다.
<v-btn @click="fetchDown" text color="blue">이어하기</v-btn>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
props: {
headers: Array,
isEnd: Boolean,
isUpEnd: Boolean,
items: Array,
fetchDown:Function,
fetchUp: Function,
rowClassMethod: Function
},
data() {
return {
timer: null
};
},
computed: {
loading() {
return this.$store.state.common.loading;
},
headerProperties() {
var properties = {};
var lHeaders = null;
lHeaders = this.headers == null ? [] : this.headers;
lHeaders.forEach(item => {
properties[item.value] = item;
});
return properties;
}
},
methods: {
isScrollVisible() {
return (
this.$refs.tableContainer.scrollHeight >
this.$refs.tableContainer.clientHeight
);
},
onScroll(e) {
// var horizontalScrollbarHeight =
// e.target.offsetHeight - e.target.clientHeight;
var scrollTop = e.target.scrollTop; // 상단 위치
var scrollHeight = e.target.scrollHeight;
var offsetHeight = e.target.offsetHeight; // 기본 위치(scroll 길이)
// scroll이 top을 찍을때
if (scrollTop === 0) {
this.throttleFetchUp();
e.target.scrollTop += 10;
// scroll이 bottom을 찍을 때
} else if (scrollHeight <= offsetHeight + scrollTop) {
this.throttleFetchDown();
e.target.scrollTop -= 10;
}
},
whenScrollNotExist(e) {
if (!this.isScrollVisible()) {
this.throttleFetch(e);
}
},
throttleFetch(e) {
if (e.deltaY > 0) {
this.throttleFetchDown();
} else {
this.throttleFetchUp();
}
},
throttleFetchDown() {
if (this.timer) clearTimeout(this.timer);
this.timer = setTimeout(this.fetchDown, 200);
},
throttleFetchUp() {
if (this.timer) clearTimeout(this.timer);
this.timer = setTimeout(this.fetchUp, 200);
}
}
};
</script>
<style scoped>
.bg-no-content {
background-color: whitesmoke !important;
}
.bg-right {
background-color: white !important;
}
.bg-right:hover {
background-color: whitesmoke !important;
}
.bg-error {
background-color: #ef9a9a;
}
.bg-error:hover {
background-color: #ffcdd2 !important;
}
#tableFixHeadDiv {
overflow-y: auto;
height: 56vh;
border-width: 1px;
}
#tableFixHeadDiv thead th {
position: sticky;
top: 0;
}
/* .boxShadow {
box-shadow: inset 0px 0px 20px 0 rgba(0, 0, 0, 0.3);
} */
/* Just common table stuff. Really. */
#scroll-target {
border-spacing: 2px;
border-collapse: collapse;
/* height: 56vh; */
width: 100%;
/* overflow: scroll; */
}
#scroll-target th,
td {
padding: 8px 16px;
}
#scroll-target tr {
border: 1px grey;
}
#scroll-target th {
background: #eee;
}
</style>
InfiniteTable.vue 사용하기
<template>
<infinite-table
:isUpEnd="isUpEnd"
:rowClassMethod="redRowIfStatusCdNot200"
:isEnd="isEnd"
:headers="headers"
:items="items"
:fetchDown="fetchDown"
:fetchUp="fetchUp"
></infinite-table>
</template>
<script>
import InfiniteTable from "@/components/common/InfiniteTable.vue";
export default {
components: { InfiniteTable },
data() {
return {
headers: [ // 예시에 나온 형태
{
text: "날짜",
value: "reg_dt",
align: "center",
class: "grey lighten-2 grey darken-4--text"
},
{
text: "ip",
value: "ip",
align: "center",
class: "grey lighten-2 grey darken-4--text"
},
{
text: "status code",
value: "status_cd",
align: "center",
class: "grey lighten-2 grey darken-4--text",
width: "2rem"
},
{
text: "url",
value: "url",
align: "center",
class: "grey lighten-2 grey darken-4--text"
},
{
text: "method",
value: "method",
align: "center",
class: "grey lighten-2 grey darken-4--text",
width: "2rem"
},
{
text: "user agent",
value: "user_agent",
align: "center",
class: "grey lighten-2 grey darken-4--text"
}
]
};
},
computed: {
headerProperties() {
var properties = {};
this.headers.forEach(item => {
properties[item.value] = item;
});
return properties;
},
isEnd() {
// 해당 범위 아래에 더이상 정보 없는지 여부
},
isUpEnd() {
// 해당 범위 아래에 정보 더 없는지 여부
},
init: {
get() {
// 최초 초기화인지 여부 가져오기
},
set(init) {
// 최초 초기화 설정 설정
}
},
startDate() {
// 시작 일시
return 시작일시;
},
endDate: {
// 종료 일시
return 시간;
},
inquiryDate() {
// 검색에 사용되는 date;
},
totalPage() {
// 전체 페이지
},
totalCount() {
// 전체 개수
},
items() {
// 정보 array [{}, {}] ;
},
},
methods: {
redRowIfStatusCdNot200(item) {
return item.status_cd == 200 ? "bg-right" : "bg-error";
},
async fetchDown() {
// 아래로 내렸을 때 정보 변경
},
async fetchUp() {
// scroll 올렸을 때 정보 변경
}
async setInit(init) {
// 초기화 했는지 여부;
},
},
async beforeMount() {},
async created() {
// 정보가져오기
},
async destroyed() {}
};
</script>
<style scoped>
#flexStyle {
display: flex;
}
</style>
728x90
'개발 > js, vue, nuxt' 카테고리의 다른 글
VUE: component와 parent간 data 이동 (0) | 2020.04.01 |
---|---|
개발 시 chrome cache 없애기 전략 (0) | 2020.03.11 |
vue를 사용하는 이유 (0) | 2020.03.10 |
댓글