天天看点

一页图纸看懂Vue组件之间的交互

一页图纸,顾名思义真的是一页图纸,让我们来慢慢展开。

一页图纸看懂Vue组件之间的交互

组件名:

Vue.component(‘my-component-name’,{}).这个形式的组件名应该是大家见过的最多的,也是最熟悉的。

一页图纸看懂Vue组件之间的交互

组件名的两种写法:

使用 kebab-case短横线分隔命名:

当使用这种命名方式,也必须用这种命名方式来引用

使用 PascalCase首字母大写:

也叫做帕斯卡命名法,重在首字母大写。

<my-component-name> 和 <MyComponentName>

都是可接受的。

注册方式

全局注册

Vue.component('my-component-name', {
  // ... 选项 ...
})
           

局部注册

  1. js对象中定义组件
var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }
           
  1. 然后再component选项中定义你要使用的组件
new Vue({
  el: '#app',
  components: {
    'component-a': ComponentA,
    'component-b': ComponentB
  }
})
           
局部注册的组件在其子组件中不可用

模块系统中局部注册

在一个假设的 ComponentB.js 或 ComponentB.vue 文件中:

import ComponentA from './ComponentA'
import ComponentC from './ComponentC'

export default {
  components: {
    ComponentA,
    ComponentC
  },
  // ...
}
           

现在 ComponentA 和 ComponentC 都可以在 ComponentB 的模板中使用了。

Prop

传递静态或动态 Prop

props: {
  title: String,//传入字符串
  likes: Number,//传入数字
  isPublished: Boolean,//传入布尔值
  commentIds: Array,//传入数组
  author: Object,//传入一个对象
  callback: Function,//传入一个方法
  contactsPromise: Promise // or any other constructor
}
           

传入一个对象的所有property

post: {
  id: 1,
  title: 'My Journey with Vue'
}
           

等价于

<blog-post
  v-bind:id="post.id"
  v-bind:title="post.title"></blog-post>
           

单向数据流的特点,尽可能使父组件和子组件的耦合性降低。

非父子组件通信的几种方法:

中央事件bus总线法

一页图纸看懂Vue组件之间的交互
var bus =new Vue();
Vue.component('component-a',{
template:'<button @click="handleEvent">传递事件</button>',
methods:{
handleEvent:function(){
bus.$emit('on-message','来自组件component-a的内容');

}
}
});
           
var app =new Vue(){
el:'#app',
data:{
message:'',
},
mounted:function(){
var _this=this;
bus.$on('on-message',function(msg){
_this.message=msg;
});
}
           

首先创建了一个名为bus 的空Vue实例,全局语法定义了组件component-a,之后创建了Vue实例app,在app初始化时,即生命周期mounted钩子函数监听到了来自bus的事件on-message,在组件component-a,点击按钮会通过bus把事件on-message发出去,此时app就会接收到来自bus 的事件,进而在回调里完成业务逻辑。

上面的说法没什么毛病就是太复杂了。

简单分为几个模块和步骤来讲的话:

  • 1.首先要有一个bus的中间件
  • 2.在两个需要通信的非父子组件的组件中引入这个中间件
  • 3.想要发送数据的组件通过vue的实例方法

    $emit

    发送事件名称和需要传递的数据,以上例子是挂载到mounted方法上。
  • 4.被传递数据的组件,也就是本处的app实例,通过vue 实例方法

    $on

    监听到事件和接收数据。

清除bus:

beforeDestory(){
bus.$off('on-message');
}
           

父链访问

一页图纸看懂Vue组件之间的交互

在子组件中,使用this.$parent可以直接访问该组件的父实例或者组件,父组件也可以通过this.children访问它的所有子组件,而且可以递归向上或者向下无限访问。直到没有父组件或子组件。

但通过这种方式将大大地增加父子组件的耦合性,所以不建议使用。

子组件索引

一页图纸看懂Vue组件之间的交互

子组件较多的情况,通过以上父链子链的形式已经很难找出我们需要的组件实例。

则可以在子组件的标签上用ref指定一个名称,comA,在父组件内通过this.$refs.comA来找到组件

<div id="app">
<button @click="handleRef">通过ref获取子组件实例</button>
<component-a ref="comA"></component-a>
           
Vue.component('component-a',{
template:'<div>子组件</div>',
data:function(){
return{
message:'子组件内容'
}
}
});

var app=new Vue({
el:'#app',
methods:{
handleRef:function(){
var msg=this.$refs.comA.message;
console.log(msg);
}
}
}
)
           

插槽slot

为什么需要插槽?vue的实用和流行的核心便是组件化,但是共用并不能代替很多需求的完善,可能需要对组件进行自定义,这就出现了插槽。

一页图纸看懂Vue组件之间的交互

简单来讲:

假设有一个名为comA的组件

此时组件经过渲染显示的是今天的天气是,此时你可能会想加入下雨,下雪等个性化定制的内容,但是直接在标签中写是没有作用的。

如图所示,slot就好像是那个异色的对话框出口,让同色的语句也能在背景展示出来。

提供一个slot出口则可以正确的显示。