组件通信方式1:props
        使用场景:[父子通信]
传递数据类型:
1:可能不是函数 ———–实质父组件想给子组件传递数据
    父组件传入属性,子组件通过props来接收,在子组件中就可以用this.xxx方式使用。
| 12
 3
 4
 5
 
 | <father :hello="123"></father>
 
 props:['hello']
 
 
 | 
2:可能是函数 ———–实质子组件想给父亲传递数据
| 12
 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事件
| 12
 3
 4
 
 | <Event2 @xxx="handler4"></Event2>
 
 <button @click="$emit('xxx','我是自定义事件xxx')">分发自定义xxx事件</button>
 
 | 
组件通信方式3:$bus 全局事件总线
【万能】 组件实例的原型的原型指向的Vue.prototype
| 12
 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 
| 12
 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组件中经常出现,实现父子数据同步。
| 12
 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:可以在子组件内部获取唯一的父组件【返回组件实例】
| 12
 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接收。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | data() {
 return {
 name: "卷儿"
 }
 },
 provide: function() {
 return {
 name: this.name
 }
 },
 
 
 | 
这种方法传递过来的数据是没有响应性的,当你改变父组件中的name时,子组件中接收的name并不会改变。
官方解释:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的。
二、响应式
方法一:传递的参数用一个方法返回
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | data() {
 return {
 name: "卷儿"
 }
 },
 provide: function() {
 return {
 newName: () => this.name
 }
 
 | 
| 12
 3
 4
 5
 6
 7
 
 | inject: ['newName'],
 computed: {
 hnewName() {
 return this.newName()
 }
 }
 
 | 
| 12
 3
 
 | <!-- 子组件中的使用方式 --><h2>{{ hnewName }} <!-- 推荐使用这种方法 -->
 <h2>{{ newName() }}
 
 | 
方法二:把需要传递的参数定义成一个对象
官方解释:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | data() {
 return {
 obj: {
 name: "卷儿"
 }
 }
 },
 provide: function() {
 return {
 
 obj: this.obj
 }
 },
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 
 | inject: ['obj'],
 computed: {
 
 objName() {
 return this.obj.name
 }
 }
 
 | 
| 12
 3
 
 | <!-- 子组件中的使用方法 --><h2>obj的name: {{objName}}</h2>
 <h2>obj的name: {{obj.name}}</h2>
 
 | 
方法三:Vue.computed
| 12
 3
 4
 5
 6
 
 | provide() {return {
 mode:this.mode,
 mode: Vue.computed(() => this.mode)
 }
 }
 
 |