• 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的方式创建                         

    1. Vue.component('mycom2', {
    2.         template: '<div>
    3.                      <h3>这是直接使用 Vue.component 创建出来的组件</h3>
    4.                      <span>123</span>
    5.                   </div>'
    6.  })

           示例:

     

     

    方式三

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

    1. <template id="tmpl">
    2.             <div>
    3.                 <h1>这是通过 template 元素,在外部定义的组件结构</h1>
    4.                 <h4>好用,不错!</h4>
    5.             </div>
    6. </template>

          2、使用id注册组件

    1.  Vue.component('mycom3', {
    2.                 template: '#tmpl'
    3.  })

        示例:

          (二)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

    1. <template>
    2. <div class="hello">
    3. <ul>
    4. <li v-for="(user,index) in users" v-bind:key="index">{{ user }}</li>
    5. </ul>
    6. </div>
    7. </template>
    8. <script>
    9. export default {
    10. name: "users",
    11. props: {
    12. users: { //父组件中子标签自定义的名字
    13. type: Array,
    14. require: true
    15. }
    16. }
    17. }
    18. </script>
    19. <style scoped>
    20. li{
    21. list-style-position: inside;
    22. }
    23. </style>

               (2)父组件App.vue

    1. <template>
    2. <div id="app">
    3. <img alt="Vue logo" src="./assets/logo.png">
    4. <Users v-bind:users="users"> </Users>
    5. </div>
    6. </template>
    7. <script>
    8. import Users from "@/components/users";
    9. export default {
    10. name: 'App',
    11. data(){
    12. return {
    13. users: ['西安邮电','西安石油','西北政法','西安工业','西安财经']
    14. }
    15. },
    16. components: {
    17. Users,
    18. }
    19. }
    20. </script>

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

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

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

              (1)子组件

     

    1. <template>
    2. <header>
    3. <h1 @click="changeTitle">{{ title }}</h1>
    4. </header>
    5. </template>
    6. <script>
    7. export default {
    8. name: "Son",
    9. data(){
    10. return {
    11. title: 'Vue.js Demo'
    12. }
    13. },
    14. methods: {
    15. changeTitle(){
    16. this.$emit('titleChanged','西安邮电大学');
    17. }
    18. }
    19. }
    20. </script>
    21. <style scoped>
    22. h1{
    23. background-color: greenyellow;
    24. }
    25. </style>

               (2)父组件

    1. <template>
    2. <div id="app">
    3. <Son v-on:titleChanged="updateTitle"></Son>
    4. <h2>{{ title }}</h2>
    5. </div>
    6. </template>
    7. <script>
    8. import Son from "@/components/Son";
    9. export default {
    10. name: "Father",
    11. data(){
    12. return {
    13. title: '传递的是一个值'
    14. }
    15. },
    16. methods: {
    17. updateTitle(e){
    18. this.title = e
    19. }
    20. },
    21. components:{
    22. Son,
    23. }
    24. }
    25. </script>

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

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

       示例:

            (1)安装mitt库:

                   npm  install  mitt

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

    1. import mitt from "mitt";
    2. const emitter = mitt();
    3. export default emitter;

            (3)创建兄弟组件

              Brother1.vue

    1. <template>
    2. <div class="Brother1">
    3. <h2>兄弟---关羽</h2>
    4. <p>{{ data1 }}&nbsp;&nbsp;&nbsp;{{ data2 }}</p>
    5. <button @click="sendData">将美酒送给三弟</button>
    6. </div>
    7. </template>
    8. <script>
    9. import emitter from "@/event";
    10. export default {
    11. name: "Brother1",
    12. data(){
    13. return {
    14. data1: "美酒",
    15. data2: ''
    16. }
    17. },
    18. methods:{
    19. //接收数据的方法
    20. receive: function () {
    21. emitter.on('two-to-one',(data)=>{
    22. console.log(data);
    23. this.data2 = data;
    24. })
    25. },
    26. sendData:function () {
    27. emitter.emit('one-to-two',this.data1);
    28. }
    29. },
    30. mounted() {
    31. //执行该方法
    32. this.receive();
    33. }
    34. }
    35. </script>
    36. <style scoped>
    37. .Brother1{
    38. color: blueviolet;
    39. font-size: 20px;
    40. border: 1px solid #bbb;
    41. margin-bottom: 10px;
    42. }
    43. </style>

              Brother2.vue

    1. <template>
    2. <div class="Brother12">
    3. <h2>兄弟---张飞</h2>
    4. <h3>{{ data1 }} &nbsp;&nbsp;&nbsp;{{ data2 }}</h3>
    5. <button @click="sendData">将宝剑送给二哥</button>
    6. </div>
    7. </template>
    8. <script>
    9. import emitter from '@/event.js';
    10. export default {
    11. name: "Brother12",
    12. data(){
    13. return {
    14. data1: "宝剑",
    15. data2: ''
    16. }
    17. },
    18. methods:{
    19. //发送数据的方法
    20. sendData: function () {
    21. emitter.emit('two-to-one',this.data1)
    22. },
    23. receive: function (){
    24. emitter.on('one-to-two',(data)=>{
    25. this.data2= data;
    26. })
    27. }
    28. },
    29. mounted() {
    30. this.receive();
    31. }
    32. }
    33. </script>
    34. <style scoped>
    35. .Brother12{
    36. color: yellowgreen;
    37. font-size: 20px;
    38. border: 1px solid #ccc;
    39. }
    40. </style>

            App.vue

    1. <template>
    2. <img alt="Vue logo" src="./assets/logo.png">
    3. <Brother1></Brother1>
    4. <Brother2></Brother2>
    5. </template>
    6. <script>
    7. import Brother1 from "@/components/Brother1";
    8. import Brother2 from "@/components/Brother2";
    9. export default {
    10. name: 'App',
    11. components: {
    12. Brother1,
    13. Brother2
    14. }
    15. }
    16. </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

    1. <template>
    2. <div>
    3. <h2>孙子:乾隆</h2>
    4. <div>爷爷:{{ getYeYeData }}</div>
    5. </div>
    6. </template>
    7. <script>
    8. import { inject } from "vue";
    9. export default {
    10. name: "QianLong",
    11. setup(){
    12. let getYeYeData = inject('giveLastWords')
    13. return {
    14. getYeYeData
    15. }
    16. }
    17. }
    18. </script>

          YongZheng.vue

    1. <template>
    2. <h2>儿子:雍正</h2>
    3. <div>父亲:{{ getFatherData}}</div>
    4. <hr/>
    5. <ql-com></ql-com>
    6. </template>
    7. <script>
    8. import { inject } from "vue";
    9. import QianLong from "@/components/QianLong";
    10. export default {
    11. name: "YongZheng",
    12. components: {
    13. "ql-com": QianLong
    14. },
    15. setup() {
    16. let getFatherData = inject('giveLastWords')
    17. return {
    18. getFatherData
    19. }
    20. }
    21. }
    22. </script>

            KangXi.vue

    1. <template>
    2. <h2>康熙:{{ lastWords }}</h2>
    3. <yz-com></yz-com>
    4. </template>
    5. <script>
    6. import YongZheng from "@/components/YongZheng";
    7. import { provide } from "vue";
    8. export default {
    9. name: "KangXi",
    10. components: {
    11. "yz-com": YongZheng
    12. },
    13. setup(){
    14. let lastWords = "整顿吏治"
    15. provide('giveLastWords',lastWords)
    16. return {
    17. lastWords
    18. }
    19. }
    20. }
    21. </script>

          App.vue

    1. <template>
    2. <img alt="Vue logo" src="./assets/logo.png">
    3. <KangXi></KangXi>
    4. </template>
    5. <script>
    6. import KangXi from "@/components/KangXi";
    7. export default {
    8. name: 'App',
    9. components: {
    10. KangXi
    11. }
    12. }
    13. </script>

    运行结果:

                           

    六、总结

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

    • 父子通信:

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

    • 兄弟通信:

                Bus(mitt);Vuex

    • 跨级通信:

                Bus(mitt);Vuex;provide / inject

     

  • 相关阅读:
    使用序列化技术保存数据 改进 IO流完成项目实战水果库存系统
    SoftwareTest3 - 要了人命的Bug
    MySQL数据库索引和事务详解
    Xcode14.3.1 真机调试iOS17的方法(无iOS17 DeviceSupport)
    【已验证-直接用】微信小程序wx.request请求服务器json数据并渲染到页面
    基于http的身份验证手段(cookie,session,token)
    新版Java面试专题视频教程——多线程篇②
    知识提取-属性抽取-学习笔记
    【Java SE】封装的详解
    关于数据库优化你知道多少?
  • 原文地址:https://blog.csdn.net/m0_37911706/article/details/125491745