Jun

只要我的心還會跳,腿還能動

我就沒有理由停下前進的步伐

Vue 基礎組件間的資料傳遞


props
<body>
  <div id="app">
    <my-component :from-parent="text" />
  </div>

  <script type="text/x-template" id="my-component">
    <div>
      <div> From parent text:{{ fromParent }} </div>
      <div> From self text:{{ text }} </div>
    </div>
  </script>

  <script>
    Vue.component('my-component', {
      props: ['fromParent'],
      template: '#my-component',
      data: () => ({
        text: '來自自己',
      }),
    });

    new Vue({
      el: '#app',
      data: {
        text: '來自父組件',
      },
    });
  </script>
</body>
<body>
  <div id="app">
    <my-component :prop-a="text" />
  </div>

  <script type="text/x-template" id="my-component">
    <h1>{{ propA }}</h1>
  </script>

  <script>
    Vue.component('my-component', {
      template: '#my-component',
      props: {
        parentMsg: null, // null 代表不檢查型別
        propA: Number, // 限定數字
        propB: [String, Number], // 多種條件可用 [ ] 隔開
        propC: {
          // 必要欄位,且限定字串型別
          type: String,
          // required: true,
        },
        propD: {
          // 數字型別,且有預設值
          type: Number,
          default: 100,
        },
        propE: {
          // Object 型別,代表可接受的是個物件或陣列的型別
          type: Object,
          default: function () {
            return {
              message: 'hello',
            };
          },
        },
        propF: {
          // 自訂的條件驗證
          validator: function (value) {
            return value > 10;
          },
        },
      },
    });

    new Vue({
      el: '#app',
      data: {
        text: 123,
      },
    });
  </script>
</body>

會發生 pass by reference

<body>
  <div id="app">
    <div>來自父組件:{{ counts }}</div>
    <br />
    <my-component :count="counts"></my-component>
    <my-component :count="counts"></my-component>
    <my-component :count="counts"></my-component>
  </div>

  <script>
    Vue.component('my-component', {
      props: ['count'],
      template: `
          <div class="component">
            <span>{{ count.num }}</span>
            <button @click="plus">add</button>
          </div>
        `,
      methods: {
        plus() {
          this.count.num++;
        },
      },
    });

    new Vue({
      el: '#app',
      data: () => ({
        counts: {
          num: 0,
        },
      }),
    });
  </script>
</body>

這時可以用 function 的形式回傳一個新的值,那麼每個元件內的變數就是獨立的了

<body>
  <div id="app">
    <div>來自父組件:{{ counts }}</div>
    <br />
    <my-component :count="counts"></my-component>
    <my-component :count="counts"></my-component>
    <my-component :count="counts"></my-component>
  </div>

  <script>
    Vue.component('my-component', {
      props: ['count'],
      template: `
          <div class="component">
            <span>{{ independent }}</span>
            <button @click="plus">add</button>
          </div>
        `,
      data() {
        return {
          independent: this.count.num,
        };
      },
      methods: {
        plus() {
          this.independent++;
        },
      },
    });

    new Vue({
      el: '#app',
      data: () => ({
        counts: {
          num: 0,
        },
      }),
    });
  </script>
</body>
單向資料流
<body>
  <div id="app">
    <p>父元件:{{ text }}<input v-model="text" /></p>
    <p>元件:<my-component :from-parent="text"></my-component></p>
  </div>

  <script>
    Vue.component('my-component', {
      template: '<span>{{ fromParent }}<input v-model="message"></span>',
      props: {
        fromParent: String,
      },
      data() {
        return {
          message: this.fromParent,
        };
      },
    });

    new Vue({
      el: '#app',
      data: {
        text: 'hello',
      },
    });
  </script>
</body>
透過 $emit 更新父元件
<body>
  <div id="app">
    <p>父元件:{{ text }}<input v-model="text" /></p>
    <hr />
    <p>元件:<my-component :from-parent="text"></my-component></p>
  </div>

  <script>
    Vue.component('my-component', {
      template: `
          <span>
            {{ fromParent }}
            <input v-model="message">
            <button @click="updateText">Update</button>
          </span>
        `,
      props: {
        fromParent: String,
      },
      data() {
        return {
          message: this.fromParent,
        };
      },
      methods: {
        updateText() {
          this.$parent.$emit('update', this.message);
        },
      },
    });

    new Vue({
      el: '#app',
      data: {
        text: 'hello',
      },
      methods: {
        selfUpdate(val) {
          this.text = val;
        },
      },
      mounted() {
        this.$on('update', this.selfUpdate);
      },
    });
  </script>
</body>
event bus

我們都知道 Vuex 可以幫助我們統一管理狀態,但如果專案沒有那麼龐大或複雜的話使用 Vuex 就有些殺雞焉用牛刀的感覺,那麼我們就可以使用 event bus 來作為組件溝通的另一項選擇

<body>
  <div id="app">
    <my-component1></my-component1>
    <hr />
    <my-component2></my-component2>
  </div>

  <script>
    // event bus
    var bus = new Vue();

    Vue.component('my-component1', {
      template: `
          <div class="my-component1">
            <input v-model="text"> 
            <button @click="submit">Submit</button>
          </div>
        `,
      data() {
        return {
          text: '123',
        };
      },
      methods: {
        submit() {
          bus.$emit('receive', this.text);
        },
      },
    });

    Vue.component('my-component2', {
      template: `
          <div class="my-component2">{{ text }}</div>
        `,
      data() {
        return {
          text: '456',
        };
      },
      created() {
        bus.$on('receive', (newText) => {
          this.text = newText;
        });
      },
    });

    var app = new Vue({
      el: '#app',
    });
  </script>
</body>