Vue

Vue시작해보기

jennyiscoding 2022. 8. 2. 10:12

설치하는 방법 :

npm install -g @vue/cli

시작부터 에러남.. 

그래서 파워쉘에서 권한 모드 변경해주었음. 

프로젝트를 만들기 위해 아래 코드 실행

vue create hello-world

버전은 2로 선택

샘 따라서 그냥 yarn으로 설치햇음.. 

 

헬로월드 폴더로 들어가서 

yarn serve실행. 

 

8081포트에서 돌아가고있음. 

 

크롬에서 Vue.js devtools다운받기!

또 App.js열었더니 오류발생.. 

찾아서 해결함.. 

vue글자가 하얀색으로 나와서 확장프로그램 설치했다. 

그리고 자동완성이 안되어서 

setting.json파일에 아래처럼 써주었다

 
{
    "eslint.workingDirectories": [
    {"mode": "auto"}
    ],
    "emmet.syntaxProfiles":{
		"vue-html":"html",
		"vue":"html"
    }
}

샘이 이거 설치하라고해서 설치도했음. 

이것도함. 

 

Helloworld컴포넌트 다 지우고 시작해보자. 

TodoList.vue라는 파일 만듬. 

vueinit치고 탭누르면 자동완성된다 

<template lang="">
    <div>
        
    </div>
</template>
<script>
export default {
    
}
</script>
<style lang="">
    
</style>

컴포넌트를 만들어보자. 

<template>
    <div>
        <div>
            <input type="text">
            <button>추가하기</button>
        </div>
    </div>
</template>
<script>
export default {
    
}
</script>
<style lang="">
    
</style>

이제 임포트해보겠다. 

App.vue코드  : 

<template>
  <div id="app">
    <TodoList />
  </div>
</template>

