欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue 中的受控與非受控組件的實現(xiàn)

 更新時間:2018年12月17日 09:43:15   作者:aryu  
這篇文章主要介紹了Vue 中的受控與非受控組件的實現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

受控組件

什么是受控組件?

其值由React控制的輸入表單元素稱為“受控組件”。

受控組件有兩個特點(diǎn):1. 設(shè)置value值,value由state控制,2. value值一般在onChange事件中通過setState進(jìn)行修改

什么時候使用受控組件?

需要對組件的value值進(jìn)行修改時,使用受控組件。比如:頁面中有一個按鈕,每點(diǎn)擊一次按鈕受控組件的值加1.

非受控組件

什么是非受控組件?

表單數(shù)據(jù)由 DOM 處理的組件非受控組件。

非受控組件有兩個特點(diǎn):1. 不設(shè)置value值,2. 通過ref獲取dom節(jié)點(diǎn)然后再取value值

<input type="text" placeholder="請輸入姓名" name='username' ref={(input) => this.usernameElem = input}/>

取值方法:this.usernameElem.value

什么時候使用非受控組件?

任何時候都不需要改變組件的value值,這時候可以使用非受控組件。

Vue 中的受控與非受控組件

熟悉 React 的開發(fā)者應(yīng)該對“受控組件”的概念并不陌生,實際上對于任何組件化開發(fā)框架而言,都可以實現(xiàn)所謂的受控與非受控,Vue 當(dāng)然也不例外。并且理解受控與非受控對應(yīng)的需求場景,可以讓我們在設(shè)計一些基礎(chǔ)組件時思路更加清晰,暴露出來的組件 API 也更加合理、統(tǒng)一。

需求

許多 UI 組件都是有狀態(tài)(stateful)的,而這個狀態(tài)是由組件外部控制還是組件內(nèi)部維護(hù),也就對應(yīng)了受控與非受控兩種模式。

例如 Tabs 組件是很常見的一種 UI 組件,它的核心狀態(tài)就是記錄當(dāng)前 active 的 Tab,并且允許用戶切換。

很多時候我們只希望 Tabs 可以正確的展示 active 的內(nèi)容、并在用戶操作時正常切換,不需要進(jìn)行任何干預(yù),那么就希望 只需要傳入所有的 Tab 內(nèi)容,不需要再做額外的配置。

但有的時候我們又希望對 Tabs 的狀態(tài)有很強(qiáng)的控制能力,例如多個關(guān)聯(lián)的 Tabs,子級 Tabs 的內(nèi)容需要根據(jù)父級 Tabs 的 active Tab 動態(tài)切換,這時候就會希望 Tabs 組件可以暴露足夠充分的 API,來實現(xiàn)業(yè)務(wù)的需求。

因此我們可以用一種通用的模式,來讓任意組件的任意狀態(tài)同時兼容受控與非受控兩種模式,讓不同需求場景下都可以使用最合理的 API。

簡化示例

我們用一個簡單的 Tabs 實現(xiàn)來演示這種通用的組件 API 設(shè)計模式,簡化的部分包括:

  • 用 index 來作為 Tab 的唯一標(biāo)識
  • Tab content 只支持字符串

可以打開 online DEMO 配合閱讀

API 設(shè)計

對于 Vue 組件而言,API 設(shè)計主要指的是內(nèi)部的 data, computed, methods 以及對外的 props, events。在這個示例中,我們會用 activeIdx 作為核心狀態(tài),所有的 API 也都會圍繞這個狀態(tài)命名。

非受控模式

如上文所說,非受控模式指的是使用者不需要關(guān)心控制組件的狀體,完全交由組件內(nèi)部維護(hù)。

因此我們的 API 會包括:

{
 props: {
  defaultActiveIdx: {
   type: Number,
   default: 0
  }
 },
 data() {
  return {
   localActiveIdx: this.defaultActiveIdx
  }
 },
 methods: {
  handleActiveIdxChange(idx) {
   this.localActiveIdx = idx;
   this.$emit("active-idx-change", idx);
  }
 }
}

