Vue 예제 – 03_Grid Component
03_Grid Component
데이터 정렬을 위해서는 3가지 정보가 필요합니다.
- 데이터 : 원시 데이터 -> 정렬되거나 서칭된 데이터
- 정렬기준 : name, power 등 정렬의 기준이 되는 기준항목
- 정렬방법 : 오름차순, 내림차순
- JavaScript – filter(), keys(), some(), toLowerCase(), indexOf(), slide(), sort(), charAt(), toUpperCase()
- VueJS – @click, :class, v-for, filters, props, template
Result
HTML
<!-- 테이블 템플릿 생성 -->
<script type="text/x-template" id="grid-template">
<table>
<thead>
<tr>
<!-- 정렬제목 영역 반복 출력 -->
<th v-for="key in columns"
@click="sortBy(key)"
:class="{ active: sortKey == key }"> <!-- 현재 정렬일 경우 클래스 추가 -->
{{ key | capitalize }} <!-- 첫 문자 대문자 처리 capitalize -->
<span class="arrow" :class="sortOrders[key] > 0 ? 'asc' : 'dsc'">
<!-- 현재 정렬 칼럼의 오름,내림차순에 따른 클래스 추가 -->
</span>
</th>
</tr>
</thead>
<tbody>
<!-- 필터나 정렬기능으로 리턴되어 온 배열 길이만큼 tr 생성 -->
<tr v-for="entry in filteredHeroes">
<!-- 이름, 파워순 정렬이므로 항목갯수만큼 반복 -->
<td v-for="key in columns">
<!-- name, power 출력 -->
{{entry[key]}}
</td>
</tr>
</tbody>
</table>
</script>
<!-- demo root element -->
<div id="demo">
<form id="search">
Search <input name="query" v-model="searchQuery">
</form>
<!-- 상단에서 만든 템플릿으로 props 형태로 전달 (데이터, 정렬항목, 검색어) -->
<demo-grid
:heroes="gridData"
:columns="gridColumns"
:filter-key="searchQuery">
</demo-grid>
</div>
- {{ key | filter function }} – filters에 정의된 함수에 key를 매개변수로 전달
JavaScript
// register the grid component
Vue.component('demo-grid', {
template: '#grid-template',
// 데이터, 정렬항목, 검색어 받기
props: {
heroes: Array, // 데이터
columns: Array, // 정렬항목
filterKey: String // 검색어
},
data: function () {
var sortOrders = {} // 기본 정렬 차순 1로 설정, 정렬시 -1,1이 스위칭
this.columns.forEach(function (key) {
sortOrders[key] = 1
})
return {
sortKey: '', // 정렬기준
sortOrders: sortOrders // 정렬기준별 차순
}
},
computed: {
filteredHeroes: function () {
var sortKey = this.sortKey // 정렬기준
var filterKey = this.filterKey && this.filterKey.toLowerCase() // 검색어 소문자로 변환
var order = this.sortOrders[sortKey] || 1 // 오름, 내림차순 변수
var heroes = this.heroes // 데이터 가져오기
if (filterKey) {
heroes = heroes.filter(function (row) {
// 검색어를 포함한 데이터일 경우 true를 리턴하여 새로운 배열로 반환
return Object.keys(row).some(function (key) {
// name을 소문자 변환후 검색어로 검색해서 있을 경우 true 반환
return String(row[key]).toLowerCase().indexOf(filterKey) > -1
})
})
}
if (sortKey) {
heroes = heroes.slice().sort(function (a, b) {
a = a[sortKey]
b = b[sortKey]
// 오름, 내림차순으로 정렬
return (a === b ? 0 : a > b ? 1 : -1) * order
})
}
return heroes
}
},
filters: {
// 앞문자 대문자 처리 함수
capitalize: function (str) {
return str.charAt(0).toUpperCase() + str.slice(1)
}
},
methods: {
// 정렬 클릭 이벤트 선언
sortBy: function (key) {
this.sortKey = key // 정렬 칼럼 선언
this.sortOrders[key] = this.sortOrders[key] * -1 // 정렬 화살표 클래스 추가 + 오름, 내림차순 처리
}
}
})
// bootstrap the demo
var demo = new Vue({
el: '#demo',
// 기본 데이터 선언
data: {
searchQuery: '',
gridColumns: ['name', 'power'],
gridData: [
{ name: 'Chuck Norris', power: Infinity },
{ name: 'Bruce Lee', power: 9000 },
{ name: 'Jackie Chan', power: 7000 },
{ name: 'Jet Li', power: 8000 }
]
}
})
- filter() – 주어진 함수의 테스트를 통과하는 모든 요소를 모아 새로운 배열로 반환
- Object.keys() – 개체 고유 속성의 이름을 배열로 반환
- some() – 배열 안의 한 요소라도 함수를 통과하는지 테스트하여 boolean 반환
- toLowerCase() – 소문자 변환
- toUpperCase() – 대문자 변환
- indexOf() – 문자열 값과 일치하는 첫번째 위치 반환. 값이 없으면 -1 반환
- slice() – 문자열을 잘라서 새로운 문자열로 반환
- sort() – 배열을 정렬하여 새로운 배열로 반환
- filters – 텍스트 형식화를 적용할 수 있는 필터 제공
CSS
body {
font-family: Helvetica Neue, Arial, sans-serif;
font-size: 14px;
color: #444;
}
table {
border: 2px solid #42b983;
border-radius: 3px;
background-color: #fff;
}
th {
background-color: #42b983;
color: rgba(255,255,255,0.66);
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
td {
background-color: #f9f9f9;
}
th, td {
min-width: 120px;
padding: 10px 20px;
}
th.active {
color: #fff;
}
th.active .arrow {
opacity: 1;
}
.arrow {
display: inline-block;
vertical-align: middle;
width: 0;
height: 0;
margin-left: 5px;
opacity: 0.66;
}
.arrow.asc {
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-bottom: 4px solid #fff;
}
.arrow.dsc {
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 4px solid #fff;
}