VueVue全家桶Vue组件通信+Vue组件插槽

Posted 前端More

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VueVue全家桶Vue组件通信+Vue组件插槽相关的知识,希望对你有一定的参考价值。

1 Vue组件通信

父向子传值:父组件设置v-bind传递数据,子组件设置props 接收数据

子向父传值: 子组件设置$emit传递数据 ,父组件设置v-on事件绑定接收数据

兄弟组件任意组件通信:通过事件车的方式传递数据, 新建一个空的全局Vue对象 EventBus,利用$emit发送 , $on接收

1.1 组件间通信基本原则

不要在子组件中直接修改父组件的状态数据
数据在哪, 更新数据的行为(函数)就应该定义在哪

1.2 vue 组件间通信方式

  • props
  • vue 的自定义事件
  • 消息订阅与发布(如: pubsub 库)
  • slot
  • vuex

1.1 props

props:让组件接收外部传过来的数据,此方式用于父组件向子组件传递数据
props传递数据原则:单向数据流,只能父传子
注意:

  • 如果需要向非子后代传递数据必须多层逐层传递
  • 兄弟组件间也不能直接props 通信, 必须借助父组件才可以
  • 所有标签属性都会成为组件对象的属性, 模板页面可以直接引用

1.父组件通过传统方式或v-bind动态绑定向子组件传送数据

 <!-- App父组件 -->
<template>
  <div>
   <!-- 传送数据一定要写在父组件的子组件标签上(通过标签属性)-->
   <!-- 1.传统方式传送数据 -->
    //<Student name='张三'/>
   <!-- 2.动态绑定传送数据(不限于形式,可能是函数)  Student.name会作为表达式自动执行 -->
    <Student :name='Student.name'/>
  </div>
</template>
<script>
//引入子组件
import Student from "./components/Student.vue";
export default 
   name: "App",
   components:  Student ,
   data() 
    return 
      Student:
        name:'张三'
      
    ;
  ,
;
</script>

2.子组件内部通过props接收父组件传递的数据

 <!-- Student子组件 -->
//第一种方式(只接收)最常用
props:['name']
//第二种方式(限制类型)
props:name:String
//第三种方式(限制类型、限制必要性、指定默认值)
props:
	name:
	type:String, //类型
	required:true, //必要性
	default:'张三' //默认值
	

备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。

App.vue 父组件

<template>
  <div>
    <!-- 传递数据 -->
    <!-- :是v-bind动态绑定 18会作为表达式自动执行 -->
    <Student name='李四' sex='女'  :age='18'></Student>
  </div>
</template>

<script>
//引入子组件

import Student from "./components/Student.vue";
export default 
   name: "App",
   components:  Student ,
;
</script>

<style>
</style>

Student.vue 子组件

<template>
  <div>
    <h2>学生姓名: name </h2>
    <h2>学生性别: sex </h2>
    <h2>学生年龄: myAge + 1 </h2>
    <button @click="updateAge">尝试修改收到的年龄</button>
  </div>
</template>

<script>
export default 
  name: "Student",
  data() 
    return 
    //若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据
      myAge: this.age,
    ;
  ,
  methods: 
    updateAge() 
      this.myAge++;
    ,
  ,
  
  //接收数据  简单声明接收
 props:['name','age','sex']
 

;
</script>

1.2 自定义事件

自定义事件用于子组件向父组件传递数据
使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)。
隔代组件或兄弟组件间通信此种方式不合适
1.绑定自定义事件
方式一: v-on

 <!-- App.vue父组件 -->
//   xxx为自定义事件  getStudentName为回调函数(在父组件中)
<Student @xxx="getStudentName" />
...
  methods: 
  //回调函数
    getStudentName(name) 
      this.studentName = name;
    ,
  ,

方式二: ref

//通过ref给Student组件打标识
<Student ref="student"  />
...
  methods: 
  //回调函数
    getStudentName(name) 
      this.studentName = name;
    ,
  ,
 mounted() 
    //通过$refs获取Student组件
    //在获取到的Student组件上绑定自定义事件xxx getStudentName为回调函数
    this.$refs.student.$on("xxx", this.getStudentName); //$on当...时
  ,

