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

vue中拆分組件的實(shí)戰(zhàn)案例

 更新時(shí)間:2022年12月05日 09:57:29   作者:我是小橘子哦?lv-4  
最近在學(xué)vue,試著寫個(gè)單頁應(yīng)用,在寫組件,拆分組件時(shí)遇到一些困惑,下面這篇文章主要給大家介紹了關(guān)于vue中拆分組件的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下

組件化是一種思維的表現(xiàn),這種技能映射到人的本質(zhì)是,一個(gè)人是否有能力把一個(gè)復(fù)雜的問題拆解、簡(jiǎn)單化的能力。

一、組件化誕生的歷史

我們?cè)谟懻撊绾尾鸱纸M件之前,是有必要簡(jiǎn)單的了解一下組件化誕生的一個(gè)歷史。

前端娛樂圈有一個(gè)獨(dú)有的生態(tài):框架。每年出現(xiàn)的框架層出不窮,根本學(xué)不完。但是總的來說還是可以分成兩個(gè)階段。

第一階段: JQ和PrototypeJS。 該階段解決了瀏覽器的兼容性問題以及API的遍歷程度

第二階段: Vue、React、Angular。解決了組件化、解耦、復(fù)用等問題

在大陸,主要討論的是Vue和React。 有些人說Vue是framework,而React是library,前者有更多的約束和更加齊全的工具鏈。而后者更加的自由。但是真的要投入生產(chǎn)的話,依舊需求認(rèn)為的給React添加很多的約束,而且Vue也是支持jsx的,所以我一直不太贊同React更加自由這樣的說話。

在我看來,它們?cè)趯?shí)際生產(chǎn)開發(fā)過程中,在那一堆工具鏈中,只是API的不同而已

它們都為前端提供了很好的組件化。而且近一年來兩者都不約而同朝著函數(shù)式跟進(jìn)。它們帶來的各種hook,給我們帶來了不一致的組件化的寫法。

二、為什么業(yè)務(wù)組件越開發(fā)越難維護(hù)

人的問題

當(dāng)然是人的問題. 或許產(chǎn)品的問題,或許整個(gè)工作流程的問題,或許上面的問題. 這些我們暫且不提,我作為開發(fā), 首先是要管好自己的代碼組織.

再次我們先排除其他外界的因素,比如產(chǎn)品經(jīng)常改需求. 僅從編碼階段來說.

以我們團(tuán)隊(duì)為例,我們團(tuán)隊(duì)內(nèi)部員工2個(gè),8個(gè)外包,外包兄弟們的招聘標(biāo)準(zhǔn)是遠(yuǎn)低于內(nèi)部的。團(tuán)隊(duì)人員每個(gè)人的編碼能力差距還是很大的。項(xiàng)目都是長(zhǎng)期維護(hù)的,一個(gè)業(yè)務(wù)模塊就會(huì)有很多人維護(hù),在上面不斷的填尿加屎。

在這里并不是說外包人員的編碼能力差,我們組就有一個(gè)外包的兄弟編碼能力、解決問題的能力相當(dāng)厲害的,比很多內(nèi)部的都好很多。這里只是從平局值上面來說。

團(tuán)隊(duì)成員的水平參差不齊, 顧及到團(tuán)隊(duì)協(xié)作, 我們?cè)诓鸱纸M件的時(shí)候需要更加的簡(jiǎn)單和清晰.

技術(shù)問題

業(yè)務(wù)邏輯和交互邏輯的糾纏不清

2.1 項(xiàng)目現(xiàn)狀

以該圖為例, A B C 分別是父子孫組件. 當(dāng)我們要控制其中一個(gè)組件的狀態(tài)的是, 可以通過很多方式來進(jìn)行控制. 這些方式的來源有可能是全局變量、vuex、時(shí)間總線來自自己父組件或子組件的改變等等.

可以看出, 改變它組件內(nèi)部狀態(tài)的來源非常的多, 維護(hù)或者修改的時(shí)候,需要翻閱的文件目錄和范圍就很廣. 自然就很難維護(hù).

