4 ๋ถ„ ์†Œ์š”

๐Ÿ“š Vue.js


๐Ÿ“š Vue.js Component

Vue Component

  • Vue์˜ ๊ฐ€์žฅ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜
  • HTML Element๋ฅผ ํ™•์žฅํ•˜์—ฌ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ๋ฅผ ์บก์Šํ™”
  • Vue์˜ ์ปดํŒŒ์ผ๋Ÿฌ์— ์˜ํ•ด ๋™์ž‘์ด ์ถ”๊ฐ€๋œ ์‚ฌ์šฉ์ž ์ง€์ • ์—˜๋ฆฌ๋จผํŠธ
  • Vue Component๋Š” Vue Instance์ด๊ธฐ๋„ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋“  ์˜ต์…˜ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉ
  • Life Cycle Hook ์‚ฌ์šฉ ๊ฐ€๋Šฅ
  • ์ „์—ญ ์ปดํฌ๋„ŒํŠธ์™€ ์ง€์—ญ ์ปดํฌ๋„ŒํŠธ



์ „์—ญ Component

  • ์ „์—ญ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋“ฑ๋กํ•˜๋ ค๋ฉด Vue.component( tagName, options ) ์„ ์‚ฌ์šฉํ•œ๋‹ค.
  • ๊ถŒ์žฅํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ ์ด๋ฆ„์€ ์ผ€๋ฐฅ ํ‘œ๊ธฐ๋ฒ•์ด๋‹ค ( ์ „๋ถ€ ์†Œ๋ฌธ์ž, - )
  • component

์ „์—ญ Component ์˜ˆ์‹œ

<div id="app">
  <my-global></my-global>
  <my-global></my-global>
</div>

<script>
  Vue.component("MyGlobal", {
    template: `<h2>์ „์—ญ ์ปดํฌ๋„ŒํŠธ์ž…๋‹ˆ๋‹ค.</h2>`,
  });
  new Vue({
    el: "#app",
  });
</script>
  • ์ถœ๋ ฅ๊ฒฐ๊ณผ



์ง€์—ญ Component

  • ์ปดํฌ๋„ŒํŠธ๋ฅผ components ์ธ์Šคํ„ด์Šค ์˜ต์…˜์œผ๋กœ ๋“ฑ๋กํ•จ์œผ๋กœ์จ ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค/์ปดํฌ๋„ŒํŠธ์˜ ๋ฒ”์œ„์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ
  • components

์ง€์—ญ Component ์˜ˆ์‹œ

<div id="app">
  <my-local></my-local>
  <my-local></my-local>
</div>
<div id="app2">
  <my-local></my-local>
  <my-local></my-local>
</div>

<script>
  new Vue({
    el: "#app",
    components: {
      "my-local": {
        template: `<h2>์ง€์—ญ ์ปดํฌ๋„ŒํŠธ์ž…๋‹ˆ๋‹ค.</h2>`,
      },
    },
  });

  new Vue({
    el: "#app2",
  });
</script>


โ€˜appโ€™ ์—์„œ component๋ฅผ ๋“ฑ๋กํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— โ€˜app2โ€™์—์„œ๋Š” component๊ฐ€ ์ถœ๋ ฅ๋˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

  • ์ถœ๋ ฅ๊ฒฐ๊ณผ



Data๋Š” ๋ฐ˜๋“œ์‹œ ํ•จ์ˆ˜์—ฌ์•ผ ํ•œ๋‹ค

<h2>Component Data ์‹ค์Šต</h2>
<div id="counter">
  <number-counter></number-counter>
  <number-counter></number-counter>
</div>
<template id="btn">
  <div>
    <span>8</span>
    <button @click="count++">ํด๋ฆญ</button>
  </div>
</template>

<script>
  Vue.component("NumberCounter", {
    template: "#btn",
    data() {
      return {
        count: 0,
      };
    },
  });
  new Vue({
    el: "#counter",
  });
