共计 2887 个字符,预计需要花费 8 分钟才能阅读完成。
这里的 hash 主要从两个方面来说。一个是 webpack 生成的 hash,另一个是页面链接中的 hash,如:http://localhost:8080/ywbk.html#restaurant 中的 #restaurant。后者在单页面应用的路由处理中经常用到。
webpack 中的 hash
webapck 每次构建都会生成一个新的 hash(主要用于生产环境)。
它的作用就是用来标记构建生成的状态,通常使用的过程中,会将它注入到构建输出(生成)的文件名中。
在 webpack.config.js 文件中的位置如下:
…
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。
hash:不管内容改变与否,所有的文件都会被重新生成一遍。这是一种粗放的模式。
chunkhash:它主要针对与 webpack 配置文件的 entry 中定义的入口文件。
contenthash: 它主要针对的是 webpack 构建的过程中,提取 (或者说分离) 出来的内容,如:extract-text-webpack-plugin
针对多页面应用的构建特点,使用 contenthash 是一个不错的选择,本文中所使用的示例 wepbakck4.x-multi-page 符合这个特点。css 的分离,js 文件的分离(webpack4 的 SplitChunk)。
为什么要在多页面应用中使用单页面应用的 hash 来实现路由的控制
演示效果
很明显的一点是传统的多页面应用的业务模块往往会出现多个页面之间会有很多相同内容,这样在单击导航实现路由切换的时候,总是会看到相同的内容,这样会给用户造成一种错觉‘为什么总是同一个页面’。这样的用户体验往往不好。最突出的就是包含二级导航的页面。(可参考圣捷集团的官网)
单页面应用给我们了一个很好的启示,可以通过将这些页面结构相似的,而只有一部分内容类同的页面组合成为一个页面。
这样做的好处显而易见,减少多页面构建生成的页面数量,我们之构建生成一级和二级页面,以及一些页面结构很少雷同的页面,而不构建生成三级页面。
优化后的示例地址
具体的实现有两种解决方案。
第一种,在每个页面中使用一个 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
构建多页面应用系列文章
构建多页面应用
构建多页面应用——单个页面的处理
构建多页面应用——模板
构建多页面应用——静态资源
构建多页面应用——优化(一)