2.触发自定义事件
方法:this.$emit(eventName, data)

 <!-- Student.vue子组件 -->
<button @click="sendStudentName">把学生名给App</button>
...
  methods: 
    sendStudentName() 
      //触发Student组件实例身上的xxx自定义事事件
      this.$emit("xxx", this.name);
    
  ,

注意

  • 解绑自定义事件:this.$off(‘xxx’)
  • 自定义事件只能触发一次:可以使用once修饰符,或$once方法。
  • 组件上也可以绑定原生DOM事件,需要使用native修饰符。
    <Student @click.native=“show” />
  • 隔代组件或兄弟组件间通信不能使用自定义事件

案例

App父组件

<template>
  <div class="app">
    <h1> msg ,学生姓名是: studentName </h1>
    <!-- 第一种:使用@或v-on -->
    <!-- <Student @atguigu="getStudentName" /> -->

    <!-- 第二种:使用ref -->
    <Student ref="student" @click.native="show" />
  </div>
</template>

<script>
import Student from "./components/Student";
export default 
  name: "App",
  components:  Student ,
  data() 
    return 
      msg: "你好啊!",
      studentName: "",
    ;
  ,
  methods: 
    getStudentName(name) 
      this.studentName = name;
    ,
    show() 
      alert(123);
    ,
  ,
  mounted() 
    this.$refs.student.$on("atguigu", this.getStudentName); //绑定自定义事件
  ,
;
</script>

<style scoped>
.app 
  background-color: gray;
  padding: 5px;

</style>

Student.vue子组件

<template>
  <div class="student">
    <h2>学生姓名: name </h2>
    <h2>当前求和为: number </h2>
    <button @click="add">点我number++</button>
    <button @click="sendStudentName">把学生名给App</button>
    <button @click="unbind">解绑atguigu事件</button>
    <button @click="death">销毁当前Student组件的实例(vc)</button>
  </div>
</template>

<script>
export default 
  name: "Student",
  data() 
    return 
      name: "张三",
      number: 0,
    ;
  ,
  methods: 
    add() 
      this.number++;
    ,
    sendStudentName() 
      //触发Student组件实例身上的atguigu事件
      this.$emit("atguigu", this.name);
    ,
    unbind() 
      this.$off("atguigu"); //解绑一个自定义事件
      // this.$off(['atguigu','demo']) //解绑多个自定义事件
      // this.$off() //解绑所有的自定义事件
    ,
    death() 
      this.$destroy(); //销毁了当前Student组件的实例,销毁后所有Student实例的自定义事件全都不奏效。
    ,
  ,
;
</script>

<style lang="less" scoped>
.student 
  background-color: pink;
  padding: 5px;
  margin-top: 30px;

</style>

1.3 全局事件总线(GlobalEventBus)

全局事件总线:适用于任意组件间通信。

安装全局事件总线:

new Vue(
	......
	beforeCreate() 
		Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
	,
    ......
) 

使用事件总线:

(1)接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身。

methods()
demo(data)…


mounted()
this. b u s . bus. bus.on(‘xxxx’,this.demo)

   (2)提供数据:this.$bus.$emit('xxxx',数据)

最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件。

main.js

//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//关闭Vue的生产提示
Vue.config.productionTip = false

//创建vm
new Vue(
	el:'#app',
	render: h => h(App),
	beforeCreate() 
		Vue.prototype.$bus = this //安装全局事件总线
	,
)

Student.vue

<

template>
	<div class="student">
		<h2>学生姓名:name</h2>
		<h2>学生性别:sex</h2>
		<button @click="sendStudentName">把学生名给School组件</button>
	</div>
</template>

<script>
	export default 
		name:'Student',
		data() 
			return 
				name:'张三',
				sex:'男',
			
		,
		mounted() 
			// console.log('Student',this.x)
		,
		methods: 
			sendStudentName()
				this.$bus.$emit('hello',this.name)
			
		,
	
</script>

<style lang="less" scoped>
	.student
		background-color: pink;
		padding: 5px;
		margin-top: 30px;
	
