一些项目因需求不同,如需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,不仅首页内容又全部显示出来了,不同页面也能正常显示各自的标题了,如下图:
该篇为功能扩展部分,解决需要优化的小功能。有时一些小需求不需要到处找插件,在自己能力和条件允许范围内,可以自己动手来实现需求。像此功能,其实也就是一条正则就解决的事, 没必要花大量时间研究插件,了解他人制定的规则,自己实现更为自在、更有效率。希望此篇对大家有帮助,谢谢~