【Vue3从零开始-第三章】3-3 vue组件单项数据流

1,330 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第16天,点击查看活动详情

前言

上一章的文章中,我们了解了vue组件之间传值的方式,今天我们继续深入了解一下vue的组件单项数据流,并在本章内容中在补充一些组件传值的知识点。

单项数据流的概念

在【vue3从零开始】的第一篇文章中,我们写过一个计数器的案例,下面我们就通过组件结合计数器来给大家讲解一下单项数据流的概念

<script>
  const app = Vue.createApp({
    data(){
      return {
        num: 1
      }
    },
    template: `
      <div>
        <hello :count="num" />
      </div>
    `
  });

  app.component('hello', {
    props: ['count'],
    template: `
      <div @click="count += 1">{{count}}</div>
    `
  })

  const vm = app.mount('#root');
</script>

首先我们定义一个父子组件,在父组件中定义了一个数据值num,并通过count属性传递给子组件。在子组件中,我们通过props接收父组件传递过来的count属性。

然后在子组件中,当我们点击DOM元素的中的count值时,会执行一个count + 1的操作。

Kapture 2022-04-17 at 18.09.07.gif

在之前的内容中,如果我们是在vue实例中的根组件写计数器的案例,是可以出现点击 + 1 的效果,但是在组件中点击了为啥没效果呢?

  • 我们在浏览器控制台已经看到效果了,当点击count值时,控制台会输出错误信息。提示我们props接收到的count是一个只读的,不可以修改。

[Vue warn]: Attempting to mutate prop "count". Props are readonly.

小结一下

单项数据流:父组件可以向子组件传递一些数据,子组件也可以接收到父组件传递过来的数据,但是子组件不允许直接修改父组件中的数据。

如果子组件想要实现这个计数器功能该怎么办呢?

app.component('hello', {
    props: ['count'],
    data(){
      return {
        myCount: this.count
      }
    },
    template: `
      <div @click="myCount += 1">{{myCount}}</div>
    `
})

这时候我们可以在子组件中定义一个属于自己的数据值myCount,这个数据值会去接收父组件传递过来的count的值,然后在子组件的模板中就可以执行myCount + 1的事件了。

chrome-capture (4).gif

疑问??????

为啥在vue里面会出现单项数据流呢?

在之前的内容中,我们了解过一个子组件定义之后,可以在其他组件里面调用多次这个子组件。

const app = Vue.createApp({
    data(){
      return {
        num: 1
      }
    },
    template: `
      <div>
        <hello :count="num" />
        <hello :count="num" />
        <hello :count="num" />
      </div>
    `
  });

如果此时我们点击第一个子组件标签就会执行子组件里面的count + 1的操作,但是count是父组件里面传递过来的值,那么就相当于修改了父组件里面data中的num数据值,这时候在父组件里面的其他两个子组件标签也会同时被修改,那每个组件之间的数据就没有完全的区分开了,就不符合vue组件里面的数据唯一性了,也会避免以后维护中出现的一些潜在的bug。

补充组件传值内容

在组件传值中,我们知道传递数据的时候可以通过静态传值或者动态传值给子组件传递一些需要的数据。

如果我们需要传递的数据量很多的时候,我们是不是还需要这样一个一个的传递呢?

<script>
  const app = Vue.createApp({
    data(){
      return {
        a: 1,
        b: 2,
        c: 3
      }
    },
    template: `
      <div>
        <hello :a="a" :b="b" :c="c" />
      </div>
    `
  });

  app.component('hello', {
    props: ['a', 'b', 'c'],
    template: `
      <div>{{a}} -- {{b}} -- {{c}}</div>
    `
  })

  const vm = app.mount('#root');
</script>

image.png

虽然页面上也可以渲染出我们想要的效果,但是这种方法对于数据量太多的时候,页面上的代码也会随之拉长,可读性不强,也不太容易维护。

那么我们可以在父组件中定义一个数据对象值,来包裹需要传递到子组件的值。

<script>
  const app = Vue.createApp({
    data(){
      return {
        params: {
          a: 1,
          b: 2,
          c: 3
        }
      }
    },
    template: `
      <div>
        <hello v-bind="params" />
      </div>
    `
  });

  app.component('hello', {
    props: ['a', 'b', 'c'],
    template: `
      <div>{{a}} -- {{b}} -- {{c}}</div>
    `
  })

  const vm = app.mount('#root');
</script>

image.png

  • 在父组件中的data函数中定义一个params对象值,然后在子组件标签上通过v-bind指令传递params给子组件,子组件中还是同样接收父组件中的a,b,c三个值。

<hello v-bind="params" /> 等同于 <hello :a="params.a" :b="params.b" :c="params.c" />

小结一下

在需要传递多个参数给子组件时,可以通过传递一个对象值,不需要在子组件标签中定义多次,易于维护可读性也会高一点。

总结

本篇文章主要讲解了组件单项数据流的概念,还补充了一点上篇文章中没有讲到的传递对象值的内容。