Vue.js

Vue.js 3.0 STEP 1 - Vue.js 기초와 Template

IT의 큰손 2024. 1. 17. 12:56
728x90

★ 보간법

  • mount하고 있는 9행 id가 app인 div요소
  • {{ }} : 콧수염 모양을 닮았다해서, 콧수염 표현식이라고도 부르며, 보간법이라고 불릅니다.
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>03-01</title>
</head>
<body>
    <div id="app">
    	<h2>{{message}}</h2>
    </div>
    <script type="text/javascript" src="https://unpkg.com/vue"></script>
    <script type="text/javascript">
    var model = { message:"Hello Vue3!" };
    var vm = Vue.createApp({
    	name : "App",
        data() {
            return model;
        }
    }).mount('#app')
    </script>
</body>
</html>

 

★ 기본 디렉티브

 

1. v-text, v-html 디렉티브

  • Vue 디렉티브는 템플릿 안에 사용하는 v-로 시작하는 속성이며, 이것을 이용해 HTML 요소와 관련된 작업을 지정할 수 있습니다.
  • v-text : {{message}} 와 같은 동일한 기능을 수행한다.
  • 즉, inner Text 속성에 연결됨. 태그 문자열을 HTML 인코딩하여 나타나기 때문에 화면에는 태그 문자열이 그대로 나타남.
<div id="app">
    <h2 v-text="message"></h2>
</div>
  • v-html : innerHTML 속성을 변경하는 것.
  • innerHTML 속성에 연결됨. 태그 문자열을 파싱하여 화면에 나타냄
<div id="app">
    <h2 v-html="message"></h2>
</div>

 

2. v-bind 디렉티브

  • 요소(Element)의 속성을 바인딩하기 위해 사용한다.
  • v-bind 디렉티브를 통해서 HTML 요소 객체의 속성이 변경됨.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ex03-3</title>
</head>
<body>
    <div id="app">
        <input id="a" type="text" v-bind:value="message">
        <br>
        <img v-bind:src="imagePath"/>
    </div>
    <script type="text/javascript" src="https://unpkg.com/vue"></script>
    <script type="text/javascript">
        var vm = Vue.createApp({
            name : "app",
            data() {
                return {
                    message : "v-bind 디렉티브",
                    imagePath : "https://contactsvc.bmaster.kro.kr/photos/18.jpg"
                };
            }
        }).mount('#app')

    </script>
</body>
</html>
  • 생략 가능 : v-bind를 생략할 수 있다.
v-bind:src -> :src
  • v-bind 디렉티브는 단방향으로만 데이터 바인딩을 수행. 즉, Vue 인스턴스의 데이터나 속성이 바뀌면 UI를 갱신.
  • 반대로 화면의 바인딩된 요소에서 값을 변경하더라도, 데이터가 바뀌지 않는다.

3. v-model 디렉티브

  • v-text, v-html, v-bind가 모두 단방향 데이터 바인딩을 지원.
  • 하지만, v-model은 양방향 데이터 바인딩을 지원
<div id="app">
    <input id="a" type="text" v-model="name">
    입력하신 이름 : <span>{{name}}</span>
</div>
<script>
    var vm = Vue.createApp({
    	name : "App",
        data() {
            return { name : "" };
        }
    }).mount("#app")
</script>
  • v-model 디렉티브를 이용한 양방향 데이터 바인딩은 checkbox, select, radio button 등에도 적용 가능.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ex03-05</title>
</head>
<body>
    <div id="app">
        <div>
            <h2>취미생활</h2>
            <input type="checkbox" id="hobbyA" value="A" v-model="hobby">
            <label for="hobbyA">운동</label><br>
            <input type="checkbox" id="hobbyB" value="B" v-model="hobby">
            <label for="hobbyB">독서</label><br>
            <input type="checkbox" id="hobbyC" value="C" v-model="hobby">
            <label for="hobbyC">음악</label><br>
            <input type="checkbox" id="hobbyD" value="D" v-model="hobby">
            <label for="hobbyD">댄스</label><br>
            <input type="checkbox" id="hobbyE" value="E" v-model="hobby">
            <label for="hobbyE">역사</label>
        </div>
        <div>
            <h2>상품 분류 선택</h2>
            <select v-model="category">
                <option value="">---- 상품 분류를 선택하세요 ----</option>
                <option value="C01">레저</option>
                <option value="C02">가전</option>
                <option value="C03">음식</option>
                <option value="C04">도서</option>
                <option value="C05">주방</option>
            </select>
        </div>
        <hr>
        <div>
            선택한 취미 : {{hobby.join(',')}} <br>
            선택한 상품 분류 : {{category}}
        </div>
    </div>
    <script type="text/javascript" src="https://unpkg.com/vue"></script>
    <script type="text/javascript">
        var vm = Vue.createApp({
            name : "App",
            data() {
                return { 
                    hobby : [],
                    category : "" 
                };
            }
        }).mount('#app')
    </script>
