Ryu.log

[Vue] Vue JS 본문

Front-end/Vue JS

[Vue] Vue JS

류뚝딱 2020. 12. 24. 15:40

Vue Study

Created: Aug 7, 2020 5:35 PM
Tags: Vue
요약: Vue JS Study

Vue JS

Webpack 사용없이 먼저 basic한 Vue를 먼저 사용해본다.

유용한 자료

Vue.js 2.3 CheatSheet

1. Vue 의 Basic 구조

<body>
  <div id="root"></div>
  <script>
    const app = new Vue({
      el: '#root',
      data: {},
      methods: {}
    })
  </script>
</body>

basic한 기본 구조

  • el
    Vue 와 html Element를 연결하여 Vue가 관리하게 한다. (Vue에게 테그 통제권을 넘긴다.)
  • data
    Vue 에서 사용할 data 들의 집합.
  • methods
  • Vue 에서 사용 할 methods 들의 집합.*

v-model

<div id="root">
  <input type="number" v-model="value">
    <div>{{value}}</div>
</div>
<script>
  const app = new Vue({
    el: '#root',
    data: {
      value: '',
    },
    methods: {}
  })
</script>

v-model

input테그와 data를 연결시켜준다.
input 테그에서 데이터 입력 시
vue에서 관리하는 data 부분인 value 변수와 동기화시켜 양방향 바인딩이 가능하도록 제공한다.

Event 핸들링

<div id="root">
    <form v-on:submit="onSubmitForm">
      <input type="number" v-model="value">
      <button type="submit">입력</button>
    </form>
    <div>{{result}}</div>
</div>
<script>
  const app = new Vue({
      el: '#root',
      data: {
        value: '',
        result: '',
      },
      methods: {
        onSubmitForm(e) {
          e.preventDefault(); // submit시 form 테그의 기본기능으로 인해 페이지가 리로드 되는 현상 을 방지함
            this.result = 'Submit!!';
            this.value = '';
        }
      }
    })
</script>

Event 핸들링

Vue에서 제공하는 이벤트 리스너 기능,
v-on: 접두사를 붙혀 사용한다.
v-on:submit="onSubmitForm" 부분을 잘 보면 form이 submit 될 때
Vue methods 에 담긴 onSubmitForm 함수를 실행시킨다.

앞쪽에 v-on: 접두사만 붙힌다면 대부분의 기존 JS 에서 사용되는 이벤트 리스너들 사용이 가능하다.( click, fucus, mouseover 등등...)
@click 과같이 축약형으로도 사용가능함.

Ref

<div id="root">
    <form v-on:submit="onSubmitForm">
      <input type="number" v-model="value" ref="answer">
      <button type="submit">입력</button>
    </form>
    <div>{{result}}</div>
</div>
<script>
  const app = new Vue({
      el: '#root',
      data: {
        value: '',
        result: '',
      },
      methods: {
        onSubmitForm(e) {
          e.preventDefault(); // submit시 form 테그의 기본기능으로 인해 페이지가 리로드 되는 현상 을 방지함
            this.result = 'Submit!!';
            this.value = '';
                        this.$refs.answer.focus();
        }
      }
    })
</script>

ref

Vue 에서 HTML element에 접근 하고 싶을 때 사용된다.
this.$refs 를 사용하여 접근할 수 있다.

@ 주의사항 : Ref 사용 시, 예제와같이 focus같은 형식의 함수를 사용하는건 무방하나,
this.$refs.answer.value = '임의의값' 이런형식으로 value 값을 바꾸게 되면
Vue에서 관리하는 data와 화면이 일치하지 않게 될 수 도있기 때문에,
정말 사용해야 할 때가아니라면 위와같은 방식으로 접근하지 않는다.

v-if, v-else

<div id="root">
    <div v-if="btn">버튼 눌림</div>
    <button v-else v-on:click="onClickButton">Button</button>
</div>

<script>
    const app = new Vue({
        el: '#root',
        data: {
            btn: false
        },
        methods: {
            onClickButton() {
                this.btn = true;
            }
        }
    })
</script>

v-if, v-else

Vue에서 조건부 분기 처리를 할 때 사용됨,
단순하게 조건문이라 생각하면 된다.
v-if 접두사를 붙혀 사용 하게 되면, 조건에 맞게 html이 그려진다.

즉, data.btn은 false기 때문에, 첫 랜더링 시에는 <div v-if="btn">버튼 눌림</div> 이 보이지 않을것이고,
버튼을 클릭하여 data로 관리하는 btn 을 true로 변경하게 되면,
<button v-else v-on:click="onClickButton">Button</button> 부분이 사라지고,
<div v-if="btn">버튼 눌림</div> 부분이 나타날 것이다.

비슷하게 화면을 보였다 안보였다 하는 기능인 v-show 도 존재한다.
단순히 true/false 값으로 화면을 보여주거나 안보여주는것이 가능하다.

