티스토리 뷰

Web

[Vue.js] Vue 기본 내용 정리

Aaron 2020. 11. 21. 17:42
반응형


|| Vue Instance Life Cycle



Life Cycle은 크게 Instance의 생성, 부착, 갱신, 소멸의 4단계로 나뉨


created (생성)

- Vue Instance 생성 후, 데이터들의 설정이 완료된 후 호출

- Instance가 화면에 부착되기 전 (Vue와 화면 연결 X)

- 서버에 데이터를 요청하여 받아오는 로직을 주로 수행

mounted (부착)

- 지정된 element에 Vue Instance 데이터가 마운트된 후 호출

- template 속성에 정의한 화면 요소에 접근할 수 있어 주로 화면 요소를 제어하는 로직 수행

- Vue와 화면이 연결된 상태(document, ready)

updated (갱신)

- Vue에서 관리되는 데이터가 변경되어 DOM이 업데이트된 상태

- 데이터 변경 후 화면 요소 제어와 관련된 로직 추가

destroyed (소멸)

- Vue Instance가 제거된 후 호출


* axios call은 Vue의 Life Cycle에서 Created or Mounted에 적합




|| 디렉티브(Directive)



Vue에서 View에 데이터를 표현하는 등의 용도로 사용하는 속성



||| 텍스트 표현



 v-text, {{ }}

innerText 속성에 연결되며 문자열 그래도 화면에 표현 (Model과의 반응성이 유지)


 v-html

innerHtml 속성에 연결되며 문자열 중 html 태그를 파싱해서 화면에 나타냄 (Model과의 반응성이 유지)



||| v-model



양방향 바인딩 처리를 위해 사용


v-model="msg"이 적용된 <input> tag의 내용이 변경되면 Vue data의 msg값도 변경

1
2
3
4
5
6
7
8
9
10
11
12
13
    <div id="app">
      <input type="text" v-model="msg" />
      <div>{{msg}}</div>
    </div>
    
    <script>
      new Vue({
        el: '#app',
        data: {
          msg: 'Hello !',
        },
      });
    </script>
cs



||| v-bind



html의 속성인 id, class, style에 model 값을 연결할 때 사용


v-bind:id="data_name"

:id="data_name"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    <div id="app">
      <div v-bind:id="idValue">속성을 바인딩</div>
      <button v-bind:[key]="btnId">버튼</button>
 
      <div :id="idValue">약어를 이용한 바인딩</div>
      <button :[key]="btnId">버튼</button><br />
 
      <a v-bind:href="link1">구글</a>
      <a :href="link2">네이버</a><br />
    </div>
    <script>
      new Vue({
        el: '#app',
        data: {
          idValue: 'test-id',
          key: 'id',
          btnId: 'btn1',
          link1: 'http://www.google.com',
          link2: 'http://www.naver.com',
        },
      });
    </script>
cs



||| v-show



조건에 따라 elements를 화면에 렌더링


style의 display를 변경(v-show 디렉티브가 false옵션을 받으면 display:none)

1
<div style="display: none;">Hello?</div>
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
    <div id="app">
      <div v-show="isShow">{{msg}}</div>
    </div>
 
    <script>
      new Vue({
        el: '#app',
        data: {
          isShow: true,
          msg: 'Hello?',
        },
      });
    </script>
cs



||| v-if, v-else-if, v-else



조건에 따라 elements를 화면에 렌더링


v-if 가 false 일 경우 주석처리  

<!-- -->

1
<div v-if="false">dd</div>
cs



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    <div id="app">
      <div>
        <span>나이 : </span>
        <input type="number" v-model="age" />
      </div>
      <div>
        요금 :
        <span v-if="age < 10">무료</span>
        <span v-else-if="age < 20">7000 원</span>
        <span v-else-if="age < 65">10000 원</span>
        <span v-else>3000 원</span>
      </div>
    </div>
 
    <script>
      const vm = new Vue({
        el: '#app',
        data: {
          age: '0',
        },
      });
    </script>
cs


v-if 와 v-show 의 차이점은

ㅇ 렌더링

v-if : false 일 경우 렌더링 X

v-show : 항상 렌더링

