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

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

相关推荐
excel2 分钟前
webpack 核心编译器 十三 节
前端
腾讯TNTWeb前端团队7 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰10 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪10 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪11 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy11 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom12 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom12 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom12 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom12 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试