v-else-if

<div v-if="type === 'A'">
  A
</div>
<div v-else-if="type === 'B'">
  B
</div>
<div v-else-if="type === 'C'">
  C
</div>
<div v-else>
  Not A/B/C
</div>

v-else-if
이름에서 알 수 있듯, v-if에 대한 else if 블록 역할을 한다. 또한 여러 개를 사용할 수 있다.

Component 의 필요성

Component 시스템을 사용하는 가장 대표적인 이유는 같은 컨텐츠를 반복적으로 사용하기 위해서 이다.

component의 기본구조

<div id="root">
    <btn-press></btn-press>
    <btn-press></btn-press>
    <btn-press></btn-press>
</div>

<script>
Vue.component('btn-press', {
  template: `
  <div>
    <div v-if="btn">버튼 눌림</div>
        <button v-else v-on:click="onClickButton">{{text}</button>
  </div>
  `,
  data() {
    return {
        btn: false
            text: 'button'
    }
  },
  methods: {
    onClickButton() {
            this.btn = true;
        }
  }
})
</script>
<script>
    const app = new Vue({
        el: '#root',
    })
</script>

Component

상단에서 진행한 버튼눌림 상태변경 메소드를 이용해서 컴포넌트를 만들어보면,
기존방식과 몇가지 다른 형태가 보인다.

  • Vue.component() 라는 Vue 인스턴스를 사용함
  • data부분이 함수로변경되고 리턴되는 객체에 사용할 data변수를 담는다.
  • template 속성에 기존 사용하던 HTML element를 넣어준다.
  • <btn-press></btn-press> 와 같은 방식으로 사용되며,
    같은 data를 공유 하지 않고 각각이 전혀 다른 data를 이용하여 랜더링을함으로 써
    여러번 중복하여 사용하여도 무방하다.

Props

Component를 만들다보면 반복적으로 사용되는 컨텐츠 이지만 컨텐츠 안쪽 내용이 달라야 할 경우가 있다. 이 때 props를 사용하여 해결한다.

<div id="root">
    <btn-press start-text="button1"></btn-press>
    <btn-press start-text="button2"></btn-press>
    <btn-press start-text="button3"></btn-press>
</div>

<script>
Vue.component('btn-press', {
  template: `
  <div>
    <div v-if="btn">버튼 눌림</div>
        <button v-else v-on:click="onClickButton">{{text}}</button>
  </div>
  `,
    props: ['startText'],
  data() {
    return {
        btn: false,
            text: this.startText
    }
  },
  methods: {
    onClickButton() {
            this.btn = true;
        }
  }
})
</script>
<script>
    const app = new Vue({
        el: '#root',
    })
</script>

props

위 예시와 같이 props를 받아 초기값을 세팅하여 렌더링이 가능하다.
참고사항으로는 React 와 다르게 Vue 에서는 props 이름을 지정할 때나, 컴포넌트 이름을 지정할 때,

HTML Tag 부분 에서는 Autribute사용과 동일하게 케밥케이스로 입력해야하나.
script 부분에서는 케밥케이스를 카멜케이스로 입력하여도 자동으로 변환하여 동일한 결과물을 출력해 줄 수 있다.

script 부분 start-text === startText

Vue에서 Webpack을 사용하는 이유

Vue프로젝트 진행 시, 위에서 진행한 예제를 빗대어보면, 아주간단한 버튼눌리는 기능을 구현하는데
컴포넌트를 반복적으로 한페이지에 계속하여 script 테그 내에 입력하여 개발진행 하는 것은 비효율적이다.

이런 문제를 해결하기 위해 Webpack을 사용한다.
Webpack을 사용하면, module 시스템을 지원하여 각각의 컴포넌트를
import export 구문을 통해 내보내고 가져올 수 있어서,
위 문제를 해결할 수 있으며, 관리하기 쉬워지며 코드가 깔끔해지는 이점이 있다.

v-for 을 이용한 반복문사용

<template></template> 내에서 템플릿 작성시 반복되는 컨텐츠를 v-for 을 이용하여 반복문 처리가 가능하다.

<template>
  <ul>
    <li v-for="item in items" v-bind:key="item">
      <div>{{ item }}</div>
    </li>
  </ul>
</template>

<script>
export default {
   data() {
    return {
      items: ['item01', 'item02', 'item03', 'item04'],
    }
  }
}
</script>

v-for

v-for을 이용하여 for loop를 돌릴때 주의할점은 v-bind:key 값으로 key값이 될만한 값을넘겨야 한다.
React에서 배열에 map() 함수 사용시에 key값 넘기지않으면 나오는 오류와 비슷하게 생각하면 된다.

v-bind를 사용하여 템플릿에 바인드하기

