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代码如下:

javascript 复制代码
{
    "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文件中代码如下:

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 &gt;&gt;</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 &gt;&gt;</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 &gt;&gt;</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 &gt;&gt;</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 &gt;&gt;</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中删除这行代码:

html 复制代码
{{block 'title'}}{{indexData.title}}{{/block}}

修改layout.html,将"{{block 'title'}}{{/block}}"修改为"{{title}}",代码如下:

html 复制代码
<!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添加最后项数据,代码如下:

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 &gt;&gt;</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回调函数进行修改, 代码如下:

javascript 复制代码
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,不仅首页内容又全部显示出来了,不同页面也能正常显示各自的标题了,如下图:

该篇为功能扩展部分,解决需要优化的小功能。有时一些小需求不需要到处找插件,在自己能力和条件允许范围内,可以自己动手来实现需求。像此功能,其实也就是一条正则就解决的事, 没必要花大量时间研究插件,了解他人制定的规则,自己实现更为自在、更有效率。希望此篇对大家有帮助,谢谢~

相关推荐
excel3 分钟前
前端必备:从能力检测到 UA-CH,浏览器客户端检测的完整指南
前端
前端小巷子9 分钟前
Vue 3全面提速剖析
前端·vue.js·面试
悟空聊架构16 分钟前
我的网站被攻击了,被干掉了 120G 流量,还在持续攻击中...
java·前端·架构
CodeSheep17 分钟前
国内 IT 公司时薪排行榜。
前端·后端·程序员
尖椒土豆sss21 分钟前
踩坑vue项目中使用 iframe 嵌套子系统无法登录,不报错问题!
前端·vue.js
遗悲风22 分钟前
html二次作业
前端·html
前端双越老师22 分钟前
【干货】使用 langChian.js 实现掘金“智能总结” 考虑大文档和 token 限制
人工智能·langchain·node.js
江城开朗的豌豆25 分钟前
React输入框优化:如何精准获取用户输入完成后的最终值?
前端·javascript·全栈
CF14年老兵26 分钟前
从卡顿到飞驰:我是如何用WebAssembly引爆React性能的
前端·react.js·trae
画月的亮29 分钟前
前端处理导出PDF。Vue导出pdf
前端·vue.js·pdf