<script>
import TodoList from "./components/TodoList";
export default {
  name: 'App',
  components : {
    TodoList,
}
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

잘나옴. 

ListItem.vue라는 파일을 만듬. 

<template>
    <li>리스트 아이템입니다</li>
</template>
<script>
export default {
    
}
</script>
<style lang="">
    
</style>

이거를 TodoList.vue에 임포트하고 Input을 선언, 사용해보겠다. 

TodoList.vue : 

<template>
    <div>
        <div>
            <input type="text" v-model="inputValue" >
            <button>추가하기</button>
            <ListItem />
        </div>
    </div>
</template>
<script>
import ListItem from "./ListItem";
export default {
    data(){ //함수다 data는 객체안에서사용할 상태리턴하면됨
        return{
            inputValue : ""
        }
    },
    components : {
    ListItem,
    }
}
</script>
<style lang="">
    
</style>

이렇게만 했을뿐인데!?

input창에 치는 글짜가 바로 상태관리가 됨!! 

이번에는 리턴에 listArray를 선언했다. 

<template>
    <div>
        <div>
            <input type="text" v-model="inputValue" />
            <button>추가하기</button>
        </div>
        <ul>
            <ListItem />
        </ul>
    </div>
</template>
<script>
import ListItem from "./ListItem";
export default {
    data(){ //함수다 data는 객체안에서사용할 상태리턴하면됨
        return{
            inputValue : "",
            listArray : []
        }
    },
    components : {
    ListItem,
    }
}
</script>
<style lang="">
    
</style>

다음으로는 이벤트를 만들어주자. 

@click="" 이런식으로 만들면 된다. 

<template>
    <div>
        <div>
            <input type="text" v-model="inputValue" />
            <button @click="">추가하기</button>
        </div>
        <ul>
            <ListItem />
        </ul>
    </div>
</template>
<script>
import ListItem from "./ListItem";
export default {
    data(){ //함수다 data는 객체안에서사용할 상태리턴하면됨
        return{
            inputValue : "",
            listArray : []
        }
    },
    components : {
    ListItem,
    },

}
</script>
<style lang="">
    
</style>

이제 함수를 만들면된다. 함수는? method라는 방식으로 만든다. 

this라는 것을 사용해야 한다. 

<template>
    <div>
        <div>
            <input type="text" v-model="inputValue" />
            <button @click="addItem">추가하기</button>
        </div>
        <ul>
            <ListItem />
        </ul>
    </div>
</template>
<script>
import ListItem from "./ListItem";
export default {
    data(){ //함수다 data는 객체안에서사용할 상태리턴하면됨
        return{
            inputValue : "",
            listArray : []
        }
    },
    components : {
    ListItem,
    },
    methods: {
        addItem(){
            this.listArray.push(this.inputValue);
            this.inputValue = "";
        }
    }
}
</script>
<style lang="">
    
</style>

허걱 여기까지 만들면 이렇게 나온다. 

이제 ListItem에 넣어보자. 

vue의 for문 사용과 key넣기, 스타일 넣기는 아래와 같다. 

<template>
    <div>
        <div>
            <input type="text" v-model="inputValue" />
            <button @click="addItem">추가하기</button>
        </div>
        <ul>
            <ListItem v-for="(value, index) in listArray" :key="index"
            :style="style"/>
        </ul>
    </div>
</template>
<script>
import ListItem from "./ListItem";
export default {
    data(){ //함수다 data는 객체안에서사용할 상태리턴하면됨
        return{
            inputValue : "",
            listArray : [],
            style: {
                color: "red"
            }
        }
    },
    components : {
    ListItem,
    },
    methods: {
        addItem(){
            this.listArray.push(this.inputValue);
            this.inputValue = "";
        }
    }
}
</script>
<style lang="">
    
</style>

출력하면 리스트 개수만큼 ListItem컴포넌트가 호출된다. 

이제 컴포넌트에 벨류를 넣어보자. 

이제 프롭스로 전달해보자. 

 

첫번째 방법. 

ListItem.vue

<template>
    <li>{{text}}</li>
</template>
<script>
export default {
    props: ["text"]
}
</script>
<style lang="">
    
</style>

그리고 TodoList에서도 text를 전달한다. 

<template>
    <div>
        <div>
            <input type="text" v-model="inputValue" />
            <button @click="addItem">추가하기</button>
        </div>
        <ul>
            <ListItem v-for="(value, index) in listArray" :key="index"
            :text="value"
            />
        </ul>
    </div>
</template>
<script>
import ListItem from "./ListItem";
export default {
    data(){ //함수다 data는 객체안에서사용할 상태리턴하면됨
        return{
            inputValue : "",
            listArray : [],
        }
    },
    components : {
    ListItem,
    },
    methods: {
        addItem(){
            this.listArray.push(this.inputValue);
            this.inputValue = "";
        }
    }
}
</script>
<style lang="">
    
</style>

더 좋은 방법은 객체로 받아서 타입을 정해주는 것이다. 

ListItem.vue

<template>
    <li>{{text}}</li>
</template>
<script>
export default {
    props: {
        text: {
            type : String
        }
    }
}
</script>
<style lang="">
    
</style>

required를 사용하면 꼭 입력값이 있어야한다는 것을 사용할수도 있다. 

<template>
    <li>{{text}}</li>
</template>
<script>
export default {
    props: {
        text: {
            type : String,
            required : true
        }
    }
}
</script>
<style lang="">
    
</style>

default값을 넣으면 값이없으면 무조건 이거를 넣어주는 역할도 해준다.

<template>
    <li>{{text}}
        <button >삭제</button>
    </li>
</template>
<script>
export default {
    props: {
        text: {
            type : String,
            required : true,
            default : "안녕!"
        }
    }
}
</script>
<style lang="">
    
</style>

이제 삭제 기능을 구현해보자. 

먼저, ListItem.vue에 삭제 버튼을 만든다. 

<template>
    <li>{{text}}</li>
</template>
<script>
export default {
    props: {
        text: {
            type : String,
            required : true,
            default : "안녕!"
        }
    }
}
</script>
<style lang="">
    
</style>

뷰에서는 이밋 기능을 사용하면 된다. 

먼저, TodoList.vue에서 index를 보내준다. 

<template>
    <div>
        <div>
            <input type="text" v-model="inputValue" />
            <button @click="addItem">추가하기</button>
        </div>
        <ul>
            <ListItem v-for="(value, index) in listArray" 
            :key="index"
            :text="value" 
            :index="index"
            />
        </ul>
    </div>
</template>
<script>
import ListItem from "./ListItem";
export default {
    data(){ //함수다 data는 객체안에서사용할 상태리턴하면됨
        return{
            inputValue : "",
            listArray : [],
        }
    },
    components : {
    ListItem,
    },
    methods: {
        addItem(){
            this.listArray.push(this.inputValue);
            this.inputValue = "";
        }
    }
}
</script>
<style lang="">
    
</style>

그 다음에는 ListItem.vue에서 클릭에 itemDelete함수를 만들어서 위로 올렸다. 

<template>
    <li>{{text}}
        <button @click="itemDelete">삭제</button>
    </li>
</template>
<script>
export default {
    props: {
        index : {
            type : Number
        },
        text: {
            type : String,
            required : true,
            default : "안녕!"
        }
    },
    methods: {
        itemDelete(){
            this.$emit('delete', this.index)
        }
    }
}
</script>
<style lang="">
    
</style>

이제 TodoList에서 emit으로 받은 것을 캐칭하는 것은 간단하다. 

TodoList.vue

<template>
    <div>
        <div>
            <input type="text" v-model="inputValue" />
            <button @click="addItem">추가하기</button>
        </div>
        <ul>
            <ListItem 
                v-for="(value, index) in listArray" 
                :key="index"
                :index="index"
                :text="value === '' ? undefined : value"
                @delete="catchDeleteItem"
            />
        </ul>
    </div>
</template>
<script>
import ListItem from "./ListItem";
export default {
    data(){ 
        return{
            inputValue : "",
            listArray : [],
        }
    },
    components: {
        ListItem
    },
    methods: {
        addItem(){
            this.listArray.push(this.inputValue);
            this.inputValue = "";
        },
        catchDeleteItem(index){
            console.log(index)
        }
    },
}
</script>
<style lang="">
    
</style>

이렇게 캐칭이 되는 것이다. 

삭제 기능을 모두 만들어보자. 

<template>
    <div>
        <div>
            <input type="text" v-model="inputValue" />
            <button @click="addItem">추가하기</button>
        </div>
        <ul>
            <ListItem 
                v-for="(value, index) in listArray" 
                :key="index"
                :index="index"
                :text="value === '' ? undefined : value"
                @delete="catchDeleteItem"
            />
        </ul>
    </div>
</template>
<script>
import ListItem from "./ListItem";
export default {
    data(){ 
        return{
            inputValue : "",
            listArray : [],
        }
    },
    components: {
        ListItem
    },
    methods: {
        addItem(){
            this.listArray.push(this.inputValue);
            this.inputValue = "";
        },
        catchDeleteItem(index){
            this.listArray.splice(index,1)
        }
    },
}
</script>
<style lang="">
    
</style>

-- 라우터 만들기 

다운받는법 : vue add router

터미널 창에 치고 엔터 

YES

YES

알아서 라우터와 뷰라는 것들을 만들어준다. 

 

yarn serve로 서버 실행해본다. 

라우터 폴더가 생겼다. 

화면도 이렇게 바꼈다 

Board라는 새로운 라우터를 열어보자. 

파일구조 : 

Board.vue 

<template>
    <div class="board">
        이곳은 게시판 입니다
    </div>
</template>

<script>
export default {
    name: "Board_",
}
</script>
<style lang="">
    
</style>

index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '../views/HomeView.vue';
import Board from "../views/Board.vue"

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    path: '/about',
    name: 'about',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
  },
  {
    path: '/board',
    name: 'Board_',
    component: Board
  }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router

