공부방
Vue Directive 본문
Template Syntax
- Vue.js는 랜더링된 DOM을 기본 Vue 인스턴스의 데이터에 선언적으로 바인딩할 수 있는 HTML기반 템플릿 구문 사용
- 보간법(Interpolation)
- 디렉티브(Directive)
보간법-Text(문자열)
- 데이터 바인딩의 가장 기본 형태 "Mustache"구문(이중 중괄호)을 사용한 텍스트 보간.
- <span>메시지: {{msg}}</span>
- Mustache 태그는 데이터 객체의 msg 속성 값으로 대체(해당 값이 변경되면 갱신)
- v-once 디렉티브를 사용하여 데이터 변경 시 업데이트 되지 않는 일회성 보간을 수행
- <span v-once>다시는 변경하지 않습니다: {{msg}}</span>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>Vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 보간법을 사용해보자. (콧수염 방식)-->
<h2>{{msg}}</h2>
<!-- v-once : 1회성 보간을 수행 -->
<h2 v-once>{{msg}}</h2>
</div>
<!-- <div id="app2">
<h2>{{msg}}</h2>
</div> -->
<script>
const app = new Vue({
el: "#app",
data: {
msg: "안녕하세요 하하",
},
});
//이렇게 하나의 html에 여러개의 Vue인스턴스를 넣어 문제는 없어
// const app2 = new Vue({
// el: "#app2",
// data: {
// msg: "안녕하세요 히히",
// },
// });
</script>
</body>
</html>
vue객체의 msg부분의 하하를 후후로 바꾸면
밑의 v-once는 바뀌지 않는다.
보간법-Raw HTML(원시 HTML)
- 이중 중괄호는 HTML이 아닌 일반 텍스트로 해석
실제 HTML을 출력하기 위해서는 v-html 디렉티브 사용 - 웹사이트에서 임의의 HTML을 동적으로 렌더링하려면 XSS 취약점으로 쉽게 이어질 수 있으므로 매우 위험할수도 있다. 신뢰할 수 있는 컨텐츠에서만 HTML 보간을 사용할 것
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>Vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 보간법을 사용해보자. (콧수염 방식)-->
<h2>{{msg}}</h2>
<!-- v-html : 실제로 코드를 HTML로 해석해버린다. -->
<h2 v-html="msg"></h2>
</div>
<script>
const app = new Vue({
el: "#app",
data() {
return {
msg: '<h2 style="color:red">이글은 빨간색입니다.</h2>',
};
},
});
</script>
</body>
</html>
보간법-JavaScript 표현식 사용
- Vue.js는 모든 데이터 바인딩 내에서 JavaScript 표현식의 모든 기능을 지원
- 한가지 제한사항은 각 바인딩에 하나의 단일표현식만 포함될 수 있다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>Vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- javascript 표현식을 사용해보자. -->
<div>{{num+1}}</div>
<div>{{msg+'하하'}}</div>
<div>{{msg.split("").reverse().join("")}}</div>
<div>{{num > 10 ? num : num**2}}</div>
<!-- 콧수염방식말고 똑같지만 v-directive -->
<div v-text="msg + '이거된다'"></div>
</div>
<script>
const app = new Vue({
el: "#app",
data() {
return {
num: 7,
msg: "안녕하세요 후후",
};
},
});
</script>
</body>
</html>
Directive(디렉티브)
- v-접두사가 있는 특수 속성
- 속성값은 단일 JavaScript 표현식이 됨.(v-for 예외)
- 역할은 표현식의 값이 변경될 때 사이드 이펙트를 반응적으로 DOM에 적용
Directive: v-text
- 엘리먼트의 textContent를 업데이트
- 일부를 갱신해야 한다면 {{}}를 사용해야함.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>Vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- v-text -->
<h2 v-text="msg"></h2>
</div>
<script>
const app = new Vue({
el: "#app",
data() {
return {
msg: '<h2 style="color:red">이글은 빨간색입니다.</h2>',
};
},
});
</script>
</body>
</html>
Directive: v-bind
- HTML요소의 속성에 Vue 상태 데이터를 값으로 할당
- Object 형태로 사용하면 value가 true인 key가 class 바인딩 값으로 할당
- 약어 제공 : v-bind:href === : href
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>Vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- v-bind -->
<div id="idValue">v-bind연습1</div>
<div v-bind:id="idValue">v-bind연습2</div>
<div :id="idValue">v-bind연습3</div>
<button v-bind:[key]="btnId">버튼</button>
<button :[key]="btnId">버튼</button>
</div>
<script>
const app = new Vue({
el: "#app",
data() {
return {
idValue: "test-id",
key: "class",
btnId: "test-btn",
};
},
});
</script>
</body>
</html>
Directive: v-model
- Html form 요소의 input 엘리먼트 또는 컴포넌트에 양방향 바인딩 처리
- form 엘리먼트 초기 'value'와 'checked', 'selected'속성을 무시함
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>Vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- v-model : 중국어, 일본어, 한국어 .... 바로 업뎃이 안됨
해결방법 : input 이벤트를 이용해서 처리를 해야함...
-->
<!-- value 속성 / checked / selected 무시됨. -->
<input type="text" value="초기값1" v-model="msg" />
<div>{{msg}}</div>
</div>
<script>
const app = new Vue({
el: "#app",
data() {
return {
msg: "초기값이라네",
};
},
});
</script>
</body>
</html>
Directive: v-show
- 조건에 따라 엘리먼트를 화면에 표시
- 항상 렌더링되고 DOM에 남아있음
- 단순히 엘리먼트에 display CSS속성을 토글하는 것
- 조건이 바뀌면 트랜지션 호출
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>Vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- v-show : 항상 렌더링 되어있음. CSS display 속성 -->
<h1 v-show="ok">하위</h1>
<input type="text" v-model="msg" />
</div>
<script>
const app = new Vue({
el: "#app",
data() {
return {
ok: false,
msg: "hello",
};
},
});
</script>
</body>
</html>
하위라는 값이 있기는 하지만 v-show라서 공간도 차지하지 않게 존재하지 않는다. 만약 공간을 차지했다면 저 hello 박스도 밑에 있었을 것이다.
display값을 true로 바꿔주면 하위가 보여진다.
나머지 코드는 위와 동일
<div id="app">
<!-- v-show : 항상 렌더링 되어있음. CSS display 속성 -->
<h1 v-show="ok">하위</h1>
<input type="text" v-model="msg" />
<button v-show="msg.trim().length !== 0">검색</button>
</div>
위와 같은 코드의 버튼을 넣어준다면 input에 아무것도 없다면 검색 버튼이 뜨지 않는다.
값이 생기면 다시 버튼이 생김
Directive: v-if, v-else-if, v-else
- 표현식 값의 참 거짓을 기반으로 엘리먼트를 조건부 렌더링함.
- 엘리먼트 및 포함된 디렉티브/컴포넌트는 토글하는 동안 삭제되고 다시 작성됨.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>Vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- v-if/else -->
<h2>범퍼카</h2>
나이 : <input type="number" v-model="age" /> <br />
<div>
요금 :
<span v-if="age < 10">10만원</span>
<span v-else-if="age < 20">50만원</span>
<span v-else-if="age == 27">공쨔</span>
<span v-else>만원</span>
</div>
</div>
<script>
const app = new Vue({
el: "#app",
data() {
return {
age: 10,
};
},
});
</script>
</body>
</html>
나이별로 요금이 바뀐다.
Directive: v-for
- 원본 데이터를 기반으로 엘리먼트 또는 템플릿 블록을 여러번 랜더링
- 디렉티브의 값은 반복되는 현재 엘리먼트에 대한 별칭을 제공하기 위해 alias in expression을 사용
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>Vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- v-for -->
<div>
<h2>숫자를 돌려보자</h2>
<span v-for="i in 10">{{i}}</span>
</div>
<div>
<h2>이름을 돌려보자</h2>
<ul>
<li v-for="name in names">{{name}}</li>
</ul>
</div>
<div>
<h2>이름을 돌려보자2</h2>
<ul>
<!-- 순서중요 -->
<li v-for="(name, index) in names">{{index+1}} : {{name}}</li>
</ul>
</div>
<div>
<h2>객체 배열을 돌려보자</h2>
<ul>
<li v-for="human in humans">{{human.name}} : {{human["age"]}}세</li>
</ul>
</div>
</div>
<script>
const app = new Vue({
el: "#app",
data() {
return {
names: ["최주호", "이세훈", "한장민", "곽형석"],
humans: [
{
name: "허재웅",
age: 333,
},
{
name: "곽형석",
age: 60,
},
{
name: "최규호",
age: 12,
},
{
name: "이세훈",
age: 2,
},
],
};
},
});
</script>
</body>
</html>
Directive: v-on
- 엘리먼트에 이벤트 리스너를 연결
- 약어 제공 : @
v-on:click === @click
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>Vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- v-on -->
<h2>{{count}}</h2>
<button v-on:click="count+=1">버튼</button>
<!-- 위에보단 밑에가 더 낫다. -->
<button v-on:click="plus">버튼</button>
<button @click="plus">버튼</button>
</div>
<script>
const app = new Vue({
el: "#app",
data() {
return {
count: 1,
};
},
methods: {
plus() {
this.count++;
console.log("메소드 실행");
},
},
});
</script>
</body>
</html>
버튼을 누르면 1이 더해짐.
Directive: v-cloak
- Vue Instance가 준비될 때까지 Mustache 바인딩을 숨기는데 사용
- [v-clock] {display: none}과 같은 CSS규칙과 함께 사용
- Vue Instance가 준비되면 v-cloak는 제거됨.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>Vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<div id="app">
<!-- v-cloak -->
<h1>1{{msg}}</h1>
<h1 v-cloak>2{{msg}}</h1>
</div>
<script>
setTimeout(function () {
const app = new Vue({
el: "#app",
data() {
return {
msg: "짝수이다.",
};
},
});
}, 3000);
</script>
</body>
</html>
창을 키자마자는 첫번째 msg만 출력되고 3초가 지나면
Vue Instance Option
Vue Method
- Vue Instance는 생성 관련된 데이터 및 메서드의 정의 가능
- method안에 data를 this.데이터이름으로 접근
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>Vue Method</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<button @click="greet">인사</button>
</div>
<script>
const app = new Vue({
el: "#app",
data() {
return {
msg: "안뇽하세요~~",
name: "OPP",
};
},
methods: {
greet() {
// this : 뷰인스턴스를 가리킨다.
alert(`${this.msg} ${this.name}님`);
},
},
});
</script>
</body>
</html>
Vue Filters
- Vue는 텍스트 형식화를 적용할 수 있는 필터를 지원
- filter를 이용하여 표현식에 새로운 결과 형식을 적용
- {{Mustache}} 구문(이중 중괄호) 또는 v-bind 속성에서 사용이 가능
- 자바스크립트 표현식 마지막에 "|" 심볼과 함께 추가 되어야함
- 필터는 체이닝이 가능
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>Vue Filter</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div>
<input type="text" v-model="msg" />
</div>
<div>
<!-- 적용하고 싶은 필더가 있다면 | 기호를 이용하자 -->
<h3>{{msg | count1}}</h3>
<!-- 필터는 체이닝도 가넝 -->
<!-- 바로 뒤에 글자입니다를 붙여줄 수 있다. -->
<h3>{{msg | count2('입력바람') | count3}}</h3>
</div>
</div>
<script>
// 전역필터
Vue.filter("count1", (val) => {
if (val.length === 0) return;
// 아무것도 안 쓰여져 있을 때 아무것도 안 뜸
return `${val} : ${val.length}글자`;
});
const app = new Vue({
el: "#app",
data() {
return {
msg: "",
};
},
filters: {
//지역필터
count2(val, alternative) {
if (val.length === 0) return alternative;
return `${val} : ${val.length}`;
},
count3(val) {
return `${val} 글자입니다.`;
},
},
});
</script>
</body>
</html>
Vue computed
- 특정 데이터의 변경사항을 실시간으로 처리할 수 있음.
- 캐싱을 이용하여 데이터의 변경이 없을 경우 캐싱된 데이터를 반환
- 작성은 method 형태로 정의하지만 Vue에서 프록시 처리하여 property처럼 사용
- 화살표 함수X
Vue computed&methods
- computed 속성 대신 methods에 함수 정의하여 사용가능(최종 결과는 같음)
- computed 속성은 종속 대상을 계산하여 저장해 놓는다.(캐싱)
즉 종속된 대상이 변경되지 않는 한 computed에 작성된 함수를 여러번 호출해도 계산을 다시 하지 않고, 계산되어 있는 결과를 반환 - methods를 호출하면 렌더링을 다시 할 때마다 항상 함수를 실행
computed
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>Vue Computed</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- Computed를 이용하여 문자열 뒤집기 -->
<div>
<input type="text" v-model="msg" />
<p>원본 : {{msg}}</p>
<p>역순1 : {{reversedMsg}}</p>
<p>역순2 : {{reversedMsg}}</p>
<p>역순3 : {{reversedMsg}}</p>
<p>역순4 : {{reversedMsg}}</p>
</div>
</div>
<script>
const app = new Vue({
el: "#app",
data() {
return {
msg: "안녕하세요",
};
},
// 딱 한번만 계산하고 변화가 없다면 해당값을 계속사용한다.
computed: {
reversedMsg() {
console.log("거꾸로 뒤집기");
return this.msg.split("").reverse().join("");
},
},
});
</script>
</body>
</html>
method
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>Vue Computed</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- Method를 이용하여 문자열 뒤집기 -->
<div>
<input type="text" v-model="msg" />
<p>원본 : {{msg}}</p>
<p>역순1 : {{reversedMsg()}}</p>
<p>역순2 : {{reversedMsg()}}</p>
<p>역순3 : {{reversedMsg()}}</p>
<p>역순4 : {{reversedMsg()}}</p>
</div>
</div>
<script>
const app = new Vue({
el: "#app",
data() {
return {
msg: "안녕하세요",
};
},
methods: {
reversedMsg() {
console.log("거꾸로 뒤집기");
return this.msg.split("").reverse().join("");
},
},
});
</script>
</body>
</html>
Vue watch
- Vue Instance의 특정 property가 변경될 때 실행할 callback 함수 설정
- 데이터를 감시
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>Vue Watch</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div>
<input type="text" v-model="msg" /> <br />
<p>원본 : {{msg}}</p>
<p>역순 : {{reversedMsg}}</p>
</div>
</div>
<script>
const app = new Vue({
el: "#app",
data() {
return {
msg: "hello",
reversedMsg: "",
};
},
watch: {
msg(newVal) {
this.reversedMsg = newVal.split("").reverse().join("");
},
},
});
</script>
</body>
</html>
위 같았으면 hello에서 바로 olleh로 바뀌어야 하지만 변화가 있을 때까지는 변화가 없다.
변화를 주자마자 값이 바껴서 들어온다.
Vue computed&watch
- computed
특정 데이터를 직접적으로 사용/가공하여 다른 값으로 만들 때 사용. 계산해야 하는 목표 데이터를 정의하는 방식으로 SW 공학에서 이야기하는 '선언형 프로그래밍' 방식 - watch
특정 데이터의 변화 상황에 맞추어 다른 data 등이 바뀌어야 할 때 주로 사용. 감시할 데이터를 지정하고 그 데이터가 바뀌면 이런 함수를 실행하라 라는 방식으로 SW 공학에서 이야기하는 '명령형 프로그래밍' 방식
'vue.js' 카테고리의 다른 글
Vue Router (0) | 2023.05.09 |
---|---|
Vue CLI (0) | 2023.05.08 |
Vue Component (0) | 2023.05.04 |
Vue Event (0) | 2023.05.03 |
vue기본 (0) | 2023.05.01 |