您好,登錄后才能下訂單哦!
一.框架的定位
框架通常只是一種設計模式的實現,它并不意味著你可以在開發中避免所有分層設計工作。
SPA 框架幾乎都是基于 MVC 或 MVVM 設計模式而建立起來的,這些模式都只是宏觀的分層設計,當代碼量開始隨著項目增大而增多時,問題就會越來越多。許多企業內部的項目仍然在使用 angularjs1.X ,你會發現許多 controller 的體積大到令人發指,稍有經驗的團隊會利用好 angularjs1 構建的 controller , service , filter 以及路由和消息機制來完成基本的拆分和解耦,這已經能讓他們的開發能力中等體量的項目,往往只有掌握了 angularjs1 玩法精髓—— directive 的隊伍,才能夠在應付大型項目時使代碼保持足夠的清晰度,當然這只是在代碼形態和模塊劃分上的工作,相當于代碼的骨骼,想要讓業務邏輯本身更加清晰,就需要更高級的建模設計知識來對業務邏輯進行分層,例如 領域驅動模型 。如果你仍然在使用 angularjs1.x 的版本進行開發,可以參考【如何重構Controller】進行基本的分層拆分設計。
有趣的是一些團隊認為無法承載大型項目是 angularjs1.x 的原罪,與他們的開發水平無關,于是將希望寄托于擁有自動化工具加持的現代化 SPA 框架,然而如果有機會觀察你就會發現,許多項目對新框架的使用方式和之前并沒有本質的差別,只不過是把以前臃腫到不行的代碼又換了一種形式塞進了前端工程里,然后借著 ES6 語法和新型框架本身的簡潔性,開始沾沾自喜地認為這是自己重構的功勞。
請記住,如果不進行結構設計,即便使用最新版本的最熱門的框架,寫出來的代碼依舊會是一團亂麻。
二. Vue開發中的script拆分優化
以 Vue 框架為例,在工程化工具和 vue-loader 的支撐下,主流的開發模式是基于 *.vue 這種單文件組件形態的。一個典型的 vue 組件包含如下幾個部分:
<template> <!--視圖模板--> </template> <script> /*編寫組件腳本*/ export default { name:'component1' } </script> <style> /*編寫組件樣式*/ </style>
script 的部分通常包含有 交互邏輯 , 業務邏輯 , 數據轉換 以及 DOM操作 ,如果不加整理,很容易變得混亂不堪。 *.vue 文件的本質是View層代碼,它應該盡可能輕量并包含與視圖有關的信息,即 特性聲明 和 事件分發 ,其他的代碼理論上都應該剝離出去,這樣當項目體量增大后,維護起來就更容易聚焦關鍵信息,下面就如何進行腳本代碼拆分提供一些思路,有一些可能是很基本的原則,為盡可能完整就放在一起,你并不需要從最開始就采納所有的建議。
1.組件劃分
這是View層減重的基礎,將可共用的視圖組件剝離出去,改為消息機制進行通信,甚至直接剝離出包含視圖和業務代碼的業務邏輯組件,都可以有效地拆分View層,降低代碼的復雜度。
2.剝離業務邏輯代碼
script 中最大的一部分一般是業務邏輯,首先將業務邏輯代碼剝離為獨立的 [name].business.js 模塊,這樣做的直觀好處就是減輕了View層,另一方面是解除了業務邏輯和頁面之間的強綁定關系,如果其他頁面也涉及到這塊業務邏輯中的個別方法,就可以直接進行復用,最后就是當項目逐漸復雜,你決定引入 vuex 來進行狀態管理時View層會相對更容易修改。
一段包含基本增刪改查邏輯的組件大概是下面的樣子:
<script> export default{ name:'XXX', methods:{ handleClickCreate(){}, handleClickEdit(){}, handleClickRefresh(){}, handleClickDelete(){}, sendCreate(){}, sendEdit(){}, sendGetAll(){}, sendDelete(){} } } </script>
簡易的剝離方式是將交互邏輯保留在視圖層,將業務邏輯部分代碼放在另一個模塊中,然后利用 ES6 擴展運算符將其加入到組件實例的方法中,如下所示:
<script> import OrderBusiness from './Order.business.js'; export default{ name:'XXX', methods:{ ...OrderBusiness, handleClickCreate(){}, handleClickEdit(){}, handleClickRefresh(){}, handleClickDelete(){}, } } </script>
這種方式只是一種形態上的模塊化拆分,并沒有對業務邏輯本身進行梳理。另一種方式是構建獨立的業務邏輯服務,保留在View層中的代碼很容易轉換為使用 vuex 時的編碼風格:
<script> import OrderBusiness from './Order.business.js'; export default{ name:'XXX', methods:{ handleClickCreate(){ OrderBusiness.sendCreate(); }, handleClickEdit(){ OrderBusiness.sendEdit(); }, handleClickRefresh(){ OrderBusiness.sendGetAll(); }, handleClickDelete(){ OrderBusiness.sendDelete(); } } } </script>
筆者的建議是,前面三個示例隨著項目體量的增長可以實現漸進式的修改。
3. 剝離數據轉換代碼
在前后端分離的開發模式下,前端所需要的數據支持需要從后端請求獲得,但請求來的原始數據通常都是無法直接使用的,甚至有可能引發代碼報錯,例如時間可能是以時間戳形式傳過來的,或者你的代碼需要取用某個對象屬性時,后臺同學卻在該屬性上掛了一個默認值 NULL 等,另一方面,開發過程中的接口改動是無法避免的,所以在代碼結構的設計上,應該盡可能將可能變化的部分聚合起來。
比較實用的做法就是為每一個接口建立一個 Transformer 函數,從后臺請求來的數據先經過 Transformer 函數變換為前臺能夠流通使用的數據結構,并在必要的屬性上添加適當的默認值防止報錯,你可以盡情地在此使用 Lodash.js 等函數工具來加工和重組自己需要的數據,即使最初后臺傳給你的數據不需要加工,也可以保留一個透傳函數或是模塊說明以提醒其他協作開發者在面對這種場景時采用類似的做法,它的功能就是 為邏輯層提供直接可用的數據 。當前端代碼越來越重時, Transformer 和 Request 部分可以很方便地移動到中間層。
4. 善用computed和filters處理數據展示
對原始數據的轉換并不能覆蓋所有場景,這就需要在定制展示的場景中利用 computed 和 filters ,它們都可以用來在不改變數據的情況下更改展示結果,例如將數據中的0或1轉換為 未完成 和 已完成 ,或者是將時間戳和當前時間作比較后改為可讀性更高的 剛剛 , 1分鐘前 , 1小時前 , 1天前 等等,這些開發場景中是不能采用強行賦值來處理的,這是就可以使用計算屬性 computed 或過濾器 filters 來處理,它們的區別是 computed 一般用于組件內部,不具有通用性,而 filters 一般用于可復用的場景,可以通過下面的形式來定義一個 展示效果為首字母大寫 的全局過濾器:
Vue.filter('capitalize', function (value) { if (!value) return ''; value = value.toString(); return value.charAt(0).toUpperCase() + value.slice(1); })
當項目中使用 vuex 來進行狀態管理時, computed 通常會等價替換為 state 中的 getter 。
5. 使用directive處理DOM操作
盡管 Vue 提供了 refs 這個接口來實現在邏輯層直接操作 DOM ,但我們應當盡可能避免將復雜的 DOM 操作放在這里,有時候頁面上 DOM 變化的場景較多,將每個變化都使用數據驅動的方式顯然是不合理的,這時就需要用到指令特性 directive ,它常用來補充實現一些業務邏輯無關的 DOM 變化(業務邏輯相關的變化大都通過數據綁定進行了自動關聯)。 directive 的基本用法可以直接參考 【官方指南】 ,需要注意的是許多初級開發者都不太在意內存泄漏的問題,在 directive 的使用中需要格外注意這一點,通常我們會在 bind 事件鉤子中綁定事件并使用屬性持有這個監聽函數,并在 unbind 鉤子中解除對同一個監聽函數的綁定,即使沒有使用自定義指令,你也需要建立在必要時解綁監聽器的編碼習慣:
Vue.directive('clickoutside',{ bind:function (el, binding){ //定義監聽器 function handler(e) { if (el.contains(e.target)) { return false; } if (binding.expression){ binding.value(e); } } el.__clickOutSide__ = handler; document.addEventListener('click', handler); }, unbind:function (el) { document.removeEventListener('click',el.__clickOutSide__); delete el.__clickOutSide__ ; } });
demo 中提供了一個簡單的 directive 示例,你可以用它來做練習。
總結
以上所述是小編給大家介紹的Vue中拆分視圖層代碼的5點建議,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對億速云網站的支持!
如果你覺得本文對你有幫助,歡迎轉載,煩請注明出處,謝謝!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。