bdfgdfg

[Vue.js] vue/cli 폴더구조 와 디렉티브 및 함수 속성 본문

웹프로그래밍/vuejs

[Vue.js] vue/cli 폴더구조 와 디렉티브 및 함수 속성

marmelo12 2023. 12. 3. 15:52
반응형

Vue/cli 구조

모든 Vue(확장자)는 싱글파일컴포넌트로 template, script, style 태그들의 구조를 가지고 있다.

 -> 싱글파일컴포넌트란 Vue의 특징인 컴포넌트를 하나의 파일에서 작성하는것을 의미하며 template, script, style의 구조를 가지고, 화면의 특정 영역에 대한 HTML,CSS,JS 코드를 관리하는 곳이라고 보면 된다.

 

template -> 해당 vue 컴포넌트를 구성하는 HTML 태그와 Vue의 문법이 들어감

script -> js코드를 작성할 수 있고, 주로 해당 뷰 컴포넌트의 속성을 정의하는 곳

style -> template에 들어가는 HTML 태그들의 css 요소를 정의. scope라는 속성을 이용해 해당 뷰 컴포넌트에만 css 적용이 가능하게끔 할 수 있다.

 

해당 컴포넌트를 하나의 최상위 컴포넌트에 트리구조로 부착되는 형식으로 SPA(Single page Application)에 특화됨

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

createApp(App).use(router).mount('#app')

위 파일은 main.js

 

위 코드가 바로 뷰 인스턴스를 생성하고, 최상위 컴포넌트인 App 컴포넌트를 부착한 후, app이라는 속성을 가진 실제 Dom 요소에 넣어 화면에 렌더링 되게끔 하는 코드

 

또한 Vue에서는 라우터 모듈(vue add router)을 통해 url 경로에 따른 웹페이지간 전환도 편하게 할 수 있다.

위는 / 경로에서는 HomView.vue 컴포넌트를 렌더링하게 되고, /about은 AboutView.vue 컴포넌트를 렌더링 하게 된다.

라우터 폴더를 만들면 View폴더와 Component폴더를 보게 되는데, 라우팅을 위한 컴포넌트(즉 최상위 컴포넌트의 바로 자식급?)는 해당 폴더에 들어가고, 해당 라우팅을 위한 컴포넌트의 하위 컴포넌트들은 Component 폴더로 들어가는게 맞다.

 -> 이 구조를 따르지 않아도 상관없지만 직관적이니 따르는게 좋아보임

 

Vue 디렉티브

vue 디렉티브 문법은 v- 라는 접두어를 가지고 있기에 기존의 HTML 속성과 구분되어 사용된다.

 

종류로는 v-show, (v-if, v-else-if, v-else), v-for, v-on, v-bind, v-model등이 있다. 이외에도 있는거 같은데 앞에것들이 중요.

 

v-show

v-show 디렉티브는 Dom 요소를 조건부로 렌더링하기 위한 디렉티브.

조건부 렌더링이라는 표현을 하지만 실제로는 v-show조건이 false인 경우 렌더링은 하되 css의 속성인 display를 none처리 해버린다. (즉 DOM에 해당 태그는 여전히 존재한다는 의미)

<template>
  <div class="home">
    <p v-show="isShow">나는 보일까?</p>
  </div>
</template>

<script>
// @ is an alias to /src

export default {
  name: 'HomeView',
  data() {
    return {
      isShow : false
    }
  }
}
</script>

 

v-if, v-else-if, v-else

v-if,v-else-if,v-else는 조건부로 태그를 렌더링 하는데 사용된다. 해당 디렉티브들을 연속적으로 이어서 사용해야하며 중간에 다른 태그가 끼어들 수 없다.

ex)

<p v-if="testA">testA</p>
<p>안뇽</p> <!-- 에러! -->
<p v-else-if="testB">testB</p>
<p v-else>ELSE</p>

 

중간에 다른 태그가 끼어들지 않는다면.

 -> testA와 testB는 false값을 줌

v-for

v-for 디렉티브를 이용하여 배열을 리스트로 렌더링 할 수 있다. item in items 와 같은 형식을 지켜야함 

