背景
在商品展示类页面开发时,图片是经常要打交道的地方,当数量不多的时候,人为调整还是可以, 但是遇到十几 甚至是上百张图片时候,就需要借助工具解决 如:
- 拿到的图片是命名不规则的(有些带有空格 有些带有横杆不统一)
- 拿到的图片命名大小写没有区分
- 拿到的图片格式不一致, 有些是png, 有些是jpg, 有些是jpeg
- 拿到的图片需要的seo优化, 要把把文件命名为有意义的名称, 包括标签 alt title 等命名
- 页面上需要重复写入的
<img>很多而且需要一定的格式
优化思路
- 先把图片素材通过工具,统一格式化所有图片命名和后缀
- 通过脚本实现自动化填补
<img>
工具篇
mac系统自带
多选需要操作的图片, 选择重新命名
mac系统支持 替换文本, 添加文本 和 修改格式
第三方软件
这里推荐使用Bluk File Rename工具(mac系统)
下载方式: 在appstore 搜索 rename 安装“批量文件名修改”
使用流程: 通过配置规则可以实现批量重命名,大写转小写,去空格 去横杆,去掉多余前缀
导入
我们以这几张图片为例, (有些包含- 有些有空格 有些开头大写)
设置规则
这里只需要配置 原文件名 和 扩展名 这两个属性就可以实现规范化的命名
生成结果
点击预览即可在下面看到 改名后的所有结果
点击右上角的改名4个文件就会默认覆盖原有路径文件
生成结果, 当然
human .jpg没有处理好,可以重复导入再设置规则,这里就不再叙述.
代码篇
1.vscode 快捷指令
vscode 提供简单高效的快捷指令 如:
ul.piclist>li*6>a[href=#]>img[src=https://picsum.photos/200/300?random\=$]
回车后自动生成
这里picsum.photos/200/300 会动态返回不同的图片
2.node + ejs模版输出
源码地址(github.com/mjsong07/in…)
实现:
- 本地文件夹的资源遍历
- 遍历出来的变量结合ejs模版实现不同定制逻辑页面需求
项目结构
使用方法
启动命令
"scripts": {
"img-build-1": "node ./src/util/generateImgContent.js --ejs_path=./img-template-1.ejs --imgPath=static/images/products/product1/pc/* --cdn=http://cdn/",
"img-build-2": "node ./src/util/generateImgContent.js --ejs_path=./img-template-2.ejs --imgPath=static/images/products/product1/mobile/* --cdn=../static/images/products/product1/mobile/"
},
直接运行
npm run img-build-1
- img-build-1 会执行generateImgContent.js代码
- 遍历文件夹路径static/images/products/product1/pc/* 所有图片,输出变量
- 同时读取img-template-1.ejs 模版
- 把变量和模版内容混合输出在dist输出
img-build.html文件
读取的文件夹图片列表
输出内容
<div class="floor-container">
<h1>pc</h1>
<div class="swiper-container">
<div class="swiper-wrapper">
<!-- 这里根据实际的情况 修改对应的模板内容 -->
<div class="swiper-wrapper"><div class="swiper-slide">
<img src="../static/images/products/product1/pc/1006-200x300.jpg" alt="1006 200x300" title="1006 200x300">
<p>"1006 200x300"</p>
</div>
</div>
<div class="swiper-wrapper"><div class="swiper-slide">
<img src="../static/images/products/product1/pc/106-200x300.jpg" alt="106 200x300" title="106 200x300">
<p>"106 200x300"</p>
</div>
</div>
<div class="swiper-wrapper"><div class="swiper-slide">
<img src="../static/images/products/product1/pc/171-200x300.jpg" alt="171 200x300" title="171 200x300">
<p>"171 200x300"</p>
</div>
</div>
<div class="swiper-wrapper"><div class="swiper-slide">
<img src="../static/images/products/product1/pc/209-200x300.jpg" alt="209 200x300" title="209 200x300">
<p>"209 200x300"</p>
</div>
</div>
<div class="swiper-wrapper"><div class="swiper-slide">
<img src="../static/images/products/product1/pc/252-200x300.jpg" alt="252 200x300" title="252 200x300">
<p>"252 200x300"</p>
</div>
</div>
<div class="swiper-wrapper"><div class="swiper-slide">
<img src="../static/images/products/product1/pc/327-200x300.jpg" alt="327 200x300" title="327 200x300">
<p>"327 200x300"</p>
</div>
</div>
<div class="swiper-wrapper"><div class="swiper-slide">
<img src="../static/images/products/product1/pc/402-200x300.jpg" alt="402 200x300" title="402 200x300">
<p>"402 200x300"</p>
</div>
</div>
<div class="swiper-wrapper"><div class="swiper-slide">
<img src="../static/images/products/product1/pc/403-200x300.jpg" alt="403 200x300" title="403 200x300">
<p>"403 200x300"</p>
</div>
</div>
<div class="swiper-wrapper"><div class="swiper-slide">
<img src="../static/images/products/product1/pc/437-200x300.jpg" alt="437 200x300" title="437 200x300">
<p>"437 200x300"</p>
</div>
</div>
<div class="swiper-wrapper"><div class="swiper-slide">
<img src="../static/images/products/product1/pc/532-200x300.jpg" alt="532 200x300" title="532 200x300">
<p>"532 200x300"</p>
</div>
</div>
<div class="swiper-wrapper"><div class="swiper-slide">
<img src="../static/images/products/product1/pc/559-200x300.jpg" alt="559 200x300" title="559 200x300">
<p>"559 200x300"</p>
</div>
</div>
<div class="swiper-wrapper"><div class="swiper-slide">
<img src="../static/images/products/product1/pc/58-200x300.jpg" alt="58 200x300" title="58 200x300">
<p>"58 200x300"</p>
</div>
</div>
<div class="swiper-wrapper"><div class="swiper-slide">
<img src="../static/images/products/product1/pc/660-200x300.jpg" alt="660 200x300" title="660 200x300">
<p>"660 200x300"</p>
</div>
</div>
<div class="swiper-wrapper"><div class="swiper-slide">
<img src="../static/images/products/product1/pc/666-200x300.jpg" alt="666 200x300" title="666 200x300">
<p>"666 200x300"</p>
</div>
</div>
<div class="swiper-wrapper"><div class="swiper-slide">
<img src="../static/images/products/product1/pc/670-200x300.jpg" alt="670 200x300" title="670 200x300">
<p>"670 200x300"</p>
</div>
</div>
<div class="swiper-wrapper"><div class="swiper-slide">
<img src="../static/images/products/product1/pc/853-200x300.jpg" alt="853 200x300" title="853 200x300">
<p>"853 200x300"</p>
</div>
</div>
<div class="swiper-wrapper"><div class="swiper-slide">
<img src="../static/images/products/product1/pc/929-200x300.jpg" alt="929 200x300" title="929 200x300">
<p>"929 200x300"</p>
</div>
</div>
<div class="swiper-wrapper"><div class="swiper-slide">
<img src="../static/images/products/product1/pc/942-200x300.jpg" alt="942 200x300" title="942 200x300">
<p>"942 200x300"</p>
</div>
</div>
<div class="swiper-wrapper"><div class="swiper-slide">
<img src="../static/images/products/product1/pc/950-200x300.jpg" alt="950 200x300" title="950 200x300">
<p>"950 200x300"</p>
</div>
</div>
<div class="swiper-wrapper"><div class="swiper-slide">
<img src="../static/images/products/product1/pc/989-200x300.jpg" alt="989 200x300" title="989 200x300">
<p>"989 200x300"</p>
</div>
</div>
</div>
</div>
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
</div>
支持参数
"scripts": {
"img-build-1": "node ./src/util/generateImgContent.js --ejs_path=./img-template-1.ejs --imgPath=static/images/products/product1/pc/* --cdn=http://cdn/",
"img-build-2": "node ./src/util/generateImgContent.js --ejs_path=./img-template-2.ejs --imgPath=static/images/products/product1/mobile/* --cdn=../static/images/products/product1/mobile/"
},
- ejs_path : "./img-template-1.ejs"; //这里为对应要输出的模板
- imgPath : "static/images/products/product1/pc/*"; //这里为遍历的图片文件夹路径
- cdn : "http://cdn/"; //这里替换为实际的业务地址, 本地调试可以使用相对地址 ../static/images/products/product1/mobile/
模版文件
img-template-1.ejs
<div class="floor-container">
<h1>pc</h1>
<div class="swiper-container">
<div class="swiper-wrapper">
<!-- 这里根据实际的情况 修改对应的模板内容 -->
<% lists.forEach(function(file){%><div class="swiper-wrapper"><div class="swiper-slide">
<img src="../static/images/products/product1/pc/<%= file.fileNameAndExt %>" alt="<%= file.fileName %>" title="<%= file.fileName %>">
<p>"<%= file.fileName %>"</p>
</div>
</div>
<% })%>
</div>
</div>
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
</div>
img-template-2.ejs
<div class="floor-container">
<div class="row">
<p class="title animation-item animation">mobile </p>
<div class="product-text">
<% lists.forEach(function(file){%><img src="<%= file.cdn %><%= file.fileNameAndExt %>" alt="<%= file.fileName %>">
<% })%>
</div>
<div class="product-img pc">
<% lists.forEach(function(file){%><img src="<%= file.cdn %><%= file.fileNameAndExt %>" alt="<%= file.fileName %>">
<% })%>
</div>
<div class="product-img mobile">
<% lists.forEach(function(file){%><img src="<%= file.cdn %><%= file.fileNameAndExt %>" alt="<%= file.fileName %>">
<% })%>
</div>
<div class="product-icon">
<% lists.forEach(function(file){%><img src="<%= file.cdn %><%= file.fileNameAndExt %>" alt="<%= file.fileName %>">
<% })%>
</div>
</div>
</div>
主要逻辑代码
generateImgContent.js
// 动态根据图片资源生成图片以及标签内容 包括 alt src 地址, title 名称
"use strict";
const glob = require("glob");
const path = require("path");
const ejs = require("ejs");
const fs = require("fs");
let imgTemplatePath = require('minimist')(process.argv.slice(2))['ejs_path'] //"./img-template-1.ejs"; //这里为对应要输出的模板
let imgPath =require('minimist')(process.argv.slice(3))['imgPath'] // "static/images/products/product1/pc/*"; //这里为遍历的图片文件夹路径
let cdn =require('minimist')(process.argv.slice(4))['cdn'] // "http://cdn/"; //这里替换为实际的业务地址, 本地调试可以使用相对地址 ../static/images/products/product1/mobile/
console.log("imgTemplatePath",imgTemplatePath)
console.log("imgPath",imgPath)
console.log("cdn",cdn)
const entryFiles = glob.sync(
imgPath
);
console.log("entryFiles", entryFiles);
// 写入文件夹操作
const writeToFile = (pathName, result) => {
//先判断文件夹是否存在,不存在则创建
const dirname = path.dirname(pathName);
if(!fs.existsSync(dirname)){
fs.mkdirSync(dirname);
}
// path: 目标文件夹的绝对路径(只支持绝对路径)
return fs.promises.writeFile(pathName, result);
};
const getCompilerTxt = async (templateName, lists) => {
// 根据用户执行的命令,拿到指定路径的模板,进行渲染创建
const templateCurrentPath = `./${templateName}`;
const templateAbsolutePath = path.resolve(__dirname, templateCurrentPath);
// 读取HTML 标签
return new Promise((resolve, reject) => {
ejs.renderFile(templateAbsolutePath, { lists }, {}, (err, result) => {
if (err) {
reject(err);
return;
}
resolve(result);
});
});
};
let outerList = [];
Object.keys(entryFiles).map(async (index) => {
const entryFile = entryFiles[index];
const fileInfo = path.parse(entryFile);
let fileName = fileInfo.name;
fileName = fileName.replaceAll("-", " ");
const fileNameAndExt = fileInfo.base;
let file = {
fileNameAndExt,
fileName,
cdn,
};
outerList.push(file);
});
async function run() {
let html = await getCompilerTxt(imgTemplatePath, outerList);
const targetPath = path.resolve("./dist", `img-build.html`);
await writeToFile(targetPath, html);
}
run();