最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue 的雙向綁定原理與用法揭秘

 更新時間:2020年05月06日 10:22:38   作者:邊城  
這篇文章主要介紹了Vue 的雙向綁定原理與用法,結(jié)合實例形式總結(jié)分析了Vue 的雙向綁定基本原理、功能、用法及注意事項,需要的朋友可以參考下

本文實例講述了Vue 的雙向綁定原理與用法。分享給大家供大家參考,具體如下:

Vue 中需要輸入什么內(nèi)容的時候,自然會想到使用 <input v-model="xxx" /> 的方式來實現(xiàn)雙向綁定。下面是一個最簡單的示例

<div id="app">
  <h2>What's your name:</h2>
  <input v-model="name" />
  <div>Hello {{ name }}</div>
</div>
new Vue({
  el: "#app",
  data: {
      name: ""
  }
});

在這個示例的輸入框中輸入的內(nèi)容,會隨后呈現(xiàn)出來。這是 Vue 原生對 <input> 的良好支持,也是一個父組件和子組件之間進(jìn)行雙向數(shù)據(jù)傳遞的典型示例。不過 v-model 是 Vue 2.2.0 才加入的一個新功能,在此之前,Vue 只支持單向數(shù)據(jù)流。

Vue 的單向數(shù)據(jù)流

Vue 的單向數(shù)據(jù)流和 React 相似,父組件可以通過設(shè)置子組件的屬性(Props)來向子組件傳遞數(shù)據(jù),而父組件想獲得子組件的數(shù)據(jù),得向子組件注冊事件,在子組件高興的時候觸發(fā)這個事件把數(shù)據(jù)傳遞出來。一句話總結(jié)起來就是,Props 向下傳遞數(shù)據(jù),事件向上傳遞數(shù)據(jù)。

上面那個例子,如果不使用 v-model,它應(yīng)該是這樣的

<input :value="name" @input="name = $event.target.value" />

由于事件處理寫成了內(nèi)聯(lián)模式,所以腳本部分不需要修改。但是多數(shù)情況下,事件一般都會定義成一個方法,代碼就會復(fù)雜得多

<input :value="name" @input="updateName" />
new Vue({
  // ....
  methods: {
    updateName(e) {
      this.name = e.target.value;
    }
  }
})

