VueJs组件之父子通讯的方式


Posted in Javascript onMay 06, 2018

组件(父子通讯)

一、概括

在一个组件内定义另一个组件,称之为父子组件。

   但是要注意的是:1.子组件只能在父组件内部使用(写在父组件tempalte中);

                                2.默认情况下,子组件无法访问父组件上的数据,每个组件实例的作用域是独立的;

那如何完成父子如何完成通讯,简单一句话:props down, events up :父组件通过 props 向下传递数据给子组件,子组件通过 events 给父组件发送

父传子:Props
子传父:子:$emit(eventName) 父$on(eventName)
父访问子:ref

下面对三个进行案例讲解:

二、父传子:Props

     组件实例的作用域是孤立的。这意味着不能 (也不应该) 在子组件的模板内直接引用父组件的数据。要让子组件使用父组件的数据,需要通过子组件的 props 选项

使用Prop传递数据包括静态和动态两种形式,下面先介绍静态props

1、静态props

<script src="https://unpkg.com/vue"></script>
<div id="example">
 <parent></parent>
</div>
<script>
 //要想子组件能够获取父组件的,那么在子组件必须申明:props
 var childNode = {
  template: '<div>{{message}}</div>',
  props: ['message']
 }
 //这里的message要和上面props中值一致
 var parentNode = {
  template: `
   <div class="parent">
   <child message="我是"></child>
   <child message="徐小小"></child>
   </div>`,
  components: {
   'child': childNode
  }
 };
 // 创建根实例
 new Vue({
  el: '#example',
  components: {
   'parent': parentNode
  }
 })
</script>

效果:

VueJs组件之父子通讯的方式

 命名约定:

     对于props声明的属性来说,在父级HTML模板中,属性名需要使用中划线写法

    子级props属性声明时,使用小驼峰或者中划线写法都可以;而子级模板使用从父级传来的变量时,需要使用对应的小驼峰写法

上面这句话什么意思呢?

<script>
 //这里需要注意的是props可以写成['my-message']或者['myMessage']都是可以的
 //但是template里的属性名,只能是驼峰式{{myMessage}},如果也写成{{my-message}}那么是无效的
 var childNode = {
  template: '<div>{{myMessage}}</div>',
  props: ['myMessage']
 }

 //这里的属性名为my-message
 var parentNode = {
  template: `
   <div class="parent">
   <child my-message="我是"></child>
   <child my-message="徐小小"></child>
   </div>`,
  components: {
   'child': childNode
  }
 };
</script>

       如果我们childNode中的myMessage改成{{my-message}}看运行结果:

VueJs组件之父子通讯的方式

2.动态props

    在模板中,要动态地绑定父组件的数据到子模板的 props,与绑定到任何普通的HTML特性相类似,就是用 v-bind。每当父组件的数据变化时,该变化也会传导给子组件

var childNode = {
  template: '<div>{{myMessage}}</div>',
  props: ['my-message']
    }

 var parentNode = {
  template: `
 <div class="parent">
 <child :my-message="data1"></child>
 <child :my-message="data2"></child>
 </div>`,
  components: {
   'child': childNode
  },
  data() {
   return {
    'data1': '111',
    'data2': '222'
   }
  }
 };

3、传递数字

初学者常犯的一个错误是使用字面量语法传递数值

<script src="https://unpkg.com/vue"></script>
<div id="example">
 <parent></parent>
</div>
<script>
 var childNode = {
  template: '<div>{{myMessage}}的类型是{{type}}</div>',
  props: ['myMessage'],
  computed: {
   type() {
    return typeof this.myMessage
   }
  }
 }
 var parentNode = {
  template: `
 <div class="parent">
 <my-child my-message="1"></my-child>
 </div>`,
  components: {
   'myChild': childNode
  }
 };
 // 创建根实例
 new Vue({
  el: '#example',
  components: {
   'parent': parentNode
  }
 })
</script>

结果:

VueJs组件之父子通讯的方式

     因为它是一个字面 prop,它的值是字符串 "1" 而不是 number。如果想传递一个实际的 number,需要使用 v-bind,从而让它的值被当作JS表达式计算

     如何把String转成number呢,其实只要改一个地方。

