All Articles

허선생님과 함께하는 Vue 기초

image.png

뷰의 특징

다른건 무조건 노드js 웹팩환경에서 바벨 돌려야 하는데 뷰는 개발환경이 굉장히 유연한 편!
웹팩을 쓰지 못하는 환경에서도 뷰를 쓸 수 있다.

또한 뷰는 웹팩기반으로 쓸 필요 없다. 예를 들어..

ex) 몰빵.html (허선생님이 5분만에 만든 내기용 파일) image.png

위와 같이 그냥 html 문서에다가 써도 된다! 리액트처럼 jsx 형식으로 안 써도 된다!
사실 jsx가 문법상 js도 html도 아니고 그냥 리액트만의 문법, 새로운 언어라고 할 수 있는데, 뷰에서 통용되는 문법은 html5와 웹 컴포넌트라는 미래용 표준 문법만으로만 만들어져있다!

문법상 표준이라서 위와 같이 작성해도 parsing error가 나지 않는다!!
하지만 표준문법에 맞는걸 써야해서 굉장히 제한적이다.

image.png

리액트와 뷰의 차이?

리액트는 1종 면허로 모는 스틱차량과 같다!
분노의 질주처럼 기어 바꿔가면서 빠르게 운전하고 싶을때 수동이 더 좋은데 마감기한이 시급한 프로젝트에는 리액트가 제격이라고 한다.

뷰는 2종 면허로 모는 오토차량과 같다.
오토차량은 기어 넣는게 없어서 운전을 처음 시작하는 사람이 몰거나 1종면허를 가지고 있는 사람이 손쉽게 몰 수 있다. 이처럼 초보자가 뷰로 작업을 해도 일정한 수준이 나온다.

설치

npx를 지원 안하기 때문에 글로벌로 깔아야한다.

설치 : npm install -g @vue/cli
버전확인 : vue --version
프로젝트 시작 : vue create 프로젝트명

설치시 manually 를 선택하면 아래와 같은 화면이 뜬다

image.png

편의상 캡쳐화면과 같이 설정을 해준다!

서버 켜기

서버 켜기 : npm run serve 를 입력하면 8080으로 서버가 들어온다.

폴더구조

image.png

views 폴더가 React에서의 pages, store가 Redux에서 store 역할을 한다.

Single File Component

뷰는 무조건 한 파일은 컴포넌트 하나이다!
하나의 컴포넌트는 template, script, style 태그로 구성되어 있다.

Component 구조

<template>
  <div></div>
</template>

<script>
export default {

};
</script>
<style scoped lang="scss">
</style>

Todo List 만들기

들어가기 앞서.. 뷰의 몇 가지 특징 더!

  • map 돌리려면 v-for를 사용한다.
  • key값 주는건 v-bind:key="todo.key"
  • 문자열 쓰려면 이렇게 {{todo.msg}}
  • 객체로 뽑아내려면 JSON.stringify 써야 한다.
  • onClick 대신에 @click="", 혹은 v-on:click 이런식으로!
  • value는 v-bind:value="땡땡"으로.. 좀 더 줄이면 :value 이렇게!
  • 뷰는 내부적으로 프록시 혹은 Object.defineProperty 사용하고 있어서 화살표함수 놉!
  • 뷰는 함수 가지고 상태변경을 하는게 아니라서 setState 안 써도 된다.

state 값을 바꾸는 예제를 간단히 살펴보자.

state 값 바꾸기

  <div>
    {{ isTrue ? "참" : "거짓" }}
    <button @click="toggleTrue">토글쓰</button>
    //생략
  </div>

