티스토리 뷰
|| 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
'Web' 카테고리의 다른 글
jQuery Selectric 정리 (2) | 2021.06.03 |
---|---|
[Lexical scoping & Closure] 어휘적 범위 지정, 클로저 (0) | 2021.01.15 |
[JDBC] JAVA JDBC(select, insert, delete, update) (2) | 2020.10.22 |
[Node.js] cheerio module 로 크롤링하기 (0) | 2020.06.23 |
[Node.js] Express Framework 사용하기 (0) | 2020.06.22 |