var parentNode = {
  template: `
 <div class="parent">
 //只要把父组件my-message="1"改成:my-message="1"结果就变成number类型
 <my-child :my-message="1"></my-child>
 </div>`,
 };

     当然你如果想通过v-bind想传一个string类型,那该怎么做呢?

    我们可以使用动态props,在data属性中设置对应的数字1

var parentNode = {
 template: `
 <div class="parent">
 <my-child :my-message="data"></my-child>
 </div>`,
 components: {
 'myChild': childNode
 },
 //这里'data': 1代表就是number类型,'data': "1"那就代表String类型
 data(){
 return {
  'data': 1
 }
 }
};

三、子转父 :$emit

 关于$emit的用法

   1、父组件可以使用 props 把数据传给子组件。
   2、子组件可以使用 $emit 触发父组件的自定义事件。

子主键

<template> 
 <div class="train-city"> 
 <span @click='select(`大连`)'>大连</span> 
 </div> 
</template> 
<script> 
export default { 
 name:'trainCity', 
 methods:{ 
 select(val) { 
  let data = { 
  cityname: val 
  }; 
  this.$emit('showCityName',data);//select事件触发后,自动触发showCityName事件 
 } 
 } 
} 
</script>

父组件

<template> 
 <trainCity @showCityName="updateCity" :index="goOrtoCity"></trainCity> //监听子组件的showCityName事件。 
<template> 
<script> 
export default { 
 name:'index', 
 data () { 
 return { 
  toCity:"北京" 
 } 
 } 
 methods:{ 
 updateCity(data){//触发子组件城市选择-选择城市的事件 
  this.toCity = data.cityname;//改变了父组件的值 
  console.log('toCity:'+this.toCity)  
 } 
 } 
} 
</script>

结果为:toCity: 大连

第二个案例

<script src="https://unpkg.com/vue"></script>

 <div id="counter-event-example">
  <p>{{ total }}</p>
  <button-counter v-on:increment1="incrementTotal"></button-counter>
  <button-counter v-on:increment2="incrementTotal"></button-counter>
 </div>
<script>
 Vue.component('button-counter', {
  template: '<button v-on:click="increment">{{ counter }}</button>',
  //组件数据就是需要函数式,这样的目的就是让每个button-counter不共享一个counter
  data: function() {
   return {
    counter: 0
   } 
  },
  methods: {
   increment: function() {
   //这里+1只对button的值加1,如果要父组件加一,那么就需要$emit事件
    this.counter += 1;
    this.$emit('increment1', [12, 'kkk']);
   }
  }
 });
 new Vue({
  el: '#counter-event-example',
  data: {
   total: 0
  },
  methods: {
   incrementTotal: function(e) {
    this.total += 1;
    console.log(e);
   }
  }
 });
</script>

详细讲解:

   1:button-counter作为父主键,父主键里有个button按钮。

   2:两个button都绑定了click事件,方法里: this.$emit('increment1', [12, 'kkk']);,那么就会去调用父类v-on所监听的increment1事件。

   3:当increment1事件被监听到,那么执行incrementTotal,这个时候才会把值传到父组件中,并且调用父类的方法。

   4:这里要注意第二个button-counter所对应的v-on:'increment2,而它里面的button所对应是this.$emit('increment1', [12, 'kkk']);所以第二个button按钮是无法把值传给他的父主键的。

 示例:一个按钮点击一次那么它自身和上面都会自增1,而第二个按钮只会自己自增,并不影响上面这个。

VueJs组件之父子通讯的方式

还有就是第一个按钮每点击一次,后台就会打印一次如下:

VueJs组件之父子通讯的方式

 四、ref ($refs)用法

ref 有三种用法

    1.ref 加在普通的元素上,用this.ref.name 获取到的是dom元素

    2.ref 加在子组件上,用this.ref.name 获取到的是组件实例,可以使用组件的所有方法。

    3.如何利用v-for 和ref 获取一组数组或者dom 节点

1.ref 加在普通的元素上,用this.ref.name 获取到的是dom元素