App.vue

<template>
  <div id="app">
    <nav>
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link> |
      <router-link to="/board">Board</router-link>
    </nav>
    <router-view/>
  </div>
</template>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

nav {
  padding: 30px;
}

nav a {
  font-weight: bold;
  color: #2c3e50;
}

nav a.router-link-exact-active {
  color: #42b983;
}
</style>

그렇다면 url 중에

localhost:3000/user/@jenny

이런거는 어떻게 할까? 

 

요기가 공식문서

https://router.vuejs.org/guide/essentials/dynamic-matching.html

 

index.js에서 url을 조금 바꿨다. 

import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '../views/HomeView.vue';
import Board from "../views/Board.vue"

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    path: '/about',
    name: 'about',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
  },
  {
    path: '/board/:id',
    name: 'Board_',
    component: Board
  }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router

이렇게 바꾸면 url에서 board뒤에 

localhost:3000/board/news 라고 치면 news를 감지할 수 있는 것이다. 

라우트를 추가하면 $route라는 객체가 자동적으로 추가가 된다.

그래서 params라는 부분에 접근할 수 있는 것이다. 

 

Board.vue코드 

<template>
    <div class="board">
        이곳은 {{boardName}}게시판 입니다
    </div>
</template>

<script>
export default {
    name: "Board_",
    data(){
        return{
            boardName : ""
        }
    },
    created(){
        this.boardName = this.$route.params.id;
    }
}
</script>
<style lang="">
    
