(15)深入理解 Vue 组件——② 父子组件间的数据传递 | Vue 基础理论实操

1,937 阅读3分钟
本文版权归 “公众号 | 前端一万小时” 所有,欢迎转载!

转载请注明出处,未经同意,不可修改文章内容。

🔥🔥🔥本系列文章已在“公众号 | 前端一万小时”更新完毕,有需要的小伙伴可按需前往查看。

🔥🔥🔥“前端一万小时”两大明星专栏——“从零基础到轻松就业”、“前端面试刷题”,已于本月大改版,合二为一,干货满满,欢迎点击公众号菜单栏各模块了解。


涉及面试题:
1. Vue 父组件向子组件传递数据?
2. 子组件像父组件传递事件?
3. 跨组件双向数据绑定?
4. 什么是可接受的 prop 类型?
5. props 后面的数据流是什么?
6. 什么是非 prop 属性?
7. props 有哪些可用的验证?

[编号:vue_15]

🔗本阶段对应的“官方文档”阅读


1 父组件向子组件传值

💡父组件向子组件传值:通过“属性”传值!

<body>
  <div id="root">
    <counter :count="0"></counter> <!-- 3️⃣父组件通过“属性”绑定“数据” count,
																	 将 count 传递出去; -->
    <counter :count="1"></counter>
  </div>
  <script>
    var counter = {  
      props: ["count"], // 4️⃣在子组件中,通过 props “接收”父组件传递过来的 count 值;
      template: "<div>{{count}}</div>" // 1️⃣首先,我们在这里定义一个子组件,并添加一个“模板”;
                                       // 5️⃣接着,子组件就可以使用这个“接收”到的“数据”。
    }
    var vm = new Vue({
      el: "#root",
      components: { // 2️⃣然后,将1️⃣中的子组件添加到 components 中;
        counter: counter
      }
    })
  </script>
</body>

❓需求:实现“点击”后计数器累加功能。

❌尝试: 子组件中直接实现计数器的累加数据的功能,页面虽然实现了,但后台会报错:

var counter = {
  props: ["count"],
  template: '<div @click="handleClick">{{count}}</div>',
  methods: {
    handleClick: function() {
      this.count ++ // 实现累加的功能
    }
  }
}

❗️报错: 不要直接修改父组件传递过来的数据。 15-01.png

2 Vue 单向数据流

单向数据流:

  • 父组件可以向子组件通过属性形式传递参数,传递的参数也可以随时随意修改;
  • 但子组件不能修改父组件传递过来的参数,只能用父组件传递的数据!

💡以上代码报错的原因:

因为子组件接收父组件传递过来的数据,并不是一个基础类型的数据类型,而是类似于 Object 这种“引用”类型的数据类型。

如果修改了“引用”类型的数据,在使用子组件时,则会造成其他子组件接收数据的错误。

🚀如何解决上边代码的问题——如何解决单向数据流存在问题?

💡分析: 子组件接收到父组件的“数据”,将接收到的“数据”复制一份放在子组件 data 的 number 里(相当于这个“数据”的副本)。

那么就能让子组件使用自己 data 里的 number ,进而在子组件的 methods 里就使用 this.number ++ 来实现累加数据的功能。

<script>
  var counter = {
    props: ["count"],
    data: function() {
      return {
        number: this.count // 1️⃣子组件把接收到的“数据”放在自己 data 里的 number 中;
      }
    },
    template: '<div @click="handleClick">{{number}}</div>',
    methods: {
      handleClick: function() {
        this.number ++ // 2️⃣接着,我们就可以在方法里使用这个副本“数据”了。将不再报错!
      }
    }
  }
  var vm = new Vue({
    el: "#root",
    components: {
      counter: counter
    }
  })
</script>

vue_15-02.gif

3 子组件向父组件传值

💡子组件向父组件传值:通过“触发监听”模式!

  • “触发”指子组件 this.$emit("事件名", 步长 step)
  • “监听”指父组件 @事件名="事件执行的方法名"

❓需求:每点击一次后,两组件的总数也会随之加 2 ?

(❗️本例中我们是先把“ 总数 total”写死的,主要为了演示“子组件向父组件传值——步长 step”。通过后边的学习,我们还可以改良本例的代码)

<body>
  <div id="root">
    <counter :count="0" @inc="handleIncrease"></counter>
    <!-- 2️⃣我们在父组件里通过 @inc 来“监听”这个来自子组件的事件,
		并把一个“方法”赋值给这个“监听”到的事件; -->
    
    <counter :count="1" @inc="handleIncrease"></counter>
    <div>总计:{{total}}</div>
  </div>

  <script>
    var counter = {
      props: ["count"],
      data: function() {
        return {
          number: this.count
        }
      },
      template: '<div @click="handleClick">{{number}}</div>',
      methods: {
        handleClick: function() {
          this.number = this.number + 2; 
          this.$emit("inc", 2) /*
          										 1️⃣当我们点击子组件时,不仅会执行上边的方法,
          										 还会“触发”一个 inc 事件;且这个事件的“步长” 2,
                               也会一并“触发”。(即,我会告诉父组件:我自己发生了改变,
                               改变了多少呢?新增了 2。
                                */
        }
      }
    }
    var vm = new Vue({
      el: "#root",
      data: {
        total: 1
      },
      components: {
        counter: counter
      },
      methods: {
        handleIncrease: function(step) { // 3️⃣紧接着,我们在根实例里定义这个“方法”;
                                         // 4️⃣同时,这个方法可以接收到的“步长” step 这个参数;
          this.total += step // 5️⃣运用“步长”,轻松实现需求。
        }
      }
    })
  </script>
</body>

vue_15-03.gif

祝好,qdywxs ♥ you!