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 相关文章推荐
javascript demo 基本技巧
Dec 18 Javascript
Javascript中this的用法详解
Sep 22 Javascript
js Calender控件使用详解
Jan 05 Javascript
原生JS实现响应式瀑布流布局
Apr 02 Javascript
JavaScript 表单处理实现代码
Apr 13 Javascript
AngularJS使用ngMessages进行表单验证
Dec 27 Javascript
JS对HTML表格进行增删改操作
Aug 22 Javascript
简单谈谈ES6的六个小特性
Nov 18 Javascript
vue+socket.io+express+mongodb 实现简易多房间在线群聊示例
Oct 21 Javascript
使用iView Upload 组件实现手动上传图片的示例代码
Oct 01 Javascript
JavaScript基于数组实现的栈与队列操作示例
Dec 22 Javascript
vue项目,代码提交至码云,iconfont的用法说明
Jul 30 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目录操作函数之获取目录与文件的类型
2010/12/29 PHP
php遍历目录输出目录及其下的所有文件示例
2014/01/27 PHP
php基于双向循环队列实现历史记录的前进后退等功能
2015/08/08 PHP
php入门教程之Zend Studio设置与开发实例
2016/09/09 PHP
PHP开发实现快递查询功能详解
2019/04/08 PHP
JS 页面内容搜索,类似于 Ctrl+F功能的实现代码
2007/08/13 Javascript
javascript 时间比较实现代码
2009/10/28 Javascript
jQuery ajax cache缓存问题
2010/07/01 Javascript
JavaScript 原型继承
2011/12/26 Javascript
js open() 与showModalDialog()方法使用介绍
2013/09/10 Javascript
函数式 JavaScript(一)简介
2014/07/07 Javascript
浅谈jquery回调函数callback的使用
2015/01/30 Javascript
js鼠标点击图片实现随机变换图片的方法
2015/02/16 Javascript
JavaScript中setMonth()方法的使用详解
2015/06/11 Javascript
每日十条JavaScript经验技巧(二)
2016/06/23 Javascript
javascript将中国数字格式转换成欧式数字格式的简单实例
2016/08/02 Javascript
js简单正则验证汉字英文及下划线的方法
2016/11/28 Javascript
scroll事件实现监控滚动条并分页显示(zepto.js)
2016/12/18 Javascript
node.js实现登录注册页面
2017/04/08 Javascript
微信小程序学习笔记之目录结构、基本配置图文详解
2019/03/28 Javascript
VUE UPLOAD 通过ACTION返回上传结果操作
2020/09/07 Javascript
浅谈终端直接执行py文件,不需要python命令
2017/01/23 Python
python机器学习之神经网络(二)
2017/12/20 Python
Python实现二叉搜索树BST的方法示例
2019/07/30 Python
pyqt5、qtdesigner安装和环境设置教程
2019/09/25 Python
Python实现名片管理系统
2020/02/14 Python
python实现简单的tcp 文件下载
2020/09/16 Python
土木工程个人自荐信范文
2013/11/30 职场文书
纠风工作实施方案
2014/03/15 职场文书
员工保密承诺书
2014/05/28 职场文书
运动会口号8字
2014/06/07 职场文书
党员个人年度总结
2015/02/14 职场文书
医学生自荐信范文(2016精选篇)
2016/01/28 职场文书
Python基础知识学习之类的继承
2021/05/31 Python
MybatisPlus代码生成器的使用方法详解
2021/06/13 Java/Android
mysql配置SSL证书登录的实现
2021/09/04 MySQL