Vue 组件通信

1.自定义事件-$emit

子组件用 $emit() 来触发事件,父组件用 $on() 来监听子组件的事件。

<html>
 <head> 
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
 </head> 
 <body> 
  <div id="app"> 
   <p>总数:{{total}}</p> 
   <my-component @increase="handleGetTotal" @reduce="handleGetTotal"> 
   </my-component> 
  </div>  
<script src = "../lib/vue.min.js" ></script> 
<script>
Vue.component('my-component', {
	template:
	 `
       <div>
          <button @click="handleIncrease">+1</button> 
          <button @click="handleReduce">-1</button>
        </div> 
      `,
	data() {
	  return {
	    counter: 0,
	  }
	},
	methods: {
	  handleIncrease() {
	    this.counter++;
	    this.$emit('increase', this.counter);
	  },
	  handleReduce() {
	    this.counter--;
	    this.$emit('reduce', this.counter);
	  },
	}
})
var app = new Vue({
  el: '#app',
  data: {
    total: 0,
  },
  methods: {
    handleGetTotal(total) {
      this.total = total;
    }
  },
}) 
</script> 

 </body>
</html>

2.使用v-model

还是点击按钮+1的效果,不过这次组件 $emit() 的事件名是特殊的 input ,在使用组件的父级,并没有在<my-component>上使用@input="handler",而是直接用了 v-model 绑定的一个数据 total。

源码如下:

<html>
 <head> 
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
 </head> 
 <body> 
  <div id="app"> 
    <p>总数:{{total}}</p>
    <my-component v-model="total"></my-component>
  </div>  
<script src = "../lib/vue.min.js" ></script> 
<script>
Vue.component('my-component', {
	template:'<button @click="handleClick">+1</button>',
  data(){
    return {
      counter:0,
    }
  },
  methods:{
    handleClick(){
      this.counter++;
      this.$emit('input',this.counter);
    },
  }
})
var app = new Vue({
  el: '#app',
  data: {
    total: 0,
  },
  methods: {
    handleGetTotal(total) {
      this.total = total;
    }
  },
}) 
</script> 
 </body>
</html>

v-model 还可以用来创建自定义的表单输入组件,进行数据双向绑定。

代码如下:

<html>
 <head> 
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
 </head> 
 <body> 
  <div id="app"> 
    <p>总数:{{total}}</p>
    <my-component v-model="total"></my-component>
    <button @click="handleReduce">-1</button>
  </div>  
<script src = "../lib/vue.min.js" ></script> 
<script>
Vue.component('my-component', {
  props:['value'],
	template:'<input :value="value" @input="updateValue" >',
  methods:{
    updateValue(event){
      this.$emit('input',event.target.value);
    }
  }
})
var app = new Vue({
  el: '#app',
  data: {
    total: 0,
  },
  methods: {
    handleReduce(){
      this.total--;
    }
  },
}) 
</script> 
 </body>
</html>

3.非父子组件通信

推荐使用一个空的 Vue 实例作为中央事件总线(bus),也就是中介。

点击传递事件,

<html>
 <head> 
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
 </head> 
 <body> 
  <div id="app"> 
    {{message}}
    <component-a></component-a>
  </div>  
<script src = "../lib/vue.min.js" ></script> 
<script>
var bus = new Vue();
Vue.component('component-a', {
  template: '<button @click="handleEvent">传递事件</button>',
  methods: {
    handleEvent(){
      bus.$emit('on-message','来自组件component-a的内容');
    }
  }
})
var app = new Vue({
  el: '#app',
  data: {
    message: '',
  },
  mounted(){
    //监听来自 bus 的事件 on-message
    bus.$on('on-message',(msg)=>{
      this.message = msg;
    })
  }
}) 
</script> 
 </body>
</html>

4.父链

在子组件中,使用 this.$parent可以直接访问该组件的父实例或组件,父组件也可以通过 this.$children 访问它所有的子组件,而且可以递归向上或向下无限访问,直到根实例或最内层的组件。

<html>
 <head> 
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
 </head> 
 <body> 
  <div id="app"> 
    {{message}}
    <component-a></component-a>
  </div>  
<script src = "../lib/vue.min.js" ></script> 
<script>
Vue.component('component-a', {
  template: '<button @click="handleEvent">通过父链直接修改数据</button>',
  methods: {
    handleEvent(){
      //访问到父链后,可以做任何操作,比如直接修改数据
      this.$parent.message = '来自组件 component-a 的内容';
    }
  }
})
var app = new Vue({
  el: '#app',
  data: {
    message: '',
  },
}) 
</script> 
 </body>
</html>

尽管 Vue 允许这样操作,但在业务中,子组件应该尽可能的避免依赖父组件的数据,更不应该去主动修改它的数据,因为这样会使得父子组件紧耦合。父子组件最好还是通过 props 和 $emit 来通信。

5.子组件索引(ref)

Vue提供了子组件索引的方法,用特殊的属性  ref 来为子组件指定一个索引名称,

代码如下:

<html>
 <head> 
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
 </head> 
 <body> 
  <div id="app"> 
    {{message}}
    <button @click="handleRef">通过 ref 获取子组件实例</button>
    <component-a ref="comA"></component-a>
  </div>  
<script src = "../lib/vue.min.js" ></script> 
<script>
Vue.component('component-a', {
  template: '<div>子组件</div>',
  data(){
    return{
      message: '我是子组件内容'
    }
  }
})
var app = new Vue({
  el: '#app',
  data: {
    message: '',
  },
  methods:{
    handleRef(){
      var msg = this.$refs.comA.message;
      this.message = msg;
    }
  }
}) 
</script> 
 </body>
</html>

在父组件模板中,子组件标签上使用 ref 指定一个名称,并在父组件内通过 this.$refs 来访问指定名称的组件。

$refs 只在组件渲染完成后才填充,并且它是非响应式的。它仅仅作为一个直接访问子组件的应急方案,应当避免在模板或计算属性中使用 $refs。 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值