Vue 组件及组件间的通信

一、什么是组件?

        组件 (Component) 是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以表现为用 is 特性进行了扩展的原生 HTML 元素。

二、创建全局组件:

    (一)Vue2.0的创建方式

       方式一

             1、使用Vue.extend创建组件

                       var com1 = Vue.extend({

                            // 通过 template 属性,指定了组件要展示的HTML结构

                         template: '<h3>这是使用 Vue.extend 创建的组件</h3>'

                       })

            2、使用 Vue.component('组件的名称', 创建出来的组件模板对象) 注册组件

                        Vue.component('myCom1', com1)

        注意:如果使用Vue.Component 注册全局组件的时候,组件的名称使用了驼峰命名,则在引用组件的时候需要大写的驼峰为小写的字母,同时,两个单词之前,使用  链接。如果不使用则直接拿名称来使用即可。

        示例:

           

        方式二

              直接使用Vue.component的方式创建                         

 Vue.component('mycom2', {

        template: '<div>

                     <h3>这是直接使用 Vue.component 创建出来的组件</h3>

                     <span>123</span>

                   </div>'

 })

       示例:

 

方式三

     1、被控制的 #app 外面,使用 template 元素,定义组件的HTML模板结构

<template id="tmpl">

            <div>

                <h1>这是通过 template 元素,在外部定义的组件结构</h1>

                <h4>好用,不错!</h4>

            </div>

</template>

      2、使用id注册组件

 Vue.component('mycom3', {

                template: '#tmpl'

 })

    示例:

      (二)Vue3.0中的创建方式:在main.js文件中注册

                  app.Component(“标签名”,组件名)

三、创建局部组件

         局部组件的创建和全局组件的创建方法一样。唯一区别的是,局部组件是在Vue实例中定义

        

四、组件中的data 和 methods:

      1、组件可以拥有自己的数据

      2、组件中的data 和实例中的data 有点不一样,实例中的data 可以为一个对象。但是组件中的data必须是一个方法

      3、组件中的data除了是一个方法,还必须返回一个对象。

      4、组件中的data 的使用方式和 实例中的data 使用方式一样

      5、组件中的Methods 的定义和使用与实例中一样

      

