IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> VUE - 8.2 - VUE组件间的通讯 -> 正文阅读

[JavaScript知识库]VUE - 8.2 - VUE组件间的通讯


在模块系统中,组件都是单文件组件,即每一个组件都在不同的组件文件中,所以传递数据需要借助一些工具和方法。传递数据的情况有,父子数据传递,子父数据传递,不同组件间数据传递。

父组件向子组件传递数据

props

  • prop用于从父组件向子组件传递数据时自组建的接收器:props:["name","age","sex"]
  • 在父组件传递数据时:<my-student name="张三" :age="16" sex="男"></my-student>
    • 注意age的传参方式,完整写法是 v-bind:age= "18",这样动态地向子组件传递数据,子组件接受到的数据就是引号里面的 数字类型的18。
    • 如果不使用v-bind:的方式传递数据,子组件接收到的数据则都是字符串类型的。
    • prop还可以是对象类型的:
       props:{
          name:[String,Number],
          age:{
              type: Number,
              default: 10
          },
          sex:{
              type: String,
              required: true
          }
      },
      

案例代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello Vue</title>
    <link rel="icon" href="../logo.svg">
</head>
<body>
    <div id="root">
        <h1>{{msg}}</h1>
        <hr>
        <!--使用组件-->
        <School></School>        
    </div> 
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    Vue.config.productionTip=false;
    // 创建Student组件
    const Student=Vue.extend({
        props:["name","age","sex"],//接收数据
        template:`
            <div>
                <p>学生姓名:{{name}}</p>
                <p>学生年龄:{{age}}</p>
                <p>学生性别:{{sex}}</p>
            </div>`
    })    
    // 创建School组件
    const School = Vue.extend({
        data(){
            return{
                name:"五道口技术学院",
                add:"北京"               
            }
        },       
        components:{ //在组建内注册局部组件
            'my-student':Student
        },
        template:`
        <div>
            <p>学校名字:{{name}}</p>
            <p>学校地址:{{add}}</p>
            <hr>       
            学生组件:  
            <!--嵌套组件并传递数据-->
            <my-student name="张三" :age="16" sex="男"></my-student>
        </div>
        `
    })    
     //注册组件(全局注册)
    Vue.component("School",School);    
    var vm = new Vue({
        el:"#root",
        data:{
            msg:"hello Vue!" 
        }
    })
</script>
</body>
</html>

效果:
在这里插入图片描述
在这里插入图片描述

子组件向父组件传递数据

一、props

把学校名传递给App组件

子组件向父组件传递数据也可以借助props:

  1. 在父组件通过v-bind 向子组件传递一个函数类型的props,
  2. 子组件通过props 接受,
  3. 在适当的事件或者钩子函数内调用传递过来的事件,并传递对应的数据。

代码:
App.vue(本案例通过子组件的按钮点击事件,实现数据的传递给父组件)

<template>
  <div id="app"> 
    <h1>{{msg}}</h1>  
    <School :getSchoolName="getSchoolName"/> 
    <hr>
    <Student/>   
  </div>
</template>
<script>
import School from './components/School';
import Student from './components/Student';
export default {
  name: 'App',
  data() {
    return { msg:"你好啊!"}
  },
  components: {School,Student},
  methods: {
    getSchoolName(name){console.log("接收学校名字:",name) }
  },
}
</script>
<style scope>
 #app{ background: #ccc;padding:5px 10px;}
</style>

School.vue

<template>
  <div class="school">
        <p>学校名字:{{name}}</p>
        <p>学校地址:{{add}}</p>
        <p>办校年限:{{age}}</p>
        <button @click = "sendSchoolName">传递学校名给App组件</button>
  </div>