localActiveIdx 是我們用來存放 active index 的組件內(nèi) data,對于非受控模式而言,雖然不希望在外部維護(hù)狀態(tài),但是仍有可能希望在外部決定初始狀態(tài),所以我們用 defaultActiveIdx 這個 props 決定 localActiveIdx 的初始值。

之后當(dāng)我們用 v-for="(tab, idx) in tabs" 指令生成所有的 Tab 時,就可以通過 idx === localActiveIdx 的方式判斷當(dāng)前 Tab 是否 active,再通過 @click="handleActiveIdxChange(idx)" 就可以實現(xiàn)對 localActiveIdx 的更新。

同樣的,我們也可以通過 {{ tabs[localActiveIdx].content }} 展示 active Tab 的內(nèi)容。

需要注意的是在 handleActiveIdxChange 的事件處理中,我們也 emit 了 active-idx-change 這一事件,這樣可以方便外部在不需要管理組件狀態(tài)的同時也可以與組件狀態(tài)保持同步。例如我們希望將 active Tab 反映在 URL 中,就可以在外部監(jiān)聽 active-idx-change 這一事件,并將當(dāng)前 index 同步到路由中,在將路由中獲取到的 index 作為 defaultActiveIdx 傳入,就可以實現(xiàn) URL 和 Tabs 的同步。

受控模式

對于受控模式來說,我們可以理解為 active index 是外部傳入的 props,由外部自行維護(hù)其狀態(tài)。

因此我們只需要添加如下 props:

props: {
 activeIdx: Number
}

由于我們已經(jīng)有對外 emit 的事件 active-idx-change,所以外部用以下方式就可以用一個 data 屬性 externalActiveIdx 維護(hù)對應(yīng)狀態(tài):

<tabs
 :tabs="tabs"
 :activeIdx="externalActiveIdx"
 @active-idx-change="this.externalActiveIdx = $event"
/>

當(dāng)然由于在這種模式下外部對狀態(tài)有完全的控制權(quán),所以在 active-idx-change 的事件處理中也可以做更為復(fù)雜的判斷,例如是否允許激活目標(biāo) Tab 之類的校驗。

而在 Tabs 組件內(nèi)部,我們還需要做一些小的修改。在受控模式中,我們所有狀態(tài)相關(guān)的處理都是直接使用 localActiveIdx,而現(xiàn)在我們的邏輯應(yīng)該變?yōu)椤叭绻嬖?activeIdx props,則使用,否則使用 localActiveIdx”。

為了保證以上邏輯不會讓我們的組件內(nèi)部實現(xiàn)變得復(fù)雜、易錯,我們引入一個 computed 屬性:

computed: {
 _activeIdx() {
  return this.activeIdx || this.localActiveIdx;
 }
}

這樣我們就可以把狀態(tài)相關(guān)的判斷改為通過 idx === _activeIdx 判斷一個 Tab 是否為激活狀態(tài),也通過 {{ tabs[_activeIdx].content }} 展示 active Tab 的內(nèi)容。

同樣,我們在 handleActiveIdxChange 的方法內(nèi)部也可以增加一個判斷,如果存在 props aciveIdx 則不更新 localActiveIdx:

handleActiveIdxChange(idx) {
 if (this.activeIdx === undefined) {
  this.localActiveIdx = idx;
 }
 this.$emit("active-idx-change", idx);
}

在一些更復(fù)雜的組件中,可能會頻繁判斷是否為受控模式并做不同的處理,這時候通過 this.activeIdx 這樣的核心狀態(tài) props 是否傳入來判斷是否為受控模式是一個不錯的實踐。

總結(jié)

最終我們?yōu)?active index 設(shè)計的完整 API 如下:

{
 props: {
  activeIdx: Number,
  defaultActiveIdx: {
   type: Number,
   default: 0
  }
 },
 data() {
  return {
   localActiveIdx: this.defaultActiveIdx
  };
 },
 computed: {
  _activeIdx() {
   return this.activeIdx || this.localActiveIdx;
  }
 },
 methods: {
  handleActiveIdxChange(idx) {
   if (this.activeIdx === undefined) {
    this.localActiveIdx = idx;
   }
   this.$emit("active-idx-change", idx);
  }
 }
}