</script>
  • ์ถœ๋ ฅ๊ฒฐ๊ณผ



Vue Component๊ฐ„ ํ†ต์‹ 

  • ์ƒ์œ„ ( ๋ถ€๋ชจ ) <-> ํ•˜์œ„ ( ์ž์‹ ) ์ปดํฌ๋„ŒํŠธ ๊ฐ„์˜ data ์ „๋‹ฌ ๋ฐฉ๋ฒ•
  • ๋ถ€๋ชจ์—์„œ ์ž์‹
    • props๋ผ๋Š” ํŠน๋ณ„ํ•œ ์†์„ฑ์„ ์ „๋‹ฌ ( Pass Props )
  • ์ž์‹์—์„œ ๋ถ€๋ชจ
    • event๋กœ๋งŒ ์ „๋‹ฌ ๊ฐ€๋Šฅ ( Emit Event )

์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๋กœ data ์ „๋‹ฌ

  • ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๋Š” ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ ๊ฐ’์„ ์ง์ ‘ ์ฐธ์กฐ ๋ถˆ๊ฐ€๋Šฅ
  • data์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ props ์†์„ฑ์˜ ๊ฐ’์„ template์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

props

<h2>Props Test</h2>
<div id="app">
  <child-component propsdata="์•ˆ๋…•ํ•˜์„ธ์š”"></child-component>
</div>

<script>
  // ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ
  Vue.component("ChildComponent", {
    props: ["propsdata"],
    template: `<span></span>`,
  });
  // ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ
  new Vue({
    el: "#app",
  });
</script>


  • ์ถœ๋ ฅ๊ฒฐ๊ณผ



  • ๋žœ๋”๋ง ๊ณผ์ •
    1. new Vue()๋กœ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์ธ ์ธ์Šคํ„ด์Šค๋ฅผ ํ•˜๋‚˜ ์ƒ์„ฑ
    2. Vue.component()๋ฅผ ์ด์šฉํ•˜์—ฌ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์ธ ChildComponent๋ฅผ ์ƒ์„ฑ
    3. <div id="app"> ๋‚ด๋ถ€์— <child-component> ๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋œ๋‹ค. ์ฒ˜์Œ ์ƒ์„ฑํ•œ ์ธ์Šคํ„ด์Šค ๊ฐ์ฒด ( Vue ) ๊ฐ€ #app์˜ ์š”์†Œ๋ฅผ ๊ฐ€์ง€๊ธฐ ๋•Œ๋ฌธ์— ๋ถ€๋ชจ์™€ ์ž์‹ ๊ด€๊ณ„๊ฐ€ ์„ฑ๋ฆฝํ•œ๋‹ค.
    4. ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์— props ์†์„ฑ์„ ์ •์˜ ['propsdata']
    5. html์— ์ปดํฌ๋„ŒํŠธ ํƒœ๊ทธ(child-component)๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.
    6. ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์— v-bind ์†์„ฑ์„ ์‚ฌ์šฉํ•˜๋ฉด ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์˜ data์˜ key์— ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ( message ) - ๊ทธ๋ƒฅ ๋ฌธ์ž์—ด์ด๋ฉด : ์‚ฌ์šฉ x, ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด : ์‚ฌ์šฉ
    7. ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์˜ message ์†์„ฑ ๊ฐ’์ธ String ๊ฐ’์ด ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์˜ propsdata๋กœ ์ „๋‹ฌ๋œ๋‹ค.
    8. ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์˜ template ์†์„ฑ์— ์ •์˜๋œ <span>\</span>์—๊ฒŒ ์ „๋‹ฌ๋œ๋‹ค.

