自定義組件v-model的實質性理解

来源:https://www.cnblogs.com/sonoda-umi/archive/2018/10/07/9750188.html
-Advertisement-
Play Games

用了幾個月Vue一直很糾結自定義組件的v-model實現,最近開始學習React時,React中受控組件與狀態提升的理念與v-model不謀而合。 轉載請註明地址: https://www.cnblogs.com/sonoda-umi/p/9750188.html 在Vue與React中其實都存在單 ...


用了幾個月Vue一直很糾結自定義組件的v-model實現,最近開始學習React時,React中受控組件與狀態提升的理念與v-model不謀而合。

 轉載請註明地址: https://www.cnblogs.com/sonoda-umi/p/9750188.html

在Vue與React中其實都存在單向數據流的概念,只不過Vue中通過各種語法糖被弱化了,比如React與Vue中的props都是單向傳輸數據的。在React中如果想實現類似於v-model的功能,需要這樣實現:

父組件:

class Calculator extends React.Component {
  constructor(props) {
    super(props);
    this.handleCelsiusChange = this.handleCelsiusChange.bind(this);
    this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);
    this.state = {temperature: '', scale: 'c'};
  }

  handleCelsiusChange(temperature) {
    this.setState({scale: 'c', temperature});
  }

  handleFahrenheitChange(temperature) {
    this.setState({scale: 'f', temperature});
  }

  render() {
    const scale = this.state.scale;
    const temperature = this.state.temperature;
    const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature;
    const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;

    return (
      <div>
        <TemperatureInput
          scale="c"
          temperature={celsius}
          onTemperatureChange={this.handleCelsiusChange} />

        <TemperatureInput
          scale="f"
          temperature={fahrenheit}
          onTemperatureChange={this.handleFahrenheitChange} />

        <BoilingVerdict
          celsius={parseFloat(celsius)} />

      </div>
    );
  }
}

子組件:

class TemperatureInput extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(e) {
    this.props.onTemperatureChange(e.target.value);
  }

  render() {
    const temperature = this.props.temperature;
    const scale = this.props.scale;
    return (
      <fieldset>
        <legend>Enter temperature in {scaleNames[scale]}:</legend>
        <input value={temperature}
               onChange={this.handleChange} />
      </fieldset>
    );
  }
}

這是一個輸入水溫從而監控水是否沸騰的一個小組件。子組件是一個溫度輸入的input控制項,父組件是由兩個溫度輸入(華氏與攝氏)與一個現實水是否沸騰的指示器組成。父組件存在一個state作為唯一數據源用於存放溫度等值於狀態,溫度通過子組件的prop傳入子組件內部通過input的value屬性顯示在基礎輸入框中,當在基礎輸入框中觸發輸入時間時,onChange事件觸發由prop傳入的onTempreture事件並附帶變化後的值,再由父組件的handleCelsiusChange/handleFahrenheitChange事件處理方法將基礎輸入框傳來的值寫入state中,再由state通過prop將溫度傳入子組件完成一次數據的更新。這其中其實已經完成了對Vue中基礎組件v-model的理解與自定義組件v-model的理解。

轉載請註明地址: https://www.cnblogs.com/sonoda-umi/p/9750188.html

在Vue官方文檔中,對原生組件v-model的解釋是這樣的:

<input
  v-bind:value="searchText"
  v-on:input="searchText = $event.target.value"
>

v-model其實是上面寫法的語法糖。其實就是將this.searchText的值通過名為value的prop傳入input組件內,而後當input事件觸發時將事件帶來的input的新值寫入this.searchText中,然後根據this.searchText中值的變化通過value的prop傳入input控制項完成input控制項上值的變化,如果去掉v-on...後,這個控制項將變為一個只讀控制項。

對於自定義組件,文檔中有這樣的解釋:

一個組件上的 v-model 預設會利用名為 value 的 prop 和名為 input 的事件,但是像單選框、覆選框等類型的輸入控制項可能會將 value 特性用於不同的目的。model 選項可以用來避免這樣的衝突:


Vue.component('base-checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: Boolean
  },
  template: `
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    >
  `
})
現在在這個組件上使用 v-model 的時候:
<base-checkbox v-model="lovingVue"></base-checkbox>

