非漁之魚,君其饗之:使用 React+Mustache 搭建一個相似螞蟻金服的 AntDesign 設計語言站點

題外話

最近一月實習入職,體驗了一把 994 的生活 (由於週三我學校還有課,一週實習四天),也算是馬老師口中的 「身在福中」 了,雖然非常疲憊,可是確實收穫頗多,公司裏面不少不少大佬,於我眼界、技術、想法都提高增益了不少,特別是技術,我一個一直在學習 Vue 的菜虛鯤忽然進了 React 項目組,羊入狼羣,不知所措,不過還好的是有點 Vue 的底子,因此學起來也不算太難...javascript

項目概述

這個月也一直在負責搭建一個相似螞蟻金服的設計語言網站,受益不淺,項目也差很少完成了,立刻上線了,因此也花些時間理一理這個項目的技術實現,由於是公司項目,爲了保密(不失業),因此我這裏不會貼任何源代碼,由於我這個項目與螞蟻金服的 AntDesign 非常類似,因此我以後的介紹都以 AntDesign 爲例 伏願:不現魚之相,仍識漁之意,一道非漁之魚,君其饗之!css

技術分析

先放一張 AntDesign 的官網截圖html

開始剖析:前端

其實整個站點結構極其簡單,我已經都畫出來了:java

  • 頭部,底部,側邊欄:這三部分結構是內容都是不變的,最多就是不一樣的選項卡被選中的時候顏色變一下
  • 正文內容,錨點定位欄,先後頁跳轉:這三部分隨着頁面的不一樣內容也會不一樣,因此這部分須要作定製化處理 ##技術棧 若是是初入門的切圖仔,製做這個網站其實也是一點壓力都沒有的,估計壓力比較大就是樣式和自適應的問題,利用 HTML+CSS+一點點的 JS 只要寫好一份頁面,而後每個頁面對應一份 HTML 和 CSS,又由於整個站點的頁面很類似,因此利用 CV 大法,能夠很快地完成整個站點 因此目錄結構可能就是: 三個文件夾:JS、CSS、HTML,而後每一個頁面一一對應 若是是這種方式寫出來的代碼,代碼結構臃腫,可維護性差,(並且顯得大公司就很沒有水準……) So,就有利用這樣的方式:
  • React:前端三大框架之一
  1. 數據驅動 DOM,將一些靜態的數據抽離出來,避免臃腫重複的 DOM 結構
  2. 組件化,使各個頁面類似的結構抽離出來,造成一個組件
  • Mustache:前端模板引擎

相似 FreeMarker 模版引擎,不過不一樣於 FreeMaker 依託於 Java 相得益彰, Mustache 是根正苗紅的前端模板引擎,十分友好好上手,語法和應用搭配 React 簡直不要太爽node

  • Gulp+Sass:CSS 預處理器和自動構建工具

利用 Sass 不再用寫麪條同樣的臃腫醜陋的 CSS 了,其中的對於 CSS 變量,函數,CSS 結構的拓展優化很是得好,又由於瀏覽器只會識別 CSS 文件,這時候須要 Gulp 自動化構建工具了,Gulp 不只僅能夠將 Sass 文件打包成 CSS 文件,並且能夠作到自動化構建,巴拉巴拉……具體可自行了解react

  • Eslint+Stylelint:代碼規範

當進行大型項目開發的時候,項目組不止一我的在開發,並且項目在版本迭代的時候須要維護,這時候代碼規範就極其重要了 ##技術實現 以上介紹了大概介紹了技術棧,那麼接下來就是怎麼實現螞蟻金服的 AntDesign 的技術實現了!So,讓咱們一層層揭下AntDesign 的 衣服 面紗吧! #####組件化 在前文中我就提到: React 的好處之一:將各個頁面類似的結構抽離出來,造成一個組件 AntDesign 站點網頁的頭部,底部,側邊欄,錨點定位欄,先後頁跳轉都是結構相同的部分,因此這些均可以抽離出來,放置在一個 Components文件夾中,單獨成一個組件,文件目錄相似這樣:jquery

Components
 |—— Header.js
 |—— NavBar.js
 |—— PageNav.js
 |—— PageTurn.js
 └── Footer.js
複製代碼
  • 頭部和尾部

頭部和尾部結構並不複雜,並且可能是靜態的固定的數據,因此能夠直接寫,而後引入各個頁面中數組

  • 側邊欄

側邊欄能夠直接寫樣式,經過重複的 DOM 結構堆砌而成 可是能夠利用 React 的好處之二:數據驅動 DOM,將一些靜態的數據抽離出來,避免臃腫重複的 DOM 結構 1.將側邊導航欄的內容數據抽成一個數組,獨立在在一個獨立的NavData.js文件中而後export出去 2.在NavBar.js中引入NavData.js,經過Array.map()方法將數組依次遍歷而後生成重複的相同DOM瀏覽器