<script src="https://unpkg.com/vue"></script>

<div id="ref-outside-component" v-on:click="consoleRef">
 <component-father ref="outsideComponentRef">
 </component-father>
 <p>ref在外面的组件上</p>
</div>
<script>
 var refoutsidecomponentTem = {
  template: "<div class='childComp'><h5>我是子组件</h5></div>"
 };
 var refoutsidecomponent = new Vue({
  el: "#ref-outside-component",
  components: {
   "component-father": refoutsidecomponentTem
  },
  methods: {
   consoleRef: function() {
    console.log(this.); // #ref-outside-component  vue实例
    console.log(this.$refs.outsideComponentRef); // div.childComp vue实例
   }
  }
 });
</script>

效果:当在div访问内点击一次:

VueJs组件之父子通讯的方式

2.ref使用在外面的元素上

<script src="https://unpkg.com/vue"></script>

<!--ref在外面的元素上-->
<div id="ref-outside-dom" v-on:click="consoleRef">
 <component-father>
 </component-father>
 <p ref="outsideDomRef">ref在外面的元素上</p>
</div>
<script>
 var refoutsidedomTem = {
  template: "<div class='childComp'><h5>我是子组件</h5></div>"
 };
 var refoutsidedom = new Vue({
  el: "#ref-outside-dom",
  components: {
   "component-father": refoutsidedomTem
  },
  methods: {
   consoleRef: function() {
    console.log(this); // #ref-outside-dom vue实例
    console.log(this.$refs.outsideDomRef); // <p> ref在外面的元素上</p>
   }
  }
 });
</script>

 效果:当在div访问内点击一次:

VueJs组件之父子通讯的方式

3.ref使用在里面的元素上---局部注册组件

<script src="https://unpkg.com/vue"></script>
<!--ref在里面的元素上-->
<div id="ref-inside-dom">
 <component-father>
 </component-father>
 <p>ref在里面的元素上</p>
</div>
<script>
 var refinsidedomTem = {
  template: "<div class='childComp' v-on:click='consoleRef'>" +
   "<h5 ref='insideDomRef'>我是子组件</h5>" +
   "</div>",
  methods: {
   consoleRef: function() {
    console.log(this); // div.childComp vue实例 
    console.log(this.$refs.insideDomRef); // <h5 >我是子组件</h5>
   }
  }
 };
 var refinsidedom = new Vue({
  el: "#ref-inside-dom",
  components: {
   "component-father": refinsidedomTem
  }
 });
</script>

  效果:当在click范围内点击一次:

VueJs组件之父子通讯的方式

4.ref使用在里面的元素上---全局注册组件

<script src="https://unpkg.com/vue"></script>
<!--ref在里面的元素上--全局注册-->
<div id="ref-inside-dom-all">
 <ref-inside-dom-quanjv></ref-inside-dom-quanjv>
</div>
<script>
 //v-on:input指当input里值发生改变触发showinsideDomRef事件
 Vue.component("ref-inside-dom-quanjv", {
  template: "<div class='insideFather'> " +
   "<input type='text' ref='insideDomRefAll' v-on:input='showinsideDomRef'>" +
   " <p>ref在里面的元素上--全局注册 </p> " +
   "</div>",
  methods: {
   showinsideDomRef: function() {
    console.log(this); //这里的this其实还是div.insideFather
    console.log(this.$refs.insideDomRefAll); // <input type="text">
   }
  }
 });
 var refinsidedomall = new Vue({
  el: "#ref-inside-dom-all"
 });
</script>

效果:当我第一次输入1时,值已改变出发事件,当我第二次在输入时在触发一次事件,所以后台应该打印两次

VueJs组件之父子通讯的方式

总结

以上所述是小编给大家介绍的VueJs组件之父子通讯的方式,希望对大家有所帮助,如果大家有任何疑问欢迎各我留言,小编会及时回复大家的!