ㅇ false일 경우

v-if : element 삭제

v-show : display:none 적용



||| v-for



배열이나 객체의 반복에 사용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    <div id="app">
      <ul>
        <li v-for="(name, i) in regions">번호 : {{i}}, 지역 : {{name}}</li>
      </ul>
    </div>
 
    <script>
      new Vue({
        el: '#app',
        data: {
          regions: ['광주''구미''대전''서울'],
        },
      });
    </script>
cs


select에 for문 사용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    <div id="app">
      <select v-model="selectedArea">
        <option v-for="(area, idx) in options" :value="area.value" :key="idx">
          {{area.text}}
        </option>
      </select>
    </div>
 
    <script>
      new Vue({
        el: '#app',
        data: {
          selectedArea: '',
          options: [
            { text: '서울', value: 'value' },
            { text: '광주', value: 'value' },
          ],
        },
      });
    </script>
cs



||| v-cloak



Vue Instance가 준비될 때까지 {{ }} 바인딩을 숨기는데 사용

Vue Instance가 준비되면 v-cloak는 제거

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<head>
    <!-- -->
    <style>
        [v-cloak]::before {
            content: '로딩중...'
        }
        [v-cloak] > * {
            display: none;
        }
    </style>
</head>
 
<body>
    <h2>v-cloak</h2>
    <div id="app">
        <h1>1 일반. - {{msg}}</h1>
        <div v-cloak>
            <h1>2 v-cloak. - {{msg}}</h1>
        </div>
    </div>
    
    <script>
        setTimeout(function () {
            new Vue({
                el: "#app",
                data: {
                    msg: "hello"
                }
            })
        }, 3000);
    </script>
</body>
</html>
cs



||| Vue 객체에서 데이터 접근



1
2
3
4
5
6
7
8
9
10
11
     <script>
      var v = new Vue({
        el: '#app',
        data: {
          id: 1,
          msg: 'Hello !!',
        },
      });
 
      console.log(v.id, v.msg, v.$data.id, v.$data.msg);
    </script>
cs




|| Vue Instance




||| Vue filter



표현식에 새로운 결과 형식을 적용

중괄호 보간법 또는 v-bind 속성에서 사용 가능


{{ message | capitalize }}

<div v-bind:id="rawId | formatId"></div>


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    <div id="app">
      <div>금액 : <input type="text" v-model="msg1" /><br /></div>
      <div>
        <h3>{{ msg1 | price }}</h3>
      </div>
    </div>
 
    <script>
      Vue.filter('price', (value) => {
        if (!value) return value;
        return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
      });
      new Vue({
        el: '#app',
        data: {
          msg1: '',
        },
      });
    </script>
cs



||| computed



특정 데이터의 변경사항을 실시간으로 처리

캐싱을 이용하여 데이터의 변경이 없을 경우 캐싱된 데이터 반환


computed 속성은 Vue instance가 생성될 때 계산 후 저장(sum() 한 번 실행)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    <body>
    <div id="app">
      <p>{{ sum }}</p>
      <p>{{ sum }}</p>
      <p>{{ sum }}</p>
    </div>
 
    <script>
      var vm = new Vue({
        el: '#app',
        data: {
          message: '안녕하세요 싸피여러분',
        },
        computed: {
          sum: function () {
            return 3 * 10000000;
          },
        },
      });
    </script>
cs


method는 함수를 사용하려고 할 때마다 계산 (sum() 세 번 실행)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    <div id="app">
      <p>{{ sum() }}</p>
      <p>{{ sum() }}</p>
      <p>{{ sum() }}</p>
    </div>
 
    <script>
      var vm = new Vue({
        el: '#app',
        data: {
          message: '안녕하세요 싸피여러분',
        },
        methods: {
          sum: function () {
            console.log('꺼꾸로 찍기');
            return 3 * 10000000;
          },
        },
      });
    </script>
cs



||| watch



Vue Instance의 특정 property가 변경될 때 실행할 collback 함수 설정


