題外話
最近一月實(shí)習(xí)入職施流,體驗(yàn)了一把 994 的生活 (因?yàn)橹苋覍W(xué)校還有課,一周實(shí)習(xí)四天)鄙信,也算是馬老師口中的 “身在福中” 了瞪醋,雖然很是疲憊,但是確實(shí)收獲頗多装诡,公司里面很多很多大佬银受,于我眼界践盼、技術(shù)、想法都提升增益了很多宾巍,特別是技術(shù)咕幻,我一個(gè)一直在學(xué)習(xí) Vue 的菜虛鯤突然進(jìn)了 React 項(xiàng)目組,羊入狼群顶霞,不知所措肄程,不過(guò)還好的是有點(diǎn) Vue 的底子,所以學(xué)起來(lái)也不算太難...
項(xiàng)目概述
這個(gè)月也一直在負(fù)責(zé)搭建一個(gè)類似螞蟻金服的設(shè)計(jì)語(yǔ)言網(wǎng)站选浑,受益匪淺蓝厌,項(xiàng)目也差不多完成了,馬上上線了古徒,所以也花些時(shí)間理一理這個(gè)項(xiàng)目的技術(shù)實(shí)現(xiàn)褂始,因?yàn)槭枪卷?xiàng)目,為了保密(不失業(yè))描函,所以我這里不會(huì)貼任何源代碼,因?yàn)槲疫@個(gè)項(xiàng)目與螞蟻金服的 AntDesign 很是相似狐粱,所以我之后的介紹都以 AntDesign 為例
伏愿:不現(xiàn)魚之相舀寓,仍識(shí)漁之意,一道非漁之魚肌蜻,君其饗之互墓!
技術(shù)分析
先放一張 AntDesign 的官網(wǎng)截圖
開(kāi)始剖析:
其實(shí)整個(gè)站點(diǎn)結(jié)構(gòu)極其簡(jiǎn)單,我已經(jīng)都畫出來(lái)了:
- 頭部蒋搜,底部篡撵,側(cè)邊欄:這三部分結(jié)構(gòu)是內(nèi)容都是不變的,最多就是不同的選項(xiàng)卡被選中的時(shí)候顏色變一下
- 正文內(nèi)容豆挽,錨點(diǎn)定位欄育谬,前后頁(yè)跳轉(zhuǎn):這三部分隨著頁(yè)面的不同內(nèi)容也會(huì)不同,所以這部分需要做定制化處理
技術(shù)棧
如果是初入門的切圖仔帮哈,制作這個(gè)網(wǎng)站其實(shí)也是一點(diǎn)壓力都沒(méi)有的膛檀,估計(jì)壓力比較大就是樣式和自適應(yīng)的問(wèn)題,利用 HTML+CSS+一點(diǎn)點(diǎn)的 JS 只要寫好一份頁(yè)面娘侍,然后每一個(gè)頁(yè)面對(duì)應(yīng)一份 HTML 和 CSS咖刃,又因?yàn)檎麄€(gè)站點(diǎn)的頁(yè)面很相似,所以利用 CV 大法憾筏,可以很快地完成整個(gè)站點(diǎn)
所以目錄結(jié)構(gòu)可能就是:
三個(gè)文件夾:JS嚎杨、CSS、HTML氧腰,然后每個(gè)頁(yè)面一一對(duì)應(yīng)
如果是這種方式寫出來(lái)的代碼枫浙,代碼結(jié)構(gòu)臃腫刨肃,可維護(hù)性差,(而且顯得大公司就很沒(méi)有水準(zhǔn)……)
So自脯,就有利用這樣的方式:
- React:前端三大框架之一
- 數(shù)據(jù)驅(qū)動(dòng) DOM之景,將一些靜態(tài)的數(shù)據(jù)抽離出來(lái),避免臃腫重復(fù)的 DOM 結(jié)構(gòu)
- 組件化膏潮,使各個(gè)頁(yè)面相似的結(jié)構(gòu)抽離出來(lái)锻狗,形成一個(gè)組件
- Mustache:前端模板引擎
類似 FreeMarker 模版引擎,不過(guò)不同于 FreeMaker 依托于 Java 相得益彰焕参, Mustache 是根正苗紅的前端模板引擎轻纪,十分友好好上手,語(yǔ)法和應(yīng)用搭配 React 簡(jiǎn)直不要太爽
- Gulp+Sass:CSS 預(yù)處理器和自動(dòng)構(gòu)建工具
利用 Sass 再也不用寫面條一樣的臃腫丑陋的 CSS 了叠纷,其中的對(duì)于 CSS 變量刻帚,函數(shù),CSS 結(jié)構(gòu)的拓展優(yōu)化非常得好涩嚣,又因?yàn)闉g覽器只會(huì)識(shí)別 CSS 文件崇众,這時(shí)候需要 Gulp 自動(dòng)化構(gòu)建工具了,Gulp 不僅僅可以將 Sass 文件打包成 CSS 文件航厚,而且可以做到自動(dòng)化構(gòu)建顷歌,巴拉巴拉……具體可自行了解
- Eslint+Stylelint:代碼規(guī)范
當(dāng)進(jìn)行大型項(xiàng)目開(kāi)發(fā)的時(shí)候,項(xiàng)目組不止一個(gè)人在開(kāi)發(fā)幔睬,而且項(xiàng)目在版本迭代的時(shí)候需要維護(hù)眯漩,這時(shí)候代碼規(guī)范就極其重要了
技術(shù)實(shí)現(xiàn)
以上介紹了大概介紹了技術(shù)棧,那么接下來(lái)就是怎么實(shí)現(xiàn)螞蟻金服的 AntDesign 的技術(shù)實(shí)現(xiàn)了麻顶!So赦抖,讓我們一層層揭下AntDesign 的 衣服 面紗吧!
組件化
在前文中我就提到:
React 的好處之一:將各個(gè)頁(yè)面相似的結(jié)構(gòu)抽離出來(lái)辅肾,形成一個(gè)組件
AntDesign 站點(diǎn)網(wǎng)頁(yè)的頭部队萤,底部,側(cè)邊欄矫钓,錨點(diǎn)定位欄浮禾,前后頁(yè)跳轉(zhuǎn)都是結(jié)構(gòu)相同的部分,所以這些都可以抽離出來(lái)份汗,放置在一個(gè) Components
文件夾中盈电,單獨(dú)成一個(gè)組件,文件目錄類似這樣:
Components
|—— Header.js
|—— NavBar.js
|—— PageNav.js
|—— PageTurn.js
└── Footer.js
- 頭部和尾部
頭部和尾部結(jié)構(gòu)并不復(fù)雜杯活,而且多是靜態(tài)的固定的數(shù)據(jù)匆帚,所以可以直接寫,然后引入各個(gè)頁(yè)面中
- 側(cè)邊欄
側(cè)邊欄可以直接寫樣式旁钧,通過(guò)重復(fù)的 DOM 結(jié)構(gòu)堆砌而成
但是可以利用 React 的好處之二:數(shù)據(jù)驅(qū)動(dòng) DOM吸重,將一些靜態(tài)的數(shù)據(jù)抽離出來(lái)互拾,避免臃腫重復(fù)的 DOM 結(jié)構(gòu)
1.將側(cè)邊導(dǎo)航欄的內(nèi)容數(shù)據(jù)抽成一個(gè)數(shù)組,獨(dú)立在在一個(gè)獨(dú)立的NavData.js
文件中然后export
出去
2.在NavBar.js
中引入NavData.js
嚎幸,通過(guò)Array.map()
方法將數(shù)組依次遍歷然后生成重復(fù)的相同DOM
Example:
export const allMenus = [
{
text: 'Ant Design',
type: 'design',
menus: [
{ text: '介紹', type: 'design1', url: '/design/introduce.html' },
{ text: '設(shè)計(jì)價(jià)值觀', type: 'design2', url: '/design/design-values.html' },
{ text: '實(shí)踐案例', type: 'design3', url: '/design/practice-case.html' },
],
},
{
text: '原則',
type: 'principle',
menus: [
...//省略原則的子選項(xiàng)
],
},
...//省略后續(xù)的菜單選項(xiàng)
];
可以將菜單欄的菜單如此抽出構(gòu)成一個(gè)數(shù)組颜矿,然后將數(shù)組 allMenus
遍歷生成 DOM
- 前后頁(yè)跳轉(zhuǎn)
前后頁(yè)跳轉(zhuǎn)中的內(nèi)容就是左側(cè)菜單欄中的子選項(xiàng),只要獲取當(dāng)前的頁(yè)面的前一項(xiàng)和后一項(xiàng)的菜單欄子選項(xiàng)就可以了嫉晶,所以也可以同樣利用剛剛抽離出來(lái)的數(shù)組allMenus
正文內(nèi)容渲染
正文內(nèi)容每頁(yè)都不一樣骑疆,所以是無(wú)法抽離成組件的,所以這個(gè)需要單獨(dú)寫替废,但是每一個(gè) HTML 文件除<body></body>
標(biāo)簽其中的內(nèi)容不一樣箍铭,其他都可以復(fù)用,所以這時(shí)候 Mustache 就派上用場(chǎng)了:
- 每個(gè)頁(yè)面單獨(dú)寫一個(gè) JS 文件椎镣,寫成一個(gè) React 類诈火,然后就等于寫 HTML一樣在類
render()
中寫頁(yè)面內(nèi)容 DOM - 將頁(yè)面的頭部菜單類別、主菜單類別状答、子菜單類別冷守、錨點(diǎn)內(nèi)容作為類的屬性一起
export
出去,這樣就能在寫錨點(diǎn)定位欄組件和頁(yè)面跳轉(zhuǎn)組件的時(shí)候使用props
接收數(shù)據(jù) - 創(chuàng)建一個(gè)單獨(dú)的 js 文件惊科,來(lái)管理這么多頁(yè)面
export
出來(lái)的數(shù)據(jù)內(nèi)容教沾,即類似上文的將導(dǎo)航欄抽成一個(gè)數(shù)組一樣,同理译断,將所有的頁(yè)面也抽成一個(gè)數(shù)組,之后就可以再使用Array.map()
方法或悲,配合 Mustache 一一將 React 渲染成 html 文件
Example:
我用 AntDesign 菜單欄的第一項(xiàng) 'Ant Design' 的 '介紹' 頁(yè)面為例:
每個(gè)頁(yè)面有自己的頭部菜單類別(headType)孙咪、主菜單類別(firstType)、子菜單類別(subType)巡语、錨點(diǎn)內(nèi)容(affixList)翎蹈,那么我們就可以直接在頁(yè)面中定制化然后暴露出去:
import React, { Component } from 'react';
export default class Introduce extends Component {
render() {
return (
<div className="content">
{/* '介紹' 頁(yè)面的 DOM 結(jié)構(gòu)*/}
</div>
);
}
}
Introduce.headType = 'design';
Introduce.firstType = 'design';
Introduce.subType = 'design1';
Introduce.affixList = [
'設(shè)計(jì)資源',
'前端實(shí)現(xiàn)',
'誰(shuí)在使用',
'社區(qū)評(píng)價(jià)',
'如何貢獻(xiàn)',
];
以此類推,創(chuàng)建這么一個(gè)數(shù)組男公,來(lái)管理這么多的頁(yè)面數(shù)據(jù):
import Introduce from '../src/pages/design/Introduce';
import DesignValues from '../src/pages/design/DesignValues';
import PracticeCase from '../src/pages/design/PracticeCase';
...//將每個(gè)頁(yè)面 export 的都引進(jìn)來(lái)
export const allPages = [
{
mainCpn: Introduce,
title: '介紹',
name: 'design/introduce.html',
},
{
mainCpn: DesignValues,
title: '設(shè)計(jì)價(jià)值觀',
name: 'design/design-values.html',
},
{
mainCpn: BarrierFree,
title: '實(shí)踐案例',
name: 'design/practice-case.html',
},
...//省略其他頁(yè)面
];
- 寫一份
base.html
作為渲染的基礎(chǔ)模版荤堪,在<body></body>
中定義一個(gè)變量,作為 Mustache 內(nèi)容填充的插槽:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>{{title}}</title>
<link rel="stylesheet" href="/css/base.css?v={{version}}" />
</head>
<body>
<div id="app">{{{ssrHtml}}}</div>
</body>
<script src="https://cdn.bootcss.com/jquery/3.4.0/jquery.min.js"></script>
<script type="text/javascript" src="/js/base.js?v={{version}}"></script>
</html>
- 利用
fs
這個(gè) node 模塊讀取base.html
的內(nèi)容枢赔,然后作為Mustache.render()
方法的渲染對(duì)象參數(shù)澄阳,再將之前構(gòu)建好的頁(yè)面數(shù)組賦值給base.html
定義好的變量 ssrHtml ,再一一遍歷作為被渲染對(duì)象踏拜,然后再使用fs
寫出各個(gè) HTML 文件
如此這般碎赢,最后便生成了整個(gè)項(xiàng)目的目錄文件
哦,對(duì)了速梗,為什么會(huì)引入了 Jquery肮塞?
因?yàn)檫@個(gè)項(xiàng)目有自適應(yīng)襟齿,所以會(huì)有動(dòng)畫和操作 DOM ,而且 React 只是單純地直接渲染 DOM 枕赵,沒(méi)有操作數(shù)據(jù)來(lái)驅(qū)動(dòng) DOM 猜欺,所以沒(méi)有和 Jq 沖突,所以可以放心地使用 Jq (其實(shí)用到 Jq 的地方也不多拷窜,就一些滾動(dòng)監(jiān)聽(tīng)之類的幾個(gè)方法)
The End
其實(shí)有很多細(xì)節(jié)的开皿,但是很多細(xì)節(jié)一聊就暴露我這個(gè)公司項(xiàng)目的源碼啊什么的了,而且由于時(shí)間實(shí)力原因装黑,可能很多問(wèn)題講不清晰副瀑,歡迎留言私信!定當(dāng)改進(jìn)加勉恋谭!