</style>

School.vue

<template>
	<div class="school">
		<h2>学校名称:name</h2>
		<h2>学校地址:address</h2>
	</div>
</template>

<script>
	export default 
		name:'School',
		data() 
			return 
				name:'尚硅谷',
				address:'北京',
			
		,
		mounted() 
			// console.log('School',this)
			this.$bus.$on('hello',(data)=>
				console.log('我是School组件,收到了数据',data)
			)
		,
		beforeDestroy() 
			this.$bus.$off('hello')
		,
	
</script>

<style scoped>
	.school
		background-color: skyblue;
		padding: 5px;
	
</style>

1.4消息订阅与发布(PubSubJS 库)

5.1 订阅消息
PubSub.subscribe(‘msg’, function(msg, data))
1
5.2 发布消息
PubSub.publish(‘msg’, data)
1
5.3 示例
订阅消息(绑定事件监听)

import PubSub from ‘pubsub-js’

export default
mounted ()
// 订阅消息(deleteTodo)
PubSub.subscribe(‘deleteTodo’, (msg, index) =>
this.deleteTodo(index)
)


1
2
3
4
5
6
7
8
9
10
发布消息(触发事件)

// this.deleteTodo(this.index)
// 发布消息(deleteTodo)
PubSub.publish(‘deleteTodo’, this.index)
1
2
3
5.4 注意
优点: 此方式可实现任意关系组件间通信(数据)
5.5 事件的2 个重要操作
绑定事件监听(订阅消息)
目标: 标签元素
事件名(类型): click/focus
回调函数: function(event)
触发事件(发布消息)
DOM 事件: 用户在浏览器上对应的界面上做对应的操作
自定义: 编码手动触发
5.6 总结
一种组件间通信的方式,适用于任意组件间通信。

使用步骤:

安装pubsub:npm i pubsub-js

引入: import pubsub from ‘pubsub-js’

接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身。

methods()
demo(data)…


mounted()
this.pid = pubsub.subscribe(‘xxx’,this.demo) //订阅消息

1
2
3
4
5
6
7
提供数据:pubsub.publish(‘xxx’,数据)

最好在beforeDestroy钩子中,用PubSub.unsubscribe(pid)去取消订阅。

学校名称:name

学校地址:address

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40


学生姓名:name


学生性别:sex


<button @click=“sendStudentName”>把学生名给School组件

1.3 非父子组件间传值


1、任意组件之间传递数据需要借助于事件车,通过事件车的方式传递数据
2、创建一个Vue的实例,让各个组件共用同一个事件机制。
3、传递数据方,通过一个事件触发eventBus. e m i t ( 方 法 名 , 传 递 的 数 据 ) 。 4 、 接 收 数 据 方 , 通 过 m o u n t e d ( ) 触 发 e v e n t B u s . emit(方法名,传递的数据)。 4、接收数据方,通过mounted()触发eventBus. emit)4mounted()eventBus.on (方法名,function(接收数据的参数)用该组件的数据接收传递过来的数据),此时函数中的this已经发生了改变,可以使用箭头函数。

首先创建一个单独的js文件bus.js,内容如下

import Vue from 'vue'
export default new Vue

父组件如下:

<template>
     <components-a></components-a>
     <components-b></components-b>
</template>

子组件a如下:

<template>
      <div>
           <button @click="abtn">A按钮</button>
      </div>
</template>
<script>
import  from '../../js/bus.js'
export default 
      name: 'components-a',
      data () 
        return 
                ‘msg':"我是组件A"
        
      ,
      methods:
           abtn:function()
                  let  _this = this;
                   //$emit这个方法会触发一个事件
                   bus .$emit("myFun", _this.msg)  
           
      

</script>

子组件b如下:

<template>
     <div>
         Vue全家桶之组件化开发

VUE复习全家桶

VueVue入门--双向绑定,Vue的组件,Axios异步通信,计算属性,插值,自定义事件

VueVue入门--双向绑定,Vue的组件,Axios异步通信,计算属性,插值,自定义事件

VueVue全家桶Vue脚手架

VueVue全家桶Vue3