message 내용이 변경되면 collback 함수가 동작

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    <div id="app">
      <p>원본 메시지: "{{ message }}"</p>
      <p>역순으로 표시한 메시지: "{{ reversedMsg }}"</p>
      <input type="text" v-model="message" />
    </div>
 
    <script>
      const app = new Vue({
        el: '#app',
        data: {
          message: 'Hello',
          reversedMsg: '',
        },
        watch: {
          message: function (newVal, oldVa) {
            this.reversedMsg = newVal.split('').reverse().join('');
          },
        },
      });
    </script>
cs




|| event



||| 페이지 이동 막기



e.preventDefault() 

혹은

@click.prevent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    <div id="app">
      <h2>페이지 이동</h2>
 
      <a href="test29.html" @click="sendMsg1">페이지 이동</a><br />
      <a href="test29.html" @click="sendMsg2">페이지 이동 막기 1</a><br />
      <a href="test29.html" @click.prevent="sendMsg1">페이지 이동 막기 2</a><br />
    </div>
 
    <script>
      new Vue({
        el: '#app',
        methods: {
          sendMsg1() {
            alert('이동할까요?');
          },
          sendMsg2(e) {
            e.preventDefault();
            alert('이동막기');
          },
        },
      });
    </script>
cs



||| 이벤트 수신



@keyup.enter == @keyup.13

@keyup.tab

@keyup.delete("Delete" "Backspace")

@keyup.esc

@keyup.space

@keyup.up

@keyup.down

@keyup.left

@keyup.right

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    <div id="app">
      아이디 :
      <input placeholder="검색할 아이디를 입력하세요" v-model="id" @keyup="sendId" />
      <input placeholder="검색할 아이디를 입력하세요" v-model="id" @keyup.13="sendId" />
      <input placeholder="검색할 아이디를 입력하세요" v-model="id" @keyup.enter="sendId" />
      <button @click="sendId">검색</button>
    </div>
    
    <script>
      new Vue({
        el: '#app',
        data: {
          id: '',
        },
        methods: {
          sendId() {
            alert(this.id);
          },
        },
      });
    </script>
cs




|| component



||| Custom Events



이벤트 발생

vm.$emit("eventName", [...parameter])


이벤트 수신

vm.$on("eventName", callback(){});


line 2) 메시지 전송 버튼을 클릭하면

line 14) 'sendMsg' 에 'Hello ~!@' 라는 'msg' 를 담아서 doAction() 이벤트 발생 this.$emit()

line 17) 이벤트를 수신하면서 msg 내용을 message에 저장. this.$on()

line 3) 저장된 message 내용을 출력


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    <div id="app">
      <button v-on:click="doAction">메세지 전송</button>
      <h2>{{message}}</h2>
    </div>
 
    <script>
      new Vue({
        el: '#app',
        data: {
          message: '',
        },
        methods: {
          doAction() {
            this.$emit('sendMsg''Hello ~!@');
          },
        },
        created() {
          this.$on('sendMsg', (msg) => {
            alert(msg);
            this.message = msg;
          });
        },
      });
    </script>
cs



|| vue-router



||| 머리말3



<router-link>는 <a> 태그로 렌더링

1
2
<router-link to="/">Home</router-link>
<router-link to="/board">게시판</router-link>
cs


현재 라우터에 맞는 컴포넌트 렌더링

1
<router-view></router-view>
cs




|| @vue/cli



새로운 프로젝트나 패키지 생성 (package.json file 생성)

vuex, router 사용과 관련된 다양한 옵션 설정

 npm init 


package.json에 설정된 module을 설치

 npm install 


@vue/cli 프로젝트 생성

 vue create <project-name> 



||| SFC(Single File Component)



 - 확장자가 ".vue"

 - template + script + style

 - 구문 강조 가능

 - component에만 CSS 범위 제한 가능

 - 전처리기를 사용해 기능 확장 가능


ㅇ <template>

- 기본 언어는 html

- 각 *.vue 파일은 한번에 최대 하나의 <template> 블록을 포함

- 내용은 문자열로 추출되어 컴파일된 Vue Component의 template 옵션으로 사용


ㅇ <script>

- 기본 언어는 js

- 각 *.vue 파일은 한번에 최대 하나의 <script> 블록을 포함

- ES2015(ES6)을 지원하여 import와 export 사용


