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(方法名,传递的数据)。4、接收数据方,通过mounted()触发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全家桶之组件化开发
VueVue入门--双向绑定,Vue的组件,Axios异步通信,计算属性,插值,自定义事件