舉一個(gè)mixins的例子:

假設(shè)它混入了這么多功能。

export default {
  mixins: [ a, b, c, d, e, f, g],
  mounted() {
    console.log(this.whoAreYou)
  }
}

這個(gè)this.whoAreYou你能夠知道來源于哪一個(gè)么? 而如果改成hook的寫法來引入某個(gè)JS中的變量:

const { IamI } = myHome()

const { IamI as me } = myHome()

這就很簡(jiǎn)潔干凈。在你維護(hù)代碼的時(shí)候,可以很好的進(jìn)行溯源。 而上面的一切,導(dǎo)致難以維護(hù)的原因總結(jié)來說有兩個(gè):

  • 混用業(yè)務(wù)變量和UI變量
  • 不區(qū)分受控組件和非受控組件

下面我會(huì)實(shí)際例子分別介紹這個(gè)兩個(gè)概念。而基于hooks的復(fù)用才是我們現(xiàn)在解決組件化復(fù)用的更好的選擇。

2.2 理想目標(biāo)

基于hook的理想模型

依舊是A B C 三個(gè)組件.但是A B C三個(gè)組件外邊飄的那些箭頭不存在了. 所有能夠控制它們的內(nèi)部狀態(tài)的方式都集中 在了controllers上面.

其中controllers部分的組織形式和vue的composition api宣傳圖表現(xiàn)一致。

將相似的功能以及用到的變量都封裝在一個(gè)函數(shù)當(dāng)中。這一切也更加好的迎合了

實(shí)際代碼如下:

<template>
  <div>
    <B setC={setC} />  
  <div>
</template>
<script setup>
  import B from 'B.js'
  import cController from 'cController.js'

  const { setC } = cController(props)
</script>

// cController.js
export default c(props) {
  const c = ref('')
  const setC() {
    c.value = 'I an cController'
  }

  return {
    c,
    setC,
  }
}

cController.js就是controllers中的一個(gè)void. 引入到A組件當(dāng)中,然后將里面的方法通過props傳給B組件.

<template>
  <div>
    <C setC={setC} />  
  <div>
</template>
<script setup>
	import C from 'C.js'
  
  props: {
  	setC: {
      type: Number,
    }
  }
</script>

也就是說,控制C組件內(nèi)部狀態(tài)的是通過引入到A組件中的controller來進(jìn)行通過,中間的B組件不做任何的處理,僅僅作為一個(gè)中轉(zhuǎn)站. 操作起來和理論都很簡(jiǎn)單。但是想要更好的拆分的話,還需要了解三個(gè)概念:

  • 業(yè)務(wù)變臉和UI變量
  • 受控組件和非受控組件
  • 控制反轉(zhuǎn)ioc

下面我通過一個(gè)實(shí)際的業(yè)務(wù)場(chǎng)景來描述。

三、舉一個(gè)實(shí)際的例子

3.1 需求背景

簡(jiǎn)單的截兩張圖. 需求大致如下:

  • 功能就是典型的筆記軟件的功能,右邊可以放各種類型的文件,點(diǎn)擊就可以在右邊渲染出對(duì)應(yīng)的內(nèi)容.
  • 目錄樹有兩個(gè)彩蛋,會(huì)根據(jù)當(dāng)前文件類型出現(xiàn)不同的操作
  • 目錄樹下面有一個(gè)固定的收藏夾,目錄樹可以在這其中滾動(dòng)

3.2 開發(fā)之前: 前端設(shè)計(jì)文檔

數(shù)據(jù)流向圖

功能還是很清楚的,但是功能其實(shí)很多. 我認(rèn)為我們團(tuán)隊(duì)在開發(fā)之前是必須要有的. 作為一個(gè)前端, 可以沒有流程圖,但是一定要下面這樣的圖. 我在別的地方?jīng)]有見過這樣的圖,所以自己給這樣的圖做了一個(gè)定義,叫數(shù)據(jù)流向圖.

關(guān)于完整的工作流程,之后再寫一篇文章進(jìn)行描述

