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

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

相关推荐
雯0609~3 分钟前
网页F12:缓存的使用(设值、取值、删除)
前端·缓存
℘团子এ6 分钟前
vue3中如何上传文件到腾讯云的桶(cosbrowser)
前端·javascript·腾讯云
学习前端的小z12 分钟前
【前端】深入理解 JavaScript 逻辑运算符的优先级与短路求值机制
开发语言·前端·javascript
彭世瑜36 分钟前
ts: TypeScript跳过检查/忽略类型检查
前端·javascript·typescript
FØund40436 分钟前
antd form.setFieldsValue问题总结
前端·react.js·typescript·html
Backstroke fish37 分钟前
Token刷新机制
前端·javascript·vue.js·typescript·vue
小五Five38 分钟前
TypeScript项目中Axios的封装
开发语言·前端·javascript
小曲程序38 分钟前
vue3 封装request请求
java·前端·typescript·vue
临枫54139 分钟前
Nuxt3封装网络请求 useFetch & $fetch
前端·javascript·vue.js·typescript
酷酷的威朗普40 分钟前
医院绩效考核系统
javascript·css·vue.js·typescript·node.js·echarts·html5