Webpack生成企业站静态页面 - 增强数据处理能力
一些项目因需求不同,如需SEO或小项目,使用angular、react或vue就大材小用了。我们可以通过webpack、gulp这些构建工具,也能快速完成html页面开发,并且也能使用less/sass/styus等样式预编译功能,以及将js、html分模块、分组件进行开发。
此篇在之前两篇基础上,增强数据处理功能力,让开发更为便捷、更为灵活。如果有朋友不了解此篇讲的是什么内容,可以去看下前面写的。
项目环境搭建 地址:Webpack生成企业站静态页面 - 项目搭建-CSDN博客
组件化 地址:Webpack生成企业站静态页面 - 组件化-CSDN博客
这里还是以首页为例,数据数据直在存放在index.html中,也能通过art-template完成数据渲染。
一、优化json数据
首先将html.data.json文件进行优化,在后期开发过程中,随着页面不断增长,json文件中数据不断增加,越积越多。久而久之,也会影响后期维护速度,所以html.data.json只存储所页面公用的数据或变量,例如头部(head标签)中内容,导航和页尾等公共数据。
html.data.json代码如下:
{"navigation": [{"name": "首页", "enName": "HOME", "path": "index.html"},{"name": "新闻动态", "enName": "NEWS", "path": "list.html"},{"name": "旅游项目", "enName": "PROJEC", "path": "javascript:;"},{"name": "服务项目", "enName": "SERVICES", "path": "javascript:;"},{"name": "公司产业", "enName": "ENTERTAINMENT", "path": "javascript:;"},{"name": "农副产品", "enName": "BY-PRODUCT", "path": "javascript:;"},{"name": "种植养殖", "enName": "GRANCHIO", "path": "javascript:;"},{"name": "联系我们", "enName": "CONTACT US", "path": "contact.html"}],"navIndexName": "首页","keywords": "新闻 旅游 服务 农产品 种植 养殖","description": "这是关于望玉岛度假村相关描述内容"
}
此时html.data.json文件中,只保留了公共部分用到的数据,首页内容将全部存放在index.html。
index.html文件中代码如下:
<!-- 修改当前页面对应标题 -->
{{$data.navIndexName = "首页"}}{{extend './template/layout.html'}}<datalist>
{"title": "首页","firstList": [
{"title": "望玉岛标题", "description": " 望玉岛度假村一日游活动方案:活动主题,放飞心情,走进自然,活动地;望玉岛度假村,行程特点;领略望玉岛... ","thumb": "images/index_09.jpg","url": "javascript:;"
},
{"title": "望玉岛标题", "description": " 望玉岛度假村一日游活动方案:活动主题,放飞心情,走进自然,活动地;望玉岛度假村,行程特点;领略望玉岛... ","thumb": "images/index_10.jpg","url": "javascript:;"
},
{"title": "望玉岛标题", "description": " 望玉岛度假村一日游活动方案:活动主题,放飞心情,走进自然,活动地;望玉岛度假村,行程特点;领略望玉岛... ","thumb": "images/index_11.jpg","url": "javascript:;"
}],"bottomList": [{"title": "新春有礼——望玉岛别墅标间推出亲民价,餐饮","datetime": "2014-10-2","url": "javascript:;"},{"title": "新春有礼——望玉岛别墅标间推出亲民价,餐饮","datetime": "2014-10-2","url": "javascript:;"},{"title": "新春有礼——望玉岛别墅标间推出亲民价,餐饮","datetime": "2014-10-2","url": "javascript:;"},{"title": "新春有礼——望玉岛别墅标间推出亲民价,餐饮","datetime": "2014-10-2","url": "javascript:;"}],"inviteList": [{"title": "2015-03-17诚招","datetime": "2014-10-2","url": "javascript:;"},{"title": "2014-03-12招聘","datetime": "2014-03-12","url": "javascript:;"},{"title": "2013-03-30诚招学生暑期工","datetime": "2014-10-2","url": "javascript:;"}]
}
</datalist>{{block 'content'}}
<!-- mainer_wrapper -->
<div id="mainer_wrapper"><!-- main --><div class="main-container"><div class="clear"></div><!-- 广告 START --><div class="box_gg"><a href="#" target="_blank"><img src="images/index_08.jpg" alt="banner" /></a></div><!-- 广告 END --><!-- box_content 最新活动 START --><div class="box_content wd490 fl"><div class="title"><a href="#" class="more">MORE >></a>最新活动</div><div class="content">{{each firstList as item}}<dl class="b_list"><dt><a href="#" target="_blank"><img src="{{item.thumb}}" alt="09" /></a></dt><dd><h2><a href="{{item.url}}" target="_blank">{{item.title}}</a></h2><span>{{item.description}}<a href="{{item.url}}" target="_blank">[详细情况]</a></span></dd></dl>{{/each}}<div class="clear"></div></div></div><!-- /box_content 最新活动 END --><!-- box_content 旅游项目 START --><div class="box_content wd490 fl mg_l15"><div class="title"><a href="#" class="more">MORE >></a>旅游项目</div><div class="content">{{each firstList as item}}<dl class="b_list"><dt><a href="#" target="_blank"><img src="{{item.thumb}}" alt="09" /></a></dt><dd><h2><a href="{{item.url}}" target="_blank">{{item.title}}</a></h2><span>{{item.description}}<a href="{{item.url}}" target="_blank">[详细情况]</a></span></dd></dl>{{/each}}<div class="clear"></div></div></div><!-- /box_content 旅游项目 END --><!-- box_content 旅游咨询 START --><div class="box_content fl" style="width:360px;"><div class="title"><a href="#" class="more">MORE >></a>旅游咨询</div><div class="content"><ul class="box_list">{{each bottomList as item}}<li><span>{{item.datetime}}</span><a href="{{item.url}}" target="_blank">{{item.title}}</a></li>{{/each}}</ul></div></div><!-- /box_content 旅游咨询 END --><!-- box_content 贵宾服务 START --><div class="box_content fl mg_l15" style="width:360px;"><div class="title"><a href="#" class="more">MORE >></a>贵宾服务</div><div class="content"><ul class="box_list">{{each bottomList as item}}<li><span>{{item.datetime}}</span><a href="{{item.url}}" target="_blank">{{item.title}}</a></li>{{/each}}</ul></div></div><!-- /box_content 贵宾服务 END --><!-- box_content 招聘信息 START --><div class="box_content fl mg_l15" style="width:240px;"><div class="title"><a href="#" class="more">MORE >></a>招聘信息</div><div class="content"><ul class="box_list">{{each inviteList as item}}<li><span>{{item.datetime}}</span><a href="{{item.url}}" target="_blank">{{item.title}}</a></li>{{/each}}</ul></div></div><!-- /box_content 招聘信息 END --><div class="clear"></div></div><!-- /main -->
</div>
<!-- /mainer_wrapper -->
{{/block}}
注意的是,此时index.html渲染title部分被删除,原因是数据都独立在各自的html中,html-loader加载内容时,合并到htmlData中的数据是唯一的,此时直接在layout.html调用title即可。
index.html中删除这行代码:
{{block 'title'}}{{indexData.title}}{{/block}}
修改layout.html,将”{{block 'title'}}{{/block}}“修改为”{{title}}“,代码如下:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><!-- 渲染头部资源 -->{{block 'head'}}{{/block}}<!-- 渲染当前页面标题 --><title>望玉岛 - {{title}}</title>
</head>
<body><!-- 引入导航HTML部分 -->{{include './header.html'}}<!-- 渲染内容部分 -->{{block 'content'}}{{/block}}<!-- 引入底部HTML部分 -->{{include './footer.html'}}
</body>
</html>
当然,以上内容修改完后,现在页面还不能按预期效果渲染出来,并且现在运行npx webpck serve还会出错,因为现在渲染数据集顶级key中还不存在title,并且art-template也不识别<datalist>标签。
二、set功能
art-template也提供了set设置变量的功能,由于html.data.json中首页数据全部清除,现在渲染的首页中间部分都为空,如下图:
我们通过set在index.html添加最后项数据,代码如下:
<!-- 修改当前页面对应标题 -->
{{$data.navIndexName = "首页"}}{{extend './template/layout.html'}}<!-- 略... -->{{set inviteList = [{"title": "2015-03-17诚招","datetime": "2014-10-2","url": "javascript:;"},{"title": "2014-03-12招聘","datetime": "2014-03-12","url": "javascript:;"},{"title": "2013-03-30诚招学生暑期工","datetime": "2014-10-2","url": "javascript:;"}
]}}{{block 'content'}}
<!-- mainer_wrapper -->
<div id="mainer_wrapper"><!-- main --><div class="main-container"><div class="clear"></div><!-- 略... --><!-- box_content 招聘信息 START --><div class="box_content fl mg_l15" style="width:240px;"><div class="title"><a href="#" class="more">MORE >></a>招聘信息</div><div class="content"><ul class="box_list">{{each inviteList as item}}<li><span>{{item.datetime}}</span><a href="{{item.url}}" target="_blank">{{item.title}}</a></li>{{/each}}</ul></div></div><!-- /box_content 招聘信息 END --><div class="clear"></div></div><!-- /main -->
</div>
<!-- /mainer_wrapper -->
{{/block}}
此时首页右下角内容则显示出来了,结果如下图:
但是set设置变量有作用域限制,当前页面设置变量只能本区域使用,而且extend好像没有传递变量功能,所以数据在共享方面还有所欠缺,要再考虑其他方式来增强数据处理能。
当然,如果set功能已能满足您的需求,后面内容可以忽略了。
三、webpack配置修改
为了改善set的不足之处,这里考虑还是将数据存放在html页面。如何自定义内容让art-template识别呢?在实现art-template模板渲染时候,就是在html-loader中preprocessor()回调函数中实现的。同理,在art-template渲染前,将自定义数据识别出来即可。
另外,把每个页面独有的数据,放在html页面中或者在循环渲染的位置,也更容易找到并修改,所以在此作些文章还是有意义的。
3.1 识别<datalist>标签
想要匹配<datalist>标签及内部数据,并将其转换为json数据,其方法无非就是使用正则进行匹配。通过正则工具,进行数据测试,匹配到需要的数据,如下图:
经过多轮测试,此正则已能满足需求,下面将使用它来完成自定义数据加载。
3.2 修改html-loader
如下图,在art-template对返回的html内容进行渲染前,把自定义数据匹配到,并且合并到htmlData中,则可以实现自定义数据全局化。
webpack.config.js文件中,将html-loader的options选项中preprocessor回调函数进行修改, 代码如下:
options: {minimize: false, // 不压缩html内容preprocessor: (content, loaderContext) => {// 正则达式let regEx = /<datalist>\s*{\s*[\s\S]*?\s*}\s*<\/datalist>/gi,// 区域html页面中json数据htmlResult = content.match(regEx),// 公共部分json数据returnData = {...htmlData},// 临时存储html中读取到的json数据data = {};// 判断htmlResult如果不为空,并且数组(match匹配到数据返回为数组格式)则转换字符串内容为json数据if(null!=htmlResult&&Array.isArray(htmlResult)){try {// 去除datalist标签htmlResult = htmlResult.map(item => {item = item.replace('<datalist>', '');item = item.replace('</datalist>', '');return JSON.parse(item);});// 合并数据htmlResult.forEach(item => {Object.assign(data, item);});// 合并到htmlData数据集中Object.assign(returnData, data);} catch (error) {console.error('html result:', error);}// 清除页面中数据content = content.replace(regEx, '');}return artTemplate.compile(content)(returnData);}
}
大家在写代码时,要多思考,在什么时候代码可能会报错。由于json数据是不可控的,大家在写的时候可能多打一个符号,或者在别的地方拷过来一些特殊符号,导致JSON.parse时编译时报错,从而导致整个js运行报错,影响其他正常程序执行。所以这里在JSON.parse位置,添加了try{}catch{}用来捕捉错误。
还有细心朋友会发现另一个细节,就是<datalist>数据不放在<block>中,html也不会渲染出来,那为什么要匹配到后将其清除呢?这是因为这里使用的是extend继承原因,layout.html中所有坑位的渲染是通过<block>完成的,不在<block>内的内容是不会被渲染。但如果是有些数据放在<block>中,或者没使用extend继承关系时,则会被渲染到页面中;所以多做此一举对于编写代码,能更为灵活操作。
此时重新运行npx webpack serve,不仅首页内容又全部显示出来了,不同页面也能正常显示各自的标题了,如下图:
该篇为功能扩展部分,解决需要优化的小功能。有时一些小需求不需要到处找插件,在自己能力和条件允许范围内,可以自己动手来实现需求。像此功能,其实也就是一条正则就解决的事, 没必要花大量时间研究插件,了解他人制定的规则,自己实现更为自在、更有效率。希望此篇对大家有帮助,谢谢~