它是有兩部分構(gòu)成:

  • 組件的模塊
  • 組件之間的控制關(guān)系

第一點(diǎn), 還是比較清楚,就是這個(gè)需求可以拆成哪幾個(gè)模塊.

第二點(diǎn), tree組件和content組件是同級(jí)組件, tree可以控制content組件內(nèi)的狀態(tài), content組件也可以改變tree內(nèi)的狀態(tài). 再深入一點(diǎn)說,就是tree點(diǎn)擊不同的文件類型, content組件部分就會(huì)渲染不同的模塊; 而當(dāng)在content組件內(nèi)對(duì)當(dāng)前閱讀的文件進(jìn)行刪除操作的時(shí)候,tree作為目錄樹自然是要刷新最新的目錄信息的.

目錄結(jié)構(gòu)

通過上面的結(jié)構(gòu)圖,可以得到下面這樣目錄結(jié)構(gòu).

邏輯控制

數(shù)據(jù)流向圖中的各個(gè)組件都放在根目錄下index.vue中掛載. 如下入

控制目錄樹的相關(guān)邏輯都放在listTreeController控制器里邊, 和右邊內(nèi)容content相關(guān)邏輯都放入到renderContentController的方法當(dāng)中.

隨后將controller中公共方法都傳進(jìn)到組件當(dāng)中. doc-aside是包括searchtree已經(jīng)other三個(gè)模塊的中轉(zhuǎn)組件. 不在這個(gè)組件中做任何的邏輯處理. 如下圖:

舉一個(gè)例子, 控制按鈕的權(quán)限. [背景]

  • 所有功能點(diǎn)都受控掛載在vuex的store上面的一個(gè)變量, 沒有權(quán)限的話,就直接通過v-if來隱藏對(duì)應(yīng)的入口

[之前實(shí)現(xiàn)]

  • 直接找到對(duì)應(yīng)的按鈕在v-if上,通過root.docAuth('createDoc')來判斷

[修改之后]

  • 創(chuàng)建來一個(gè)authoControllers.jsindex.vue引入, 需要用的地方是應(yīng)用的是

[具體實(shí)現(xiàn)]

export default function authController({ root }) {
  const menuAuth = {
    [MENTY_TYPE.rename]: root.docAuth('rename'),
    [MENTY_TYPE.delete]: root.docAuth('delete')
    // ....
  }
}

雖然在Index.vue中引入,不管是通過props,還是通過依賴注入來給子組件來使用,都不重要.重要的是,它統(tǒng)一管理, 并在index.vue中引入是唯一一個(gè)入口. 當(dāng)我們維護(hù)的時(shí)候, 只需要通過子組件一路找到對(duì)應(yīng)的controller就可以找到對(duì)應(yīng)的邏輯了.

拆分的原則

  • 對(duì)于組件的拆分一開始不需要太細(xì)
  • 拆分好受控組件和非受控組件

3.3 受控組件和非受控組件

我們使用的任何UI框架都是受控組件, 受控組件的概念就是它里面的狀態(tài)都是受調(diào)用它的組件來控制的. 非受控組件反之.

3.4 開發(fā)進(jìn)行: 邏輯變量和UI變量

UI變量其實(shí)很好理解. 像element-ui的組件中所需要的屬性就是UI變量. 但是對(duì)于我們實(shí)際業(yè)務(wù)當(dāng)中, 會(huì)對(duì)這些進(jìn)行一定擴(kuò)展.

舉一個(gè)例子, 在上面的目錄中dialog組件的顯示或隱藏,是通過model-value / v-model來進(jìn)行控制的, true就顯示, false就隱藏起來.

隱藏和顯示的漸入漸出效果是elementUI框架內(nèi)置的.

平時(shí)工作中很多人是這樣傳的:

<el-dialog :v-model="data.id === XXXX">
  // code
</el-dialog>
props = {
  data: {
    type: Object
  }
}

