Vue中v-model解析、sync修飾符解析

上善若水,水善利萬物而不爭。——《道德經》
簡介

在平時開發是常常用到一些父子組件通訊,常常用到props、vuex等等,這裏面記錄另外的三種方式v-model、sync是怎麼使用,再說是怎麼實現,其實v-model、sync都是語法糖。還有$attr、$listener實現父子組件通訊。
使用方式
v-model

    2.2.0+ 新增

v-mode1其實就是一個語法糖,默認會利用名爲value的props和名爲input的事件,可是像單選框、複選框等類型的輸入龍劍可能會講value特性用於不一樣的目的。

v-model的使用場景:當子組件須要改變父組件經過props傳入的值

父組件

    父組件經過v-model綁定值
    如需根據v-model傳入的值改變,而觸發其餘更新請經過watch傳入的值

子組件

    聲明model對象 設置事件event和prop字段
    經過porps接受父組件傳送值
    修改是經過this.$emit廣播事件

代碼示例:

父組件代碼

<template>
  <children v-model="message"></children>
</template>
<script>
import children from "./children.vue";
export default {
  components: {
    children
  },
  data() {
    return {
      message: "parent"
    };
  },
  watch: {
    // 監聽message變化
    message(newV, oldV) {
      console.log(newV, oldV);
    }
  }
};
</script>

子組件代碼

<template>
  <h1>{{ message }}</h1>
</template>
<script>
export default {
  model: {
    prop: "message", //這個字段,是指父組件設置 v-model 時,將變量值傳給子組件的 msg
    event: "input" //這個字段,是指父組件監聽 parent-event 事件
  },
  props: {
    message: String //此處必須定義和model的prop相同的props,由於v-model會傳值給子組件
  },
  mounted() {
    //這裏模擬異步將msg傳到父組件v-model,實現雙向控制
    setTimeout(_ => {
      this.$emit("input", "children");
      //將這個值經過 emit 觸發parent-event,將some傳遞給父組件的v-model綁定的變量
    }, 1500);
  }
};
</script>

上面這個示例是經過v-model實現的,下面不經過v-model實現一樣效果。
不使用 v-model 實現

代碼示例以下:

父組件代碼修改

<template>
  <Children :message="message" @input="(event) => { message = event }"/>
</template>
<script>
// 不變
</script>

子組件代碼修改

<template>
  // 不變
</template>
<script>
export default {
  props: {
    message: String
  },
  mounted() {
    setTimeout(() => {
      this.$emit("input", "children");
    }, 1500);
  }
};
</script>

只是把v-model拆分爲props和@input事件,子組件不須要配置model,只須要接受props和經過this.$emit廣播事件就能夠。 固然這個相對於v-model方法比較簡便,可是靈活度查不少,選擇使用那種看我的喜愛。 在線地址:

不能放iframe只能放一放一個連接了本篇代碼實例
sync

    2.3.0+ 新增

在有些狀況下,咱們可能須要對一個 prop 進行**「雙向綁定」。不幸的是,真正的雙向綁定**會帶來維護上的問題,由於子組件能夠修改父組件,且在父組件和子組件都沒有明顯的改動來源。

這也是爲何咱們推薦以 update:myPropName 的模式觸發事件取而代之。同時也能夠經過sync修飾符來實現。

在上面代碼的基礎上大體修改以下:

父組件

    經過修改觸發事件input爲update:myPropName實現相同效果

子組件

    經過修改this.$emit(update:myPropName)

代碼以下:

父組件代碼修改

  // 修改以下
  <Children :message="message" @update:input="(event) => { message = event }"/>

子組件代碼修改

  // 其餘不變
  this.$emit("update:input", "children");

sync實現

上面的代碼能夠經過sync簡寫爲下面代碼:

父組件代碼修改

  // 修改以下
  <Children :messag.sync="message"/>

子組件代碼修改

  // 其餘不變
  this.$emit("update:messag", "children");

同時sync也支持對象,要配合v-bind實現能夠簡寫爲:,可是要注意這個對象以下兩條:

    注意帶有 .sync 修飾符的 v-bind 不能和表達式一塊兒使用 (例如 v-bind:title.sync=」doc.title + ‘!’」 是無效的)。取而代之的是,你只能提供你想要綁定的屬性名,相似 v-model。 將 v-bind.sync 用在一個字面量的對象上,例如 v-bind.sync=」{ title: doc.title }」,是沒法正常工做的,由於在解析一個像這樣的複雜表達式的時候,有不少邊緣狀況須要考慮。

attrs、listeners
$attrs

    2.4.0 新增

    類型:{ [key: string]: string }
    只讀
    詳細: 包含了父做用域中不做爲 prop 被識別 (且獲取) 的特性綁定 (class 和 style 除外)。當一個組件沒有聲明任何 prop 時,這裏會包含全部父做用域的綁定 (class 和 style 除外),而且能夠經過 v-bind="$attrs" 傳入內部組件——在建立高級別的組件時很是有用。

$listeners

    2.4.0 新增

    類型:{ [key: string]: Function | Array<Function> }
    只讀
    詳細: 包含了父做用域中的 (不含 .native 修飾器的) v-on 事件監聽器。它能夠經過 v-on="$listeners" 傳入內部組件——在建立更高層次的組件時很是有用。

實現通訊

實現父子組件通訊

父組件代碼

<template>
  <div class="parent">
    <Children
      :message="message"
      @upDate="upDate"
      type="del"
      @input="(event) => { message = event }"
    />
  </div>
</template>

<script>
import Children from "./Children";
export default {
  components: {
    Children
  },
  data() {
    return {
      message: "parent",
      type: "del"
    };
  },
  methods: {
    upDate (event) {
      console.log(event);
      this.type = event;
    }
  },
  watch: {
    message: function() {
      console.log("更新message值爲" + this.message);
    }
  }
};
</script>

子組件代碼

<template>
  <div v-bind="$attrs" v-on="$listeners" class="children">{{message}} <span @click="$listeners.upDate('data')">{{$attrs.type}}</span></div>
</template>

<script>
export default {
  props: {
    message: String
  },
  mounted() {
    // console.log(this.$attrs);
    // console.log(this.$listeners);
    setTimeout(() => {
      this.$emit("input", "children");
      this.$emit('upDate', 'add')
    }, 1500);
  }
};
</script>

同時$attrs、$listeners都是能夠跨域父子組件,能夠父子子子組件傳遞,相似於react中的context,只是一部分設計理念相同。
總結

其實就是檢測到.sync修飾符,在complier階段會編譯生成多個prop,生成多個事件。其實像這個指令、修飾符、自定義指令都是在vue編譯是解析成爲v8能執行的代碼。

不管是vue、babel、react的complier編譯階段大體分爲三個階段:

    經過詞法解析parse生成抽象AST或抽象代碼樹
    優化AST,好比vue標記靜態節點,babal中抽取靜態代碼,這個階段被稱爲optimize或者優化AST樹
    在AST代碼的階段上,生成可執行代碼,這個過程能夠叫作codegen

v-model、sync均可以實現父子組件通訊,而且能夠在子組件中修改父組件傳入的值。在日常見解的時候進場能夠用到這兩種方式,具體選擇那種方式看我的喜愛。在element-ui這個input組件也用到相關的屬性。
相關文章
相關標籤/搜索