<script>
export default {
  methods: {
   toggleTrue() {
      this.isTrue = !this.isTrue;
  },
}
// 생략

라잌 디스.
this로 모든게 다 해결쓰!

image.png

image.png

개발자 도구를 열어서 확인해보면 토글쓰를 누를 때마다 state 값이 바뀌는게 보인다.
물론 chrome extension 중 vue.js devtools를 깔아야 확인 가능쓰!

preventDefault 걸어주기

<template>
  <form @submit.prevent="">
      <input type="text" placeholder="할일이 뭐가 있을까~">
      <button ></button>
  </form>
</template>

위와 같이 <form @submit.prevent=""> 라고 써주면 preventDefault가 자동으로 걸린다.

뷰에서 이벤트 관리하기

뷰는 이벤트 중심적으로 설계되어 있다. emit을 이용해 하위 컴포넌트가 상위 컴포넌트에게 이벤트를 발생 시키는데, 첫번째 인자론 이벤트가 발생하는 곳, 두번째 인자론 그 이벤트에 담기는 값을 넣어준다.

emit을 이용해 이벤트를 보내기만 하면 소용이 없고 submit을 써줘야 이벤트를 받을 수 있다. 하지만 이벤트를 받지 않아도 딱히 에러는 발생하지 않는다.

아래는 로직이 들어간 CreateTodo.vue 코드이다.

//CreateTodo.vue
<template>
  <form @submit.prevent="submitTodo">
      <input type="text" placeholder="할일이 뭐가 있을까~" :value="text" @keyup="handleChange"
      />
      <input type="text" v-model="person" placeholder="누가할까?" >
      <button >확인쓰</button>
  </form>
</template>

<script>
export default {

  data() {
    return {
      text: '',
      person: '',
    };
  },
  methods: {
    submitTodo() {
      this.$emit('submit', {
        text: this.text,
        person: this.person,
      });
      this.text = '';
      this.person = '';
    },
    handleChange(ev) {
      console.log(ev.target.value);
      this.text = ev.target.value;
    },
  },
  watch: {
    //   useEffect와 같은 것~
    text() {
      this.$emit('input', this.text);
    },
  },
};
</script>

<style>

</style>

CreateTodo 컴포넌트를 App에서 불러와보면..

//App.vue
<template>
  <div>
    {{ isTrue ? "참" : "거짓" }}
    <button @click="toggleTrue">토글쓰</button>
    <CreateTodo @submit="addTo~o" v-model="textttt"/>
    <ul>
      <li v-for="todo in todos" v-bind:key="todo.key"
      :style="{ backgroundColor: todo.done ? 'blue' : 'yellow'}"
      :class="{
        done: todo.done,
        yeri: todo.person === '예리님',
      }">
        {{ todo.msg}}
        {{todo.person}}
        <button @click="e => toggleTodo(todo.key)">{{todo.done ? "완료쓰" : "완료하기"}}</button>
      </li>
    </ul>
  </div>
</template>

<script>
import CreateTodo from '@/components/CreateTodo.vue';

export default {
  components: {
    CreateTodo,
  },
  props: {
    foo: {
      required: false,
      type: Number,
      default() { return 1; },
    },
  },
  // state를 모아놓는 애들을 데이터
  data() {
    return {
      // state를 초기화
      todos: [
        { key: 1, msg: '밥먹기', done: false },
        { key: 2, msg: '화장실가기', done: false },
        { key: 2, msg: '잠자기', done: false },
      ],
      isTrue: true,
      textttt: '',
    };
  },
  methods: {
    toggleTodo(key) {
      this.todos = this.todos.map(todo => ((todo.key === key)
        ? { ...todo, done: !todo.done }
        : todo));
    },
    console(...value) {
      value.forEach(console.log);
    },
    toggleTrue() {
      this.console('ddd');
      this.isTrue = !this.isTrue;
    },
    addTodo({ text, person }) {
      this.todos = this.todos.concat({
        key: Date.now(),
        msg: text,
        person,
        done: false,
      });
    },
  },
};
</script>
<style scoped lang="scss" >
$color: #f0f3f6;
ul,li {
  padding: 0;
  list-style: none;
  background-color: $color;
}
</style>

image.png

위의 코드로 완성된 화면은 이렇게 뙇!
근데 가운데의 화장실가기와 잠자기는 묶여있는지 뭘 눌러도 둘이 같이 선택이 된다.
이건 나중에 왜 그런지 원인을 파악해볼 예정쓰..!

급하게 마무리하는 것 같지만 나는 얼른 나가야하므로.. 다음 기회에 뷰를 쓰게될 일이 생긴다면 더 열심히 정리해볼 생각이다!

Reference

  • 허선생님의 꿀같은 강의