</body>
</html>
  • 다중 선택의 경우는 배열을 이용해야 하여, hobby : []
  • 단일 선택은 문자열로 값을 받아내기 때문에, category : ""
  • checkbox,radio와 같이 input 요소를 사용하는 경우는 각각의 input 요소마다 v-model 디렉티브를 적용하지만,
  • select와 같이 값을 선택하는 요소를 감싸는 부모 요소가 있다면, 부모 요소인 select에 v-model 디렉티브를 한 번만 적용한다는 점도 주의해야 한다.
  • checkbox로 선택, 미선택으로 구분하여 값을 전달하는 경우
<div id="app">
    위의 내용에 동의하십니까?
    <input type="checkbox" v-model="agree" true-value="yes" false-value="no" />
    <hr>
    <span> 선택된 값 : {{agree}} </span>
</div>
<script type="text/javascript" src="https://unpkg.com/vue"></script>
<script type="text/javascript">
var vm = Vue.createApp({
    name : "App",
    data : {
    	return {
            agree : "no"
        };
    }
}).mount('#app')
</script>

 

4. 수식어

  • v-model 디렉티브는 몇 가지의 수식어를 지원한다.
  • v-model에서 사용할 수 있는 수식어는 다음과 같다.
  • 1. lazy : 입력폼에서 다른 요소로 포커스가 이동하는 이벤트가 발생할 때, 입력한 값을 데이터와 동기화
<input type="text" v-model.lazy="name" />
  • number : 이 수식어를 지정하면 숫자가 입력될 경우 number 타입의 값으로 자동 형변환되어 데이터를 옵션 값으로 반영
<input type="text" v-model.number="num"/>
  • trim : 이 수식어를 지정하면 문자열의 앞뒤 공백을 자동으로 제거한다.
<input type="text" v-model.trim="message"/>
  • number 수식어를 사용한 예
  • 숫자로 형변환이 가능한 값을 입력하면 정상적으로 형변환 되어 숫자로 값이 저장.
  • 하지만, 100aaa 를 입력하게 되면 숫자로 형변환이 가능한 숫자부분만 값을 할당.
  • 처음부터 문자열을 입력하게 되면 문자열로 형변환 되어 값을 할당. 
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>03-07</title>
</head>
<body>
    <div id="app">
        <input type="text" v-model.number="num"><br>
        입력된 수 : <span>{{ num }}</span>
    </div>
    <script type="text/javascript" src="https://unpkg.com/vue"></script>
    <script type="text/javascript">
    var vm = Vue.createApp({
        name : "App",
        data() {
            return { num : 0 };
        }
    }).mount('#app')
    </script>
</body>
</html>
  • 한글에 대한 바인딩이 잘 되지 않는 부분에 대한, 해결법
  • @input="changeName"과 같이 이벤트 핸들러 메서드를 등록하여 name 데이터로 부여
<div id="app">
    <input id="a" type="text" :value="name" @input="changeName">
    <br>
    입력하신 이름 : <span>{{name}}</span>
</div>
<script type="text/javascript" src="https://unpkg.com/vue"></script>
<script type="text/javascript">
var vm = Vue.createApp({
    name : "App",
    data() {
        return { name : "" };
    },
    methods : {
        changeName(e) {
            this.name = e.target.value;
        }
    }
}).mount("#app")

 

5. 조건 렌더링 디렉티브

  • v-show : 화면에 보여줄지 말지를 결정하는 디렉티브
<div id="app">
    예금액 : <input type="text" v-model="amount"/>
    <img v-show="amount < 0 " src="https://contactsvc.bmaster.kro.kr/img/error.png"
        title="마이너스는 허용하지 않습니다."
        style="width:15px; height: 15px; vertical-align: middle;"/>