</template>
<script>
export default {
    name:'School',
    props:['getSchoolName'],
    data() {
        return {
            name:"五道口技术学院",
            add:"北京",
            age:100
        }
    },
    methods: {
      sendSchoolName(){ this.getSchoolName(this.name); }
    },
}
</script>
<style scope>
  .school{background: rgb(180, 95, 95); color: #fff;padding: 5px 10px;}
</style>

效果(点击了按钮):
在这里插入图片描述

二、自定义事件

把学生名传递给App组件

  • 父组件内给子组件定义一个自定义事件
    • 定义自定义事件可以在组件上直接定义自定义事件。
    • 也可以给子组件添加 ref = student 属性,通过 $.refs. student.$on() 定位到组件,给组件添加自定义事件 。
  • 在子组件内部在合适的事件或者钩子函数内部,通过 $emit 触发这个自定义事件(本案例通过按钮的点击事件触发)。

App.vue

<template>
  <div id="app"> 
    <h1>{{msg}}</h1>  
    <!--子给父传数据: 通过父组件给子组件传递函数类型的props实现 -->
    <School :getSchoolName="getSchoolName"/> 
    <hr>
     <!--子给父传数据: 通过父组件给子组件绑定一个自定义事件实现 -->
    <Student @getStudentName = 'getStudentName'/>   
	<hr>
     <!--子给父传数据: 通过父组件利用 ref 给子组件绑定一个自定义事件实现 -->  
    <Student ref="student"/>   
  </div>
</template>

<script>
import School from './components/School';
import Student from './components/Student';
export default {
  name: 'App',
  data() {
    return {
      msg:"你好啊!"
    }
  },
  components: {School,Student},
  methods: {
    getSchoolName(name){
      console.log("接收学校名字:",name)
    },
    getStudentName(name){
      console.log("接收学生名字:",name)
    }
  },
}
</script>
<!--...-->

Student.vue

<template>
  <div class="student">
        <p>学生姓名:{{name}}</p>
        <p>学生年龄:{{age}}</p>
        <p>学生性别:{{sex}}</p>
        <button @click = "sendStudentName">传递学生名给App组件</button>
  </div>
</template>
<script>
export default {
    name:'Student',
    data() {
        return {
            name:"张三",
            age:18,
            sex:"男"
        }
    },
    methods: {
        sendStudentName(){
            this.$emit("getStudentName",this.name);
             this.$emit("getStuName",this.name);
        }
    },
    //页面挂在完毕
     mounted() {
      // 通过ref 为student组件绑定自定义事件
      this.$refs.student.$on("getStuName",this.getStudentName);
    },
}
</script>
<!--...-->

效果:(依次点击两个按钮后的效果)
在这里插入图片描述
注意:第一个和第二个组件的自定义事件页面加载完毕就可以触发,但是第三个自定义事件须要5秒后才可以触发成功。

自定义事件其他问题

  • 事件修饰符:自定义事件上也可以添加事件修饰符,默认事件可以添加的,自定义事件都可以绑定自定义事件是通过: <Student @getStudentName.sync = 'getStudentName'/>
  • 解绑自定义事件,定义的额自定义事件,最好在使用完以后找个合适的时机解绑掉,类似定时器使用完最好也要清除定时器一样:vm.$off( [event, callback] ) =>this.$off('getStudentName')
  • 扩展:组件上的事件都是通过v-on:/ @ 添加的自定义事件,那么要想在组件上使用原生事件,比如 click 事件,就需要添加一个后缀.native<Student @click.native = 'getStudentName'/>

自定义事件中的this

上例中第三个组件使用的 ref 标记组件,然后在methods中定义好回调函数,最后在mounted钩子函数内部使用:

  • this.$refs.student.$on("getStuName",fn):因为是 student 组件点用的自定义事件,所以 fn 回调函数中的this指向触发自定义事件的组件.
  • 案例中回调函数使用的是methods中的定义好的函数,因为methods中函数都是vue管理的函数,所以函数中this都是指向vue的实例对象vm
    • 解决办法: this.$refs.student.$on("getStuName",(name)=>{/*...*/})
      • 箭头函数没有this,所以如果使用this则需要向上一级查找。
      • mounted函数是vue管理的函数,this指向vm,所以回调函数内的this又指向了vm

组件间的通讯

还是用上述的案例,需求是把学生姓名传递给学校:
第一个办法可以借助 props 和自定义事件把数据传递给Student的名字传递父组件App,再通过父组件传递给School组件,可以实现,但是比较繁琐。
还可以通过全局事件总线和消息的订阅和发布来实现

全局事件总线

全局事件总线的使用需要三步骤:安装,监听和触发

  1. 安装全局事件总线:
    	// main.js
    	import Vue from 'vue'
    	import App from './App.vue';
    	Vue.config.productionTip = false
    	new Vue({
    	  beforeCreate(){
    	  //安装全局事件总线
    	    Vue.prototype.$bus = this
    	  },
    	  render: h => h(App), 
    	}).$mount('#app')
    
  2. 在需要数据的组件内部定义并监听全局事件总线的一个事件,并在回调函数内部,获取到需要的数据。
    School.Vue
    <template>
     <div class="school">
           <p>学校名字:{{name}}</p>
           <p>学校地址:{{add}}</p>
           <p>办校年限:{{age}}</p>
           <button @click = "sendSchoolName">传递学校名给App组件</button>
     </div>
    </template>
    <script>
    export default {
       name:'School',
       props:['getSchoolName'],
       data() {
           return {
               name:"五道口技术学院",
               add:"北京",
               age:100
           }
       },
       methods: {
         sendSchoolName(){}
       },
       mounted() {
           this.$bus.$on("StudentName",(name)=>{
             console.log("School接收到的数据",name);
           })
       },
    }
    </script>
    <!-- ...-->
    
  3. 在提供数据的组件内触发全局事件总线的该事件,并传入数据。
    Student.vue
    <template>
      <div class="student">
            <p>学生姓名:{{name}}</p>
            <p>学生年龄:{{age}}</p>
            <p>学生性别:{{sex}}</p>
            <button @click = "sendStudentName">传递学生名给School组件</button>
      </div>
    </template>	
    <script>
    export default {
        name:'Student',
        data() {
            return {
                name:"张三",
                age:18,
                sex:"男"
            }
        },
        methods: {
            sendStudentName(){
                this.$bus.$emit("StudentName",this.name);
            }
        },
    }
    </script>
    <!--...-->
    
  4. 在App根组件中分别引入两个子组件:
    App.vue
<template>
  <div id="app"> 
    <h1>{{msg}}</h1>  
    <School/> 
    <hr>
    <Student/> 
  </div>
</template>
<script>
import School from './components/School';
import Student from './components/Student';
export default {
  name: 'App',
  data() {
    return {
      msg:"你好啊!"
    }
  },
  components: {School,Student},
}
</script>
<!--...-->

5.点击Student组件的 ‘传递学生名给Schoo组件’ 按钮得到的效果:在这里插入图片描述

消息订阅和发布

需求:还是上述的案例,将学校名称传递学生组件,使用消息订阅和发布来完成数据的传递,消息的订阅和发布需要借助第三方工具,本案例用的是 pubsub-js 插件:

  1. 打开命令行,进入到项目代码中,下载 pubsub-js 插件:pubsub-js插件安装
  2. 订阅:谁需要数据,谁就订阅消息,在订阅消息之前需要引入 pubsub-js 插件:
    Student.vue(student组件接受学校名字,所以student组件订阅消息)
    <template>
      <div class="student">
            <p>学生姓名:{{name}}</p>
            <p>学生年龄:{{age}}</p>
            <p>学生性别:{{sex}}</p>
            <button @click = "sendStudentName">传递学生名给School组件</button>
      </div>
    </template>
    
    <script>
    import pubsub from 'pubsub-js';// 引入插件
    export default {
        name:'Student',
        data() {
            return {
                name:"张三",
                age:18,
                sex:"男"
            }
        },
        methods: {
            sendStudentName(){
                this.$bus.$emit("StudentName",this.name);
            }
        },
        mounted() {
            // 消息订阅,谁需要数据,谁订阅消息,
            //只有订阅了,发布的时候才能收到想要的数据。
            // 订阅消息最好在页面挂载完毕之后立即订阅。
            // msgName:消息的名字
            // data:传入的参数
            // this.pubId: 
             // pubsub订阅消息返回的时消息的ID(取消订阅也需要用到此ID)
             // 之所以用this.pubId,因为订阅和销毁在不同作用域中,无法使用变量。
            this.pubId = pubsub.subscribe("SchoolName",(msgName,data)=>{
              	console.log("消息名字:",msgName);
            	console.log("Student组件收到学校名字:",data);
            })
        },
        beforeDestory(){
        	//订阅的消息最好在组件销毁前取消订阅。
    		pubsub.unsubScribe(this.pubId);
    	}
    }
    </script>
    
  3. 订阅完消息,就等待消息的发布了,谁提供数据,谁就发布消息,并传入所需的数据。本案例中是School组件提供数据,所以在School组件内内部发布消息。触发机制是按钮点击时发布消息, 在发布消息之前也需要引入 pubsub-js 插件:
    School
    <template>
      <div class="school">
            <p>学校名字:{{name}}</p>
            <p>学校地址:{{add}}</p>
            <p>办校年限:{{age}}</p>
            <button @click = "sendSchoolName">传递学校名给Student组件</button>
      </div>
    </template>
    <script>
    import pubsub from 'pubsub-js';
    export default {
        name:'School',
        props:['getSchoolName'],
        data() {
            return {
                name:"五道口技术学院",
                add:"北京",
                age:100
            }
        },
        methods: {
          sendSchoolName(){
            // 发布消息:谁提供数据谁发布消息,同时传入需要的数据给消息订阅者
            pubsub.publish("SchoolName",this.name);
          }
        },
        mounted() {
            this.$bus.$on("StudentName",(name)=>{
              console.log("School接收到的数据",name);
            })
        },
    }
    </script>
    <!--...-->
    
  4. 效果:(点击了‘传递学校名给Student组件’ 按钮)在这里插入图片描述
  5. 解析:
    1. 引入插件后得到一个subpub对象 。
    2. 订阅消息:pubsub.subscribe("SchoolName",(msgName,data)=>{})
      1. 最好在页面挂在完毕的钩子函数内部订阅:mounted(){}
      2. 订阅的回调函数最好写成箭头函数,保证this指向vm。
      3. 回调函数接受两个参数:
        1. msgName 消息的名字(SchoolName)
        2. data:需要的数据,本案例是学校的名字
      4. 订阅的消息最好在组件销毁前取消订阅:beforsDestory(){}
    3. 发布消息:pubsub.publish("SchoolName",this.name)
      1. 消息的发布一般实在一个合适的时机,比如点击时触发,同时传入需要的数据。
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-10 22:22:38  更:2022-03-10 22:25:46 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:30:50-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码