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 相关文章推荐
EasySlider 基于jQuery功能强大简单易用的滑动门插件
Jun 11 Javascript
jquery遍历select元素(实例讲解)
Dec 31 Javascript
一个html5播放视频的video控件只支持android的默认格式mp4和3gp
May 08 Javascript
javascript基于DOM实现省市级联下拉框的方法
May 14 Javascript
javascript动态获取登录时间和在线时长
Feb 25 Javascript
jquery遍历标签中自定义的属性方法
Sep 17 Javascript
d3.js中冷门却实用的内置函数总结
Feb 04 Javascript
jQuery插件select2利用ajax高效查询大数据列表(可搜索、可分页)
May 19 jQuery
利用ES6的Promise.all实现至少请求多长时间的实例
Aug 28 Javascript
AngularJS中的作用域实例分析
May 16 Javascript
vue模仿网易云音乐的单页面应用
Apr 24 Javascript
React中Ref 的使用方法详解
Apr 28 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
第十二节 类的自动加载 [12]
2006/10/09 PHP
PHP简单系统查询模块代码打包下载
2008/06/07 PHP
PHP5 面向对象(学习记录)
2009/12/02 PHP
php 类自动载入的方法
2015/06/03 PHP
PHP实现用户登录的案例代码
2018/05/10 PHP
PHP 模拟登陆功能实例详解
2019/09/10 PHP
基于Laravel-admin 后台的自定义页面用法详解
2019/09/30 PHP
js解析与序列化json数据(三)json的解析探讨
2013/02/01 Javascript
js遍历、动态的添加数据的小例子
2013/06/22 Javascript
js改变鼠标的形状和样式的方法
2014/03/31 Javascript
通过location.replace禁止浏览器后退防止重复提交
2014/09/04 Javascript
node.js中的querystring.parse方法使用说明
2014/12/10 Javascript
JavaScript代码因逗号不规范导致IE不兼容的问题
2016/02/25 Javascript
JavaScript地理位置信息API
2016/06/11 Javascript
详解nodejs中的process进程
2017/03/19 NodeJs
springMVC + easyui + $.ajaxFileUpload实现文件上传注意事项
2017/04/23 Javascript
在Vue中使用highCharts绘制3d饼图的方法
2018/02/08 Javascript
纯js封装的ajax功能函数与用法示例
2018/05/14 Javascript
微信小程序倒计时功能实例代码
2018/07/17 Javascript
Vue.js图片预览插件使用详解
2018/08/27 Javascript
JS实现TITLE悬停长久显示效果完整示例
2020/02/11 Javascript
js实现鼠标切换图片(无定时器)
2021/01/27 Javascript
[08:42]DOTA2每周TOP10 精彩击杀集锦vol.2
2014/06/25 DOTA
Python实现从URL地址提取文件名的方法
2015/05/15 Python
Python数据操作方法封装类实例
2017/06/23 Python
详解Python之unittest单元测试代码
2018/01/24 Python
python3使用SMTP发送HTML格式邮件
2018/06/19 Python
Selenium定位元素操作示例
2018/08/10 Python
python flask 如何修改默认端口号的方法步骤
2019/07/12 Python
pytorch多GPU并行运算的实现
2019/09/27 Python
pytorch实现MNIST手写体识别
2020/02/14 Python
jupyter notebook 参数传递给shell命令行实例
2020/04/10 Python
python3.7添加dlib模块的方法
2020/07/01 Python
销售会计工作职责
2013/12/02 职场文书
军训的自我鉴定
2013/12/10 职场文书
如何做好员工培训计划?
2019/07/09 职场文书