</div>
<script type="text/javascript" src="https://unpkg.com/vue"></script>
<script type="text/javascript">
    var vm = Vue.createApp({
        name : "App",
        data() {
            return { amount : "" };
        },
    }).mount("#app")
</script>
  • v-if : 조건에 부합하지 않을 경우 렌더링을 수행하지 않도록 함.
  • 하지만, v-if는 HTML 요소를 만들어내지는 않는다.
<div id="app">
    예금액 : <input type="text" v-model="amount"/>
    <img
        v-if="amout < 0"
        src="https://contactsvc.bmaster.kro.kr/img/error.png"
        title="마이너스는 허용하지 않습니다."
        style="width: 15px; height: 15px; vertical-align: middle;" />
</div>
<script type="text/javascript" src="https://unpkg.com/vue"></script>
<script type="text/javascript">
    var vm = Vue.createApp({
        name : "App",
        data() {
            return { amount : "" };
        },
    }).mount("#app")
</script>
  • v-else, v-else-if 디렉티브
  • 계좌 잔고에 따라 고객의 등급을 평가하는 예제
<div id="app">
    잔고 : <input type="text" v-model="balance" />
    <br>
    회원님의 등급 :
    <span v-if="balance >= 1000000">Gold</span>
    <span v-else-if="balance >= 500000">Silver</span>
    <span v-else-if="balance >= 200000">Bronze</span>
    <span v-else>Basic</span>
</div>
<script type="text/javascript" src="https://unpkg.com/vue"></script>
<script type="text/javascript">
var vm = Vue.createApp({
    name : "App",
    data() {
        return { balance : 0 }
    }
}).mount("#app")

 

6. 반복 렌더링 디렉티브

  • v-for : 반복적인 데이터를 렌더링하기 위해서 v-for 디렉티브를 사용한다.
  • contacts라는 배열의 갯수 만큼 for문을 돌아 반복되어 나타난다.
<div id="app">
    <table id="list">
        <thead>
            <tr>
                <th>번호</th>
                <th>이름</th>
                <th>전화번호</th>
            </tr>
        </thead>
        <tbody id="contacts">
            <tr v-for="contact in contacts" :key="contact.no">
                <td>{{contact.no}}</td>
                <td>{{contact.name}}</td>
                <td>{{contact.tel}}</td>
            </tr>
        </tbody>
    </table>
</div>
<script type="text/javascript" src="https://unpkg.com/vue"></script>
<script type="text/javascript">
    var vm = Vue.createApp ({
        name : "App",
        data() {
            return {
                "pageno" : 1,
                "pagesize" : 4,
                "totalcount" : 100,
                "contacts" : [
                    { "no" : 1011, "name" : "RM", "tel" : "010-3456-8299" },
                    { "no" : 1012, "name" : "정국", "tel" : "010-3456-8298" },
                    { "no" : 1013, "name" : "제이홉", "tel" : "010-3456-8297" },
                    { "no" : 1014, "name" : "슈가", "tel" : "010-3456-8296" },
                ]
            }
        }
    }).mount('#app')
</script>
  • 원본 데이터가 객체인 경우 => 키를 이용해 값에 접근하는 해시맵 구조이기 때문에 Key, Value 값을 얻어낼 수 있는 구조 사용
<div id="app">
    <select id="regions">
        <option disabled="disabled" selected>지역을 선택하세요.</option>
        <option v-for="(val, key) in regions" :value="key" :key="key">
            {{ val }}
        </option>
    </select>
</div>
<script type="text/javascript" src="https://unpkg.com/vue"></script>
<script type="text/javascript">
var vm = Vue.createApp({
    name : "App",
    data() {
        return {
            regions : {
                "A" : "Asia",
                "B" : "America",
                "C" : "Europe",
                "D" : "Africa",
                "E" : "Oceania"
            }
        }
    }
}).mount("#app")
</script>
  • 인덱스 번호를 함께 표현해야 한다면
  • 배열 데이터인 경우
<tr v-for="(contact, index) in contacts" ...>
  • 객체 데이터인 경우
<option v-for="(val, key, index) in regions" ...>

 