這裡的 lovingVue 的值將會傳入這個名為 checked 的 prop。同時當 <base-checkbox> 觸發一個 change 事件並附帶一個新的值的時候,這個 lovingVue 的屬性將會被更新。

其實就是將原來v-model預設使用的名為value的prop與名為input的event自定義一個名字使用,在上面自定義組件中存在

props: {
    checked: Boolean
  }

說明checked本質上還是一個prop,然後在子組件的model屬性中將自定義的prop與event註冊,而觸發model中event時也就是通過觸發子組件的事件在父組件中修改綁定自定義prop的變數的值的過程,這樣這個過程就很明顯了:

1.父組件創建一個名為tmp變數綁定名為checked的prop的值(已被修飾為v-model)並根據父組件中tmp值的變化將變化後的值傳入子組件中,引起子組件checkbox狀態變化;

2.子組件中checkbox被勾選,觸發checkbox的change事件,通過this.$emit方法觸發子組件的change事件並將change事件產生的新值傳入;

3.因為在model屬性中已將v-model語法糖中event註冊為change(換成其他名字也都可以),v-model會自動將子組件傳來的值傳入tmp變數中;

4.Vue監聽到tmp值的變化,執行第一步,更新子組件中checkbox的狀態;

 

其實上面的子組件可以換個寫法更容易理解:

Vue.component('base-checkbox', {
  model: {
    prop: 'checked',
    event: 'test'
  },
  props: {
    checked: Boolean
  },
  template: `
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('test', $event.target.checked)"
    >
  `
})

父組件中調用時可以這樣寫:

<base-checkbox :checked="something" @test="something='子組件中的$event.target.value'"></base-checkbox>

這樣對v-model的理解也就一目瞭然了。

轉載請註明地址: https://www.cnblogs.com/sonoda-umi/p/9750188.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 大數據又稱黑暗數據,是指人腦無法處理的海量數據聚合成的信息資產,在民生、IT、金融、農業、通信等方面都有廣泛應用。未來5年大數據行業呈井噴趨勢,人才需求火爆,2018年大數據人才缺口更是高達900萬。以後想要做大數據相關的工作,需要學習哪些技術知識? 羅馬不是一天建成的,大數據工程師也不是短時間能鍛 ...
  • RDB RDB是將當前數據生成快照保存到硬碟上。 RDB的工作流程: 1. 執行bgsave命令,Redis父進程判斷當前是否存在正在執行的子進程,如RDB/AOF子進程,如果存在bgsave命令直接返回。 2. 父進程執行fork操作創建子進程,fork操作過程中父進程被阻塞。 3. 父進程for ...
  • 本文對Flutter的29種佈局控制項進行了總結分類,講解一些佈局上的優化策略,以及面對具體的佈局時,如何去選擇控制項。 ...
  • 本文主要介紹Flutter佈局中的FittedBox、AspectRatio、ConstrainedBox,詳細介紹了其佈局行為以及使用場景,並對源碼進行了分析。 ...
  • js中innerHTML與innerText的用法與區別 用法: <div id="test"> <span style="color:red">test1</span> test2 </div> 在JS中可以使用:test.innerHTML: 也就是從對象的起始位置到終止位置的全部內容,包括Ht ...
  • 在大家在網上平常瀏覽網頁的時候,想必各位都會看到選項卡功能,在這裡給大家詳解一下用原生js、jQuery如何來寫一些基本的選項卡 話不多說,先給各位看一下功能圖: 好了,下邊開始寫代碼了: HTML代碼: CSS代碼: *{ margin: 0; padding: 0; } ul{ overflow ...
  • react將dom解耦,不用直接操作dom,使用了狀態機制,當狀態改變時視圖就會相應更新。我們知道在react中,父組件可以將一些狀態傳遞給子組件,讓子組件的視圖相應更新,這時我們會發現,只有有關聯的組件才可以依次傳遞,那些沒有父組件與子組件關係的組件,這些組件之間的某些狀態是共用的,這時就需要re ...
  • 正則表達式(Regular Expression)是電腦科學的一個概念。 正則表達式使用單個字元竄來描述、匹配一系列符合某個句法規則的字元竄。 在很多文本編輯器里, 正則表達式通常用來被檢索替換哪些符合某個模式的文本。 "正則表達式實例" 創建 JavaScript通過內置對象 RegExp支持正 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...