Javascript 相关文章推荐
用JavaScrpt实现文件夹简单轻松加密的实现方法图文
Sep 08 Javascript
几个常用的JavaScript字符串处理函数 - split()、join()、substring()和indexOf()
Jun 02 Javascript
JavaScript 提升运行速度之循环篇 译文
Aug 15 Javascript
Javascript中判断对象是否为空
Jun 10 Javascript
禁止按回车键提交表单的方法
Jun 11 Javascript
Angularjs使用指令做表单校验的方法
Mar 31 Javascript
Angular.js中定时器循环的3种方法总结
Apr 27 Javascript
Angular2学习教程之ng中变更检测问题详解
May 28 Javascript
jQuery常见面试题之DOM操作详析
Jul 05 jQuery
Vue.js分页组件实现:diVuePagination的使用详解
Jan 10 Javascript
详解Vue的常用指令v-if, v-for, v-show,v-else, v-bind, v-on
Oct 12 Javascript
微信小程序发送短信验证码完整实例
Jan 07 Javascript
vue自动化表单实例分析
May 06 #Javascript
node+koa2+mysql+bootstrap搭建一个前端论坛
May 06 #Javascript
JS中this的指向以及call、apply的作用
May 06 #Javascript
如何利用@angular/cli V6.0直接开发PWA应用详解
May 06 #Javascript
Less 安装及基本用法
May 05 #Javascript
es6新特性之 class 基本用法解析
May 05 #Javascript
JS同步、异步、延迟加载的方法
May 05 #Javascript
You might like
有关 PHP 和 MySQL 时区的一点总结
2008/03/26 PHP
ThinkPHP调用百度翻译类实现在线翻译
2014/06/26 PHP
PHP实现长文章分页实例代码(附源码)
2016/02/03 PHP
PHP+sqlite数据库操作示例(创建/打开/插入/检索)
2016/05/26 PHP
javascript 写类方式之九
2009/07/05 Javascript
javascript学习笔记(十八) 获得页面中的元素代码
2012/06/20 Javascript
jQuery拖拽 &amp; 弹出层 介绍与示例
2013/12/27 Javascript
jQuery中;function($,undefined) 前面的分号的用处
2014/12/17 Javascript
jQuery EasyUI 为Combo,Combobox添加清除值功能的实例
2017/04/13 jQuery
实现jquery放大镜的两种方法
2018/02/22 jQuery
浅谈Node框架接入ELK实践总结
2019/02/22 Javascript
详解实现一个通用的“划词高亮”在线笔记功能
2019/04/23 Javascript
Vue项目从webpack3.x升级webpack4不完全指南
2019/04/28 Javascript
[04:23]DOTA2上海特锦赛小组赛第一日 TOP10精彩集锦
2016/02/27 DOTA
Python中的列表生成式与生成器学习教程
2016/03/13 Python
pytorch使用tensorboardX进行loss可视化实例
2020/02/24 Python
python实现简单学生信息管理系统
2020/04/09 Python
python关于倒排列的知识点总结
2020/10/13 Python
基于 HTML5 的 WebGL 3D 版俄罗斯方块的示例代码
2018/05/28 HTML / CSS
Cotton On美国网站:澳洲时装连锁品牌
2016/10/25 全球购物
在线实验室测试:HealthLabs.com
2020/05/03 全球购物
大学本科毕业生求职简历的自我评价
2013/10/09 职场文书
销售会计工作职责
2013/12/02 职场文书
让生命充满爱演讲稿
2014/05/10 职场文书
入党积极分子对十八届四中全会期盼的思想汇报
2014/10/17 职场文书
群众路线剖析材料(四风)
2014/11/05 职场文书
地方课程教学计划
2015/01/19 职场文书
三孔导游词
2015/02/05 职场文书
2015学生会文艺部工作总结
2015/04/03 职场文书
2015年食品安全工作总结
2015/05/15 职场文书
2016年会领导致辞稿
2015/07/29 职场文书
庭外和解协议书
2016/03/23 职场文书
基于Redis延迟队列的实现代码
2021/05/13 Redis
Html5大屏数据可视化开发的实现
2021/06/11 HTML / CSS
怎么禁用Windows 11快照布局? win11不使用快照布局的技巧
2021/11/21 数码科技
React自定义hook的方法
2022/06/25 Javascript