v-bind 를 사용하면 템플릿안에서 자바스크립트 문법이나 data값들을 바인딩시킬 수 있다.

<template>
  <div id="screen" v-bind:class="state">{{message}}</div>
</template>
<script>
export default {
   data() {
    return {
      state: 'waiting',
      message: 'v-bind example'
    }
  },
  methods: {
  },
}
</script>
<style scoped>
  #screen {
    width:300px;
    height: 200px;
    text-align:center;
    user-select: none;
  }
  #screen.waiting {
    background:aqua;
  }
</style>

v-bind

위와같이 원하는 class 값에 v-bind 디렉티브를 이용하여 data값을 바인딩 시켜주면
템플릿 내에서 JavaScript 표현식을 사용 할 수 있기 때문에 methods로 적절히 컨트롤 해주면 강력한 기능을 사용할 수 있다.

축약형으로는 v-bind:class="":class="" 이런 방식으로도 사용 가능하다.

computed

<template></template> 쪽에서도 간단한 로직 정도는 계산하여 사용 할 수 있다.

<template>
    <div>
      <div id="screen" v-bind:class="state">{{message}}</div>
        <div>{{array.reduce((a, c) => a + c, 0) / this.result.length || 0}}</div>
    </div>
</template>
<script>
export default {
   data() {
    return {
            array: [10,20,30],
      state: 'waiting',
      message: 'v-bind example'
    }
  },
  methods: {
  },
}
</script>

그러나 작업을 진행하며 로직이 복잡해지거나 길어질때 template쪽에 다 작성하는 것은 옳지 않다
어느정도 로직있는 계산식이라면 computed 를 사용하는게 옳다.

<template>
    <div>
      <div id="screen" v-bind:class="state">{{message}}</div>
        <div>{{average}}</div>
    </div>
</template>
<script>
export default {
   data() {
    return {
            array: [10,20,30],
      state: 'waiting',
      message: 'v-bind example'
    }
  },
    computed: {
        average() {
      return this.array.reduce((a, c) => a + c, 0) / this.result.length || 0;
    }
    }
  methods: {
  },
}
</script>

computed

Vue 는 data가 변경될 시 리랜더링이 일어난다.
이때 기존처럼 template 쪽에 로직을 구현하면 리랜더링이 일어날때마다 해당 로직을 다시 계산한다.

computed 에서 이러한 로직을구현하게 되면 data.message가 변경되어 리랜더링이 일어나더라도
average는 캐싱되어 값을 기억하여 쓸데없이 다시 계산하는 낭비를 방지할 수 있다.

성능에 영향이 많은 computed는 꼭 신경써서 챙기는게 좋다.

v-show

v-showv-if와 비슷하게 element를 show, hide를 시켜줄수 있다.

<template>
    <div>
      <div id="screen" v-bind:class="state">{{message}}</div>
      <div v-if="array.length">{{average}}</div>
        <div v-show="array.length">{{average}}</div>
    </div>
</template>
<script>
export default {
   data() {
    return {
            array: [10,20,30],
      state: 'waiting',
      message: 'v-bind example'
    }
  },
    computed: {
        average() {
      return this.array.reduce((a, c) => a + c, 0) / this.result.length || 0;
    }
    }
  methods: {
  },
}
</script>

v-show

위와같이 보통은 두가지 방식을 사용하여 show, hide 처리를 한다.
조금더 조건여부를 더 넣어줄수있는 v-if 를 많이 사용한다고 한다.

v-showv-if 는 비슷하지만 약간의 차이가 있다.
v-if 는 조건이 true 일 때 화면에 element를 포함시켜 랜더링 하지않는다.
v-show 는 조건이 true 일 때 화면에 element를 포함시켜 랜더링하고 style display:none; 속성을 삽입하여 hide 처리를 한다.

template

<template></template> 영역 안에서 element들은 꼭 최상위 부모 element가 존재하여야한다.
이때 의미없는 div 테그로 한번 감싸주어야 하는 상황이 발생하는데,
<template></template> 안에서 한번더 <template></template> 로 감싸주게되면
이를 방지 해줄 수있다.

<template>
    <template>
      <div id="screen" v-bind:class="state">{{message}}</div>
        <div v-show="array.length">{{average}}</div>
    </template>
</template>

template

<template></template> 테그로 감싸서 빌드를하게되면 완료된 파일을 크롬 디버거로 열어보면
<template></template> 테그는 Dom에 별다른 노드를 추가하지않고 안쪽 children 들만 추가한다.

<template></template>Vue 에서는 감싸주는 역할로 쓸 수 있다.
물론 v-show v-if 등 다른 element와 동일하게 Vue 디렉티브를 사용하는것도 가능하다.

React 에서 <></> Fragment Component로 감싸주는것과 동일한 기능이라고 생각하면 될 것 같다.

Comments