Vue组件间传值

首先 vue 组件化的一个框架。
既然是组件化。
那么一定存在组件和组件之间传值的问题

在讨论组件和组件怎么传值的问题之前,
可以先看看组件与组价之间有三种关系。

  1. 父->子
  2. 子->父
  3. 平行组件之间传值.

1. 父子组件间传值.

一个父组件里面包含了一个子组件,需要把父组件的数据传递给子组件以便于子组件显示.

数据流动方向:父组件数据 -> 子组件

子组件利用绑定属性的方式绑定父组件的数据属性,从而获取父组件的值.

  Vue.component('pview',{
    template:`<div>
    <input type="text" v-model='message'>
    <!-- 这里使用 v-bind 表达式绑定父容器的数据属性 -->
      <cview :msg="message"></civew>
    </div>`,
    data:function(){
      return {
        message:'message in parentView'
      }
    }
  })

  Vue.component('cview',{
    template:`<p>从父组件获取到的值:{{msg}}</p>`,
    props:['msg'] // 子组件需要使用 props来接收
  })
  

html

 <div id='app'>
    <pview></pview>
    <selfview outter-Data='这是普通扩展属性'></selfview>
  </div>

结果:

父->子传值.gif

上述demo中,在子组件的顶级利用 v-bind:表达式绑定父组件的 data 属性.并在子组件内部使用 props 属性来接收这个msg,即可在子组件内部使用{{msg}} or this.msg 了.

补充:

我们可以在子组件标签里使用 v-bind:msg = 父组件数据属性,并子子组件内搭配 props:['msg'] 来获取到从父组件传递过来的属性数据.

子组件扩展属性

这里的子组件扩展属性和父组件就没有关系了,完全是子组件自己的数据行为.

数据流动方向:子组件扩展属性 -> 子组件

Vue.component('selfview', {
    template:`<button @click="on_click"> {{outterData}} -- {{innerData}}</button>`,
    props:['outterData'], // 属性扩展都需要些在这里. *** 注意,扩展属性写的是 outter-Data ,这里写的是 outterData .
    data:function() {
      return {
        innerData:'这是组件自己内部的数据属性字段'
      }
    }
  })
  
  
  <!-- 注意,这里不是使用的:outter-Data 而是普通的 outter-Data -->
  <selfview outter-Data='这是普通扩展属性'></selfview>
  

html

 <div id='app'>
    <pview></pview>
    <selfview outter-Data='这是普通扩展属性'></selfview>
  </div>

结果:

子组件自己的普通扩展属性,注意命名方式

总结:

  • 在子组件顶级标签里可以使用 :msg='父组件属性'(v-bind:不要忘记冒号) & props['msg'] 的方式拿到父组件属性数据.
  • 也可以完全扩展一个属性自己的数据属性 msg='自己的扩展的属性值' & props:['msg']

子组件可以通过扩展属性绑定 :msg='parentMSG' & props:['msg'] 的方式给从父组件那里获取到值.


子组件往父组件传值

子组件通过 属性 的方式从父组件获取数据.

当子组件需要向父组件传递数据(数据流向:子组件 -> 父组件) ,一般是通过事件来实现.

Vue.component('pview',{
    template:`<div>
      <h3>我是父组件</h3>从子组件传递过来的值:{{dataFromCview}}
      <cview @send-data-to-pview="showDataFromCView"></cview>
      </div>`,
    data:function() {
      return {
        dataFromCview:''
      }
    },
    methods:{
    // 父组件提供事件响应函数,并利用第一个参数data获取子组件传递过来的数据
      showDataFromCView(data) {
        this.dataFromCview = data
      }
    }
  })

  Vue.component('cview',{
    template:`<div>
      <input type='text' v-model='name'/>
      <button  @click='on_click'>传值</button>
      </div>`,
    data:function(){
      return {
        name:''
      }
    },
    methods:{
      on_click(){
        // 定义了一个事件,触发这个事件的响应函数是绑定了父组件的showDataFromCview方法,并将子组件的 this.name 属性以参数的形式传递回去.
        this.$emit('send-data-to-pview',this.name)
      }
    }

  })

html

<div id='app'>
    <pview></pview>
  </div>

结果:

子->父传值.gif

总结:

子组件从父组件传递值的时候,是利用 自定义事件指向父组件的某个方法,并在子组件内部触发这个自定义事件,间接的触发定义在父组件身上的方法,在利用参数的形式将数据从子组件传递到父组件身上去 .

补充:

当然,子组件定义的事件,不光可以绑定和触发父组件的方法,也可以直接修改父组件的属性值.

子组件定义一个 on_change_pview_data_pro 事件,在触发这个 on_change_pview_data_pro 事件时,直接修改父组件的 name 属性.

Vue.component('pview',{
    template:`<div style='border:1px solid black'>
      <h3>我是父组件</h3>
      <p>从子组件传递过来的值:{{dataFromCview}}</p>
      <p>子组件通过事件直接修改父组件的name属性:{{name}}</p>
      <cview @send-data-to-pview="showDataFromCView" @on_change_pview_data_pro="name='通过事件常量传值'"></cview>
      </div>`,
    data:function() {
      return {
        dataFromCview:'',
        name: '这是name默认值'
      }
    },
    methods:{
      showDataFromCView(data) {
        
        this.dataFromCview = data
      }
    }
  })

  Vue.component('cview',{
    template:`<div style='border:1px solid red;margin:5px;'>
      <p>我是子组件</p>
      <input type='text' v-model='name'/>
      <button  @click='on_click'>传值</button><br>
      <button @click='on_change_pview_data_pro'>通过事件直接修改父组件的属性值</button>
      </div>`,
    data:function(){
      return {
        name:''
      }
    },
    methods:{
      on_click(){
        // 定义了一个事件,触发这个事件的响应函数是绑定了父组件的showDataFromCview方法,并将子组件的 this.name 属性以参数的形式传递回去.
        this.$emit('send-data-to-pview',this.name)
      },
      on_change_pview_data_pro() {
       // 子组件直接触发事件,没有传递参数,因为没有绑定事件响应函数(父组件的某个方法)
       // 而是直接修改父组件的某个数据属性(name)的值为常量(通过事件常量传值)
       // @on_change_pview_data_pro="name='通过事件常量传值'"
        this.$emit('on_change_pview_data_pro')
      }
    }

  })
  