五、组件间的通信方式

                         

          【组件间的关系】:A 和 B、B 和 C、B 和 D 都是父子关系,C 和 D 是兄弟关系,A 和 C 是隔代关系(可能隔多代)

        (父子间通信(props/$emit)父组件A通过props的方式向子组件B传递,B to A 通过在 B 组件中 $emit, A 组件中 v-on 的方式实现。

            1、父组件向子组件传值

               (1)子组件users.vue

<template>
  <div class="hello">
    <ul>
      <li v-for="(user,index) in users" v-bind:key="index">{{ user }}</li>
    </ul>
  </div>
</template>

<script>
export default {
  name: "users",
  props: {
    users: {  //父组件中子标签自定义的名字
      type: Array,
      require: true
    }
  }
}
</script>

<style scoped>
 li{
   list-style-position: inside;
 }
</style>

           (2)父组件App.vue

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <Users v-bind:users="users"> </Users>
  </div>
</template>

<script>
import Users from "@/components/users";
export default {
  name: 'App',
  data(){
    return {
      users: ['西安邮电','西安石油','西北政法','西安工业','西安财经']
    }
  },
  components: {
    Users,
  }
}
</script>

【总结】父组件通过props向下传递数据给子组件。

【注】组件中的数据共有三种形式:data、props、computed

       2、子组件向父组件传值(通过事件形式)

          (1)子组件

<template>
  <header>
    <h1 @click="changeTitle">{{ title }}</h1>
  </header>
</template>
<script>
export default {
  name: "Son",
  data(){
    return {
      title: 'Vue.js Demo'
    }
  },
  methods: {
    changeTitle(){
      this.$emit('titleChanged','西安邮电大学');
    }
  }
}
</script>

<style scoped>
 h1{
   background-color: greenyellow;
 }
</style>

           (2)父组件

<template>
  <div id="app">
    <Son v-on:titleChanged="updateTitle"></Son>
    <h2>{{ title }}</h2>
  </div>
</template>
<script>
import Son from "@/components/Son";
export default {
  name: "Father",
  data(){
    return {
      title: '传递的是一个值'
    }
  },
  methods: {
    updateTitle(e){
      this.title = e
    }
  },
  components:{
    Son,
  }
}
</script>

      【总结】子组件通过events(事件)给父组件发送消息,实际上就是子组件把自己的数据发送到父组件。

       ()兄弟间通信:使用第三方库mitt创建一个中央事件总线(事件中心),用它来触发(emit)事件和监听(on)事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级。当我们的项目比较大时,可以选择更好的状态管理解决方案vuex。

   示例:

        (1)安装mitt库:

               npm  install  mitt

        (2)创建事件中心(event.js)

import mitt from "mitt";
const emitter = mitt();
export default emitter;

        (3)创建兄弟组件

          Brother1.vue

<template>
  <div class="Brother1">
    <h2>兄弟---关羽</h2>
    <p>{{ data1 }}&nbsp;&nbsp;&nbsp;{{ data2 }}</p>
    <button @click="sendData">将美酒送给三弟</button>
  </div>
</template>

<script>
import emitter from "@/event";
export default {
  name: "Brother1",
  data(){
    return {
      data1: "美酒",
      data2: ''
    }
  },
  methods:{
    //接收数据的方法
    receive: function () {
      emitter.on('two-to-one',(data)=>{
        console.log(data);
        this.data2 = data;
      })
    },
    sendData:function () {
      emitter.emit('one-to-two',this.data1);
    }
  },
  mounted() {
    //执行该方法
    this.receive();
  }
}
</script>

<style scoped>
   .Brother1{
     color: blueviolet;
     font-size: 20px;
     border: 1px solid #bbb;
     margin-bottom: 10px;
   }
</style>

          Brother2.vue

<template>
  <div class="Brother12">
    <h2>兄弟---张飞</h2>
    <h3>{{ data1 }} &nbsp;&nbsp;&nbsp;{{ data2 }}</h3>
    <button @click="sendData">将宝剑送给二哥</button>
  </div>
</template>

<script>
import emitter from '@/event.js';
export default {
  name: "Brother12",
  data(){
    return {
      data1: "宝剑",
      data2: ''
    }
  },
  methods:{
    //发送数据的方法
    sendData: function () {
      emitter.emit('two-to-one',this.data1)
    },
    receive: function (){
      emitter.on('one-to-two',(data)=>{
        this.data2= data;
      })
    }
  },
  mounted() {
    this.receive();
  }
}
</script>

<style scoped>
 .Brother12{
   color: yellowgreen;
   font-size: 20px;
   border: 1px solid #ccc;
 }
</style>

        App.vue

<template>
  <img alt="Vue logo" src="./assets/logo.png">
    <Brother1></Brother1>
    <Brother2></Brother2>
</template>

<script>
import Brother1 from "@/components/Brother1";
import Brother2 from "@/components/Brother2";

export default {
  name: 'App',
  components: {
    Brother1,
    Brother2
  }
}
</script>

运行结果

                 

         (三)跨级通信(provide/inject)

             provide / inject 类似于消息的订阅和发布。provide 提供或发送数据, inject 接收数据。  

             Vue3 的 provide / inject 只能在 setup 期间调用,使用之前,必须从 vue 显示导入 provide/inject 方法。

            provide( name,value ):函数接收两个参数

                     name:定义提供 property 的 name 。

                     value :property 的值。

            inject(name,default):函数有两个参数

                     name:接收 provide 提供的属性名。

                    default:设置默认值,可以不写,是可选参数。

      附:setup钩子函数位于created 和beforeCreated之前,用于代替created 和beforeCreated

            (1)在setup函数中定义的变量和方法最后都是需要 return 出去的 不然无法再模板中使用

           (2)由于在执行 setup函数的时候,还没有执行 Created 生命周期方法,所以在 setup 函数中,无法使用 data 和 methods 的变量和方法

           (3)在setup函数里不能访问到this。由于我们不能在 setup函数中使用 data 和 methods,所以 Vue 为了避免我们错误的使用,直接将 setup函数中的this修改成了 undefined

           (4)setup函数只能是同步的不能是异步的

           (5)provide/inject 只能写在setup中

示例:

     QianLong.vue

<template>
   <div>
     <h2>孙子:乾隆</h2>
     <div>爷爷:{{ getYeYeData }}</div>
   </div>
</template>

<script>
import { inject } from "vue";
export default {
  name: "QianLong",
  setup(){
    let getYeYeData =  inject('giveLastWords')
    return {
      getYeYeData
    }
  }
}
</script>

      YongZheng.vue

<template>
  <h2>儿子:雍正</h2>
  <div>父亲:{{ getFatherData}}</div>
  <hr/>
  <ql-com></ql-com>
</template>

<script>
import { inject } from "vue";
import QianLong from "@/components/QianLong";
export default {
  name: "YongZheng",
  components: {
    "ql-com": QianLong
  },
  setup() {
    let getFatherData = inject('giveLastWords')
    return {
      getFatherData
    }
  }
}
</script>

        KangXi.vue

<template>
  <h2>康熙:{{ lastWords }}</h2>
  <yz-com></yz-com>
</template>

<script>
import YongZheng from "@/components/YongZheng";
import { provide } from "vue";

export default {
  name: "KangXi",
  components: {
    "yz-com": YongZheng
  },
  setup(){
    let lastWords = "整顿吏治"
    provide('giveLastWords',lastWords)
    return {
      lastWords
    }
  }

}
</script>

      App.vue

<template>
  <img alt="Vue logo" src="./assets/logo.png">
  <KangXi></KangXi>
</template>

<script>
import KangXi from "@/components/KangXi";
export default {
  name: 'App',
  components: {
        KangXi
    }
}
</script>

运行结果:

                       

六、总结

           组件间通信常见使用场景可以分为三类:

  • 父子通信:

           父向子传递数据是通过 props,子向父是通过 events($emit);

  • 兄弟通信:

            Bus(mitt);Vuex

  • 跨级通信:

            Bus(mitt);Vuex;provide / inject

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

上庸者-不服周

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值