* ES6 문법에서 백틱(`)을 사용하여 변수 바인딩, 변수의 값을 문자열로

1
.post(`${SERVER_URL}/user/login`, user)
cs


* ES6를 지원하지 않는 브라우저에서도 실제 동작이 가능하도록 하위 버전 ES6으로 바꿔주는 것이

babel.config.js


ㅇ <style>

- 각 *.vue 파일은 여러 개의 <style> 태그 지원

- scoped 속성을 이용하여 현재 component에서만 사용 가능한 CSS 지정 가능



||| vuex 속성 상태



State

- 단일 상태 트리 사용

- application마다 하나의 저장소를 관리(data)

- 접근 : this.$store.state.data_name


Getters

- Vue Instance의 Computed와 같은 역할

- State를 기반으로 계산(computed) -> 복잡한 계산식 처리

- 사용 : this.$store.getters.countMsg


Mutations

- State의 상태를 변경하는 유일한 방법(methods)

- 호출 : store.commit('정의된 이름')


Actions

- 상태를 변이 시키는 대신 액션으로 변이에 대한 커밋 처리(비동기 methods)

- 호출 : this.$store.dispatch('function')



||| 저장소(Store)



ㅇ State

- 저장소에서 data 속성의 역할

- application에서 공유해야 할 data 관리

- 접근 : this.$store.state.data_name


ㅇ Getters

- component가 vuex의 state를 직접 접근하는 코드 중복을 해결

- Store의 state를 참조하는 Getters 활용

- 정의

1
2
3
4
5
getters: {
    countMsg(state) {
        state.count += 1;
    }
}
cs

- 사용

1
this.$store.getters.countMsg
cs



ㅇ mapGetters

- getters를 더 간단하게 호출

store.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
export default new Vuex.Store({
  state: {
    count: 0,
  },
    countMsg(state) {
      let msg = "10번보다 ";
      if (state.count > 10) {
        msg += "많이 ";
      } else {
        msg += "적게 ";
      }
      return msg + " 호출됨(" + state.count + ")";
    },
    msg1(state) {
      return "msg1 : " + state.count;
    },
    msg2(state) {
      return "msg2 : " + state.count;
    },
    msg3(state) {
      return "msg3 : " + state.count;
    },
  },
});
cs


Result.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
  <div>
    <h2>{{ $store.getters.msg1 }}</h2>
    <h2>{{ $store.getters.msg2 }}</h2>
    <h2>{{ $store.getters.msg3 }}</h2>
  </div>
</template>
 
<script>
import { mapGetters } from "vuex";
 
export default {
  computed: {
    ...mapGetters(["countMsg""msg1""msg2""msg3"]),
 
    countMsg() {
      return this.$store.getters.countMsg;
    },
  },
};
</script>
cs


ㅇ Mutations

- State 값 변경을 위해 사용

- 각 컴포넌트에서 State 값을 직접 변경하는 것은 비권장

- State의 값의 추척을 위해 동기적 기능에 사용

- Mutations는 직접 호출이 불가능하고 store.commit('정의된 이름')으로 호출

[ Mutations 등록 ]

store.js

mutations: {}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
export default new Vuex.Store({
  state: {
    count: 0,
  },
  mutations: {
    ADD_ONE(state) {
      state.count += 1;
    },
    ADD_COUNT(state, payload) {
      state.count += payload;
    },
    ADD_OBJ_COUNT(state, payload) {
      state.count += payload.num;
    },
  },
  // ...
});
cs


Mutations 조회 ]

Subject.vue

store.commit('')

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<script>
export default {
  name"Subject",
  props: ["title"],
  data() {
    return {
      count: 0,
    };
  },
  methods: {
    addCount: function() {
      this.count += 1;
      this.$store.commit("ADD_ONE");
      // this.$store.state.count++;
    },
    addTenCount: function() {
      this.count += 10;
      this.$store.commit("ADD_COUNT"10);
    },
    addObjCount: function() {
      let num = Math.round(Math.random() * 100);
      this.count += num;
      this.$store.commit("ADD_OBJ_COUNT", { num });
    },
  },
};
</script>
cs

Result.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
  <div>
    <h2>{{ total }}</h2>
    <h2>{{ countMsg }}</h2>
  </div>
</template>
 
<script>
import { mapGetters } from 'vuex';
export default {
  computed: {
    ...mapGetters(['countMsg']),
    total() {
      return this.$store.state.count;
    },
  },
};
</script>
cs


ㅇ mapMutations

Subject.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script>
import { mapMutations } from "vuex";
export default {
  name"Subject",
  props: ["title"],
  data() {
    return {
      count: 0,
    };
  },
  methods: {
    ...mapMutations({
      addMOne: "ADD_ONE",
      addMTenCount: "ADD_TEN_COUNT",
      addMObjCount: "ADD_OBJ_COUNT",
    }),
// ...
</script>
cs


ㅇ Actions

- 비동기 작업의 결과를 적용하려고 할 때 사용

- Mutations는 상태 관리를 위해 동기적으로 처리하고 비동기적인 처리는 Actions가 담당

- Actions는 비동기 로직의 처리가 종료되면 Mutations 호출

- this.$store.dispatch('function'); 로 호출

[ Actions 등록]

store.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export default new Vuex.Store({
  state: {
    count: 0,
  },
  actions: {
    asyncAddOne(context) {
      setTimeout(() => {
        context.commit("addOne");
      }, 2000);
    },
  },
  mutations: {
    // ..
  },
  getters: {
    // ..
  },
});
cs


[ Actions 호출]

this.$store.dispatch('function');

Subject.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<script>
import { mapMutations } from "vuex";
export default {
  name"Subject",
  props: ["title"],
  data() {
    return {
      count: 0,
    };
  },
  methods: {
    ...mapMutations({
      addMOne: "ADD_ONE",
      addMTenCount: "ADD_TEN_COUNT",
      addMObjCount: "ADD_OBJ_COUNT",
    }),
    // ..
    addObjCount: function() {
      let num = Math.round(Math.random() * 100);
      this.count += num;
      this.addMObjCount({ num });
    },
    asyncCount() {
      this.$store.dispatch("asyncAddOne");
    },
  },
};
</script>
cs


ㅇ mapActions

Subject.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script>
import { mapMutations, mapActions } from "vuex";
 
export default {
  // ..
  methods: {
    ...mapMutations({
      addMOne: "ADD_ONE",
      addMTenCount: "ADD_TEN_COUNT",
      addMObjCount: "ADD_OBJ_COUNT",
    }),
 
    ...mapActions(["asyncAddOne"]),
    // ..
    asyncCount() {
      this.asyncAddOne();
    },
  },
};
</script>
cs



|| Etc..



||| data value 사용



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
    <img :src='src'/>
</template>
 
<script>
export default {
  data() {
      return {
          user: null,
          isOk: false,
          src: 'hello.png'
      }
  }
};
</script>
cs


||| 파라미터 사용



1
this.$route.params.변수명
cs



||| use data function in Component



함수로 만든 후 return

1
2
3
4
5
6
7
8
9
<script>
export default {
  data: function () {
    return {
      list: [],
    };
  },
};
</script>
cs



||| Cross-origin (CORS)



웹 페이지 상의 제한된 리소스를 최초 자원이 서비스된 도메인 밖의 다른 도메인으로부터 요청할 수 있게 허용하는 구조

출처 : 위키백과


교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)는 추가 HTTP 헤더를 사용하여, 한 서버에서 실행 중인

웹 애플리케이션이 다른 서버의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제


웹 애플리케이션은 리소스가 자신의 출처(도메인, 프로토콜, 포트)와 다를 때 교차 출처 HTTP 요청을 실행


이 API를 사용하는 웹 애플리케이션은 자신의 출처와 동일한 리소스만 불러올 수 있으며, 다른 출처의 리소스를 불러오려면 그 출처에서 올바른 CORS 헤더를 포함한 응답을 반환해야 함


CORS 체제는 브라우저와 서버 간의 안전한 교차 출처 요청 및 데이터 전송을 지원.

출처 https://developer.mozilla.org/ko/docs/Web/HTTP/CORS




반응형
댓글
최근에 올라온 글
최근에 달린 댓글
링크
Total
Today
Yesterday