Example:

export const allMenus = [
    {
      text: 'Ant Design',
      type: 'design',
      menus: [
        { text: '介紹', type: 'design1', url: '/design/introduce.html' },
        { text: '設計價值觀', type: 'design2', url: '/design/design-values.html' },
        { text: '實踐案例', type: 'design3', url: '/design/practice-case.html' },
      ],
    },
    {
      text: '原則',
      type: 'principle',
      menus: [
        ...//省略原則的子選項
      ],
    },
    ...//省略後續的菜單選項
  ];
複製代碼

能夠將菜單欄的菜單如此抽出構成一個數組,而後將數組 allMenus 遍歷生成 DOM

  • 先後頁跳轉 先後頁跳轉中的內容就是左側菜單欄中的子選項,只要獲取當前的頁面的前一項和後一項的菜單欄子選項就能夠了,因此也能夠一樣利用剛剛抽離出來的數組 allMenus #####正文內容渲染 正文內容每頁都不同,因此是沒法抽離成組件的,因此這個須要單獨寫,可是每個 HTML 文件除<body></body>標籤其中的內容不同,其餘均可以複用,因此這時候 Mustache 就派上用場了:
  1. 每一個頁面單獨寫一個 JS 文件,寫成一個 React 類,而後就等於寫 HTML同樣在類render()中寫頁面內容 DOM
  2. 將頁面的頭部菜單類別、主菜單類別、子菜單類別、錨點內容做爲類的屬性一塊兒export出去,這樣就能在寫錨點定位欄組件和頁面跳轉組件的時候使用props接收數據
  3. 建立一個單獨的 js 文件,來管理這麼多頁面export出來的數據內容,即相似上文的將導航欄抽成一個數組同樣,同理,將全部的頁面也抽成一個數組,以後就能夠再使用Array.map()方法,配合 Mustache 一一將 React 渲染成 html 文件 Example: 我用 AntDesign 菜單欄的第一項 'Ant Design' 的 '介紹' 頁面爲例:

每一個頁面有本身的頭部菜單類別(headType)、主菜單類別(firstType)、子菜單類別(subType)、錨點內容(affixList),那麼咱們就能夠直接在頁面中定製化而後暴露出去:

import React, { Component } from 'react';

export default class Introduce extends Component {
  render() {
    return (
      <div className="content">
        {/* '介紹' 頁面的 DOM 結構*/}
       </div>
    );
  }
}

Introduce.headType = 'design';
Introduce.firstType = 'design';
Introduce.subType = 'design1';
Introduce.affixList = [
  '設計資源',
  '前端實現',
  '誰在使用',
  '社區評價',
  '如何貢獻',
];
複製代碼

以此類推,建立這麼一個數組,來管理這麼多的頁面數據:

import Introduce from '../src/pages/design/Introduce';
import DesignValues from '../src/pages/design/DesignValues';
import PracticeCase from '../src/pages/design/PracticeCase';
...//將每一個頁面 export 的都引進來

export const allPages = [
  {
    mainCpn: Introduce,
    title: '介紹',
    name: 'design/introduce.html',
  },
  {
    mainCpn: DesignValues,
    title: '設計價值觀',
    name: 'design/design-values.html',
  },
  {
    mainCpn: BarrierFree,
    title: '實踐案例',
    name: 'design/practice-case.html',
  },
...//省略其餘頁面
];
複製代碼
  1. 寫一份base.html做爲渲染的基礎模版,在<body></body>中定義一個變量,做爲 Mustache 內容填充的插槽:
<!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>
複製代碼
  1. 利用fs這個 node 模塊讀取base.html的內容,而後做爲 Mustache.render()方法的渲染對象參數,再將以前構建好的頁面數組賦值給 base.html定義好的變量 ssrHtml ,再一一遍歷做爲被渲染對象,而後再使用fs寫出各個 HTML 文件

如此這般,最後便生成了整個項目的目錄文件 哦,對了,爲何會引入了 Jquery? 由於這個項目有自適應,因此會有動畫和操做 DOM ,並且 React 只是單純地直接渲染 DOM ,沒有操做數據來驅動 DOM ,因此沒有和 Jq 衝突,因此能夠放心地使用 Jq (其實用到 Jq 的地方也很少,就一些滾動監聽之類的幾個方法)

The End

其實有不少細節的,可是不少細節一聊就暴露我這個公司項目的源碼啊什麼的了,並且因爲時間實力緣由,可能不少問題講不清晰,歡迎留言私信!定當改進加勉!

相關文章
相關標籤/搜索