從上面的示例來看 v-model 節(jié)約了不少代碼,最重要的是可以少定義一個事件處理函數(shù)。所以 v-model 實際干的事件包括

  • 使用 v-bind(即 :)單向綁定一個屬性(示例::value="name"
  • 綁定 input 事件(即 @input)到一個默認(rèn)實現(xiàn)的事件處理函數(shù)(示例:@input=updateName
  • 這個默認(rèn)的事件處理函數(shù)會根據(jù)事件對象帶入的值來修改被綁定的數(shù)據(jù)(示例:this.name = e.target.value

自定義組件的 v-model

Vue 對原生組件進(jìn)行了封裝,所以 <input> 在輸入的時候會觸發(fā) input 事件。但是自定義組件應(yīng)該怎么呢?這里不妨借助 JsFiddle Vue 樣板的 Todo List 示例。

JsFiddle 的 Vue 樣板

點擊 JsFilddle 的 Logo,在上面彈出面板中選擇 Vue 樣板即可

樣板代碼包含 HTML 和 Vue(js) 兩個部分,代碼如下:

<div id="app">
 <h2>Todos:</h2>
 <ol>
  <li v-for="todo in todos">
   <label>
    <input type="checkbox"
     v-on:change="toggle(todo)"
     v-bind:checked="todo.done">

    <del v-if="todo.done">
     {{ todo.text }}
    </del>
    <span v-else>
     {{ todo.text }}
    </span>
   </label>
  </li>
 </ol>
</div>
new Vue({
 el: "#app",
 data: {
  todos: [
   { text: "Learn JavaScript", done: false },
   { text: "Learn Vue", done: false },
   { text: "Play around in JSFiddle", done: true },
   { text: "Build something awesome", done: true }
  ]
 },
 methods: {
   toggle: function(todo){
    todo.done = !todo.done
  }
 }
})

定義 Todo 組件

JsFiddle 的 Vue 模板默認(rèn)實現(xiàn)一個 Todo 列表的展示,數(shù)據(jù)是固定的,所有內(nèi)容在一個模板中完成。我們首先要做事情是把單個 Todo 改成一個子組件。因為在 JsFiddle 中不能寫成多文件的形式,所以組件使用 Vue.component() 在腳本中定義,主要是把 <li> 內(nèi)容中的那部分拎出來:

Vue.component("todo", {
  template: `
<label>
  <input type="checkbox" @change="toggle" :checked="isDone">
  <del v-if="isDone">
    {{ text }}
  </del>
  <span v-else>
    {{ text }}
  </span>
</label>
`,
  props: ["text", "done"],
  data() {
    return {
      isDone: this.done
    };
  },
  methods: {
    toggle() {
      this.isDone = !this.isDone;
    }
  }
});

原來定義在 App 中的 toggle() 方法也稍作改動,定義在組件內(nèi)了。toggle() 調(diào)用的時候會修改表示是否完成的 done 的值。但由于 done 是定義在 props 中的屬性,不能直接賦值,所以采用了官方推薦的第一種方法,定義一個數(shù)據(jù) isDone,初始化為 this.done,并在組件內(nèi)使用 isDone 來控制是否完成這一狀態(tài)。

相應(yīng)的 App 部分的模板和代碼精減了不少:

<div id="app">
  <h2>Todos:</h2>
  <ol>
    <li v-for="todo in todos">
      <todo :text="todo.text" :done="todo.done"></todo>
    </li>
  </ol>
</div>
new Vue({
  el: "#app",
  data: {
    todos: [
      { text: "Learn JavaScript", done: false },
      { text: "Learn Vue", done: false },
      { text: "Play around in JSFiddle", done: true },
      { text: "Build something awesome", done: true }
    ]
  }
});

不過到此為止,數(shù)據(jù)仍然是單向的。從效果上來看,點擊復(fù)選框可以反饋出刪除線線效果,但這些動態(tài)變化都是在 todo 組件內(nèi)部完成的,不存在數(shù)據(jù)綁定的問題。

為 Todo List 添加計數(shù)

為了讓 todo 組件內(nèi)部的狀態(tài)變化能在 Todo List 中呈現(xiàn)出來,我們在 Todo List 中添加計數(shù),展示已經(jīng)完成的 Todo 數(shù)量。因為這個數(shù)量受 todo 組件內(nèi)部狀態(tài)(數(shù)據(jù))的影響,這就需要將 todo 內(nèi)部數(shù)據(jù)變化反應(yīng)到其父組件中,這才有 v-model 的用武之地。

這個數(shù)量我們在標(biāo)題中以 n/m 的形式呈現(xiàn),比如 2/4 表示一共 4 條 Todo,已經(jīng)完成 2 條。這需要對 Todo List 的模板和代碼部分進(jìn)行修改,添加 countDonecount 兩個計算屬性:

<div id="app">
  <h2>Todos ({{ countDone }}/{{ count }}):</h2>
  <!-- ... -->
</div>
new Vue({
  // ...
  computed: {
    count() {
      return this.todos.length;
    },
    countDone() {
      return this.todos.filter(todo => todo.done).length;
    }
  }
});

現(xiàn)在計數(shù)呈現(xiàn)出來了,但是現(xiàn)在改變?nèi)蝿?wù)狀態(tài)并不會對這個計數(shù)產(chǎn)生影響。我們要讓子組件的變動對父組件的數(shù)據(jù)產(chǎn)生影響。v-model 待會兒再說,先用最常見的方法,事件:

  • 子組件 todotoggle() 中觸發(fā) toggle 事件并將 isDone 作為事件參數(shù)
  • 父組件為子組件的 toggle 事件定義事件處理函數(shù)
Vue.component("todo", {
  //...
  methods: {
    toggle(e) {
      this.isDone = !this.isDone;
      this.$emit("toggle", this.isDone);
    }
  }
});
<!-- #app 中其它代碼略 -->
<todo :text="todo.text" :done="todo.done" @toggle="todo.done = $event"></todo>

這里為 @toggle 綁定的是一個表達(dá)式。因為這里的 todo 是一個臨時變量,如果在 methods 中定義專門的事件處理函數(shù)很難將這個臨時變量綁定過去(當(dāng)然定義普通方法通過調(diào)用的形式是可以實現(xiàn)的)。

事件處理函數(shù),一般直接對應(yīng)于要處理的事情,比如定義 onToggle(e),綁定為 @toggle="onToggle"。這種情況下不能傳入 todo 作為參數(shù)。

普通方法,可以定義成 toggle(todo, e),在事件定義中以函數(shù)調(diào)用表達(dá)式的形式調(diào)用:@toggle="toggle(todo, $event)"。它和 todo.done = $event` 同屬表達(dá)式。

注意二者的區(qū)別,前者是綁定的處理函數(shù)(引用),后者是綁定的表達(dá)式(調(diào)用)

現(xiàn)在通過事件方式已經(jīng)達(dá)到了預(yù)期效果

改造成 v-model

之前我們說了要用 v-model 實現(xiàn)的,現(xiàn)在來改造一下。注意實現(xiàn) v-model 的幾個要素

  • 子組件通過 value 屬性(Prop)接受輸入
  • 子組件通過觸發(fā) input 事件輸出,帶數(shù)組參數(shù)
  • 父組件中用 v-model 綁定
Vue.component("todo", {
  // ...
  props: ["text", "value"],  // <-- 注意 done 改成了 value
  data() {
    return {
      isDone: this.value  // <-- 注意 this.done 改成了 this.value
    };
  },
  methods: {
    toggle(e) {
      this.isDone = !this.isDone;
      this.$emit("input", this.isDone); // <-- 注意事件名稱變了
    }
  }
});
<!-- #app 中其它代碼略 -->
<todo :text="todo.text" v-model="todo.done"></todo>

.sync 實現(xiàn)其它數(shù)據(jù)綁定

前面講到了 Vue 2.2.0 引入 v-model 特性。由于某些原因,它的輸入屬性是 value,但輸出事件叫 inputv-model、value、input 這三個名稱從字面上看不到半點關(guān)系。雖然這看起來有點奇葩,但這不是重點,重點是一個控件只能雙向綁定一個屬性嗎?

Vue 2.3.0 引入了 .sync 修飾語用于修飾 v-bind(即 :),使之成為雙向綁定。這同樣是語法糖,添加了 .sync 修飾的數(shù)據(jù)綁定會像 v-model 一樣自動注冊事件處理函數(shù)來對被綁定的數(shù)據(jù)進(jìn)行賦值。這種方式同樣要求子組件觸發(fā)特定的事件。不過這個事件的名稱好歹和綁定屬性名有點關(guān)系,是在綁定屬性名前添加 update: 前綴。

比如 <sub :some.sync="any" /> 將子組件的 some 屬性與父組件的 any 數(shù)據(jù)綁定起來,子組件中需要通過 $emit("update:some", value) 來觸發(fā)變更。

上面的示例中,使用 v-model 綁定始終感覺有點別扭,因為 v-model 的字面意義是雙向綁定一個數(shù)值,而表示是否未完成的 done 其實是一個狀態(tài),而不是一個數(shù)值。所以我們再次對其進(jìn)行修改,仍然使用 done 這個屬性名稱(而不是 value),通過 .sync 來實現(xiàn)雙向綁定。

Vue.component("todo", {
  // ...
  props: ["text", "done"],  // <-- 恢復(fù)成 done
  data() {
    return {
      isDone: this.done  // <-- 恢復(fù)成 done
    };
  },
  methods: {
    toggle(e) {
      this.isDone = !this.isDone;
      this.$emit("update:done", this.isDone); // <-- 事件名稱:update:done
    }
  }
});
<!-- #app 中其它代碼略 -->
<!-- 注意 v-model 變成了 :done.sync,別忘了冒號喲 -->
<todo :text="todo.text" :done.sync="todo.done"></todo>

揭密 Vue 雙向綁定

通過上面的講述,我想大家應(yīng)該已經(jīng)明白了 Vue 的雙向綁定其實就是普通單向綁定和事件組合來完成的,只不過通過 v-model.sync 注冊了默認(rèn)的處理函數(shù)來更新數(shù)據(jù)。Vue 源碼中有這么一段

// @file: src/compiler/parser/index.js

if (modifiers.sync) {
  addHandler(
    el,
    `update:${camelize(name)}`,
    genAssignmentCode(value, `$event`)
  )
}

從這段代碼可以看出來,.sync 雙向綁定的時候,編譯器會添加一個 update:${camelize(name)} 的事件處理函數(shù)來對數(shù)據(jù)進(jìn)行賦值(genAssignmentCode 的字面意思是生成賦值的代碼)。

展望

目前 Vue 的雙向綁定還需要通過觸發(fā)事件來實現(xiàn)數(shù)據(jù)回傳。這和很多所的期望的賦值回傳還是有一定的差距。造成這一差距的主要原因有兩個

  1. 需要通過事件回傳數(shù)據(jù)
  2. 屬性(prop)不可賦值

在現(xiàn)在的 Vue 版本中,可以通過定義計算屬性來實現(xiàn)簡化,比如

computed: {
  isDone: {
    get() {
      return this.done;
    },
    set(value) {
      this.$emit("update:done", value);
    }
  }
}

說實在的,要多定義一個意義相同名稱不同的變量名也是挺費腦筋的。希望 Vue 在將來的版本中可以通過一定的技術(shù)手段減化這一過程,比如為屬性(Prop)聲明添加 sync 選項,只要聲明 sync: true 的都可以直接賦值并自動觸發(fā) update:xxx 事件。

當(dāng)然作為一個框架,在解決一個問題的時候,還要考慮對其它特性的影響,以及框架的擴(kuò)展性等問題,所以最終雙向綁定會演進(jìn)成什么樣子,我們對 Vue 3.0 拭目以待。

感興趣的朋友可以使用在線HTML/CSS/JavaScript代碼運行工具http://tools.jb51.net/code/HtmlJsRun測試上述代碼運行效果。

希望本文所述對大家vue.js程序設(shè)計有所幫助。

相關(guān)文章

  • vite+vue3+element-plus搭建項目的踩坑記錄

    vite+vue3+element-plus搭建項目的踩坑記錄

    這篇文章主要介紹了vite+vue3+element-plus搭建項目的踩坑記錄,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • 基于electron+vue3+ts搭建桌面端應(yīng)用并且可以熱更新

    基于electron+vue3+ts搭建桌面端應(yīng)用并且可以熱更新

    這篇文章主要為大家詳細(xì)介紹了如何基于electron+vue3+ts搭建桌面端應(yīng)用并且可以熱更新,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以參考下
    2023-10-10
  • vue3.0 CLI - 1 - npm 安裝與初始化的入門教程

    vue3.0 CLI - 1 - npm 安裝與初始化的入門教程

    這篇文章主要介紹了vue3.0 CLI - 1 - npm 安裝與初始化的入門教程,本文通過實例代碼相結(jié)合的形式,給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-09-09
  • Vue 2.0中生命周期與鉤子函數(shù)的一些理解

    Vue 2.0中生命周期與鉤子函數(shù)的一些理解

    這篇文章主要給大家介紹了關(guān)于Vue 2.0中生命周期與鉤子函數(shù)的相關(guān)資料,對大家學(xué)習(xí)或者使用vue2.0具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨小編一起來看看吧。
    2017-05-05
  • Vue動態(tài)添加屬性到data的實現(xiàn)

    Vue動態(tài)添加屬性到data的實現(xiàn)

    在vue中請求接口中,一個請求方法可能對應(yīng)后臺兩個請求接口,所以請求參數(shù)就會有所不同。需要我們先設(shè)置共同的參數(shù),然后根據(jù)條件動態(tài)添加參數(shù)屬性
    2022-08-08
  • 簡單談?wù)刅ue 模板各類數(shù)據(jù)綁定

    簡單談?wù)刅ue 模板各類數(shù)據(jù)綁定

    Vue.js 的模板是基于 DOM 實現(xiàn)的。這意味著所有的 Vue.js 模板都是可解析的有效的 HTML,且通過一些特殊的特性做了增強。Vue 模板因而從根本上不同于基于字符串的模板,請記住這點。
    2016-09-09
  • elementui中tabel組件的scope.$index的使用及說明

    elementui中tabel組件的scope.$index的使用及說明

    這篇文章主要介紹了elementui中tabel組件的scope.$index的使用及說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • vue2如何使用face-api.js實現(xiàn)人臉識別功能

    vue2如何使用face-api.js實現(xiàn)人臉識別功能

    本文介紹了如何在Vue.js項目中利用face-api.js實現(xiàn)人臉識別功能,首先需要安裝Vue.js和face-api.js以及其依賴TensorFlow.js,接著,下載并配置必要的模型文件到項目目錄,之后,將人臉識別功能封裝成Vue組件,并在組件中通過視頻流進(jìn)行人臉檢測和結(jié)果展示
    2024-09-09
  • vue實現(xiàn)點擊隱藏與顯示實例分享

    vue實現(xiàn)點擊隱藏與顯示實例分享

    在本篇文章中小編給大家分享了vue如何實現(xiàn)點擊隱藏與顯示的相關(guān)內(nèi)容,有需要的朋友們跟著學(xué)習(xí)下。
    2019-02-02
  • Vue如何由本地js中存放的url地址獲取圖片

    Vue如何由本地js中存放的url地址獲取圖片

    這篇文章主要介紹了Vue如何由本地js中存放的url地址獲取圖片問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-09-09

最新評論

平原县| 贵港市| 宾川县| 哈尔滨市| 大竹县| 潞西市| 南郑县| 拉萨市| 临湘市| 鲁山县| 斗六市| 威远县| 贡嘎县| 黄梅县| 蒙山县| 青川县| 邻水| 东至县| 太保市| 庆元县| 唐河县| 沙河市| 南充市| 额敏县| 梨树县| 舞钢市| 定远县| 龙门县| 潞城市| 新郑市| 依兰县| 扬州市| 双牌县| 北碚区| 瑞昌市| 即墨市| 兴安县| 青铜峡市| 屏南县| 怀集县| 八宿县|