2022-12-20【技術(shù)】Vue2的12種組件通信(上)

Vue2.x 組件通信方式

Vue2.x 組件通信共有12種

  • props
  • $emit / v-on
  • .sync
  • v-model
  • ref
  • children /parent
  • attrs /listeners
  • provide / inject
  • EventBus
  • Vuex
  • $root
  • slot

父子組件通信可以用:

  • props
  • $emit / v-on
  • attrs /listeners ref
  • .sync v-model
  • children /parent

跨層級(jí)組件通信可以用:

  • provide/inject
  • EventBus
  • Vuex
  • attrs /listeners
  • $root

Vue2.x 通信使用寫法

下面把每一種組件通信方式的寫法一一列出

1呛凶、props

父組件向子組件傳送數(shù)據(jù),這應(yīng)該是最常用的方式了
子組件接收到數(shù)據(jù)之后,**不能直接修改**父組件的數(shù)據(jù)。會(huì)報(bào)錯(cuò)揪利,所以當(dāng)父組件重新渲染時(shí),數(shù)據(jù)會(huì)被覆蓋祭往。如果子組件內(nèi)要修改的話推薦使用 computed
<template>
    <child :msg="msg"></child>
</template>

// Child.vue 接收
export default {
  // 寫法一 用數(shù)組接收
  props:['msg'],
  // 寫法二 用對(duì)象接收挡爵,可以限定接收的數(shù)據(jù)類型、設(shè)置默認(rèn)值咒唆、驗(yàn)證等
  props:{
      msg:{
          type:String,
          default:'這是默認(rèn)數(shù)據(jù)'
      }
  },
  mounted(){
      console.log(this.msg)
  },
}

2届垫、sync

可以幫我們實(shí)現(xiàn)父組件向子組件傳遞的數(shù)據(jù) 的雙向綁定,所以子組件接收到數(shù)據(jù)后可以直接修改全释,并且會(huì)同時(shí)修改父組件的數(shù)據(jù)装处。

// Parent.vue
        <template>
            <child :page.sync="page"></child>
        </template>
        <script>
        export default {
            data(){
                return {
                    page:1
                }
            }
        }
        </script>
        
        // Child.vue
        <template>
            <el-button @click="open()">點(diǎn)擊我改變頁(yè)面數(shù)</el-button>
            <div>當(dāng)前頁(yè)碼數(shù):{{currentPage}}</div>
        </template>
        <script>
        export default {
            props:["page"],
            computed: {
                // 當(dāng)我們?cè)谧咏M件里修改 currentPage 時(shí),父組件的 page 也會(huì)隨之改變
                currentPage: {
                      get(){
                          return this.page
                      },
                      set(newVal){
                          this.$emit("update:page", newVal)
                      }
                  }
            },
            methods: {
              open(){
                  this.currentPage = 10
              },
          }
        }
        </script>

3浸船、v-model

和 .sync 類似妄迁,可以實(shí)現(xiàn)將父組件傳給子組件的數(shù)據(jù)為雙向綁定,子組件通過 $emit 修改父組件的數(shù)據(jù)

// Parent.vue
        <template>
            <child v-model="value"></child>
            <div>父組件:{{value}}</div>
        </template>
        <script>
        export default {
            data(){
                return {
                    value:1
                }
            }
        }
        
        // Child.vue
        <template>
            <input :value="value" @input="handlerChange">
            <div>子組件: {{value}}</div>
        </template>
        export default {
            props:["value"],
            // 可以修改事件名李命,默認(rèn)為 input
            model:{
                event:"updateValue"
            },
            methods:{
                handlerChange(e){
                    this.$emit("input", e.target.value)
                    // 如果有上面的重命名就是這樣
                    this.$emit("updateValue", e.target.value)
                }
            }
        }
        </script>

4登淘、ref

ref 如果在普通的DOM元素上,引用指向的就是該DOM元素;
如果在子組件上项戴,引用的指向就是子組件實(shí)例形帮,然后父組件就可以通過 ref 主動(dòng)獲取子組件的屬性或者調(diào)用子組件的方法槽惫。

// Child.vue
        export default {
            data(){
                return {
                    name:"小趙"
                }
            },
            methods:{
                someMethod(msg){
                    console.log(msg)
                }
            }
        }
        
        // Parent.vue
        <template>
            <child ref="childFlag"></child>
        </template>
        <script>
        export default {
            mounted(){
                const childData = this.$refs.childFlag
                console.log(childData.name) // 小趙
                childData.someMethod("調(diào)用了子組件的方法")
            }
        }
        </script>