๋™์  props

  • v-bind๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ถ€๋ชจ์˜ ๋ฐ์ดํ„ฐ์— props๋ฅผ ๋™์ ์œผ๋กœ ๋ฐ”์ธ๋”ฉ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋ฐ์ดํ„ฐ๊ฐ€ ์ƒ์œ„์—์„œ ์—…๋ฐ์ดํŠธ ๋  ๋•Œ๋งˆ๋‹ค ํ•˜์œ„ ๋ฐ์ดํ„ฐ๋กœ๋„ ์ „๋‹ฌ๋œ๋‹ค.
  • v-bind์— ๋Œ€ํ•œ ๋‹จ์ถ• ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ๊ฐ„๋‹จํ•˜๋‹ค.
v-bind
<child v-bind:my-message="parentMsg"></child>

๋‹จ์ถ• ๊ตฌ๋ฌธ
<child :my-message="parentMsg"></child>

  • ๋™์  props
<div id="app">
  <child-component
    v-for="(food , i) in foods"
    :key="i"
    :foods="food"
    :msg="msg[i]"
  ></child-component>
</div>

<script>
  Vue.component("ChildComponent", {
    props: ["foods", "msg"],
    template: `<h2>์—ญ์‹œ (์ด,๊ฐ€)  !! </h2>`,
  });

  new Vue({
    el: "#app",
    data() {
      return {
        foods: ["์‚ฌํƒ•", "์ดˆ์ฝœ๋ฆฟ", "๊ณผ์ž", "์Œ๋ฃŒ์ˆ˜"],
        msg: ["์ตœ๊ณ ์•ผ", "๋ณ„๋กœ์•ผ", "์งฑ์ด์•ผ", "๊ตณ์ด์•ผ"],
      };
    },
  });
</script>
  • ์ถœ๋ ฅ๊ฒฐ๊ณผ




  • ๊ฐ์ฒด์˜ ์†์„ฑ ์ „๋‹ฌ props
    • ์˜ค๋ธŒ์ ํŠธ์˜ ๋ชจ๋“  ์†์„ฑ์„ ์ „๋‹ฌ ํ•  ๊ฒฝ์šฐ, v-bind:prop-name ๋Œ€์‹  v-bind๋งŒ ์ž‘์„ฑํ•จ์œผ๋กœ์จ ๋ชจ๋“  ์†์„ฑ์„ prop์œผ๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.
post{
  id: 1,
  title: 'hello'
}
<blog-post v-bind="post"></blog-post>

// ์œ„ ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋™์ž‘
<blog-post
  v-bind:id="post.id"
  v-bind:title="post.title"></blog-post>
  • ๊ฐ์ฒด์˜ ์†์„ฑ ์ „๋‹ฌ props
<div id="app">
  <member-view
    :member="{name: 'JS', age: '44', email: 'ggg@naver.com'}"
  ></member-view>
</div>

<script>
  Vue.component("MemberView", {
    props: ["member"],
    template: `<div>
                <div>์ด๋ฆ„ : </div>
                <div>๋‚˜์ด : </div>
                <div>์ด๋ฆ„ : </div>
                </div>`,
  });
  new Vue({
    el: "#app",
  });
</script>
  • ์ถœ๋ ฅ๊ฒฐ๊ณผ



์‚ฌ์šฉ์ž ์ •์˜ ์ด๋ฒคํŠธ ( Custom Events )

  • ์ด๋ฒคํŠธ ์ด๋ฆ„
    • ์ปดํฌ๋„ŒํŠธ ๋ฐ props์™€๋Š” ๋‹ฌ๋ฆฌ, ์ด๋ฒคํŠธ๋Š” ์ž๋™ ๋Œ€์†Œ๋ฌธ์ž ๋ณ€ํ™˜์„ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š”๋‹ค.
    • ๋Œ€์†Œ๋ฌธ์ž๋ฅผ ํ˜ผ์šฉํ•˜๋Š” ๋Œ€์‹ ์— emitํ•  ์ •ํ™•ํ•œ ์ด๋ฒคํŠธ ์ด๋ฆ„์„ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅ
    • v-on์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋Š” ํ•ญ์ƒ ์ž๋™์œผ๋กœ ์†Œ๋ฌธ์ž ๋ณ€ํ™˜๋œ๋‹ค.
    • ์ด๋ฒคํŠธ ์ด๋ฆ„์€ kebab-case ( ์†Œ๋ฌธ์ž, - ์‚ฌ์šฉ ) ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ถŒ์žฅ
