首頁 > 軟體

一起來學習Vue的元件間通訊方式

2022-03-31 16:00:47

props

父元件可以通過props向下傳遞資料給子元件

靜態的Props

通過為子元件在父元件中的預留位置新增特性的方式來達到傳值的目的

動態Props

在模版中要動態的繫結父元件的資料到子模版的props,與繫結任何普通的HTML特性相類似,用v-bind,每當父元件的資料發生變化的時候,該變化會傳導給子元件

props驗證

可以為元件的props指定驗證規則,如果傳入的資料不符合規則,Vue會發出警告

props: {
    // 基礎型別檢測 (`null` 意思是任何型別都可以)
    propA: Number,
    // 多種型別
    propB: [String, Number],
    // 必傳且是字串
    propC: {
      type: String,
      required: true
    },
    // 數位,有預設值
    propD: {
      type: Number,
      default: 100
    },
    // 陣列/物件的預設值應當由一個工廠函數返回
    propE: {
      type: Object,
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定義驗證函數
    propF: {
      validator: function (value) {
        return value > 10
      }
    }
  }

type 可以是(String,Number,Boolean,Function,Object,Array,Symbol)原生構造器

type也可以是自定義建構函式,使用instenceof檢測

prop是當先繫結的,當父元件的屬性變化是,將傳導給子元件,但是不會反過來,這是為了防止子元件無意修改了父元件的狀態。

修改prop資料

  • prop 作為初始值傳入後,子元件想把他當作區域性資料來用
  • prop 作為初始值傳入,有子元件處理成其他資料輸出
  • 注意:js中物件和陣列是參照型別,指向同一個記憶體空間,如果prop是一個物件或陣列,在子元件內部改變它會影響父元件的狀態
    • 處理方法1:這個時候需要定義一個區域性變數,並用prop初始化它,但是區域性變數只能接受prop初始值,當父元件的值發生變化的時候,無法接收到最新值
    • 處理方法2:定義一個計算屬性,處理prop值並返回
    • 初始方法3:使用變數儲存prop的初始值,並使用watch來觀察prop的值的變化,當發生變化的時候更新變數的值

$emit

$emit(‘自定義時間名’,要傳送的資料)觸發當前範例上的事件

父元件

<template>
    <children @addCount="addCount" :count="count"/>
<template>
<script>
  import children from "./children";
  export default {
    name:'index',
    components: {Children},
    data () {
      return {
        count:0
      }
    },
    methods:{
      addCount(data){
        this.count = data.count;
      }
    }
  }
</script>

子元件

<template>
  <div>
    <h3>計數器:{{count}}</h3> 
    <button @click='add'>+++</button>
  </div>
</template>
<script>
  export default {
    name:'children',
    props:['count'], // 用來接收父元件傳給子元件的資料
    methods:{
      add() {
        // 觸發父元件的方法
        this.$emit('addCount',{count: count + 1});
      }
    }
  }
</script>

$on

$on(‘事件名’,callback)監聽事件,監聽當前範例上的自定義事件

父元件

<template>
   <div>
        <span>{{count}}</span>
        <children/>
   </div>
<template>
<script>
  import { bus } from '../main.js';  
  import children from "./children";
  export default {
    name:'index',
    components: {Children},
    data () {
      return {
        count:0
      }
    },
    mounted(){
        bus.$on('addCount',(val)=>{
            this.count++;
        })
    }
  }
</script>

子元件

<template>
    <button @click='add'>count+++</button>
</template>
<script>
import { bus } from '../main.js';
export default {
    name:'children',
    methods:{
      add() {
        // 觸發父元件的方法
        bus.$emit('addCount',{});
      }
    }
}
</script>

main檔案

export var bus = new Vue();

注意: e m i t 和 emit和 emit和on的事件必須在一個公共的範例上, e m i t 觸 發 的 事 件 emit觸發的事件 emit觸發的事件on才能監聽到。

$parent(不常用)

指向當前元件樹的根範例,如果當前範例沒有父範例,則範例將會指向自己。

  • $parent既可以接受父元件資料,又可以修改父元件資料,是雙向的。
  • $parent可以呼叫父元件的方法

子元件

<template>
    <button @click='actionParent'>觸發父元件發方法</button>
</template>
<script>
export default {
    name:'children',
    methods:{
      actionParent() {
        console.log(this.$parent.name);
        this.$parent.parentPrint(); // 觸發父元件的方法
      }
    }
}
</script>

$children(不常用)

指向當前範例的直接子元件,返回的是一個元件的集合。

需要注意: children 並 不 保 證 順 序 , 也 不 是 響 應 式 的 。 如 果 你 發 現 自 己 正 在 嘗 試 使 用 children並不保證順序,也不是響應式的。如果你發現自己正在嘗試使用 children並不保證順序,也不是響應式的。如果你發現自己正在嘗試使用children進行資料繫結,考慮使用一個陣列配合v-for來生成子元件,並且使用Array作為真正的來源。

for(let i=0; i<this.$children.length; i++){
    console.log(this.$children[i].name); // 輸出子元件的name
}

$attrs

包含了父作用域中不作為prop被識別(且獲取)的特性繫結(class,style除外)。當一個元件沒有宣告任何prop時,這裡會包含所有父作用域的繫結,並且可以通過v-bind="$attrs"傳入內部元件–在建立高階別的元件時非常有用。

簡單說:接收除了props宣告外的所有繫結屬性(calss,style除外)

上圖的$attrs中只有age,gender兩個屬性{ age: “20”, gender: “man” }

在grandson上通過v-bind="$attrs",可以將屬性繼續向下傳遞,讓grendson也能存取到父元件的屬性。
這種方式當傳遞多個屬性時會顯得很便捷,不需要一條一條進行繫結。

如果想要新增其他屬性,可繼續繫結屬性,注意:繼續繫結的屬性和$attr中的屬性有重複時,繼續繫結的屬性優先順序會更高

$listeners

包含了父級作用域中的(不含.native修飾器的)v-on事件監聽器,他可以通過v-on="$listeners"傳入內部元件–在建立更高層次的元件時非常有用。

簡單說:接收除了帶有.native事件修飾符的所有事件監聽器

child元件繫結了帶有.native的click事件和一個自定義事件,$listeners輸出的結果為:{customEvent:fn}

通過v-on="  listeners"將事件監聽器繼續向下傳遞,讓grandson存取到事件。並且可以使用emit觸發傳遞下來的事件。

如果想要新增其他事件監聽器,可以繼續繫結事件

注意:繼續繫結的事件和$listeners中的事件有重複的時候,不會被覆蓋。當grandson觸發customEvent時,child和parent的事件都會被觸發,觸發順序類似於冒泡。

使用場景

  • 元件傳值時使用,父親,兒子,孫子三級傳遞引數互動。
  • 對一些UI庫進行二次封裝的時候使用,比如element-ui中的元件不能滿足自己的使用場景時,會二次封裝,但是又想保留它自己的屬性和方法,這個時候使用。

$refs

this.$refs是一個物件,持有當前元件中註冊過ref特性的所有DOM元素和子元件範例

注意:$refs只有在元件渲染完成之後才填充,在初始渲染的時候不能存取他們,並且它是非響應式的,因此不能用它在模版中做資料繫結。

父元件

<template>
    <div>
       <div ref="testDom">123</div>
       <child ref="child" />
       <button @click="openChild" >觸發子元件</button>
    </div>
</template>
<script>
import Child form './child.vue'
export default {
    components:{
        Child
    },
    
    mounted(){
        console.log(this.$refs.testDom) // <div>123</div>
        console.log(this.$refs.child.name) // 粉刷匠
    },
    methods:{
        openChild(){
            this.$refs.child.open();
        }
    }
    
}
</script>

子元件

<template>
   <div>{{name}}</div>
</template>
<script>
export default {
   data(){
      return {
        name:"粉刷匠"
      }
   },
   methods:{
        open(){
            alter("點選了")
        }
   }
}
</script>

注意:當ref和v-for一起使用的時候,獲取到的將會是一個陣列,包含迴圈陣列源。

provide && inject

provide/inject是vue2.2版本之後新增的高階元件,這兩個元件要一起使用。
允許一個祖先元件向其所有的子孫後代注入一個依賴。無論元件層次有多深,並在其上下游關係成立的事件裡始終有效。類似於React的上下文。

provide選項是一個物件 或返回一個物件的函數。該物件包含可注入其子孫的property。

inject有下面兩種:

  • 一個字串陣列
  • 一個物件
    • 物件的key是原生的繫結名,
    • value
      • 在可用的注入內容中搜尋用的key(字串/Symbol)
      • 或一個物件
        • from property是在可用的注入內容中搜尋用的key(字串/Symbol)
        • default property是降級情況下使用的value

provide和inject繫結並不是可響應的,這是vue官方刻意為之的。如果你傳入一個可監聽的物件,那麼其物件的property還是可響應的。

缺點:在任意層級都能存取導致資料追蹤比較難,所以provide/inject能不使用就不使用,儘量使用vuex。在元件庫開發的可以使用

副元件

<template>
	<div class="test">
		<son prop="data"></son>
	</div>
</template>
 
<script>
export default {
	name: 'Father',
	provide: {
		chontrol: this
	}
    data(){
        return {
            name:"啊哈哈"
        }
    }
}

// 某一級子元件/孫子元件

<template>
	<div>
		{{name}}
	</div>
</template>
 
<script>
export default {
	name: 'son',
	inject: ["chontrol"]
    props: {
        name: {
          type: Object,
          default: () => ({}),
        },
    }    
  },
}
</script>

總結

本篇文章就到這裡了,希望能夠給你帶來幫助,也希望您能夠多多關注it145.com的更多內容!


IT145.com E-mail:sddin#qq.com