文转载自微信公众号「全栈修仙之路」,作者阿宝哥。转载本文请联系全栈修仙之路公众号。
在日常工作中,文件上传是一个很常见的功能。在上传文件时,我们可以选择上传单个文件,也可以通过设置 multiple 属性来上传多个文件。
本文阿宝哥将介绍如何上传目录及如何压缩目录并上传,压缩目录的功能是通过 JSZip 这个库来实现。利用这个库还可以实现在线预览 ZIP 文件的功能,感兴趣的小伙伴可以阅读 JavaScript 如何在线解压 ZIP 文件? 这篇文章。下面我们先来介绍如何实现压缩目录并上传的功能。
1.1 选择目录
在浏览器端,要实现压缩目录并上传的功能。首先我们要先实现选择目录的功能,要实现该功能,我们可以直接使用 HTMLInputElement 元素的 webkitdirectory 属性:
<input type="file" id="uploadFile" webkitdirectory />
当设置了 webkitdirectory 属性之后,我们就可以选择目录了。当阿宝哥选择了 useAxios 目录之后,就会显示以下确认框:
点击上传按钮之后,我们就可以获取文件列表。列表中的文件对象上含有一个 webkitRelativePath 属性,用于表示当前文件的相对路径。在进行目录压缩的时候,我们就会使用到该属性。
虽然通过 webkitdirectory 属性可以很容易地实现选择目录的功能,但在实际项目中我们还需要考虑它的兼容性。比如在 IE 11 以下的版本就不支持该属性,其它浏览器的兼容性如下图所示:
(图片来源 —— https://caniuse.com/?search=webkitdirectory)
1.2 压缩目录
在 JavaScript 如何在线解压 ZIP 文件? 这篇文章中,阿宝哥介绍了在浏览器端如何使用 JSZip 这个库实现在线解压 ZIP 文件的功能。JSZip 这个库除了可以解析 ZIP 文件之外,它还可以用来创建和编辑 ZIP 文件。这里阿宝哥基于 JSZip 库提供的 API,封装了一个 generateZipFile 函数:
function generateZipFile(
zipName, files,
options = { type: "blob", compression: "DEFLATE" }
) {
return new Promise((resolve, reject) => {
const zip = new JSZip();
for (let i = 0; i < files.length; i++) { // 添加目录中包含的文件
zip.file(files[i].webkitRelativePath, files[i]);
}
zip.generateAsync(options).then(function (blob) { // 生成zip文件
zipName = zipName || Date.now() + ".zip";
const zipFile = new File([blob], zipName, {
type: "application/zip",
});
resolve(zipFile);
});
});
}
在以上代码中,我们使用 file(name, data [,options]) 方法,把目录中的文件依次添加到 zip 对象中,然后再通过 generateAsync 方法来生成 ZIP 文件。在生成 ZIP 文件时,我们可以设置该文件的类型。这里我们设置的默认类型为 blob 类型,除了支持 blob 类型之外,它还支持 base64、uint8array 和 arraybuffer 等类型。
1.3 上传压缩 ZIP 文件
在压缩目录生成 ZIP 文件之后,我们就可以通过 XMLHttpRequest 或 fetch API 来上传压缩文件。下面阿宝哥将以 axios 为例,来实现文件上传的功能。
html 代码
<input type="file" id="uploadFile" webkitdirectory />
<button id="submit" onclick="uploadFile()">上传文件</button>
js 代码
const uploadFileEle = document.querySelector("#uploadFile");
const uploadOptions = { needZip = true };
const request = axios.create({
baseURL: "http://localhost:3000/",
timeout: 5000,
});
async function uploadFile({ needZip } = uploadOptions) {
if (!uploadFileEle.files.length) return;
let fileList = uploadFileEle.files;
if (needZip) { // 对目录进行ZIP压缩
let webkitRelativePath = fileList[0].webkitRelativePath;
let zipFileName = webkitRelativePath.split("/")[0] + ".zip";
fileList = [await generateZipFile(zipFileName, fileList)];
}
uploadFiles({ // 上传文件列表
url: "/upload/multiple",
files: fileList,
});
}
在 uploadFile 函数中,如果有启用目录压缩功能,我们就会调用 generateZipFile 函数生成 ZIP 文件,如果没有的话,就会直接调用 uploadFiles 函数来上传目录中的所有文件,当然你也可以对文件列表进行过滤,比如限制文件类型或文件的大小等。
下面我们来看一下 uploadFiles 函数的具体实现:
function uploadFiles({ url, files, fieldName = "file" }) {
if (!url || !files.length) return;
let formData = new FormData();
for (let i = 0; i < files.length; i++) {
formData.append(fieldName, files[i], files[i].name);
}
return request.post(url, formData);
}
在 uploadFiles 函数中,我们通过创建 FormData 对象来保存文件的信息,然后通过 request(axios 实例)来执行上传操作。
2.1 接收 ZIP 文件
在服务端要实现文件上传功能也比较简单,这里阿宝哥以 koa 为例来实现文件上传的功能。如果你对 koa 还不了解的话,建议你先大致浏览一下 koa 的官方文档。
const path = require("path");
const Koa = require("koa");
const cors = require("@koa/cors");
const multer = require("@koa/multer");
const Router = require("@koa/router");
const app = new Koa();
const router = new Router();
const UPLOAD_DIR = path.join(__dirname, "/public/upload");
const storage = multer.diskStorage({
destination: async function (req, file, cb) { // 设置文件的存储目录
cb(null, UPLOAD_DIR);
},
filename: function (req, file, cb) { // 设置文件名
cb(null, `${file.originalname}`);
},
});
const multerUpload = multer({ storage });
router.get("/", async (ctx) => {
ctx.body = "压缩文件目录上传示例(阿宝哥)";
});
router.post(
"/upload/multiple",
multerUpload.fields([
{
name: "file",
},
]),
async (ctx, next) => {
ctx.body = {
status: "success",
msg: "文件上传成功",
};
}
);
// 注册中间件
app.use(cors());
app.use(router.routes()).use(router.allowedMethods());
app.listen(3000, () => {
console.log("app starting at port 3000");
});
在以上代码中,我们通过 @koa/multer 这个中间件来处理文件上传,对该中间件感兴趣的小伙伴,可以自行阅读官方文档。接下来,我们来继续讨论另一个问题 —— 如何接收目录并按照文件目录结构进行存放?
2.2 接收文件目录
前面我们已经知道,当 input[type="file"] 使用了 webkitdirectory 属性之后,返回 File 对象的 webkitRelativePath 属性就会存放当前文件相对于当前目录的相对路径:
因此当我们在服务端处理文件目录上传的功能时,我们就可以通过该属性来创建对应的目录结构,具体的处理逻辑如下所示:
const fse = require("fs-extra");
const storage = multer.diskStorage({
destination: async function (req, file, cb) {
// 把useAxios@demo.vue中的@替换为路径分隔符
let relativePath = file.originalname.replace(/@/g, path.sep);
let index = relativePath.lastIndexOf(path.sep);
let fileDir = path.join(UPLOAD_DIR, relativePath.substr(0, index)); // 生成文件路径
await fse.ensureDir(fileDir); // 确保当前目录存在
cb(null, fileDir);
},
filename: function (req, file, cb) {
let parts = file.originalname.split("@"); // 对路径进行拆分
cb(null, `${parts[parts.length - 1]}`); // 获取文件名
},
});
为什么 originalname 文件原始名称会包含 @ 符号呢?这样因为使用 useAxios/demo.vue 这种路径形式时,是不能获取到完整的路径名称,只能获取到文件名。为了解决这个问题,阿宝哥在上传文件时,手动把文件相对路径中的 / 符号替换为 @ 然后再进行上传,对应的处理逻辑如下:
function uploadFiles({ url, files, fieldName = "file" }) {
if (!url || !files.length) return;
let formData = new FormData();
for (let i = 0; i < files.length; i++) {
formData.append(fieldName, files[i], files[i].webkitRelativePath.replace(/\//g, "@"));
}
return request.post(url, formData);
}
好的,压缩目录上传和目录上传已经介绍完了,感兴趣的小伙伴可以动手试试看。由于完整的示例代码内容比较多,阿宝哥就不放具体的代码了。有需要的小伙伴,可以访问以下地址浏览示例代码。
https://gist.github.com/semlinker/af57349c16d203cc2ec845d4b5a6b445
注意:以上代码仅供参考,请根据实际业务进行调整。
本文阿宝哥介绍了如何利用 input[type="file"] 元素的 webkitdirectory 属性来实现选择目录的功能,然后利用 JSZip 这个库来实现目录压缩,最后通过 axios 来上传目录压缩后的 ZIP 文件 。此外,阿宝哥还介绍了如何使用 koa 来实现接收目录并按照文件目录结构进行存放的功能。
JSZip 官方文档
MDN - webkitdirectory
JavaScript 如何在线解压 ZIP 文件?
作网页设计是一门需要创新、技术熟练和对细节的理解的艺术。成功的网页设计旨在创建一个导航方便、功能齐全、信息丰富、吸引人的网站,最终实现吸引访问者、提供信息和刺激用户行动的目标。以下是一个全面的教程,一步一步地指导你进行网页设计。
网页设计是指利用图形、排版、色彩等元素,以美观、易用、有效的方式向用户呈现网页内容和功能的过程。它涉及到用户界面设计、用户体验设计、视觉设计等多个方面。在制作网页设计时,设计师需要考虑网页的整体布局、导航结构、配色、字体选择等因素,以及用户的需求和行为习惯。一个成功的网页设计应该能够吸引用户的注意力,提供清晰的信息传达和良好的用户体验。
在制作网页设计时,设计师需要考虑以下几个方面:
目标用户:了解目标用户的特点和需求,以便根据自己的喜好和习惯进行设计。
页面布局:确定页面的整体结构和元素的位置,使其符合用户的阅读习惯和视觉体验。
导航设计:设计清晰易用的导航菜单,方便用户浏览和导航网页的不同部分。
色彩选择:选择适合主题和目标用户的色彩搭配,提升网页的视觉吸引力和用户体验。
字体选择:选择易读、符合网页风格的字体,使文字内容更加清晰易读。
图片和图标:使用合适的图片和图标来增加网页的视觉效果和吸引力。
响应设计:考虑不同设备和屏幕尺寸的适应性,使网页能够在不同的平台上很好地显示和使用。
即时设计是专门为现代UI/UX设计师设计的。它结合了强大的编辑和排版功能,以及大量的现代功能,如符号(可重用组件)和响应布局,是网页设计的有力工具。
https://ad.js.design/online/ui/?source=tt&plan=btt724
即时设计的强大功能
交互式原型:即时设计不仅是一种图形设计工具,而且还支持原型设计。这使得设计师能够在界面中创建和预览完整的交互式界面过程,大大提高了网页设计的效率。
设计共享与合作:即时设计提供 Cloud 功能,这是一个允许设计师将项目上传到云中并与团队或客户共享的在线平台。他们可以直接在网页上评论、测试原型和下载资源。该功能大大提高了团队之间的合作效率。
易用性和灵活性:对于初学者来说,即时设计的简单直观的用户界面非常友好。所有的工具和菜单都经过精心设计和安排,使用户能够快速理解和使用。更重要的是,即时设计的强大灵活性也体现在它对插件的支持上。有成千上万的插件可供选择,以扩展即时设计的功能,并使网页设计过程更加顺畅。
可以完美应对从简单的图标设计到复杂的应用程序和制作网页设计。
29000+设计元素,支持导出保存
https://js.design/community?category=explore&source=tt&plan=btt724
网页设计的界面布局在制作网页设计时非常重要,它决定了网页的整体结构和用户体验。良好的界面布局可以提供清晰的导航和容易浏览的内容,使用户能够轻松地找到他们需要的信息。
在制作网页设计时,有几个关键的网页布局原则需要考虑:
一致性:保持网页布局的一致性可以让用户更容易理解和使用网站。这包括统一的导航栏、相似的页面结构和一致的字体和颜色选择。
对齐:正确的对齐元素可以帮助用户更好地理解网页的结构和信息水平。使用对齐线将元素对齐到网格或页面边缘,使页面看起来更整洁和专业。
重点:通过使用不同的字体、颜色、大小和风格来突出重要的内容和功能。这可以帮助用户更快地找到他们需要的信息。
简洁:避免过多的设计元素和冗余信息,保持界面简洁直观。简单的界面可以提高用户的注意力和理解能力。
响应设计:考虑到不同设备和屏幕尺寸的用户,使用响应设计来适应不同的屏幕尺寸和分辨率。这可以提供更好的用户体验,并确保网页能够在各种设备上正常显示。
色彩搭配:色彩搭配是制作网页设计的一个非常重要的环节,它可以直接影响用户对网页的感知和体验。合理的色彩搭配可以使网页看起来更美观、更舒适,并能传达特定的情感和信息。因此,色彩搭配的重要性不容忽视。
确定网页的布局是制作网页设计的第一步。网页布局包括确定网页的整体结构和组织模式,以及每个元素在页面中的位置和排列模式。
以下是制作网页设计时的网页布局示例:
头部(Header):包含网页的标题和导航栏通常位于页面顶部。
内容区(Content):包含网页的主要内容,可分为文章、图片、视频等多个部分。
侧边栏(Sidebar):它位于内容区旁边,用于显示与主要内容相关的其他信息,如相关链接、广告等。
脚部(Footer):页面底部,包括版权信息、联系方式等。
在确定网页布局时,需要考虑用户体验和页面可读性。合理的布局可以帮助用户快速找到所需的信息,提高用户满意度。
菜单栏是网页设计的重要组成部分,可以帮助用户快速导航到网站的不同页面。为了优化用户体验,设计师应考虑以下几点:
清晰的标签和分类:菜单栏应包含易于理解的标签,以便用户能够快速找到他们想要的内容。标签应简洁明了,并与网站内容相关。同时,菜单栏应按逻辑分类,使用户能够轻松找到自己需要的信息。
易于使用的导航:菜单栏的设计应简单易用。用户应该能够轻松地找到他们想要的页面,并在不同的页面之间快速切换。为了实现这一点,设计师可以使用下拉菜单、分级菜单和其他技术来组织和显示菜单栏。
响应设计:随着移动设备的普及,设计师还应考虑不同屏幕尺寸下菜单栏的性能。菜单栏应能够适应不同的屏幕尺寸,并且在小屏幕上显示时不会占用太多的空间。设计师可以使用折叠菜单或隐藏菜单等技术来实现响应设计。
用户体验地图模板案例分享
https://js.design/community?category=detail&type=resource&id=64f601fb448fb96d0c508d80&source=tt&plan=btt724
兼容性测试是网页设计过程中非常重要的一步,确保网页能够在不同的浏览器、操作系统和设备上正常显示和运行。以下是一些兼容性测试的建议和步骤:
选择测试工具:首先,选择适合您制作网页设计项目的兼容性测试工具。有许多免费和付费的工具可供选择,如BrowserStack、CrossBrsesting和Sauce Labs等。这些工具可以模拟不同的浏览器和设备,并提供详细的测试报告。
测试不同的浏览器:确保您的网页在主流浏览器(如Chrome)中、Firefox、Safari和Edge)它可以正常显示和运行。检查网页的布局、字体、颜色和交互元素是否在不同的浏览器中一致。
测试不同的操作系统:制作网页设计也需要考虑不同的操作系统,如Windows、Mac和Linux等。测试您的网页在不同操作系统中的兼容性,以确保它能在每个操作系统中正常运行。
测试不同的设备:现在用户使用各种设备访问网页,包括台式电脑、笔记本电脑、平板电脑和手机。测试您的网页在不同设备上的兼容性,以确保它能够正确地显示和操作各种设备。
解决兼容性问题:在进行兼容性测试时,可能会发现一些兼容性问题,如布局混乱、字体显示错误或交互功能不能正常使用。及时记录和解决这些问题,以确保您的网页能够在各种环境中提供良好的用户体验。
响应性设计是指网页可根据不同设备的屏幕大小和分辨率进行自适应性设计。为确保网页能在不同设备上正常显示和使用,需进行响应性设计测试。
下面是制作网页设计时常用的一些响应设计测试方法:
设备测试:使用不同的设备(如手机、平板电脑、笔记本电脑等)进行测试。),检查不同设备的网页布局和功能是否正常。测试可以通过手动测试或模拟器进行。
屏幕尺寸测试:测试不同屏幕尺寸下网页的显示效果。浏览器的开发者工具可以用来模拟不同的屏幕尺寸,也可以用真实的设备进行测试。
浏览器兼容性测试:测试网页在不同浏览器上的显示效果和功能是否正常。普通浏览器包括Chrome、Firefox、Safari、Edge等。可以使用浏览器开发工具进行测试,也可以使用在线兼容性测试工具。
性能测试:测试网页的加载速度和性能。为了提高性能,工具可以用来测试网页的加载时间,并优化网页的代码和资源。
用户体验测试:测试网页的用户体验是否良好。为了改进网页的设计和功能,你可以邀请用户进行测试,收集他们的反馈和建议。
下面是在线准备步骤:
确认网页的内容和功能:上线前仔细检查网页的内容和功能,确保没有错误或缺失。检查网页的文本、图片、链接和交互功能,以确保它们能够正常显示和运行。
测试网页兼容性:不同的浏览器和设备可能会影响网页的显示和功能,因此需要进行兼容性测试。在主流浏览器中测试网页(例如chrome)、Firefox、Safari等。显示效果和功能是否正常,以及不同设备(如手机、平板电脑、电脑等)。
优化网页的加载速度:用户对网页的加载速度非常敏感,因此需要优化网页的加载速度,提高用户体验。利用浏览器缓存,通过压缩图片、合并和压缩CSS和JavaScript文件,减少网页的加载时间。
备份网页和数据库:上线前必须备份网页的文件和数据库,防止数据丢失或网页因意外情况无法访问。文件传输协议可以使用(FTP)将网页文件备份到本地或云存储,并对数据库进行备份。
配置网页的域名和服务器:上线前需要配置网页的域名和服务器。将域名指向网页的服务器IP地址,以确保服务器的配置和环境能够支持网页的正常运行。
设置网页访问权限:根据网页的需要,可以设置一些访问权限来控制用户访问和操作网页。您可以使用用户名和密码进行身份验证,也可以使用访问控制列表(ACL)限制特定用户或IP地址的访问。
监控和分析网页的性能:上线后,需要对网页的性能进行监控和分析,了解用户访问和网页运行情况。您可以使用网页分析工具(如谷歌) Analytics)对网页数据进行收集和分析,优化网页的设计和功能。
准备发布材料:网页设计完成后,需要准备一些发布网页的材料。其中包括HTML文件、CSS样式表、JavaScript脚本和其它媒体文件(如图片、视频等)。
导出网页文件:将设计好的网页导出为HTML文件。确保所有链接和资源文件的路径在导出过程中是正确的。
选用合适的服务器:选用合适的服务器托管您的网页。您可以选择建立自己的服务器,也可以选择使用第三方托管服务。
上传网页文件:将导出的HTML文件和相关资源文件上传到服务器。上传FTP工具或网页编辑器的上传功能。
配置服务器:根据服务器的要求进行相应的配置。它可能包括设置域名、配置数据库、设置文件权限等。
测试网页:在发布网页之前,必须进行测试。确保网页能够正常显示和工作在不同的浏览器和设备上。
域名分析:如果你有自己的域名,你需要在你的服务器上分析域名。这样,用户就可以通过域名访问你的网页。
网页发布:一切准备就绪后,您可以正式发布您的网页。您可以通过访问您的域名或服务器的IP地址来查看您的网页。
要知道,网页设计的成功制作不是一蹴而就的。最好的效果只有通过反复试验和不断优化才能达到。希望以上指南能帮助你打造一个功能强大、吸引人、有用的网页设计。
人人都是产品经理【起点学院】,BAT实战派产品总监手把手系统带你学产品、学运营。
周末连续两天给大家讲了面向对象编程的主要特性「封装」和「继承」,如果你期待今天继续讲「多态」这个特性,可能你要失望了,今天并没有「多态」,而是教你如何优化网页加载速度,我就是这么不按规矩出牌,哈哈。
周末在家宅着,刷了不少的网页,发现很多网站都没有优化它的加载速度,有时打开一个网页要等待10来秒才能加载完成,虽然网页内容很不错,但是给我的第一印象就是慢,不能忍啊!
其实有很多简单粗暴,又很有疗效的优化方法,我觉得有必要给各位产品经理分享一下,好让你们去督催开发哥哥优化,改善一下网页的加载体验~
首先,我们来看下网页的加载流程。打开一个网页,会先拉取一个html页面,然后浏览器解析了这个html页面后,会根据页面的内容,去拉取javascript、css和图片文件,最终根据这些文件,将页面渲染出来。
我们可以看到,影响一个网页展示速度的主要因素不是网页本身,而是它依赖的一些其它文件。如果优化了这些资源的加载速度,那么网页展示的速度也就上去了。
有哪些简单粗暴的方法呢?让我来一一列举:
一个网页中,图片资源的大小占比是最多的,而且单个的文件的大小也很可观。因此,在保证图片质量不变的情况下,尽可能的使用高压缩率的图片格式,图片格式可以按照这个优先级选择webp > jpeg > png > bmp。同时也要根据图片展示尺寸来拉取大小最为匹配的图片资源,不要没事就把原图拉下来使用。以前我就遇到过这种情况,一个196*196大小区域展示的图片,它的文件竟然达到了几兆,最后才发现把1960*1960分辨率的原图拉下来了。
大部分浏览器在发出请求时,会带上这个标记「Accept-Encoding: gzip, deflate」,表示这个浏览器可以接受以gzip压缩方式传输数据,如果你的网页服务器也支持gzip压缩数据,那么数据以gzip方式传输时,会减少70~80%的流量。
同一个站点下面的不同页面,往往都会复用一部分资源文件,如果把这些资源文件设置为可缓存的,那么在刷新或者跳转到另一个页面时,都无须再从网络拉取相关资源,这样就大大加快了网页的加载速度。
有的网站对于不同的终端制作了不同的页面,比如说在手机上访问微博,会从weibo.com重定向至weibo.cn,每一次重定向都会导致浏览器重新发起请求,延长加载时间。对于这种情况,应该尽可能使用响应式设计,一个weibo.com站点覆盖至所有终端。
CDN是一种静态内容分发网络,它在每个省,甚至每个城市都部署有自己的服务器,用于分发这些静态内容,那么当某个城市的用户要拉取某个资源时,他会首选从本地的CDN服务器上拉取,这样可以保证他最快速的获得该资源。据砖家统计,网络资源中有70%的是静态资源。这就意味着,有70%的内容产生后是不会变化,那么将它们全部放在CDN上面,可以提升这70%的资源的下载速度。
很多人喜欢把不同的图片挂在不同当域名下,比如说图片A挂在a.pm-teacher.com,图片B挂在b.pm-teacher.com。当一个网页同时使用图片A和图片B时,浏览器需要查询两个域名,要知道,每次解析域名都是会浪费时间的,所以尽可能的将全部图片放在一个域名下。
这里说的压缩和第2点并不重复,上面提到的压缩是不改变文件内容的压缩。而css和js中有大量的空格和变量命名(如hello="hello word";),如果将这些空格去除,并用简单的字母来代换变量名(如a="hello word";),那么这些css和js原文件的大小也会缩小,这样也对加快拉取速度是有帮助的。
不知道你有没有看出来,上面提到的优化方案的核心就3点:减少请求数、减少资源大小、找最快的服务器。如果你是一个网站的产品经理,快去找你们的开发确认是否有做过类似的优化吧。
给产品经理讲技术,微信公众号(pm_teacher),人人都是产品经理专栏作家。资深程序猿,专注客户端开发若干年,对前端、后台技术略懂,热衷于对新的科技领域的探索。
*请认真填写需求信息,我们会在24小时内与您取得联系。