Vue组件间通信的全部方法

组件通信方式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修改
    }
  }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值