html

 <div id='app'>
    <pview></pview>
  </div>

结果

子->父传值-直接在事件里修改父组件的属性值.gif

两个平行的组价之间传递消息

首先回顾父子间数据如何传递的:

  • 数据流从父组件 --- >子组件 通过 属性

    • 子组件利用属性 :msg='pmsg' & 'props:['msg']' 拿到父组件的数据属性.
    • 子组件也可以自定义 msg='abc' & props:['msg'] 来扩展自己的自定义属性.
  • 数据流从 子组件 --- > 父组件 通过 事件

    • 子组件通过非常正统的 子组件事件 & 父组件事件响应方法的方式来传递数据
      • 子组件在定义一个自定义事件,@send-data-to-pview='showDataFromCView' ,给此事件绑定一个父组件的事件响应函数.
      • 子组件在内部触发这个自定义事件,并通过第二个参数将数据传递到父组件事件响应方法里.
    // 子组件事件绑定父组件事件响应函数
    <cview @send-data-to-pview="showDataFromCView" ></civew>
    
        // 子组件触发这个事件 & 传递参数
    on_click(){
        this.$emit('send-data-to-pview',this.name)
         },
      
      // 父组件提供事件响应方法,并接受参数
       showDataFromCView(data) {
        this.dataFromCview = data
      }
    
   + 子组件事件直接修改父组件的数据属性值/
   
   ```JavaScript
   // 注意,这里的 name 是父组件的属性
  <cview @on_change_pview_data_pro="name='通过事件常量传值'"></cview>
  
   ```

也就是说,到目前为止,父子组件间传递数据.

+ 父 --> 子,利用`属性`
+ 子 --> 父,利用`事件`.


而**平行的两个组件之间**,是里用`事件`来传递值的.


**场景**

一个 **talker** 用来说一些话.
一个 **listener** 用来听 **talker**说的这些话.



```JavaScript

let Event = new Vue()

 Vue.component('talker',{
   template:`<div>
       talker Says: <input type='text' @keyup='isSaying' v-model='content' />
     </div>`,

   data:function(){
     return {
       content:'我还什么都没说'
     }
   },
   methods:{
     isSaying() {
       // Event 通过 $emit,直接发送一个 event-talker-saying 的事件.
       // 并传出这个 this.content 数据.

       Event.$emit('event-talker-saying',this.content)
     }
   }
 })

 Vue.component('listener',{
   template:`<div>
     <span>i heard talker says:</span>
     <span style='font-weight:800;font-size:30px'>{{talkerSay}}</span>
     </div>`,

   data:function(){
     return {
       talkerSay:''
     }
   },
   // 事件监听
   // 当组件加载到 DOM 中去时 ,绑定并监听这个事件
   mounted() {
     Event.$on('event-talker-saying',(content)=>{
       this.talkerSay = content
     })
   },

 })


html

<div id='app'>

    <talker></talker>
    <listener></listener>
  </div>

它俩是平级的.

结果

平级组件间传值.gif

主要步骤:

  • 使用 new Vue() 构造函数,获取一个没有作用域的全局vue事件实例.Event
  • talker组件在合适的时机,使用Event触发事件event-talker-saying,并传递参数.
isSaying() {
        // Event 通过 $emit,直接发送一个 event-talker-saying 的事件.
        // 并传出这个 this.content 数据.

        Event.$emit('event-talker-saying',this.content)
        }

  • listener在合适的时机(onmounted()),订阅事件,并在二个参数箭头函数里,拿到触发事件带过来的数据.
// 事件监听
    // 当组件加载到 DOM 中去时 ,绑定并监听这个事件
    mounted() {
      Event.$on('event-talker-saying',(content)=>{
        this.talkerSay = content
      })
    },
    
    // 补充一点,由于this作用域的问题,在这里推荐使用箭头函数.

最后总结:

  • 数据传递方向
    • 父 -> 子 利用属性!!!****属性!!!****属性!!!

      • 子组件身上利用属性

        • 绑定父组件属性 :msg='pmg'

        • 自己的扩展属性 msg='hellworld'

        • 别忘了子组件内部的 props:['msg']

    • 子 -> 父 利用事件!!!****事件!!!****事件!!!

      • 子组件身上自己订阅自定义事件

        • 事件可以绑定父组件的某个方法作为事件响应函数.

        • 事件也可可以直接以常量的方式修改父组件数据属性的值.

      • 事件定义了,需要触发.

        • 子组件在合适的时机里,去触发这个事件.this.$emit('event-name',param)
    • A -> B 平级的两个组件使用 事件!!!****事件!!!****事件!!!

      • 需要传递数据的一方,利用一个全局的事件对象 let Event = new Vue(),来触发一个事件,并传递事件数据.
       Event.$emit('event-talker-saying',this.content)
   - 需要接受数据的这一方,则在一个合适的时机,监听此事件,并根据第二个箭头匿名函数拿到事件传递过来的数据.
        Event.$on('event-talker-saying',(content)=>{
        this.talkerSay = content
      })
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容