7. 여러 요소를 묶어서 반복 렌더링하기

  • 여러 요소를 묶어서 반복 렌더링을 하고 싶다면, <template> 요소와 v-for 디렉티브를 함께 사용하면 됨.
  • <template> 태그는 렌더링 내용에는 포함되지 않습니다. 단지, 요소들을 그룹으로 묶어주기 위한 용도로만 사용.
  • 가급적, key 특성을 부여하도록 하고, 반복 렌더링되는 각각의 요소 노드를 추적하고 요소를 재사용할 수 있도록 key 특성에 반드시 고유 값을 바인딩하는 것이 좋다.
<div id="app">
    <table id="list">
        <thead>
            <tr>
                <th>번호</th>
                <th>이름</th>
                <th>전화번호</th>
            </tr>
        </thead>
        <tbody id="contacts">
            <template v-for="(contact, index) in contacts" :key="contact.no">
                <tr>
                    <td>{{contact.no}}</td>
                    <td>{{contact.name}}</td>
                    <td>{{contact.tel}}</td>
                </tr>
                <tr class="divider" v-if="index % 4 === 3">
                    <td colspan="3"></td>
                </tr>
            </template>
        </tbody>
    </table>
</div>
<script type="text/javascript" src="https://unpkg.com/vue"></script>
<script type="text/javascript">
var vm = Vue.createApp({
    name : "App",
    data() {
        return {
            "contacts": [
                    { "no" : 1011, "name" : "RM", "tel" : "010-3456-8299" },
                    { "no" : 1012, "name" : "정국", "tel" : "010-3456-8298" },
                    { "no" : 1013, "name" : "제이홉", "tel" : "010-3456-8297" },
                    { "no" : 1014, "name" : "슈가", "tel" : "010-3456-8296" },
                    { "no" : 1011, "name" : "진", "tel" : "010-3456-8295" },
                    { "no" : 1012, "name" : "뷔", "tel" : "010-3456-8294" },
                    { "no" : 1013, "name" : "지민", "tel" : "010-3456-8293" },
            ]
        }
    }
}).mount("#app")
</script>

 

8. 기타 디렉티브

  • v-pre 디렉티브 : HTML 요소에 대한 컴파일을 수행하지 않는다.
  • 즉,  v-pre 디렉티브로 인해, Vue 인스턴스는 컴파일하지 않고 {{message}} 문자열을 그대로 출력한다.
<span v-pre>{{message}}</span>
  • v-once 디렉티브 : HTML 요소를 단 한번만 렌더링하도록 설정한다.
  • 즉, 초기 렌더링을 수행할 때 단 한번만 데이터를 바인딩하여 출력한다.
  • 초기 렌더링이 완료된 후에는 데이터가 변경되더라도 다시 렌더링 되지 않는다.
<div id="app">
	<span v-once>{{message}}</span>
</div>
  • v-cloak 디렉티브 : 화면 초기에 컴파일되지 않은 템플릿은 나타나지 않도록 할 수 있다.
  • 가끔 v-for 디렉티브를 이용해 많은 데이터를 출력하거나 할 때에 콧수염 표현식이 화면에 일시적으로 나타나는 경우가 있다. 복잡한, UI일수록 이런 경우가 빈번히 발생된다.
<style>
    [v-clock] { display:none; }
</style>
<body>
    <div id="app" v-cloak>
</body>
  • 동적 아규먼트(Dynamic Argument)
  • v-bind 디렉티브나 이벤트 처리를 위한 v-on 디렉티브에서 사용할 수 있다.
<!-- v-bind 예시-->
<element v-bind:[attrName] = "[attrValue]"></element>
<element :[attrName] = "[attrValue]"></element>

<!-- v-on 예시 -->
<element v-on:[eventName] = "[function code]"></element>
<element @[eventName] = "[function code]"></element>
  • 예시
<div id="app">
    <img v-bind:[image1.srcattr]="image1.src"
        :[image1.titleattr]="image1.title"/>
</div>
<script type="text/javascript" src="https://unpkg.com/vue"></script>
<script type="text/javascript">
var vm = Vue.createApp({
    name : "App",
    data() {
        return {
            image1 : {
                srcattr:"src", src:"https://contactsvc.bmaster.kro.kr/photos/18.jpg",
                titleattr: "title", "title" :  "Lily's photo"
            }
        };
    }
}).mount("#app")
</script>
728x90