通過通過接口拿到的,或者自己組件的數(shù)據(jù)傳進(jìn)來之后,再進(jìn)行對(duì)v-model的控制. data.id這樣的變量就是業(yè)務(wù)變量, 通過業(yè)務(wù)變量來直接控制UI的組件的顯示和隱藏,就是業(yè)務(wù)變量和UI變量的混用. 或者說**業(yè)務(wù)邏輯和交互邏輯的混用. **

混用之后的后果,就是我們進(jìn)行維護(hù)的時(shí)候, 需要查看的變量或者說字段就成倍的增加, 交互變量和業(yè)務(wù)變量交織在一起. 這部分的代碼同時(shí)承載了業(yè)務(wù)邏輯和交互邏輯.

DDD領(lǐng)域模型也是可以解決這個(gè)問題, 之后我會(huì)再開篇幅聊一聊.

所以我們就需要將業(yè)務(wù)邏輯和交互邏輯給拆開. 如下:

<template>
  <el-dialog :v-model="isShow">
    <template slot="header">
      {{ dialogTitle }}
    </template>
    <template slot="content">
      // type === 創(chuàng)建表單
      // type === 移動(dòng)文件夾目錄
    </template>
  </el-dialog>
</temaplte>
props = {
  isShow: {
    type : Boolean,
    desc: '是否顯示彈窗'
  },
  type: {
    type: String,
    desc: '彈窗的類型'
  }
}

其中ishowtype 就可以視為UI變量, 它們不關(guān)心外界是通過了什么判斷, 只關(guān)系傳進(jìn)來的是true還是false.

四、持續(xù)的優(yōu)化

不管一開始代碼是如何規(guī)劃的,如何組織的.最重要的還是要持續(xù)的去維護(hù). 屎山到了之后, 前面的維護(hù)者沒有一個(gè)人是無辜的. 但是也不需要過早的去維護(hù).什么時(shí)候到了維護(hù)重構(gòu)的時(shí)機(jī)呢?

  • 當(dāng)碰到這里用的代碼別的地方也用到的時(shí)候
  • 這個(gè)變量出現(xiàn)在好幾個(gè)地方,被好幾個(gè)地方都set的時(shí)候, 而自己搞不懂它們set的順序的時(shí)候
  • 函數(shù)復(fù)雜到自己看了半天都看不明白的時(shí)候

五、可能的問題

問題一: 中轉(zhuǎn)的組件沒有掛載任何邏輯,為什么還存在?

  • 為了之后可能的拆分
  • 讓結(jié)構(gòu)更加的清晰

問題二: 中轉(zhuǎn)的組件要掛載這么多辦法, 或許太難看?

  • 實(shí)在是太多可以使用vue的$attr$listeners
  • 為了維護(hù)對(duì)于數(shù)據(jù)的溯源

五、實(shí)踐是學(xué)習(xí)前端的捷徑

前端是一門手藝活,只有實(shí)踐才能夠提高技術(shù). 前端的天花板確實(shí)相比其他方向的低,但是也不是我這樣的普通人說能夠觸碰就能觸碰到的. 就算很多高端大佬嗤之以鼻的業(yè)務(wù)代碼, 寫的時(shí)候如果不多思考如何寫的簡(jiǎn)潔,怎么寫優(yōu)雅,寫十年和寫三年也是沒有差別的.

業(yè)務(wù)才能創(chuàng)造價(jià)值, 有了價(jià)值才能有我們前端工程師生存的空間. 所以為了提升自己的價(jià)值, 提升自己的工資. 平時(shí)寫業(yè)務(wù)代碼的時(shí)候,想想這樣寫會(huì)有什么問題, 如何寫才能夠更加好. 在這個(gè)基礎(chǔ)上, 才能看明白那些框架存在的意義. 業(yè)務(wù)是在輪子之上的,如果對(duì)業(yè)務(wù)的代碼都不理解, 又怎么能夠真正的寫好輪子呢?

所以我們?cè)诒U蠘I(yè)務(wù)按時(shí)完成的情況下,應(yīng)該多嘗試,多實(shí)踐.

總結(jié)

到此這篇關(guān)于vue中拆分組件的文章就介紹到這了,更多相關(guān)vue拆分組件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論