通過這種 API 設(shè)計方式,可以讓我們設(shè)計的基礎(chǔ)組件使用方式更一致,拓展性更強(qiáng),不論是開發(fā)還是使用時思路也會更加簡潔清晰。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • element前端實現(xiàn)壓縮圖片的功能

    element前端實現(xiàn)壓縮圖片的功能

    本文主要介紹了element前端實現(xiàn)壓縮圖片的功能,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • Vue中如何動態(tài)顯示表格內(nèi)容

    Vue中如何動態(tài)顯示表格內(nèi)容

    這篇文章主要介紹了Vue中如何動態(tài)顯示表格內(nèi)容問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • Vue使用NProgress實現(xiàn)頁面頂部的進(jìn)度條顯示效果

    Vue使用NProgress實現(xiàn)頁面頂部的進(jìn)度條顯示效果

    這篇文章主要介紹了vue Nprogress頁面頂部進(jìn)度條功能實現(xiàn),NProgress是頁面跳轉(zhuǎn)是出現(xiàn)在瀏覽器頂部的進(jìn)度條,本文通過實例代碼給大家講解,需要的朋友可以參考下
    2022-12-12
  • 在Vue中是如何封裝axios

    在Vue中是如何封裝axios

    這篇文章主要介紹在Vue中是如何封裝axios的相關(guān)資料,axios的封裝主要是幫助我們簡化代碼和利于后期的更新維護(hù),感興趣的小伙伴可以和小編一起來閱讀下面文章的具體內(nèi)容
    2021-10-10
  • vue中利用Promise封裝jsonp并調(diào)取數(shù)據(jù)

    vue中利用Promise封裝jsonp并調(diào)取數(shù)據(jù)

    Promise就是一個給一步操作提供的容器,在這個容器里,有兩個階段無法改變的階段,這兩個階段在文中給大家提到。對vue中利用Promise封裝jsonp并調(diào)取數(shù)據(jù) 的相關(guān)知識感興趣的朋友,跟隨小編一起看看吧
    2019-06-06
  • Vue3中內(nèi)置組件Teleport的基本使用與典型案例

    Vue3中內(nèi)置組件Teleport的基本使用與典型案例

    Teleport是一種能夠?qū)⑽覀兊哪0逡苿拥紻OM中Vue app之外的其他位置的技術(shù),下面這篇文章主要給大家介紹了關(guān)于Vue3中內(nèi)置組件Teleport的基本使用與典型案例的相關(guān)資料,需要的朋友可以參考下
    2023-04-04
  • vue.nextTick()與setTimeout的區(qū)別及說明

    vue.nextTick()與setTimeout的區(qū)別及說明

    這篇文章主要介紹了vue.nextTick()與setTimeout的區(qū)別及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • 基于vue3+TypeScript實現(xiàn)一個簡易的Calendar組件

    基于vue3+TypeScript實現(xiàn)一個簡易的Calendar組件

    最近在學(xué)習(xí) react,在學(xué)習(xí)到使用 react 開發(fā) Calendar 組件的時候,突然聯(lián)想到使用 vue 進(jìn)行 Calendar 功能的實現(xiàn),因為目前使用的技術(shù)棧是 vue,剛好可以加深下對 vue3 和 ts 的使用印象,所以本文給大家介紹了基于vue3+TypeScript實現(xiàn)一個簡易的Calendar組件
    2024-05-05
  • vue無限輪播插件代碼實例

    vue無限輪播插件代碼實例

    這篇文章主要介紹了vue無限輪播插件,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • Vue跨端渲染實現(xiàn)多端無縫銜接

    Vue跨端渲染實現(xiàn)多端無縫銜接

    這篇文章主要介紹了Vue跨端渲染實現(xiàn)多端無縫銜接,Vue跨端渲染是一種基于Vue框架的跨平臺開發(fā)技術(shù),能夠?qū)崿F(xiàn)Web、iOS和Android三端的無縫銜接,提高開發(fā)效率和用戶體驗
    2023-05-05

最新評論