</style>

crated ()  : 뷰가 처음 생기는 시점에서 호출되는 것. 

url로 준 params가 boardName이라는 변수에 들어가는 것이다. 

 

다음으로는 쿼리스트링에 대해 알아보자. 

종종 이런 주소를 본다. 

http://localhost:8081/board/sports?articleId=300

이거는 어떻게 처리가 될까?

query로 들어가는 것을 볼수있다. 

두개 넣으려면 &를 쓴다. 

http://localhost:8081/board/sports?articleId=300&token=sklfj 라고 쓰면

 

그리고 이렇게 할수도 있다. 

Board.vue코드 : 

<template>
    <div class="board">
        이곳은 {{$route.params.id}}게시판 입니다
        파라미터를 뽑으려면 {{$route.query.name}}이렇게 합니다.
    </div>
</template>

<script>
export default {
    name: "Board_",
}
</script>
<style lang="">
    
</style>

http://localhost:8081/board/sports?name=JENNY 라고 치면 결과는 이렇게 나온다. 

 

App.vue파일을 이렇게 바꿀수도 있다. 

name : ' ~  ' => 이부분 무조건 따옴표. 쌍따옴표 쓰면 에러남. 

 

<template>
  <div id="app">
    <nav>
      <router-link :to="{name:'home'}">Home</router-link> |
      <router-link :to="{name:'about'}">About</router-link> |
      <router-link :to="{name:'Board_'}">Board</router-link>
    </nav>
    <router-view/>
  </div>
</template>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

nav {
  padding: 30px;
}

nav a {
  font-weight: bold;
  color: #2c3e50;
}

nav a.router-link-exact-active {
  color: #42b983;
}
</style>

 

보통은 이렇게 객체 형태로 쓴다. 

안에 파라미터도 넣어보자. 

App.vue 파일

<template>
  <div id="app">
    <nav>
      <router-link :to="{name:'home'}">Home</router-link> |
      <router-link :to="{name:'about'}">About</router-link> |
      <router-link :to="{name:'Board_', params: {name: 'newsㄴㄴ'}}">게시판</router-link>
    </nav>
    <router-view/>
  </div>
</template>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

nav {
  padding: 30px;
}

nav a {
  font-weight: bold;
  color: #2c3e50;
}

nav a.router-link-exact-active {
  color: #42b983;
}
</style>

Board.vue파일

<template>
    <div class="board">
        이곳은 {{$route.params.name}}게시판 입니다
        파라미터를 뽑으려면 {{$route.query.name}}이렇게 합니다.
    </div>
</template>

<script>
export default {
    name: "Board_",
}
</script>
<style lang="">
    
</style>

결과 : 

 

query도 넣는다면?

App.vue

<template>
  <div id="app">
    <nav>
      <router-link :to="{name:'home'}">Home</router-link> |
      <router-link :to="{name:'about'}">About</router-link> |
      <router-link :to="{name:'Board_', params: {name: 'news'}, query:{search:'검색어'}}">게시판</router-link>
    </nav>
    <router-view/>
  </div>
</template>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

nav {
  padding: 30px;
}

nav a {
  font-weight: bold;
  color: #2c3e50;
}

nav a.router-link-exact-active {
  color: #42b983;
}
</style>

결과 :