mixin
http://localhost:8080/test-mixin
mixin을 활용하면 전역변수나 전역메소드 같은 효과를 줄 수 있다.다음과 같은 mixin파일을 생성한다. (위치나 이름은 자유롭게 설정할 수 있다.)
/src/components/mixin/commonMixin.js
export default {
data() {
return {
mixin: {
test: 'mixinTest'
}
}
},
methods: {
mixinTest() {
console.log('This is mixin method')
}
}
}
다음과 같은 테스트 파일을 생성한다.
/src/views/TestMixin.vue
<template><div><h1>Mixin Test</h1><p>{{ mixin.test }}</p></div></template><script>
import commonMx from '@/components/mixin/commonMixin'
export default {
mixins: [commonMx],
data() {
return {}
},
created() {
this.mixinTest()
}
}
</script>
import 할때 @/components/mixin/commonMixin와 같이 @를 사용하면 현재 서버의 절대 경로를 사용하게 된다.
화면 출력(mixin Test)과 콘솔 출력(This is mixin method)을 확인 할 것.
Bootstrap-vue
http://localhost:8080/test-bootstrap
부트스트랩이란 트위터에서 사용하는 각종 레이아웃, 버튼, 입력창 등의 디자인을 css와 javascript로 만들어서 사용하기 쉽도록 제공하는 라이브러리이다. (부트스트랩을 이용한 상용 디자인 프레임워크도 많이 있다.)
vue에서 bootstrap를 사용해 보자.다음과 같이 bootstrap-vue를 설치 한다.
https://bootstrap-vue.org/docs공식 문서를 참고하여 어떤 버전을 설치해야 하는지 확인 한다.
> npm install bootstrap@4.6.1 bootstrap-vue@2.22.0 --save
main.js파일에 다음과 같이 설정 한다.
/src/main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
// bootstrap
import { BootstrapVue } from 'bootstrap-vue'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
Vue.use(BootstrapVue)
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
부트스트랩 컴포넌트: https://bootstrap-vue.org/docs/components다음과 같이 몇가지 부트스트랩 컴포넌트를 확인 해 본다.
/src/views/TestBootstrap.vue
<template><div><h1>Botstrap Test</h1><b-row><b-col><h3>Left</h3></b-col><b-col style="text-align: left"><h3>Center</h3><div><h4>button</h4><b-button>Button</b-button><b-button variant="danger">Button</b-button><b-button variant="success">Button</b-button><b-button variant="outline-primary">Button</b-button></div><div><h4>input text</h4><b-form-input placeholder="Enter your name"></b-form-input></div><div><h4>checkbox</h4><b-form-checkbox id="checkbox-1" name="checkbox-1" value="accepted" unchecked-value="not_accepted">
I accept the terms and use
</b-form-checkbox></div><div><h4>radio</h4><b-form-group><b-form-radio name="some-radios" value="A">Option A</b-form-radio><b-form-radio name="some-radios" value="B">Option B</b-form-radio></b-form-group></div><div><h4>select</h4><b-form-select v-model="selected" :options="options"></b-form-select></div><div><h4>textarea</h4><b-form-textarea id="textarea" placeholder="Enter something..." rows="3" max-rows="6"></b-form-textarea></div><div><h4>input group</h4><b-input-group prepend="Username" class="mt-3"><b-form-input></b-form-input><b-input-group-append><b-button variant="outline-success">Button</b-button><b-button variant="info">Button</b-button></b-input-group-append></b-input-group></div><div><h4>table</h4><b-table striped hover :items="items"></b-table></div></b-col><b-col><h3>Right</h3></b-col></b-row></div></template><script>
export default {
data() {
return {
selected: null,
options: [
{ value: null, text: 'Please select an option' },
{ value: 'a', text: 'This is First option' },
{ value: 'b', text: 'Selected Option' },
{ value: { C: '3PO' }, text: 'This is an option with object value' },
{ value: 'd', text: 'This one is disabled', disabled: true }
],
items: [
{ age: 40, first_name: 'Dickerson', last_name: 'Macdonald' },
{ age: 21, first_name: 'Larsen', last_name: 'Shaw' },
{ age: 89, first_name: 'Geneva', last_name: 'Wilson' },
{ age: 38, first_name: 'Jami', last_name: 'Carney' }
]
}
}
}
</script><style scoped>
div h4 {
margin-top: 20px;
}
</style>
component
http://localhost:8080/test-comp
header와 footer를 component로 구성해 본다.
1) Header component 만들기
/src/views/comp/Header.vue
<template><div><div style="background-color: yellow; height: 50px">This is header</div><hr /></div></template><script>
export default {}
</script>
2) Footer component 만들기
/src/views/comp/Footer.vue
<template><div><hr /><span>COPYRIGHT COMPANY ALL RIGHTS RESERVED.</span></div></template><script>
export default {}
</script>
3) component 호출하기
/src/views/comp/index.vue
<template><div><app-header /><h1>Component Test</h1>
여기는 body 영역
<app-footer /></div></template><script>
import Header from '@/views/comp/Header.vue'
import Footer from '@/views/comp/Footer.vue'
export default {
components: {
'app-header': Header,
'app-footer': Footer
}
}
</script>
app-header라는 이름은 변경이 가능하다.(kebab-case로 가능)
4) router 세팅은 이렇게
/src/router/index.js
{
path: '/test-comp',
component: () => import('../views/comp') // 호출되는 파일이 index.vue인 경우에는 파일명을 생략할 수 있다.
}
만일 컴포넌트에서 호출하는 파일이 index.vue로 되어있으면 해당 파일명을 생략할 수 있다.(../views/comp/index.vue ⇒ ../views/comp)
URL을 호출했을때 Header와 Footer가 한 페이지 내에 함께 존재하는지 확인 한다.
Not Found
존재하지 않는 url을 호출해도 페이지에는 아무런 에러 메세지가 없다.(예: http://localhost:8080/abc123 --> 이런 페이지는 없지만 화면은 깨끗하게 잘 나온다.)
1) Not Found 페이지 만들기
다음과 같이 Not Found에서 사용할 페이지를 만든다. (위치는 크게 상관 없지만 보통 component들이 모여있는 곳에 작성 한다)
/src/components/NotFound.vue
<template><div><h1 class="text-60">404</h1><p class="text-36 subheading mb-3">Page not found!</p><p class="mb-5 text-muted text-18">Sorry! The page you were looking for doesn't exist.</p><a class="btn btn-lg btn-primary btn-rounded" href="/">Go back to home</a></div></template><script>
export default {}
</script>
2) Router 설정
Not Found를 설정하기 위해서는 라우터의 설정이 중요하다.다음과 같은 설정은 반드시 라우터 설정의 맨 하단에 위치해야 한다.
/src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
...
{
path: '/test-comp',
component: () => import('../views/comp')
},
{
path: '*', // NotFound 설정을 위한 path('*')는 반드시 맨 하단에 위치 해야 한다.
component: () => import('../components/NotFound.vue')
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
path: '*'의 뜻는 모든 path를 잡아낸다는 뜻이다. 따라서 맨 하단에 위치해야 위에서 놓치는(존재 하지 않는)URL의 모든 것을 잡아낼 수 있다.(맨 상단에 있으면 어떤 일이 발생 할까??)
다음과 같이 존재하지 않는 url을 방문해 보자http://localhost:8080/abc123
props
http://localhost:8080/test-family/props
부모 컴포넌트에서 자식 컴포넌트로 값을 전달 할 수 있다.
1) 자식1(Alice) 컴포넌트 만들기
/src/views/family/props/Child1.vue
<template><div><h3>Hi, I am Alice</h3><p>I have to {{ job }}</p><p>{{ user.name }} {{ user.who }}</p></div></template><script>
export default {
props: {
job: {
type: String,
required: false,
default: 'Nothing'
},
user: {
type: Object,
required: false,
default: null
}
}
}
</script>
props로 선언된 부분을 통해 부모 컴포넌트에서 프로퍼티를 전달할 수 있다.
2) 자식2(Bob) 컴포넌트 만들기
/src/views/family/props/Child2.vue
<template><div><h3>Greeting to you, I am Bob</h3><p>I have to {{ job }}</p></div></template><script>
export default {
props: {
job: {
type: String,
required: false,
default: 'Nothing'
}
}
}
</script>
3) 부모(Parent) 컴포넌트 만들기
/src/views/family/props/Parent.vue
<template><div><h1>Props Test</h1><h2>I am Parent</h2><p>I will make my children do something.</p><div style="border: 1px solid red"><alice job="homework" :user="myAlice" /></div><div style="border: 1px solid blue"><bob job="clean my room" /></div></div></template><script>
import Alice from './Child1.vue'
import Bob from './Child2.vue'
export default {
components: {
Alice,
Bob
},
data() {
return {
myAlice: {
name: 'Alice',
who: 'My daughter'
}
}
}
}
</script>
<alice job="something" />와 같이 job프로퍼티를 통해 자식 컴포넌트에 값을 전달할 수 있다.자세한 props사용에 대해서는 https://kr.vuejs.org/v2/guide/components-props.html 문서를 참조 할 것.
변수를 전달할때는 v-bind를 이용 해서 전달 한다.(v-bind:user는 :user와 같다.)
4) Router 세팅
/src/router/index.js
{
path: '/test-family/props',
component: () => import('../views/family/props/Parent.vue')
},
라우터 세팅 후 페이지를 확인해 볼 수 있다.전달하는 job의 값에 따라 자식 컴포넌트의 job값이 달라짐을 확인 할 것.
emit
http://localhost:8080/test-family/emit
자식 컴포넌트에서 발생한 사건을 부모 컴포넌트로 전달할 수 있다.
1) 자식1(Alice) 컴포넌트 만들기
/src/views/family/emit/Child1.vue
<template><div><h3>Hi, I am Alice</h3><p>I want my parent to give me money.</p><b-button variant="primary" @click="updateTodo">Money</b-button></div></template><script>
export default {
methods: {
updateTodo: function () {
this.$emit('updateTodo', 'give to Alice money')
}
}
}
</script>
this.$emit('updateTodo', 'give to Alice money') 와 같이 $emit을 통해 부모로 부터 프로퍼티로 할당 받은 updateTodo 를 호출할 수 있다.(여기에 기록된 updateTodo 메소드는 부모 메소드가 아니라 부모가 호출한 자식 컴포넌트의 속성명이다.)
2) 자식2(Bob) 컴포넌트 만들기
/src/views/family/emit/Child2.vue
<template><div><h3>Greeting to you, I am Bob</h3><p>I want my parent to give me food.</p><b-button variant="success" @click="updateTodo">Food</b-button></div></template><script>
export default {
methods: {
updateTodo: function () {
this.$emit('updateTodo', 'feed Bob food')
}
}
}
</script>
Bob은 Alice와는 다른 요구를 한다. (feed Bob food)
3) 부모 컴포넌트 만들기
/src/views/family/emit/Parent.vue
<template><div><h1>Emit Test</h1><h2>I am Parent</h2><p>I have to do something for my children.</p><p style="font-weight: bold">I will {{ todo }}</p><div style="border: 1px solid red"><alice @updateTodo="updateTodo($event)" /></div><div style="border: 1px solid blue"><bob @updateTodo="updateTodo($event)" /></div></div></template><script>
import Alice from './Child1.vue'
import Bob from './Child2.vue'
export default {
components: {
Alice,
Bob
},
data() {
return {
todo: 'do nothing'
}
},
methods: {
updateTodo: function (newTodo) {
this.todo = newTodo
}
}
}
</script>
부모 컴포넌트는 자식 컴포넌트 호출 시 <alice @updateTodo="updateTodo($event)" />에서 $event를 통해 자식 컴포넌트에서 전달한 값을 받을 수 있다. (객체도 가능함)
4) Router 세팅
/src/router/index.js
{
path: '/test-family/emit',
component: () => import('../views/family/emit/Parent.vue')
},
중요 포인트 부모와 자식 컴포넌트에서 사용하는 updateTodo이름이 중복 되는데 누구를 호출하는지 구분할 수 있어야 한다.(호출 메소드와 응답 메소드를 짝지을 수 있어야 한다.)
event bus
http://localhost:8080/test-family/event-bus
자식 컴포넌트 끼리 event를 발생 시킬 수 있다. (하지만 권장하지는 않는다. Store를 사용하면 된다.)
1) EventBus 파일 생성
/src/views/family/eventBus/eventBus.js
import Vue from 'vue'
export const EventBus = new Vue()
2) 자식1(Alice) 컴포넌트 만들기
/src/views/family/eventBus/Child1.vue
<template><div><h3>Hi, I am Alice</h3><p>
I said: Hey Bob. where's my stuff??
<b-button size="sm" variant="primary" @click="whatIsaid">send to Bob</b-button></p><p>Bob said:</p></div></template><script>
import { EventBus } from './eventBus'
export default {
data() {
return {
count: 0
}
},
methods: {
whatIsaid: function () {
this.count += 1
EventBus.$emit('aliceSaid', `Give me my stuff ! x ${this.count}`)
}
}
}
</script>
EventBus.$emit('eventName', 'message') 를 통해서 이벤트를 전파할 수 있다.eventName: 전파하는 이벤트 이름message: 전파하는 메세지(객체도 가능함)
3) 자식2(Bob) 컴포넌트 만들기
/src/views/family/eventBus/Child2.vue
<template><div><h3>Greeting to you, I am Bob</h3><p>Alice said to me: {{ aliceMessage }}</p><p>
Bob said: I don't know. <b-button size="sm" variant="success">reply to Alice</b-button>(여기를 구현해 보도록
하자.)
</p></div></template><script>
import { EventBus } from './eventBus'
export default {
data() {
return {
aliceMessage: ''
}
},
created() {
EventBus.$on('aliceSaid', message => {
this.aliceMessage = message
})
}
}
</script>
EventBus.$on('eventName', function (message) { ... })를 통해서 메세지를 받을 수 있다.
함수 function (message) { ... }는 message => { ... }와 같다. (화살표 함수)
4) 부모 컴포넌트 만들기
/src/views/family/eventBus/Parent.vue
<template><div><h1>Event Bus Test</h1><h2>I am Parent</h2><p>Let's listen to the children's conversation.</p><div style="border: 1px solid red"><alice /></div><div style="border: 1px solid blue"><bob /></div></div></template><script>
import Alice from './Child1.vue'
import Bob from './Child2.vue'
export default {
components: {
Alice,
Bob
},
data() {
return {}
}
}
</script>
부모 컴포넌트에서는 그냥 두 자식컴포넌트를 호출했을 뿐이다.
자식1(Alice)컴포넌트의 [send to Bob]버튼을 통해 메세지 전달 테스트를 해보자.
자식2(Bob)컴포넌트에서 자식1(Alice)컴포넌트로 메세지를 보내 보자. ([reply to Alice]버튼 기능 구현)
Store (Vuex)
UserList: http://localhost:8080/test-user/listUserInfo: http://localhost:8080/test-user/info
Vuex란 state를 관리할 수 있도록 도와주는 상태 관리 라이브러리이다. 상세 설명은 (여기) 참고
보통 Store라고 명칭 한다.
가상의 User정보를 store를 통해 호출해 본다.
1) User Store 파일 생성(빈 파일 생성)
/src/store/models/user.js
export default {
state: {
// state에 사용할 모델이나 값을 선언 한다.
},
getters: {
// getters을 통해 state값을 호출 한다.
},
mutations: {
// mutations는 동기적이어야 함.(비동기 사용 불가)
},
actions: {
// action은 비동기적 사용이 가능하다. (action에서 mutation을 호출하는 방법을 권장함)
}
}
2) Store의 index파일에서 User Store파일 import 하기
/src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import User from './models/user'
// Load Vuex
Vue.use(Vuex)
// Create Store
export default new Vuex.Store({
modules: {
User
}
})
3) User Store 파일 코딩
위와 같이 빈 파일을 만들었으면 이제는 다음과 같이 가상의 User정보를 조회하는 Store를 만들어 보자.
/src/store/models/user.js
export default {
state: {
// state에 사용할 모델이나 값을 선언 한다.
User: {
id: 0,
name: null,
username: null,
email: null
}, // User 상세 정보용 state
UserList: [] // User 리스트용 state
},
getters: {
// getters을 통해 state값을 호출 한다.
User: state => state.User,
UserList: state => state.UserList
},
mutations: {
// mutations는 동기적이어야 함.(비동기 사용 불가)
setUser(state, data) {
state.User = data
},
setUserList(state, data) {
state.UserList = data
}
},
actions: {
// action은 비동기적 사용이 가능하다. (action에서 mutation을 호출하는 방법을 권장함)
// 사용자 정보 출력
actUserInfo(context, payload) {
console.log('actUserInfo', payload) // payload를 통해 검색 조건을 받을 수 있다.
const testUserInfo = {
id: payload,
name: 'test',
username: 'testUser',
email: 'test@email.com'
} // 이 값을 RestAPI에서 받아오면 된다.
context.commit('setUser', testUserInfo) // mutation을 통해 User값을 세팅 한다.
},
// 사용자 리스트 조회
actUserList(context, payload) {
console.log('actUserList', payload) // payload를 통해 검색 조건을 받을 수 있다.
const testUserList = ['user1', 'user2', 'user3'] // 이 값을 RestAPI에서 받아오면 된다.
context.commit('setUserList', testUserList) // mutation을 통해 UserList값을 세팅 한다.
}
}
}
참고 actions에서 정의하는 메소드의 첫번째 파라미터context는 보통 { commit }만 받아서 처리하는 예제가 많다.하지만 context에는 { commit }외에도 유용하게 사용할 수 있는 여러 항목들이 많이 있기 때문에 context자체를 사용해서 익숙해 지는 것을 권장 한다.
4) User List 파일 생성
/src/views/user/UserList.vue
<template><div><h1>Store Test</h1><div><h3>User List</h3><b-button variant="primary" @click="searchUserList">Search</b-button><div style="border: 1px solid red">
{{ userList }}
</div></div></div></template><script>
export default {
data() {
return {
searchParams: null // 검색 조건을 넣을 수 있음
}
},
computed: {
userList() {
return this.$store.getters.UserList
}
},
methods: {
searchUserList() {
this.$store.dispatch('actUserList', this.searchParams) // 검색 조건을 넘겨 준다.
}
}
}
</script>
- 검색: this.$store.dispatch('actUserList', this.searchParams)를 통해 검색 실행을 시킬 수 있다.
- 조회: this.$store.getters.UserList를 통해 UserList정보를 가져올 수 있다.
5) User Info 파일 생성
/src/views/user/UserInfo.vue
<template><div><h1>Store Test</h1><div><h3>User Info</h3><b-container fluid><b-row><b-col style="text-align: right">User.id</b-col><b-col style="text-align: center"><b-form-input v-model="id" placeholder="User.id를 검색하세요.(1~10)" /></b-col><b-col style="text-align: left"><b-button variant="primary" @click="searchUserInfo">Get User Info</b-button></b-col></b-row></b-container><div style="border: 1px solid red">
{{ userInfo }}
</div></div></div></template><script>
export default {
data() {
return {
id: null // 검색할 User.id
}
},
computed: {
userInfo() {
return this.$store.getters.User
}
},
methods: {
searchUserInfo() {
this.$store.dispatch('actUserInfo', this.id)
}
}
}
</script>
위와 같이 세팅된 Store의 정보는 다른 컴포넌트에서도 실시간으로 받아볼 수 있다.(this.$store.getters.User를 통해 동일한 User정보를 받을 수 있음)
'-js notes- > vue.js' 카테고리의 다른 글
vue.js기초- 백엔드와 연결 (0) | 2022.09.30 |
---|---|
vue 기초 코드 (0) | 2022.09.30 |