前端架构设计1:代码核心
現(xiàn)在的前端領(lǐng)域, 隨著JS框架, UI框架和各種庫(kù)的豐富, 前端架構(gòu)也變得十分的重要. 如果一個(gè)大型項(xiàng)目沒(méi)有合理的前端架構(gòu)設(shè)計(jì), 那么前端代碼可能因?yàn)椴煌拈_(kāi)發(fā)人員隨意的引入各種庫(kù)和UI框架, 導(dǎo)致代碼量變得異常臃腫, 最終結(jié)果可能是代碼變得無(wú)法維護(hù), 頁(yè)面性能低下,不得已只能推翻重構(gòu). 所以我們需要在項(xiàng)目開(kāi)始前, 同樣的需要對(duì)前端代碼進(jìn)行架構(gòu), 一旦前端架構(gòu)師設(shè)計(jì)出所有前端開(kāi)發(fā)人員都要遵循的檢驗(yàn)機(jī)制, 建立起系統(tǒng)設(shè)計(jì)的規(guī)范, 那么項(xiàng)目就擁有了可以衡量代碼質(zhì)量的標(biāo)準(zhǔn), 前端開(kāi)發(fā)人員也能享受到更高效的工作流. 所以, 前端架構(gòu)的定義可以用以下一句話來(lái)總結(jié):
前端架構(gòu)是一系列工具和流程的集合, 旨在提升前端代碼的質(zhì)量, 并實(shí)現(xiàn)高效, 可持續(xù)的工作流.
本系列的前端架構(gòu)文章, 將分別圍繞前端架構(gòu)的四個(gè)核心展開(kāi), 分別是代碼, 流程, 測(cè)試, 文檔.
前端架構(gòu)的四個(gè)核心
(一) 代碼
歸根到底, 所有的網(wǎng)站都是由一堆文本文件和資源文件組成的. 當(dāng)我們面對(duì)制作網(wǎng)站所產(chǎn)生的大量代碼時(shí), 就會(huì)發(fā)現(xiàn)為代碼和資源設(shè)定一個(gè)期望是多么重要. 在代碼部分, 我們會(huì)專注于如果實(shí)現(xiàn)系統(tǒng)架構(gòu)中的HTML, CSS, JavaScript.
(二) 流程
現(xiàn)在早已過(guò)了FTP上傳文件的時(shí)代, 那么現(xiàn)在重要的是思考怎么用工具和流程構(gòu)建一個(gè)高效且避免出錯(cuò)的工作流. 工作流變得越來(lái)越復(fù)雜, 那些用于它們的工具也同樣如此. 這些工具在提高生產(chǎn)力, 加快效率和保持代碼一致性上帶來(lái)了驚人的效果, 但也伴隨著過(guò)度工程化和抽象化的風(fēng)險(xiǎn). 所以, 現(xiàn)有的工作流是需要改變的.
(三) 測(cè)試
要構(gòu)建一個(gè)可擴(kuò)展和可持續(xù)優(yōu)化的系統(tǒng), 必須保證新代碼和老代碼能夠很好的兼容. 我們的代碼不會(huì)獨(dú)立存在, 它們都是大型系統(tǒng)中的一部分. 創(chuàng)建覆蓋面廣泛的測(cè)試方案, 能確保老代碼還能正常運(yùn)作.
(四) 文檔
一般而言, 如果不是團(tuán)隊(duì)中的重要成員要離開(kāi), 我們幾乎都不會(huì)意識(shí)到文檔的重要性. 等到那個(gè)時(shí)候, 大家將不得不停下手頭的工作, 優(yōu)先編寫所有的文檔. 作為前端機(jī)構(gòu)師, 你要善于在項(xiàng)目開(kāi)發(fā)的同時(shí)編寫良好的文檔.
代碼核心
(一) HTML
在前端的架構(gòu)中, HTML作為頁(yè)面的基礎(chǔ)是十分重要的. 如果初始的HTML寫得很爛, 將要寫出很多不必要的CSS和JavaScript來(lái)彌補(bǔ). 反之, 如果如果初始的HTML寫得足夠好, 就能寫出根據(jù)可擴(kuò)展性和可維護(hù)的CSS和JavsScript.
首先我們來(lái)看一些初級(jí)的前端工程師可能寫出的HTML代碼:
<div id="header" class="clearfix"> <div id="header-screen" class="clearfix"> <div id="header-inner" class="container-12 clearfix"> <div id="nav-header" role="navigation"> <div class="region" region-navigation> <div class="block block-system block-menu"> <div class="block-inner"> <div class="content"> <ul class="menu"> <li class="first leaf"> <a href="#">菜單1</a> </li> <li class="second leaf"> <a href="#">菜單2</a> </li> </ul> </div> </div> </div> </div> </div> </div> </div>這類"div亂燉"的代碼, 是很多初級(jí)的前端為應(yīng)付切頁(yè)面的工作寫出來(lái)的. 只是單純?yōu)榱诉€原psd圖, 而完全你不考慮HTML的可讀性和可維護(hù)性.
隨后, 在HTML5之后, 標(biāo)簽的語(yǔ)義化受到了大家的重視, 采用語(yǔ)義化的標(biāo)簽, 不僅增加了代碼的可讀性, 也有利于SEO. HTML語(yǔ)義化標(biāo)簽的使用,這也是在前端架構(gòu)中需要考慮到的,下面我們來(lái)看一下使用語(yǔ)言化標(biāo)簽寫的這段代碼:
<header><section><nav> <ul> <li> <a href="#"> 菜單1 </a> </li> <li> <a href="#"> 菜單2 </a> </li> </ul> </nav> </section> </header>但是如果我們的頁(yè)面的菜單有數(shù)10項(xiàng)的時(shí)候, 就會(huì)額外添加<li><a href="#">菜單N</a></li>, 這類重復(fù)的工作量完全可以交給Mustache這類模板引擎來(lái)解決, 已Vue中的模板引擎語(yǔ)法來(lái)寫HTML, 會(huì)減少很多的工作量 :
<template><header><section> <nav> <ul> <li v-for="(item, index) in navList" :key="index"> <a href="#"> {item} </a> </li> </ul> </nav> </section> </header> </template> <script> export default { data() { navList:['菜單1','菜單2','菜單3','菜單4','菜單5','菜單6','菜單7','菜單8','菜單9','菜單10'] } } </script>你也可以使用Handlebars, Jade, artTemplate各種模板引擎到你的項(xiàng)目中, 當(dāng)然這些都是需要取決于前端架構(gòu)師前期的所選擇的技術(shù)選型. 做為前端架構(gòu)師, 需要評(píng)估HTML產(chǎn)生的過(guò)程, 你對(duì)內(nèi)容的順序, 使用的元素和CSS類名有多大的控制權(quán)? 這些元素在將來(lái)改動(dòng)起來(lái)會(huì)有多大難度? 模板的易用性? 你可以通過(guò)系統(tǒng)做出更改, 還是需要手動(dòng)處理? 通過(guò)回答這些問(wèn)題, 可能會(huì)顛覆你自己構(gòu)建HTML和CSS的方法.
(二) CSS
構(gòu)建CSS現(xiàn)在有很多成熟的方法, 例如使用新的命名空間, 擴(kuò)充數(shù)據(jù)屬性或在JavaScript里面定義CSS. 這些方法你可以從BootStrap, ElementUI這類UI框架中找到影子. 下面, 介紹3種比較常用的方法.
1.OOCSS方法(Object-Oriented CSS 面向?qū)ο蟮腃SS)
<div class="toggle simple"><div class="toggle-control open"> <h1 class="toggle-title">標(biāo)題</h1> </div> <div class="toggle-details open"> 詳細(xì)內(nèi)容 </div> </div>上面這段代碼就展示了如何使用OOCSS方法創(chuàng)建一個(gè)可切換的HTML代碼, OOCSS有兩個(gè)主要的原則:
- 分離結(jié)構(gòu)和外觀
- 分離容器和內(nèi)容
分離結(jié)構(gòu)和外觀
這里的toggle用來(lái)控制結(jié)構(gòu),?simple用來(lái)控制外觀,這就是分離結(jié)構(gòu)和外觀的表現(xiàn). 這樣可以實(shí)現(xiàn)外觀的復(fù)用, 例如當(dāng)前的simple皮膚使用直角, 而complex皮膚可能使用圓角, 還加了陰影.
分離容器和內(nèi)容
這里使用toggle-title就是分離容器和內(nèi)容的表現(xiàn), 無(wú)論toggle-title的容器是用的<h1>還是<h2>或者是<div>, 一旦加上了toggle-title這個(gè)類名, 那么該容器均已該類名所定義的樣式呈現(xiàn)內(nèi)容.
2.SMACSS方法(Scalable and Modular Architecture for CSS 模塊化架構(gòu)的可擴(kuò)展的CSS)
<div class="toggle toggle-simple"><div class="toggle-control is-active"> <h2 class="toggle-title">標(biāo)題2</h2> </div> <div class="toggle-detail is-active"> 詳細(xì)內(nèi)容 </div> </div>上面的這段代碼基本展示了如何使用SMACSS方法,在我個(gè)人的理解中, OOCSS更多的其實(shí)是提供了一種CSS構(gòu)建思想, 該思想要求將結(jié)構(gòu)和外觀分離, 將容器和內(nèi)容分離. 但是并沒(méi)有提供一套完整的CSS構(gòu)建規(guī)范, 而SMACSS是提供了一套樣式系統(tǒng), 該樣式系統(tǒng)有5個(gè)具體類別:
- 基礎(chǔ): 如果不添加CSS類名, 標(biāo)記會(huì)以什么外觀呈現(xiàn)
- 布局: 把頁(yè)面分成一些區(qū)域
- 模塊: 設(shè)計(jì)中的模塊化, 可復(fù)用的單元
- 狀態(tài): 描述在特定的狀態(tài)或情況下, 模塊或布局的的顯示方法
- 主題: 一個(gè)可選的視覺(jué)外觀層, 可以讓你更換不同主題
基礎(chǔ)
//base.css body, form { margin: 0; padding: 0; } a { color: #039; } a:hover { color: #03F; }在基礎(chǔ)代碼中, 應(yīng)該規(guī)定的是頁(yè)面中的一些通用樣式,例如將body的margin和padding設(shè)置為0 , 設(shè)置a標(biāo)簽的顏色等. 類似于某些人常用的initial.css文件.
布局
//layout.css #header, #article, #footer { width: 960px; margin: auto; } #article { border: solid #CCC; border-width: 1px 0 0; }這里的布局指的是頁(yè)面中一些通用的布局組件, 例如頭部, 側(cè)邊欄, 主體和底部這些. 這些布局組件會(huì)在多個(gè)頁(yè)面通用, 所以最好把其放入到一個(gè)css文件中. 方便復(fù)用. 在SMACSS中, 推薦將布局容器的頂級(jí)標(biāo)簽設(shè)置為id, 這樣確保了每個(gè)頁(yè)面中擁有唯一持有該樣式的布局容器, 也方便其css和js選擇器的使用. 當(dāng)然, 你也可以使用一個(gè)唯一的類名替代id.
模塊
//module.css//module1 .module1 > h2 { padding: 5px; } .module1 span { padding: 5px; } //module2 .module2 > h2 { padding: 10px; } .module2 span { padding: 10px; }模塊是指頁(yè)面中可以單獨(dú)分離并提取出來(lái)復(fù)用的部分, 例如導(dǎo)航條, 側(cè)邊欄, 對(duì)話框或一些widget等. 所以, 模塊禁止使用id, 而應(yīng)該采用類名的方式.
狀態(tài)
<div id="header" class="is-collapsed"> <form> <div class="msg is-error"> There is an error! </div> <label for="searchbox" class="is-hidden">Search</label> <input type="search" id="searchbox"> </form> </div>State 負(fù)責(zé)定義元素不同的狀態(tài)下,所呈現(xiàn)的樣式. 上面的一段代碼中,已is-開(kāi)頭的就是表示狀態(tài)的類名,?is-collapsed,?is-error等類名不會(huì)單獨(dú)使用, 而是和前面的布局和模塊一起使用. 下面的代碼, 就是在tab欄模塊和狀態(tài)一起使用:
//state.css .tab {background-color: purple; color: white; } .is-tab-active { background-color: white; color: black; }主題
// module-name.css .mod {border: 1px solid; } //theme.css .mod { border-color: blue; }這里的主題理解為皮膚更加合適, 已上面的代碼為例, 在module-name.css中定義了邊框除顏色之外的樣式, 在theme.css文件中定義了該邊框的顏色, 這樣的好處就是, 如果定義其他顏色的類名去覆蓋這些有顏色的樣式, 那么就可以通過(guò)類名去切換皮膚的顏色. 達(dá)到更換主題的效果.
更多關(guān)于SMACSS的方法, 請(qǐng)參考:?https://smacss.com/book
3.BEM方法(Block Element Modifier 塊元素修飾符)
<div class="toggle toggle--simple"><div class="toggle__control toggle__control--active"> <h2 class="toggle__title">標(biāo)題3</h2> </div> <div class="toggle__details toggle__details--active"> ... </div> ... </div>BEM是由Yandex提出的給一個(gè)CSS命名方法, 該方法要求使用一個(gè)CSS類名, 盡可能使用以下三者組成:
- 塊名: 所屬組件的名稱
- 元素: 元素在塊里面的名稱
- 修飾符: 任何與塊或元素相關(guān)聯(lián)的的修飾符
塊名
這里的塊名很多初學(xué)者會(huì)以為是inline-block中的塊, 其實(shí)這里的塊名指的是一個(gè)獨(dú)立的模塊或組件. 例如一個(gè)<header>可以用做一個(gè)模塊,?<header>中的<nav>可以用作一個(gè)模塊. 模塊之間是可以相互嵌套的. 上面的示例代碼中 ,toggle就是一個(gè)獨(dú)立的模塊
元素
元素是指無(wú)法用在其他塊名中的部分, 在BEM方法中, 元素跟在塊名后面使用__連接, 之所以約定使用雙下劃線是因?yàn)榉奖阍趬K名中使用單下劃線命名. 上面示例代碼中的toggle__control,?toggle__title就是塊名+元素的命名方式.
修飾符
修飾符與SMACSS中的狀態(tài)類似, 在BEM方法中, 修飾符需要跟在元素后面使用--連接. 有的人會(huì)覺(jué)得這種寫法會(huì)使得代碼冗余, SMACSS使用is-active同樣可以表示同樣的作用, 為什么上面的代碼要使用toggle__details--active呢? 其實(shí), 如果單獨(dú)看open和is-active這兩個(gè)名字, 我們并不知道它們的含義是什么, 但是當(dāng)看到一個(gè)toggle__details--active的類名, 我們就知道它是表示: 這個(gè)元素的名稱是details, 位置在toggle組件里, 狀態(tài)為active.
(三) JavaScript
1.框架的選擇
這里我不想陷入Angular, React, Vue三大框架之爭(zhēng). 我是一個(gè)Vue的開(kāi)發(fā)者, 我深知MVVM框架給我們開(kāi)發(fā)者帶了極大的便利, 不用再以jQuery不停的操作DOM的形式去開(kāi)發(fā), 而是只關(guān)注數(shù)據(jù)的改變, 以數(shù)據(jù)去驅(qū)動(dòng)DOM的改變. 這能夠把更多的時(shí)間放入到業(yè)務(wù)邏輯的處理上.
就目前三大框架的生態(tài)系統(tǒng)來(lái)看, 大部分業(yè)務(wù)三大框架實(shí)現(xiàn)起來(lái)其實(shí)并沒(méi)有什么大的差別,框架的選擇更多的取決于項(xiàng)目中團(tuán)隊(duì)人員的偏好和學(xué)習(xí)成本. 比如Vue的學(xué)習(xí)成本就相比于Angular要小太多. 雖然我是一個(gè)Vue的開(kāi)發(fā)者, 但我不得不說(shuō)在React中使用JSX的語(yǔ)法讓寫代碼變得很愉快.
這里我還想說(shuō)的是:?其實(shí)你很可能不需要任何的框架!
有很多成功的網(wǎng)站只不過(guò)是采用了一些模板語(yǔ)法, 加上少量手動(dòng)創(chuàng)建的Sass文件和幾十個(gè)Javascript函數(shù)創(chuàng)建而成. 當(dāng)項(xiàng)目的規(guī)模足夠龐大, 需要犧牲代碼文件體積大小去換取框架所帶來(lái)的開(kāi)發(fā)效率的提高時(shí), 再考慮評(píng)估引入哪類JS框架和UI框架, 否則不要輕易放棄精簡(jiǎn)方案.
2.選擇一套JavaScript代碼規(guī)范
每個(gè)人寫代碼的方式是不同的, 有些人可能喜歡用==, 但有的喜歡用===; 有的人可能習(xí)慣給每個(gè)變量使用var去聲明, 但有的喜歡使用一個(gè)var加逗號(hào)運(yùn)算符去同時(shí)聲明多個(gè)變量. 這些代碼習(xí)慣可能并不會(huì)對(duì)程序運(yùn)行造成影響. 但是在大型業(yè)務(wù)中, 面臨多個(gè)開(kāi)發(fā)者共同開(kāi)發(fā)時(shí), 如果沒(méi)有一套代碼規(guī)范, 那么就會(huì)出現(xiàn)代碼難以維護(hù), 難以閱讀的情況. 為了讓新加入的團(tuán)隊(duì)成員也能夠快速熟悉相關(guān)的代碼, 并且讓代碼可以維護(hù), 一套Javascript代碼規(guī)范不論是開(kāi)發(fā)大型項(xiàng)目和小型項(xiàng)目, 都是必須的.
如果公司沒(méi)有代碼定制自己的代碼規(guī)范, 可以使用大公司所制定的代碼規(guī)范, 這里向大家推薦以下三個(gè)代碼規(guī)范:
-
Airbnb JavaScript Style Guide
Airbnb JavaScript Style Guide
Airbnb的Javascript號(hào)稱是"最合理的編寫JavaScript代碼的方式", 也是互聯(lián)網(wǎng)中最流行的JavaScript代碼規(guī)范, 它在Github上足有6萬(wàn)star, 幾乎覆蓋了JavaScript的每一項(xiàng)語(yǔ)言特性.?
-
Google JavaScript Style Guide
oogle JavaScript Style Guide
Google的JavaScript代碼規(guī)范相比于Airbnb代碼規(guī)范更加全面, 它不僅從代碼美感,性能角度和代碼特性對(duì)編寫Js代碼進(jìn)行了規(guī)范, 同時(shí)也對(duì)Js的命名, 導(dǎo)入方式, Js代碼文檔進(jìn)行了規(guī)范. 在Introduction中, Google團(tuán)隊(duì)表明, 在項(xiàng)目中全部使用了Google的Js規(guī)范, 才能被叫做Google Style的代碼!?
-
JavaScript Standard Style Guide
JavaScript Standard Style Guide
standard JS是一個(gè)功能強(qiáng)大的 JavaScript 代碼規(guī)范, 自帶 linter 和自動(dòng)代碼糾正, 無(wú)需配置, 自動(dòng)格式化代碼. 可以在編碼早期就發(fā)現(xiàn)代碼中的低級(jí)錯(cuò)誤. 這個(gè)代碼規(guī)范被很多知名公司所采用, 比如 NPM、GitHub、mongoDB 等.?
下面截取部分airbnb的ES5規(guī)范, 來(lái)對(duì)比一下使用了規(guī)范和未使用規(guī)范的區(qū)別:
數(shù)組
- 使用直接量創(chuàng)建數(shù)組
- 拷貝數(shù)組時(shí), 使用slice
- 使用slice將類數(shù)組對(duì)象轉(zhuǎn)換成數(shù)組
字符串
- 使用單引號(hào)''包裹字符串
- 程序化生成的字符串使用join連接而不是使用連接符。尤其是 IE 下
比較運(yùn)算符 & 等號(hào)
- 優(yōu)先使用?===和?!==而不是?==和?!=
- 使用快捷方式
空白
- 使用 2 個(gè)空格作為縮進(jìn)
- 大括號(hào)前放一個(gè)空格
- 使用空格把運(yùn)算符隔開(kāi)
?
總結(jié)
以上是生活随笔為你收集整理的前端架构设计1:代码核心的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 记一次,jvm 内存溢出
- 下一篇: (十三)java版spring clou