構建多頁面應用——hash

這裏的hash主要從兩個方面來講。一個是webpack生成的hash,另外一個是頁面連接中的hash,如:http://localhost:8080/ywbk.html#restaurant中的#restaurant。後者在單頁面應用的路由處理中常常用到。css

webpack中的hash

webapck每次構建都會生成一個新的hash(主要用於生產環境)。html

它的做用就是用來標記構建生成的狀態,一般使用的過程當中,會將它注入到構建輸出(生成)的文件名中。vue

webpack.config.js文件中的位置以下:react

...
output: {
  path: path.resolve(__dirname, 'dist/'),
  filename: isDev ? 'assets/js/[name].js' : 'assets/js/[name].[contenthash].js',
  publicPath: isDev ? config.devUrl : config.deployUrl
},
module: {
  rules: [
    ...
    {
      include: path.resolve(__dirname, 'assets/imgs/other/'),
      test: /\.(png|jpe?g|gif)$/,
      use: [
        {
          loader: 'file-loader',
          options: {
            name: isDev ? '[name].[ext]' : '[name].[hash].[ext]',
            outputPath: 'assets/imgs/'
          }
        }
      ]
    }
    ...
  ]
}
...
plugins: plugins.concat([
  new MiniCssExtractPlugin({
    filename: isDev ? 'assets/css/[name].css' : 'assets/css/[name].[contenthash].css',
    chunkFilename: isDev ? 'assets/css/[id].css' : 'assets/css/[id].[contenthash].css'
  })
  ...
])

若是項目是第一次構建,那麼全部的靜態資源都會被添加同一個hash,當第二構建若是有內容改變,構建生成的文件會被賦予新的hash。爲了提升見構建的速度,減小構建生成沒必要要的文件(若是第一次生成的文件和第二次生成的文件內容相同,那麼不必從新在生成一次)。爲此webpack提供了三個hash字段可供選擇,分別是hash、chunkhash、contenthash。webpack

  • hash:無論內容改變與否,全部的文件都會被從新生成一遍。這是一種粗放的模式。
  • chunkhash:它主要針對與webpack配置文件的entry中定義的入口文件。
  • contenthash: 它主要針對的是webpack構建的過程當中,提取(或者說分離)出來的內容,如:extract-text-webpack-plugin

針對多頁面應用的構建特色,使用contenthash是一個不錯的選擇,本文中所使用的示例wepbakck4.x-multi-page符合這個特色。css的分離,js文件的分離(webpack4的SplitChunk)。git

爲何要在多頁面應用中使用單頁面應用的hash來實現路由的控制

演示效果github

很明顯的一點是傳統的多頁面應用的業務模塊每每會出現多個頁面之間會有不少相同內容,這樣在單擊導航實現路由切換的時候,老是會看到相同的內容,這樣會給用戶形成一種錯覺‘爲何老是同一個頁面’。這樣的用戶體驗每每很差。最突出的就是包含二級導航的頁面。(可參考聖捷集團的官網web

單頁面應用給咱們了一個很好的啓示,能夠經過將這些頁面結構類似的,而只有一部份內容類同的頁面組合成爲一個頁面。vue-router

這樣作的好處顯而易見,減小多頁面構建生成的頁面數量,咱們之構建生成一級和二級頁面,以及一些頁面結構不多雷同的頁面,而不構建生成三級頁面。api

優化後的示例地址

具體的實現有兩種解決方案。

第一種,在每一個頁面中使用一個vue(結合vue-router)的示例(也可使用,react,angular)。

第二種,本身實現對不一樣hash的處理。

注:若是使用hash,在開發的時候必定要模擬一個服務器環境,直接用瀏覽器打開是沒法實現的,瀏覽器控制檯會提示跨域的錯誤。

本文所使用的示例用的是第二種方案。

具體的實現過程以下:

在生成子導航的模擬數據中添加了一個type值,

tabs: [
  {
    cn_name: '聖捷投資',
    en_name: 'SHENGJIE INVESTMENT',
    type: 'investment'
  }, {
    cn_name: '董事長致辭',
    en_name: 'CHAIRMANS SPEECH',
    type: 'speech'
  }
  ...
]

這樣使用pug-loader處理生成的html對應的元素中會包含一個data-type自定義屬性。參考代碼以下:

<div class="tabs">
  <div class="tab-item active" data-type="finance">
    <div>互聯網金融</div>
    <div>ONLINE FINANCE</div>
  </div>
  <div class="tab-item" data-type="allfinance">
    <div>全品類金融</div>
    <div>WHOLE CATEGORY FINANCE</div>
  </div>
  ...
</div>

而後,使用JavaScript經過控制觸發條件,如url的hash改變,進而控制頁面的展現效果。參考代碼以下:

···
$('.tab-item').on('click', function() {
  var type = $(this).data('type')
  window.location.hash = type
  tab(this, type)
})
···

首先,單點擊二級導航時,改變url的hash。這樣作可讓用戶經過操做瀏覽器的前進和後退按鈕來控制頁面,此外使用瀏覽器的前進和後退按鈕的好處是,瀏覽能夠記錄頁面的狀態。(只用上面的代碼沒法實現想要的效果)

其次,使用hashchange這個瀏覽器自帶的監聽hash改變的api(他兼容>=ie8的瀏覽器,因此能夠放心使用)。

···
$(window).on('hashchange', function() {
  tabcheck()
})
···

經過它們,就能夠輕鬆的實現url的hash

爲了頁面呈現更好的效果,能夠給頁面添加一個滾動的動畫,若是不使用hash在傳統的頁面中實現有些棘手。

那麼針對頁面底部的網站導航,如何結合hash來操做頁面並實現一致的路由切換效果呢?

這裏須要監聽頁面的load狀態,在webpack中,使用commonjs來組織js代碼塊,須要注意window.load(...)無效的狀況。

具體的實現就不一一介紹了,可參考demo中tabs.js文件的代碼

源代碼

webpack4.x multi-page

構建多頁面應用系列文章

相關文章
相關標籤/搜索