ex)

Vue에서 v-for 디렉티브를 사용할 시 key를 바인딩하도록 설명하는데 이는 Vue가 in place patch(변경된 부분만 업데이트)전략을 사용하기 때문이다. 해당 key는 리스트의 요소를 Unique하게 인식할 수 있는 값을 넣어줘야함.

 -> key가 필요한 이유는 리스트 순서가 바뀌고 해당 리스트의 요소가 다른 내용과 함께 사용되는 경우에 특히필요

 -> 만약 리스트 내용만 단순히 뿌린다면 굳이 필요하지 않을듯.

 

<template>
  <div class="home">
    <ul>
      <li v-for="user in userList" :key="user.id">
        {{ user.name}}
      </li>
    </ul>
  </div>
</template>

<script>
// @ is an alias to /src
import axios from 'axios'

export default {
  name: 'HomeView',
  data() {
    return {
      userList : []
    }
  },
  created() {
    this.getUserList();
  },
  methods : {
    async getUserList() {
      let result = await axios.get('https://jsonplaceholder.typicode.com/users')
                  .catch(err => {
                    console.log(err);
                  });
      if(result.status === 200) {
        this.userList = result.data;
      }
    }
  }
}
</script>

v-on

v-on 디렉티브는 addEventListener와 거의 동일하다고 생각된다. (event객체를 받을수도 있음)

v-on:이벤트이름="메소드 이름" 으로 정의한다.

<button v-on:click="clickBtn">버튼</button>
//축약어
<button @click="clickBtn">버튼</button>

 

<template>
  <div class="home">
    // 버튼클릭 연결 v-on:click을 @click으로 줄일 수 있음.
    <button v-on:click="clickBtn">버튼</button>  
  </div>
</template>

<script>
// @ is an alias to /src
import axios from 'axios'
//import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'HomeView',
  data() {
    return {
      userList : [],
      eventText : 'emit받기전'
    }
  },
  created() {
    this.getUserList();
  },
  methods : {
    async getUserList() {
      let result = await axios.get('https://jsonplaceholder.typicode.com/users')
                  .catch(err => {
                    console.log(err);
                  });
      if(result.status === 200) {
        this.userList = result.data;
      }
    },
    clickBtn() {
      alert('버튼을 클릭함');
    }
  }
}
</script>

 

 

또한컴포넌트 통신에서 상위 컴포넌트에 emit을 통해서 이벤트를 전달할수도 있는데 해당 인자의 문자열을 이벤트이름에 넣을 수 있다.

하위 컴포넌트에서 부모로 emit을 보내어 컴포넌트 통신을 v-on 디렉티브로 해보면

 

먼저 상위컴포넌트 코드

<template>
  <div class="home">
    <p>{{eventText}}</p>
    <HelloWorld msg="test" v-on:childEvent="eventFunc" />
  </div>
</template>

<script>
// @ is an alias to /src
import axios from 'axios'
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'HomeView',
  components : {
    HelloWorld
  },
  data() {
    return {
      userList : [],
      eventText : 'emit받기전'
    }
  },
  created() {
    this.getUserList();
  },
  methods : {
    async getUserList() {
      let result = await axios.get('https://jsonplaceholder.typicode.com/users')
                  .catch(err => {
                    console.log(err);
                  });
      if(result.status === 200) {
        this.userList = result.data;
      }
    },
    eventFunc() {
      this.eventText = 'emit을 받았습니다';
    }
  }
}
</script>

 