用ref 注冊(cè)子組件,父組件可以通過this.$refs.xx.fn調(diào)用子組件里的函數(shù)辩撑,但是有時(shí)會(huì)出現(xiàn) fn 為定義的情況界斜,這是為什么呢?

vue 官網(wǎng)中ref 下有一段話 "關(guān)于 ref 注冊(cè)時(shí)間的重要說明:因?yàn)?ref 本身是作為渲染結(jié)果被創(chuàng)建的合冀,在初始渲染的時(shí)候你不能訪問它們 - 它們還不存在各薇!$refs 也不是響應(yīng)式的,因此你不應(yīng)該試圖用它在模板中做數(shù)據(jù)綁定君躺。"

也就是說 ref 只有等頁(yè)面加載完成好之后你才能調(diào)用 this.refs 峭判,如果你使用v-if 、v-for渲染頁(yè)面的話棕叫,那么在剛開始頁(yè)面沒沒渲染之前你是拿不到this.refs 的林螃,所以要等到頁(yè)面渲染之后拿才可以

解決辦法:

1、如果你在mounted里獲取this.$refs俺泣,因?yàn)閐om還未完全加載疗认,所以你是拿不到的, update階段則是完成了數(shù)據(jù)更新到 DOM 的階段(對(duì)加載回來的數(shù)據(jù)進(jìn)行處理)伏钠,此時(shí)横漏,就可以使用this.$refs了

2、如果寫在method中熟掂,那么可以使用 this.$nextTick(() => {}) 等頁(yè)面渲染好再調(diào)用缎浇,這樣就可以了

3、或者加個(gè)定時(shí)器延時(shí)加載this.$refs(這個(gè)方法還沒有試)赴肚。

拓展:

通過 refs 結(jié)合on 綁定事件 (比v-on更靈活)

//父組件
<template>
  <div id="app">
    <Student ref="student"></Student>
  </div>
</template>
 
<script>
import Student from './components/student.vue'
console.log(Student)
 
export default {
  name: 'App',
  components: {
    Student
  },
  mounted () {
    this.$refs.student.$on('knowSomething', this.doSomething) //給student組件綁定自定義事件
    /*
    this.$refs.student.$on('knowSomething', this.doSomething) //doSomething函數(shù)中的this指向
    的是父組件App組件
    
    this.$refs.student.$on('knowSomething', () =>{
     這里的this指向的是父組件App組件
    })
    
    this.$refs.student.$on('knowSomething', function(){
      這里的this指向的是觸發(fā)knowSomething事件的組件
    })
    
    */
    //this.$refs.student.$once('knowSomething', this.doSomething) //綁定自定義事件素跺,
    但是只能觸發(fā)一次
    
  },
  methods: {
    doSomething (name, something) {
      alert('APP知道了學(xué)生' + name + '在' + something)
    }
  }
}
</script>
 
//子組件
<template>
  <div>
    <div>{{ student.name }}--{{ student.age }}</div>
    <button @click="tellApp">tellApp</button>
    <button @click="unbind">解綁knowSomething事件</button>
    
  </div>
</template>
 
<script>
export default {
  data () {
    return {
      student: {
        name: '張三',
        age: '18'
      }
    }
  },
  methods: {
    tellApp () {
      this.$emit('knowSomething', this.student.name, '學(xué)習(xí)')
    },
    unbind(){
    this.$off('knowSomething') //解綁knowSomething事件
    /*
    this.$off(['knowSomething','a','b']) //解綁多個(gè)事件
    this.$off() //解綁所有事件
    */
    }
  }
}
</script>

5、$emit / v-on

子組件通過派發(fā)事件的方式給父組件數(shù)據(jù)尊蚁,或者觸發(fā)父組件更新等操作亡笑。

// Child.vue 派發(fā)
        <template>
          <div>
              <el-button @click="handleClick()">點(diǎn)擊派發(fā)</el-button>
          </div>
        </template>
        
        <script>
        export default {
          data(){
              return { msg: "這是發(fā)給父組件的信息" }
          },
          methods: {
              handleClick(){
                  this.$emit("sendMsg",this.msg)
              }
          },
        }
        </script>
        // Parent.vue 響應(yīng)
        <template>
            <child v-on:sendMsg="getChildMsg"></child>
            // 或 簡(jiǎn)寫
            <child @sendMsg="getChildMsg"></child>
        </template>
        
        export default {
            methods:{
                getChildMsg(msg){
                    console.log(msg) // 這是父組件接收到的消息
                }
            }
        }

