Vue.js - 동적으로 테이블 행 병합하기, 동적 rowspan(1)
이 글은 사수 없는 주니어 프론트 개발자가 혼자서 구글링도 해보고 혼자 머리 싸매고 고민해서 겨우겨우 간신히 해결한 경험을 바탕으로 작성되었습니다.
들어가기 전
나는 JAVA 국비 6개월 과정을 수료하고, 어쩌다보니 프론트 개발자로 취업을 하게 되었다. 입사한 회사(현 직장)에서 내가 맡은 서비스는 PHP+Vue.js로 개발 되어있고, 예전에 백엔드 개발자 분들이 프론트도 같이 만들어 백엔드와 프론트의 의존도가 매우 높고 중간중간 백엔드스러운 코드들이 많았다. 그리고 회사 특성상 팀 당 프론트 개발자가 한 명이라 사수 없이 대형 프로젝트의 프론트 전반을 맡게된 나 자신. 신규 프로젝트를 하면서 동적으로 테이블 행을 병합해야하는 과제에 직면하게 되는데....
내가 구현해야할 화면
- 내가 구현해야할 화면은 위 사진처럼 날짜 컬럼에서 같은 날짜끼리는 행이 병합되는 테이블이었다.
데이터 형식
{
table_data: [
{ created_at: '2020-01-01', data1: '', data2: '', data3: '' },
...
]
}
- api 호출 시 테이블에 보여줘야할 데이터의 형식은 위와 같다.
기존 코드
// template 영역
...
<table>
<thead>
<tr>
<th>날짜</th>
<th>데이터1</th>
<th>데이터2</th>
<th>데이터3</th>
</tr>
</thead>
<tbody>
<tr v-for="item in tableData">
<td class="dynamic"> {{ item.created_at }} </td>
<td> {{ item.data }} </td>
<td> {{ item.data }} </td>
<td> {{ item.data }} </td>
</tr>
</tbody>
</table>
...
// script 영역
...
updated () {
$(".dynamic").each(function () {
var rows = $(".dynamic:contains('" + $(this).text() + "')");
if (rows.length > 1) {
rows.eq(0).attr("rowspan", rows.length);
rows.not(":eq(0)").remove();
}
});
}
...
- 기존 프로젝트에서도 행병합을 구현한 부분이 있었다. 기존 레거시 코드에서는 위처럼
updated()
훅에 제이쿼리를 사용해 행을 병합했다.
- 하지만 Vue.js에서는 제이쿼리 사용을 권장하고 있지않다. 나는 이 부분을 Vue스럽게 바꿔보기로 했다.
내가 개선한 코드
// template 영역
...
<table>
<thead>
<tr>
<th>날짜</th>
<th>데이터1</th>
<th>데이터2</th>
<th>데이터3</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in tableData">
<td
v-if="index == 0 || item.created_at === tableData[index-1].created_at"
:rowSpan="getRowSpan(tableData, item)"
>
{{ item.created_at }}
</td>
<td> {{ item.data }} </td>
<td> {{ item.data }} </td>
<td> {{ item.data }} </td>
</tr>
</tbody>
</table>
...
// script 영역 - methods
...
getRowSpan(arr, data) {
let rowSpan = 0;
arr.forEach(item => {
if(item.created_at == data.created_at) rowSpan++;
});
return rowSpan;
}
...
- 0번째 요소의 날짜는 무조건 보여준다.
- 반복문 내부에서 현재 요소와 이전 요소의 날짜가 같다면 현재 요소의 날짜를 렌더링하지 않는다.
- tableData에서 현재 요소의 날짜와 같은 날짜를 갖고 있는 요소의 개수를 반환하는 함수를 이용해 rowSpan을 부여한다.
마치며...
{
table_data: [
{ created_at: '2020-01-01', data1: '', data2: '', data3: '' },
...
]
}
// template 영역
...
<table>
<thead>
<tr>
<th>날짜</th>
<th>데이터1</th>
<th>데이터2</th>
<th>데이터3</th>
</tr>
</thead>
<tbody>
<tr v-for="item in tableData">
<td class="dynamic"> {{ item.created_at }} </td>
<td> {{ item.data }} </td>
<td> {{ item.data }} </td>
<td> {{ item.data }} </td>
</tr>
</tbody>
</table>
...
// script 영역
...
updated () {
$(".dynamic").each(function () {
var rows = $(".dynamic:contains('" + $(this).text() + "')");
if (rows.length > 1) {
rows.eq(0).attr("rowspan", rows.length);
rows.not(":eq(0)").remove();
}
});
}
...
- 기존 프로젝트에서도 행병합을 구현한 부분이 있었다. 기존 레거시 코드에서는 위처럼
updated()
훅에 제이쿼리를 사용해 행을 병합했다. - 하지만 Vue.js에서는 제이쿼리 사용을 권장하고 있지않다. 나는 이 부분을 Vue스럽게 바꿔보기로 했다.
내가 개선한 코드
// template 영역
...
<table>
<thead>
<tr>
<th>날짜</th>
<th>데이터1</th>
<th>데이터2</th>
<th>데이터3</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in tableData">
<td
v-if="index == 0 || item.created_at === tableData[index-1].created_at"
:rowSpan="getRowSpan(tableData, item)"
>
{{ item.created_at }}
</td>
<td> {{ item.data }} </td>
<td> {{ item.data }} </td>
<td> {{ item.data }} </td>
</tr>
</tbody>
</table>
...
// script 영역 - methods
...
getRowSpan(arr, data) {
let rowSpan = 0;
arr.forEach(item => {
if(item.created_at == data.created_at) rowSpan++;
});
return rowSpan;
}
...
- 0번째 요소의 날짜는 무조건 보여준다.
- 반복문 내부에서 현재 요소와 이전 요소의 날짜가 같다면 현재 요소의 날짜를 렌더링하지 않는다.
- tableData에서 현재 요소의 날짜와 같은 날짜를 갖고 있는 요소의 개수를 반환하는 함수를 이용해 rowSpan을 부여한다.
마치며...
// template 영역
...
<table>
<thead>
<tr>
<th>날짜</th>
<th>데이터1</th>
<th>데이터2</th>
<th>데이터3</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in tableData">
<td
v-if="index == 0 || item.created_at === tableData[index-1].created_at"
:rowSpan="getRowSpan(tableData, item)"
>
{{ item.created_at }}
</td>
<td> {{ item.data }} </td>
<td> {{ item.data }} </td>
<td> {{ item.data }} </td>
</tr>
</tbody>
</table>
...
// script 영역 - methods
...
getRowSpan(arr, data) {
let rowSpan = 0;
arr.forEach(item => {
if(item.created_at == data.created_at) rowSpan++;
});
return rowSpan;
}
...
나의 사수이자 선생님인 구글을 통해 짠 코드지만 저 코드도 사실 완벽하지 않다. 반복문 안에 조건문이 있어 배열의 길이 개수만큼 조건문을 연산하기 때문에, 렌더링 시 성능저하가 생길 수도 있다. 때문에 api 호출해서 응답값을 받을 때 계산을 하는 것도 좋은 방법인 것 같다.
Author And Source
이 문제에 관하여(Vue.js - 동적으로 테이블 행 병합하기, 동적 rowspan(1)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@gyumin_2/Vue.js-동적으로-테이블-행-병합하기-동적-rowspan1저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)