组件通信方式1:props
使用场景:[父子通信]
传递数据类型:
1:可能不是函数 ———–实质父组件想给子组件传递数据
父组件传入属性,子组件通过props来接收,在子组件中就可以用this.xxx方式使用。
1 2 3 4 5
| <father :hello="123"></father>
props:['hello']
|
2:可能是函数 ———–实质子组件想给父亲传递数据
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 41 42
| <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事件
1 2 3 4
| <Event2 @xxx="handler4"></Event2>
<button @click="$emit('xxx','我是自定义事件xxx')">分发自定义xxx事件</button>
|
组件通信方式3:$bus 全局事件总线
【万能】 组件实例的原型的原型指向的Vue.prototype
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
new Vue({ el:'#app', render: h => h(App), beforeCreate(){ Vue.prototype.$bus = this } })
bus.$on('globalEvent',(val)=>{ this.brothermessage=val; })
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <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组件中经常出现,实现父子数据同步。
1 2 3 4 5 6 7 8 9
| <h2>不使用sync修改符</h2> <!-- 给子组件绑定一个自定义事件:update:money --> <Child :money="money" @update:money="handler"></Child> <h2>使用sync修改符</h2> <Child :money.sync="money"></Child>
<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:可以在子组件内部获取唯一的父组件【返回组件实例】
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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
| <template> <div> <h2>BABA有存款: {{ money }}</h2> <button @click="borrowFromXM">找小明借钱100</button><br /> <button @click="borrowFromXH">找小红借钱150</button><br /> <button @click="borrowFromAll">找所有孩子借钱200</button><br /> <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接收。
1 2 3 4 5 6 7 8 9 10 11 12
| data() { return { name: "卷儿" } }, provide: function() { return { name: this.name } },
|
这种方法传递过来的数据是没有响应性的,当你改变父组件中的name时,子组件中接收的name并不会改变。
官方解释:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的。
二、响应式
方法一:传递的参数用一个方法返回
1 2 3 4 5 6 7 8 9 10
| data() { return { name: "卷儿" } }, provide: function() { return { newName: () => this.name }
|
1 2 3 4 5 6 7
| inject: ['newName'], computed: { hnewName() { return this.newName() } }
|
1 2 3
| <!-- 子组件中的使用方式 --> <h2>{{ hnewName }} <!-- 推荐使用这种方法 --> <h2>{{ newName() }}
|
方法二:把需要传递的参数定义成一个对象
官方解释:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| data() { return { obj: { name: "卷儿" } } }, provide: function() { return { obj: this.obj } },
|
1 2 3 4 5 6 7 8
| inject: ['obj'], computed: { objName() { return this.obj.name } }
|
1 2 3
| <!-- 子组件中的使用方法 --> <h2>obj的name: {{objName}}</h2> <h2>obj的name: {{obj.name}}</h2>
|
方法三:Vue.computed
1 2 3 4 5 6
| provide() { return { mode:this.mode, mode: Vue.computed(() => this.mode) } }
|