组件通信方式1:props
使用场景:[父子通信]
传递数据类型: 1:可能不是函数 -----------实质父组件想给子组件传递数据
父组件传入属性,子组件通过props来接收,在子组件中就可以用this.xxx方式使用。
//父组件
<father :hello="123"></father>
//子组件
props:['hello']
//this.hello 为123
2:可能是函数 -----------实质子组件想给父亲传递数据
// 子组件
<template>
<header>
<h1 @click="changeTitle">h1</h1>//绑定一个点击事件
</header>
</template>
<script>
export default {
name: 'app-header',
methods:{
changeTitle() {
this.$emit("titleChanged","子向父组件传值");//自定义事件 传递值“子向父组件传值”
}
}
}
</script>
// 父亲
<template>
<div id="app">
<app-header v-on:titleChanged="updateTitle" ></app-header>//与子组件titleChanged自定义事件保持一致
<h2>{{title}}</h2>
</div>
</template>
<script>
import Header from "./components/Header"
export default {
name: 'App',
data(){
return{
title:"传递的是一个值"
}
},
methods:{
updateTitle(e){ //声明这个函数
this.title = e;
}
},
components:{
"app-header":Header,
}
}
</script>
特殊情况:路由传递props
1:布尔值类型,把路由中params参数映射为组件props数据
2:对象,静态数据,很少用
3:函数,可以把路由中params|query参数映射为组件props数据
组件通信方式2:自定义事件
$emit $on[简写@]
事件:原生DOM事件----【click|mouseenter........】
事件:自定义事件-----[子给父传递数据]
组件绑定原生DOM事件,并非原生DOM事件,而是所谓的自定义事件。 如果你想把自定义事件变为原生DOM事件,需要加上修饰符.native修饰 这个修饰符,可以把自定义事件【名字:原生DOM类型的】变为原生DOM事件,
//父亲
<Event2 @xxx="handler4"></Event2>
//子组件
<button @click="$emit('xxx','我是自定义事件xxx')">分发自定义xxx事件</button>
组件通信方式3:$bus 全局事件总线
【万能】 组件实例的原型的原型指向的Vue.prototype
//在main.js书写Vue类的时候
//创建vm
new Vue({
el:'#app',
render: h => h(App),
// beforeCreate中模板未解析,且this是vm
beforeCreate(){
Vue.prototype.$bus = this //安装全局事件总线
}
})
//在某一个组件中
bus.$on('globalEvent',(val)=>{
this.brothermessage=val;
})
//在另外一个组件中
//触发全局事件globalEvent
bus.$emit('globalEvent',val)
}
组件通信方式4:pubsub-js【发布订阅消息】
在vue中根本不用
【React】中使用的频率较高 ----万能
组件通信方式5:Vuex[仓库]
数据是非持久化的 ---万能的
核心概念:state mutations actions getters modules
如果业务逻辑复杂,很多组件之间需要同时处理一些公共的数据,这个时候才有上面这一些方法可能不利于项目的维护,vuex的做法就是将这一些公共的数据抽离出来,然后其他组件就可以对这个公共数据进行读写操作,这样达到了解耦的目的。
组件通信方式6:插槽
父子通信【结构】 slot
插槽的主要作用是传递结构,可以直接让子组件不用书写自己的结构,在element-ui中使用的频率非常高
默认插槽
具名插槽:需要书写name
作用域插槽:子组件的数据来源于父组件,但是子组件的自己的结构有父亲决定。
7:v-model实现组件通信
v-model:指令,可以收集表单数据【text、radio、checkbox、range】等等
切记:v-model收集checkbox需要用数组收集
v-model:实现原理 :value @input
<h2>v-model底层实现原理</h2>
<input type="text" placeholder="与v-model功能一样" :value="msg1" @input="handler"/>
handler(e){
this.msg1 = e.target.value;
},
v-model实现父子数据交换
<CustomInput v-model="msg2"></CustomInput>
//子组件
<template>
<div>
<input type="text" :value="value" @input="$emit('input',$event.target.value)">
</div>
</template>
<script type="text/ecmascript-6">
export default {
props:['value']
}
</script>
8:属性修饰符.sync
可以实现父子数据同步。
在elementUI组件中经常出现,实现父子数据同步。
<h2>不使用sync修改符</h2>
<!-- 给子组件绑定一个自定义事件:update:money -->
<Child :money="money" @update:money="handler"></Child>
<h2>使用sync修改符</h2>
<Child :money.sync="money"></Child>
//前面两者所代表的含义是一样的,都是给子组件传递了一个money数据,然后还给子组件传递了自定义事件update:money
//子组件
<span>小明每次花100元</span>
<button @click="$emit('update:money',money-100)">花钱</button>
9:$attrs与$listeners
父子组件通信
$attrs:组件实例的属性,可以获取到父亲传递的props数据(前提子组件没有通过props接受)
$listeners:组件实例的属性,可以获取到父亲传递自定义事件(对象形式呈现)
10:$children与$parent
可以实现父子组件通信
ref:可以在父组件内部获取子组件---实现父子通信
在使用子组件的时候打上ref,然后直接通过this.$refs调用就行了,可以直接调用子组件的data
$children:可以在父组件内部获取全部的子组件【返回数组】
$parent:可以在子组件内部获取唯一的父组件【返回组件实例】
//父组件
<template>
<div>
<h2>BABA有存款: {{ money }}</h2>
<button @click="borrowFromXM">找小明借钱100</button><br />
<button @click="borrowFromXH">找小红借钱150</button><br />
<button @click="borrowFromAll">找所有孩子借钱200</button><br />
<!-- ref:可以获取到真实DOM节点,可以获取相应组件的实例VC -->
<!-- ref也算在一种通信手段:在父组件中可以获取子组件(属性|方法) -->
<Son ref="son" />
<Daughter ref="dau" />
</div>
</template>
<script>
import Son from "./Son";
import Daughter from "./Daughter";
export default {
name: "ChildrenParentTest",
data() {
return {
money: 1000,
};
},
methods: {
//小明借用100元
borrowFromXM() {
//父亲的钱加上100元
this.money += 100;
this.$refs.son.money -= 100;
},
borrowFromXH() {
this.money += 150;
this.$refs.dau.money -= 150;
},
borrowFromAll() {
//VC:$children属性,可以获取当前组件的全部子组件[这个属性在用的时候很少用索引值获取子组件,因为没有办法确定数组里面的元素到底是哪一个子组件]
this.money += 400;
this.$children.forEach((item) => {
item.money -= 200;
});
},
},
components: {
Son,
Daughter,
},
};
//女儿组件
<template>
<div style="background: #ccc; height: 50px;">
<h3>女儿小红: 有存款: {{money}}</h3>
<button @click="giveMoney">给BABA钱: 100</button>
</div>
</template>
<script>
export default {
name: 'Daughter',
data () {
return {
money: 20000
}
},
methods: {
giveMoney(){
this.money-=100;
this.$parent.money+=100;
}
}
}
//儿子组件
<template>
<div style="background: #ccc; height: 50px;">
<h3>儿子小明: 有存款: {{money}}</h3>
<button @click="giveMoney">给BABA钱: 50</button>
</div>
</template>
<script>
export default {
name: 'Son',
data () {
return {
money: 30000
}
},
methods: {
giveMoney(){
this.money-=50;
//$parent,VC一个属性,可以获取当前组件(属性|方法)
this.$parent.money+=50;
}
}
}
</script>
11.localStorage/sessionStorage
直接将数据存储在本地浏览器上,使用的时候直接调用本地数据就行
持久化存储。
12. provide/inject
主要解决深层次的组件嵌套,祖先组件向子孙组件之间传值。
一层嵌套的父子组件可以使用props来传值,props本身就是有响应性的。
根据自身代码选择合适的传值方式,并不一定非要用provide/inject的传值。
前言
官网概念:这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在其上下游关系成立的时间里始终生效。
一、基本用法
在父组件中使用provide传值,在子组件中用inject接收。
// 父组件
data() {
return {
name: "卷儿"
}
},
provide: function() {
return {
name: this.name
}
},
这种方法传递过来的数据是没有响应性的,当你改变父组件中的name时,子组件中接收的name并不会改变。
官方解释:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的。
二、响应式
方法一:传递的参数用一个方法返回
// 父组件
data() {
return {
name: "卷儿"
}
},
provide: function() {
return {
newName: () => this.name
}
// 子组件
inject: ['newName'],
computed: {
hnewName() {
return this.newName()
}
}
<!-- 子组件中的使用方式 -->
<h2>{{ hnewName }}</h2> <!-- 推荐使用这种方法 -->
<h2>{{ newName() }}</h2>
方法二:把需要传递的参数定义成一个对象
官方解释:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的。
// 父组件
data() {
return {
obj: {
name: "卷儿"
}
}
},
provide: function() {
return {
// 传递一个对象
obj: this.obj
}
},
// 子组件
inject: ['obj'],
computed: {
// 也可以不用计算属性重新定义
objName() {
return this.obj.name
}
}
<!-- 子组件中的使用方法 -->
<h2>obj的name: {{objName}}</h2>
<h2>obj的name: {{obj.name}}</h2>
方法三:Vue.computed
provide() {
return {
mode:this.mode, //不具有响应性,也就是说在父组件修改了mode,子组件inject部分不会响应
mode: Vue.computed(() => this.mode) //具有响应性,子组件inject会跟随父组件provide修改
}
}