[Vue.js] filter(필터) 기본 사용법 및 전역 filter 설정 방법: 검색 필터 샘플 스크립트 및 돈 콤마 찍기 스크립트
Vue.js는 필터(filter)를 사용하여 텍스트의 형식화를 적용할 수 있다. 가령, 숫자 3자리 수 마다 콤마 찍기(돈 표기법), 또는 텍스트로 입력받은 값을 날짜형식으로 포맷팅하거나, 입력받은 문자를 모두 소문자 또는 대문자로 변경하거나 첨부한 파일의 크기를 표시, 입력 받은 문자의 첫 글자만 대문자 처리 등의 필터링 기능을 구현하여 사용할 수 있다.
필터(filter)를 적용하는 방법 2가지
1. 콤포넌트 옵션(속성)에 로컬 필터를 정의하는 방법
콤포넌트 속성 중에 filter() 속성에 필터를 정의하여 사용한다.
[html]
<div id="app">
<h2>Todos:</h2>
<input type="text"
v-model="filterText" placeholder="숫자를 입력하세요">
<span>입력 text : {{filterText}}</span>
<br/>
<span>{{filterText | moneyPoint | strUnit}}</span>
</div>
[js]
new Vue({
el: "#app",
data : {
arrText: ['Korea','English','Monkey','Kor','Kind'],
filterText: '',
arrNumbers: [1,2,3,4,5,6,7,8,9,10],
},
methods: {
},
filters: {
//3자리마다 콤마 찍기
moneyPoint: function (value) {
return value.toString().replace(/B(?=(d{3})+(?!d))/g, ",");
},
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
},
toUppercase(value) {
return value.toUpperCase();
},
strUnit: function (value) {
return `${value} 원`;
}
},
})
2. 전역필터 설정하는 방법
콤포넌트가 아닌 모든 곳에서 filter를 사용하고자하는 경우 전역 filter를 Vue 인스턴스 생성 이전에 filter를 정의하여 사용한다.
Vue.filter('moneyFilter', function (value) {
return value.toString().replace(/B(?=(d{3})+(?!d))/g, ",");
});
Vue.filter('unit', function (value) {
return `${value} 원`;
});
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})
Vue.filter('to-lowercase', function(value) {
return value.toLowerCase();
})
new Vue({
el: '#app',
render: h => h(App)
})
필터체인( 필터 체이닝)
필터를 여러개의 파이프(|)를 사용하여 연결할 수 있다. 가령 아래 스니펫과 같이 2개의 필터를 사용하게되면 앞쪽부터 적용된다.
- 기본 필터 체이닝 : {{ message | filterA | filterB }}
- 필터에 파라미터가 추가된 경우 : {{ message | filterA(‘arg1’, arg2) }}
[HTML]
<div id="app">
<h2>Todos:</h2>
<input type="text"
v-model="filterText" placeholder="숫자를 입력하세요">
<span>입력 text : {{filterText}}</span>
<br/>
<span>{{filterText | moneyPoint | strUnit}}</span>
</div>
[JS]
new Vue({
el: "#app",
data : {
arrText: ['Korea','English','Monkey','Kor','Kind'],
filterText: '',
arrNumbers: [1,2,3,4,5,6,7,8,9,10],
},
methods: {
},
filters: {
moneyPoint: function (value) {
return value.toString().replace(/B(?=(d{3})+(?!d))/g, ",");
},
strUnit: function (value) {
return `${value} 원`;
}
},
})
[CSS]
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
[결과]
필터(filter)를 사용하는 방법
filter는 중괄호 보간법(mustache)과 v-bind 표현법 중에 선택하여 사용할 수 있다.
필터는 렌더링하고자 하는 문자열(변수) 뒤에(자바스크립트 표현식 마지막) 파이프(|)를 추가한 후 필터명을 지정한다.
// 중괄호 보간법(mustache)
{{ message | capitalize }}
// v-bind 표현법
<div v-bind:id="rawId | formatId"></div>
computed 속성(property) 내에 filter 사용방법
Vue의 filter를 사용하는 방법 외에 , computed() 프로퍼티(속성)에서 필터를 정의하여 사용할 수 도 있다.
[html]
<div id="app">
<h2>Todos:</h2>
<div>
<input type="text" v-model="filterText">
<ul>
<li v-for="item in searchFiltered">{{item}}</li>
</ul>
</div>
</div>
[JS]
new Vue({
el: "#app",
data : {
arrText: ['Korea','English','Monkey','Kor','Kind'],
filterText: '',
arrNumbers: [1,2,3,4,5,6,7,8,9,10],
},
methods: {
myFilters() {
this.arrNumbers = this.arrNumbers.filter(x=> x>1);
}
},
computed: {
searchFiltered() {
return this.arrText.filter((element)=>{
return element.match(this.filterText);
});
},
getNumber: function() {
return this.arrNumbers.filter(function (number) {
return number % 2 === 0
})
}
}
})
[CSS]
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
[실행결과]
K를 입력한 결과 K로 시작하는 단어만 출력한다. 이런 방식으로 검색 필터를 만들 수 있다.
콤포넌트 속성에서 로컬필터를 만들어서 사용하거나 computed() 속성에 필터를 만들어서 사용하는 경우, 동일한 기능을 하는 필터를 매번 새롭게 생성하는 콤포넌트들에서 중복적으로 정의 후 사용해야한다면 번거롭고 귀찮을 수 있다. 이러한 문제를 해결하기 위해 Mixins를 사용하여 처리하면 해결할 수 있다.
Mixins
Mixins는 Vue 컴포넌트에 재사용 가능한 기능을 배포하는 유연한 방법입니다. mixin 객체는 모든 구성 요소 옵션을 포함할 수 있습니다. 컴포넌트에 mixin을 사용하면 해당 mixin의 모든 옵션이 컴포넌트의 고유 옵션에 “혼합”됩니다. dictionaryMixin.js 임의 자바스크립트 파일 하나를 생성한다.
export const dictionaryMixin = {
data() {
return {
arrText: ['Korea','English','Monkey','Kor','Kind'],
filterText: ''
}
},
computed: {
searchFiltered() {
return this.arrText.filter((element)=>{
return element.match(this.filterText);
});
}
}
}
컴포넌트 내 스크립트에서 import 문을 사용하여 불러온다. 기존 html에서 동일하게 사용가능하다.
<div id="app">
<h2>Todos:</h2>
<div>
<input type="text" v-model="filterText">
<ul>
<li v-for="item in searchFiltered">{{item}}</li>
</ul>
</div>
</div>
..........
<script>
import { dictionaryMixin } from './lib/dictionaryMixin';
export default {
mixins: [dictionaryMixin]
}
</script>
Global mixins
mixin은 전역으로 설정할 수 있다. 모든 인스턴스, 콤퍼넌트에 자동으로 추가됨으로 최대한 사용을 자제(?) 주의해서 사용한다. 웬만하면 로컬 컴포넌트에 추가하여 사용하는것을 권장한다. main.js 파일 안에 vue.mixin()를 사용하여 정의
[main.js]
import Vue from 'vue';
import { Filter } from '@/test/lib/mixin/filter';
import App from './App.vue';
let app;
if (!app) {
Vue.mixin(Filter);
app = new Vue({
render: h => h(App),
}).$mount('#app');
}
[/test/lib/mixin/ 폴더안에 filter.js]
filters: {
// 금액 돈 표기 수치값 3자리 마다 콤마 적용
$_filter_comaStr(value = '') {
const rtnValue = ` ${value}`;
return String(rtnValue).replace(/B(?=(d{3})+(?!d))/g, ',');
},
// 텍스트 형식의 문자열을 날짜 및 시간 포맷팅
$_filter_strDate(value = '', format, pdate, ptime) {
const dd = pdate || '.';
const td = ptime || ':';
let targetStr = String(value);
if (targetStr) {
switch (format) {
case 'yyyy':
targetStr = targetStr.substr(0, 4);
break;
case 'yyyyMM':
targetStr = targetStr.substr(0, 4) + dd + targetStr.substr(4, 2);
break;
case 'yyyyMMdd':
targetStr = targetStr.substr(0, 4) + dd + targetStr.substr(4, 2) + dd + targetStr.substr(6, 2);
break;
case 'HHmm':
targetStr = targetStr.substr(0, 2) + td + targetStr.substr(2, 2);
break;
case 'HHmmss':
targetStr = targetStr.substr(0, 2) + td + targetStr.substr(2, 2) + td + targetStr.substr(4, 2);
break;
default:
targetStr = null;
break;
}
}
return targetStr;
},
// 파일사이즈 표시
$_filter_bytes(bytes = 0, decimals) {
const k = 1024;
const dm = decimals <= 0 ? 0 : decimals || 2;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
const retVal = parseFloat((bytes / (k ** i)).toFixed(dm));
return `${retVal} ${sizes[i]}`;
},
},
};
export default Filter;
vue.js 검색 필터 만들기
입력값의 대소문자 구분을 없애기 위해 toLowerCase()적용한 검색 필터 기능 구현 샘플코드이다.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" >
</head>
<body>
<div id="app">
<div class="panel panel-default">
<div class="panel-heading" style="font-weight:bold">
<span class="glyphicon glyphicon-align-justify"></span> All Resources</div>
<div class="row">
<div class="search-wrapper panel-heading col-sm-12">
<input class="form-control" type="text" v-model="searchQuery" placeholder="Search" />
</div>
</div>
<div class="panel-body" style="max-height: 400px;overflow-y: scroll;">
<table v-if="resources.length" class="table">
<thead>
<tr>
<th>Resource</th>
</tr>
</thead>
<tbody>
<tr v-for="item in filteredResources">
<td><a v-bind:href="item.uri" target="_blank">{{item.title}}</a></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>
[JS]
new Vue({
el: '#app',
data() {
return {
searchQuery:'',
resources:[
{title:"aaa",uri:"aaaa.com",category:"a",icon:null},
{title:"add",uri:"aaaa.com",category:"a",icon:null},
{title:"aff",uri:"aaaa.com",category:"a",icon:null},
{title:"bbb",uri:"bbbb.com",category:"b",icon:null},
{title:"bdd",uri:"bbbb.com",category:"b",icon:null},
{title:"bsb",uri:"bbbb.com",category:"b",icon:null},
{title:"ccc",uri:"cccc.com",category:"c",icon:null},
{title:"ddd",uri:"dddd.com",category:"d",icon:null}
]
};
},
computed: {
filteredResources (){
if(this.searchQuery){
return this.resources.filter((item)=>{
return item.title.startsWith(this.searchQuery.toLowerCase());
})
}else{
return this.resources;
}
}
}
})
[결과]
검색 필터 예제 2
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" >
</head>
<body>
<div id="app">
<div class="panel panel-default">
<div class="panel-heading">
<strong> All Resources</strong></div>
<div class="row">
<div class="search-wrapper panel-heading col-sm-12">
<input class="form-control" type="text" v-model="searchQuery" placeholder="Search" />
</div>
</div>
<div class="table-responsive">
<table v-if="resources.length" class="table">
<thead>
<tr>
<th>Resource</th>
</tr>
</thead>
<tbody>
<tr v-for="item in resultQuery">
<td><a v-bind:href="item.uri" target="_blank">{{item.title}}</a></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>
new Vue({
el: '#app',
data() {
return {
searchQuery: null,
resources:[
{title:"ABE Attendance",uri:"aaaa.com",category:"a",icon:null},
{title:"Accounting Services",uri:"aaaa.com",category:"a",icon:null},
{title:"Administration",uri:"aaaa.com",category:"a",icon:null},
{title:"Advanced Student Lookup",uri:"bbbb.com",category:"b",icon:null},
{title:"Art & Sciences",uri:"bbbb.com",category:"b",icon:null},
{title:"Auxiliares Services",uri:"bbbb.com",category:"b",icon:null},
{title:"Basic Skills",uri:"cccc.com",category:"c",icon:null},
{title:"Board of Trustees",uri:"dddd.com",category:"d",icon:null}
]
};
},
computed: {
resultQuery(){
if(this.searchQuery){
return this.resources.filter((item)=>{
return this.searchQuery.toLowerCase().split(' ').every(v => item.title.toLowerCase().includes(v))
})
}else{
return this.resources;
}
}
}
})
[결과]
json array 중복 객체 제거방법
필터 filter(), findIndex()를 사용하여 배열의 중복되는 객체 제거하는 방법
데이터를 추가 또는 삭제시 배열에 중복으로 밀어넣은 후 중복을 제거하는 방법이 개발시 더 편할 수 있다.
팝업창에서 받아와 데이터를 추가해야하고 메인화면 뷰 상에서 추가 또는 삭제해야하는 상황이면 더더욱 그렇다.
그냥 개인적인 생각이다. 개발이 편한 방법으로 !!
const result = this.data.selectedKeymsgList.filter((item1, idx1) =>
this.data.selectedKeymsgList.findIndex((item2, idx2) =>
item1.keymsgId === item2.keymsgId) === idx1);
this.data.selectedList = result;
findIndex() 함수는 콜백함수에 정의한 조건이 true인 항목의 index를 리턴해준다.
var result = arr.filter(function(item1, idx1){
return arr.findIndex(function(item2, idx2){
return item1.id == item2.id
}) == idx2;
});
[REFERENCE]
- https://kr.vuejs.org/v2/guide/filters.html
- https://kr.vuejs.org/v2/guide/mixins.html
- https://stackoverflow.com/questions/52558770/vuejs-search-filter
[유용한 자료]
[Vue.js] JSFiddle 웹사이트에서 코드 작성 및 실행 결과 확인