그리고 하위 컴포넌트 코드

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <button @click="testFunc">버튼</button>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  methods : {
    testFunc() {
      this.$emit('childEvent');
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>

</style>

하위 컴포넌트에서 버튼 태그가 있고 @click(v-on:click="testFunc"와 동일)디렉티브를 통해 부모 컴포넌트로 childEvent라는 emit값을 전달한다.

 

이후 상위 컴포넌트인 HelloWorld 태그에서

<HelloWorld msg="test" v-on:childEvent="eventFunc" />

해당 emit을 받게되는 경우 상위 컴포넌트는 eventFunc함수를 호출

eventFunc() {
      this.eventText = 'emit을 받았습니다';
    }

실행해보면

버튼은 하위컴포넌트에 정의된 요소임

 

버튼 클릭시

값이 바뀜.

 

v-bind

v-bind는 단반향 바인딩 디렉티브로 태그의 속성에 값을 바인딩을 하기 위해 사용된다.

<input type="text" v-bind:value="message">
//축약어
<input type="text" :value="message">

v-bind뒤에 오는 값은 속성에따라 정의해야한다. ex) v-bind:id, v-bind:class등등..

 

 

실제 사용코드

<template>
  <div class="home">
    <label for="id">아이디</label>
    <input id="id" type="text" :value="textMsg" /> 
  </div>
</template>

<script>

export default {
  name: 'HomeView',
  data() {
    return {
      textMsg : 'idValue',
    }
  },
  methods : {
    
  }
}
</script>

 

단방향 바인딩이기에 만약 textMsg라는 속성이 변경이 되면 반응성을 통해 화면은 변하게 되지만 사용자가 input의 값을 직접넣으면 textMsg의 값은 변하지않는다는 점.

변하지않고 있음.

 

v-model

v-model은 양방향 바인딩으로 v-bind에서 사용자가 input에다 입력한 값이 textMsg에는 반영이 안되었다면 v-model은 양방향 바인딩이기에 textMsg도 같이 업데이트가 된다. 

 

 

함수 속성(옵션 API)

data : data함수안에 해당 컴포넌트가 가지고 있는 객체등이 선언되는 곳.(뷰 컴포넌트가 사용하는 데이터)

methods : methods는 컴포넌트가 사용할 함수를 선언하는 곳. 보통 이벤트 핸들러 함수가 선언되거나 기타 사용할 함수를 정의한다.

computed - 반환되는 값이 있으며, computed안에 선언된 함수와 연결된 데이터가 바뀔 때만 해당 함수가 호출되고, 기본적으로 캐싱을 이용함. (리턴되는 값이 로직이 필요하다면 여기서 선언하는게 좋음)

export default {
  data() {
    return {
      baseValue: 10,
    };
  },
  computed: {
    computedValue() {
      // baseValue가 변경될 때만 호출되는 로직
      return this.baseValue * 2;
    },
  },
};

watch - computed가 반환되는 값이 있다면 watch는 반환되는 값은 없음. 다만 data함수에 연결된 데이터가 값이 변경되면 추가적인 action(콜백)을 취할 수 있음.

export default {
  data() {
    return {
      valueToWatch: 'initial value',
    };
  },
  watch: {
    valueToWatch(newValue, oldValue) {
      // 값이 변경될 때마다 호출되는 로직
      console.log(`Value changed from ${oldValue} to ${newValue}`);
    },
  },
};

props - 부모 컴포넌트로 부터 전달받은 속성들

created - 뷰 라이프 사이클 중 컴포넌트가 생성된 직후 호출되는 함수 (주로 데이터 초기화등의 작업)

mounted - 컴포넌트가 DOM에 부착된 후 호출되는 함수

beforeUpdate, update - 데이터가 변경되어 뷰가 업데이트 되기 '전' 과 '후'에 호출되는 함수

provide, inject - 부모 컴포넌트에서 자식에게 데이터를 전달할 떄 사용 (props와 같이 직계자식에게만 전달 할 수 있는 속성의 경우 부모노드와 자식노드간의 레벨이 2이상 차이나는경우 자식을 여러번 거쳐서 데이터가 전달되어야하지만 provide, inject를 통해 바로 전달가능)

 

 

뷰 컴포넌트 라이프 사이클

https://be-a-weapon.tistory.com/entry/Vuejs-Vue%EC%9D%98-%EB%9D%BC%EC%9D%B4%ED%94%84%EC%82%AC%EC%9D%B4%ED%81%B4

여기가 잘설명되어있음.

 

 

 

 

 

 

 

 

 

반응형

'웹프로그래밍 > vuejs' 카테고리의 다른 글

[Vue.js] $refs, 믹스인, Vuex, slot  (1) 2023.12.05
Comments