6、attrs /listeners

多層嵌套組件傳遞數(shù)據(jù)時(shí)横朋,如果只是傳遞數(shù)據(jù)仑乌,而不做中間處理的話就可以用這個(gè),比如父組件向?qū)O子組件傳遞數(shù)據(jù)時(shí)琴锭。

attrs:包含父作用域里除class和style除外的非props屬性集合晰甚。通過this.attrs 獲取父作用域中所有符合條件的屬性集合,然后還要繼續(xù)傳給子組件內(nèi)部的其他組件决帖,就可以通過 v-bind="$attrs"

listeners:包含父作用域里.native除外的監(jiān)聽事件集合厕九。如果還要繼續(xù)傳給子組件內(nèi)部的其他組件,就可以通過v?on="linteners"使用方式是相同的地回。

// Parent.vue
        <template>
            <child :name="name" title="1111" ></child>
        </template
        export default{
            data(){
                return {
                    name:"小趙"
                }
            }
        }
        
        // Child.vue
        <template>
            // 繼續(xù)傳給孫子組件
            <sun-child v-bind="$attrs"></sun-child>
        </template>
        export default{
            props:["name"], // 這里可以接收扁远,也可以不接收
            mounted(){
                // 如果props接收了name 就是 { title:1111 }俊鱼,否則就是{ name:"小趙", title:1111 }
                console.log(this.$attrs)
            }
        }
<!--父組件 parent.vue-->
        <template>
            <child :name="name" :message="message" @sayHello="sayHello"></child>
        </template>
        <script>
        export default {
            inheritAttrs: false,
            data() {
                return {
                    name: '通信',
                    message: 'Hi',
                }
            },
            methods: {
                sayHello(mes) {
                    console.log('mes', mes) // => "hello"
                },
            },
        }
        </script>
        <!--子組件 child.vue-->
        <template>
            <grandchild v-bind="$attrs" v-on="$listeners"></grandchild>
        </template>
        <script>
        export default {
            data() {
                return {}
            },
            props: {
                name,
            },
        }
        </script>
        <!--孫子組件 grand-child.vue-->
        <template>
        </template>
        <script>
        export default {
            created() {
                this.$emit('sayHello', 'hello')
            },
        }
        </script>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市畅买,隨后出現(xiàn)的幾起案子并闲,更是在濱河造成了極大的恐慌,老刑警劉巖谷羞,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件帝火,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡湃缎,警方通過查閱死者的電腦和手機(jī)犀填,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嗓违,“玉大人九巡,你說我怎么就攤上這事□寮荆” “怎么了比庄?”我有些...
    開封第一講書人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)乏盐。 經(jīng)常有香客問我,道長(zhǎng)制恍,這世上最難降的妖魔是什么父能? 我笑而不...
    開封第一講書人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮净神,結(jié)果婚禮上何吝,老公的妹妹穿的比我還像新娘。我一直安慰自己鹃唯,他們只是感情好爱榕,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著坡慌,像睡著了一般黔酥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上洪橘,一...
    開封第一講書人閱讀 49,784評(píng)論 1 290
  • 那天跪者,我揣著相機(jī)與錄音,去河邊找鬼熄求。 笑死渣玲,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的弟晚。 我是一名探鬼主播忘衍,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼逾苫,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了枚钓?” 一聲冷哼從身側(cè)響起铅搓,我...
    開封第一講書人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎秘噪,沒想到半個(gè)月后狸吞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡指煎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年蹋偏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片至壤。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡威始,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出像街,到底是詐尸還是另有隱情黎棠,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布镰绎,位于F島的核電站脓斩,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏畴栖。R本人自食惡果不足惜随静,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望吗讶。 院中可真熱鬧燎猛,春花似錦、人聲如沸照皆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)膜毁。三九已至昭卓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間瘟滨,已是汗流浹背葬凳。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留室奏,地道東北人火焰。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像胧沫,于是被迫代替她去往敵國(guó)和親昌简。 傳聞我的和親對(duì)象是個(gè)殘疾皇子占业,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容