<h2>์‚ฌ์šฉ์ž ์ •์˜ ์ด๋ฒคํŠธ</h2>
<div id="app">
  <button v-on:click="doAction">๋ฉ”์„ธ์ง€ ์ „์†ก</button>
  <h2></h2>
</div>

<script>
  new Vue({
    el: "#app",
    data() {
      return {
        msg: "",
      };
    },
    methods: {
      doAction() {
        // ์—ฌ๊ธฐ์„œ this ๋Š” Vue, $๋Š” ์ˆจ๊ฒจ์ ธ์žˆ๋Š” ๊ฒƒ์ด๋‹ค. ์—ฌ๊ธฐ์— emit์ด ์žˆ๋‹ค.
        // ์ด๊ฒƒ์ด ์ด๋ฒคํŠธ๋ฅผ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์œผ๋กœ ๋ฐœ์ƒ
        // ๋‘๋ฒˆ์งธ ๊ฐ’์„ ์ธ์ž๋กœ ์ „๋‹ฌํ•œ๋‹ค. ์—ฌ๋Ÿฌ๊ฐœ ๊ฐ€๋Šฅ
        this.$emit("sendMsg", "์•ˆ๋…•ํ•˜์„ธ์š” !!!");
      },
    },
    crated() {
      // emit์— ๋Œ€ํ•œ ๋ฐ˜์‘, ๋ฏธ๋ฆฌ ๋ฐ›์„ ์ค€๋น„๋ฅผ ํ•˜๊ณ  ์žˆ์–ด์•ผ ํ•œ๋‹ค ( created )
      // emit ์ด๋ž‘ on ์ด๋ž‘ ๋ณ€์ˆ˜๊ฐ€ ์ง์ง๊ฟ์ด๋‹ค
      // msg == '์•ˆ๋…•ํ•˜์„ธ์š” !!!'
      this.$on("sendMsg", (msg) => {
        this.msg = msg;
      });
    },
  });
</script>
  • ์ถœ๋ ฅ๊ฒฐ๊ณผ



ํ•˜์œ„์—์„œ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ๋กœ event ์ „๋‹ฌ

<h2>ํ•˜์œ„์—์„œ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ๋กœ event ์ „๋‹ฌ</h2>

<div id="app">
  <h4>์ข‹์•„ํ•˜๋Š” ํŒŒํŠธ !!</h4>
  <h2>์ด ํˆฌํ‘œ์ˆ˜ : </h2>
  <subject v-on:addtotcount="addTotalCount" title="์ฝ”๋”ฉ"></subject>
  <subject v-on:addtotcount="addTotalCount" title="์•Œ๊ณ ๋ฆฌ์ฆ˜"></subject>
</div>

<script>
  Vue.component("Subject", {
    template: `<button v-on:click="addCount"> : 8</button>`,
    props: ["title"],
    data: function () {
      return {
        count: 0,
      };
    },
    methods: {
      addCount: function () {
        this.count += 1;
        // ๋ถ€๋ชจ v-on:์ด๋ฆ„์— ํ•ด๋‹นํ•˜๋Š” ์ด๋ฆ„์˜ ์ด๋ฒคํŠธ๋ฅผ ํ˜ธ์ถœ
        this.$emit("addtotcount");
      },
    },
  });
  new Vue({
    el: "#app",
    data: {
      total: 0,
    },
    methods: {
      addTotalCount: function () {
        this.total += 1;
      },
    },
  });
</script>
  • ์ถœ๋ ฅ๊ฒฐ๊ณผ