父子组件通过props和自定义事件($emit发送)来互传数据
父组件通过props向子组件传递数据
子组件通过事件向父组件发送消息
父传子:
- 子组件在props中创建一个属性,用以接收父组件传过来的值
- 父组件中注册子组件
- 在子组件标签(在父组件文件中)中添加子组件props中创建的属性,也可以不添加直接用props里设置的默认值
- 把需要传给子组件的值赋给该属性
ps: 在Vue2中组件的props的数据流动改为了只能单向流动,即只能由组件外(调用组件方)通过组件的DOM属性attribute传递props给组件内,组件内只能被动接收组件外传递过来的数据,并且在组件内,不能修改由外层传来的props数据。但是若是父组件传来的值时数组或对象时,可以修改且不报错。父组件传递给子组件的,实际上只是一个引用地址,当子组件修改这个对象时,是真的修改了在堆空间中保存的数值,当然父组件中的值也会发生变化,但是引用地址没有进行修改,所以并没有报错。不能重新赋值便是这个原因。,遇到此类情况尽量避免在子组件中修改,可以让父组件自己修改比如通过自定义事件。
子传父(自定义事件):
-
在子组件中创建一个按钮,给按钮绑定一个点击事件
- 在响应该点击事件的函数中使用$emit来触发一个自定义事件,并传递一个参数
- 在父组件中的子标签中监听该自定义事件并添加一个响应该事件的处理方法
插槽
-
默认插槽与具名插槽
我们知道我们可以在父组件里使用子组件标签来使用子组件,但是在引用Child
组件的同时,希望在Child
组件的指定位置
插入一段内容:<h1> 父组件插入的数据</h1>
。
如果我们直接在父组件文件中的子组件标签内直接写入是不会生效的,该标签内写的任何东西都不会渲染出来。这时候我们就需要插槽 slot。
插槽:
也可称其为Vue
的内容分发机制,它的主要作用就是向父组件文件中的子组件
的指定位置
插入一段内容,这个内容可以是HTML
或者其他的组件。
默认插槽实现步骤:
- 在子组件里想要的位置写入标签<slot></slot> 标签内部可以写入其他的内容作为默认内容。
-
1 <!-- 子组件 --> 2 <template id="child"> 3 <div> 4 <slot> 5 默认内容 6 </slot> 7 </div> 8 </template>
- 在父组件里子组件标签内写入 我们想要插入到刚才子组件slot标签位置 的内容 。
-
1 <!-- 父组件 --> 2 <div id="app"> 3 <h1>12346</h1> 4 <child> 5 想要插入得内容 6 </child> 7 </div>
- 这时我们父组件想要插入的内容便可以显示在页面上在子组件的该位置。若是没有插入内容,那便显示子组件插槽本身的默认内容。
-
具名插槽
具名插槽便是给插槽起一个名字,即给<slot></slot>
定义一个name
属性,然后在父组件中子组件标签内容里使用v-slot:name或者#name绑定name属性,我们推荐v-slot
是写在<template>
元素上的包裹想要插入得内容,因为<template>
在处理的过程中不会渲染成真实的DOM
节点。当然我们也可以用老版本写法slot="name"的方式写在其余标签上,只不过会渲染成真实dom节点。
这样即使多个插槽也能插入得内容与位置一一对应:
作用域插槽
我们有些时候需要在父组件里访问到子组件的数据,直接操作子组件中的数据提高效率。
1 <!-- 父组件 --> 2 <div id="app"> 3 <h1>父组件</h1> 4 <child> 5 {{user.id}} 6 </child> 7 </div> 8 9 <!-- 子组件 --> 10 <template id="child"> 11 <div> 12 <slot > 13 {{user.name}} 14 </slot> 15 </div> 16 </template> 17 <script> 18 19 const child = { 20 template: '#child', 21 data(){ 22 return { 23 24 user:{ 25 name:"郑大侠", 26 id:22 27 } 28 } 29 } 30 } 31 const app = new Vue({ 32 el: '#app', 33 data: { 34 35 }, 36 components: { 37 child 38 } 39 })
现在我们想要在父级子组件标签内直接将user.name显示为user.id,显然不会实现;
我们可以将子组件中的数据列如user作为slot标签的一个属性绑定到插槽里 <slot :user="user"></slot>,第一个user是我们自定义的。绑定在 <slot>
元素上的 attribute 被称为插槽 prop。现在在父级作用域中,我们可以使用带值的 v-slot
来定义我们提供的插槽 prop 的名字:<template v-slot:default="slotProps">。这里是默认插槽。
设置名为slotProps的对象来接受来自该插槽的所有属性,当然也可以设置为其他的名字。这样一来我们便可在父级作用域中访问该user数据了。
作用域插槽的内部工作原理是将你的插槽内容包裹在一个拥有单个参数的函数里,这意味着 v-slot
的值实际上可以是任何能够作为函数定义中的参数的 JavaScript 表达式。所以在支持的环境下 ,你也可以使用 对象解构来传入具体的插槽 prop,如下:
1 <template v-slot:default="{ user }"> 2 {{ user.id }} 3 </template>
该插槽提供了多个 prop 的时候。它同样开启了 prop 重命名等其它可能,例如将 user
重命名为 person
:
1 <template v-slot:default="{ user:person }"> 2 {{ pserson.id }} 3 </template>