JavaScript实战笔记(五) 预览本地图片

简介: JavaScript实战笔记(五) 预览本地图片

前言


一般情况下,实现本地图片预览有两种方法,一种是 DataURL,一种是 BlobURL

所以在开始介绍怎么展示本地图片之前,我们花一点时间了解一下什么是 DataURL 和 BlobURL


正文


1、DataURL


(1)介绍

DataURL 就是以 data: 开头的 URL,它将数据编码成特定的格式,并允许开发者在文档中嵌入

(2)格式

data:[<mediatype>][;base64],<data>


data::前缀部分,DataURL 都必须以 data: 开头

[<mediatype>]:表明数据的 MIME 类型,可选项,默认为 text/plain;charset=US-ASCII

MIME 的标准格式是 type/subtype,其中,type 表明数据的分类,subtype 表明具体的类型

常见的 type 和 subtype 如下:


  • 若 type 为 text ,表明数据是普通文本,例如 text/plain、text/html
  • 在DataURL 中,如果数据是普通文本,还可以在后面用 charset 指定编码,例如 charset=UTF-8
  • 若 type 为 image,表明数据是图像类型,例如 image/jpeg、image/png
  • 若 type 为 audio,表明数据是音频类型,例如 audio/mpeg、audio/wav
  • 若 type 为 video,表明数据是视频类型,例如 video/webm、video/ogg
  • 若 type 为 application,表明数据是二进制类型,例如 application/octet-stream


[;base64]:可选项,添加后表明后面的数据 <data> 是经过 Base64 编码的

如果数据是简单文本,那么可以直接嵌入,不需要经过 Base64 编码,因此可以省略

如果数据是其它类型,那么必须加上 ;base64,并在后面嵌入以 Base64 编码的数据

<data>:实际的数据,可以是普通文本,可以是经过 Base64 编码的数据

如果是经过 Base64 编码的数据,那么前面必须要有 ;base64

(3)例子

  • 普通文本
// 不指定文本编码,显示乱码:浣犲ソ
data:text/plain,你好
// 指定文本编码为 UTF-8,显示正确:你好
data:text/plain;charset=UTF-8,你好
// 指定文本编码为 UTF-8,并使用 Base64 编码数据,显示正确:你好
data:text/plain;charset=UTF-8;base64,5L2g5aW9


  • 其它类型,例如图片
data:image/jpeg;base64,iVBORw0KGgoAAAANSUhE...


2、Base64


(1)介绍


Base64 是一种基于二进制的编码协议


它的主要目的是用六十四个可打印字符表示所有数据(包括中文、二进制等)


在默认情况下,这六十四个可打印字符包括 [A-Z|a-z|0-9|+|/]


(2)原理


Base64 的编码过程很简单,下面我们直接用一个例子来进行讲解

原数据:Hello,原数据二进制:01001000 01100101 01101100 01101100 01101111
1、将原数据,每 3 个字节分为 1 组,这样就能得到多组 24 个二进制位
(01001000 01100101 01101100) (01101100 01101111)
如果不足 24 个二进制位,后面会讲如何处理
2、将每组 24 个二进制位,每 6 个二进制位分为 1 个小组,这样每个大组包含 4 个小组
(010010 000110 010101 101100) (011011 000110 1111)
如果不足 6 个二进制位,后面补 0;如果不足一组 6 个二进制位,用 = 代替
(010010 000110 010101 101100) (011011 000110 111100 =)
3、对每组 6 个二进制位,在前面添加两个二进制位 00,这样每个大组包含 4 个字节
(00010010 00000110 00010101 00101100) (00011011 00000110 00111100 =)
4、最后对照编码表,查询每个字节对应的编码,就能得到原数据的 Base64 编码
SGVsbG8=
实际上编码表也很简单,如下:
二进制字节 00000000 ~ 00011001 对应编码 A ~ Z
二进制字节 00011010 ~ 00110011 对应编码 a ~ z
二进制字节 00110100 ~ 00111101 对应编码 0 ~ 9
二进制字节 00111110 对应编码 +
二进制字节 00111111 对应编码 /


(3)应用

Web API 中有编码和解码 Base64 数据的方法,分别是 btoa()atob()

  • btoa():编码,对数据进行 Base64 编码
  • atob():解码,对经过 Base64 编码后的数据解码
let originalStr = 'Hello'
let encodedData = window.btoa(originalStr)
let decodedData = window.atob(encodedData)
console.log(encodedData) // SGVsbG8=
console.log(decodedData) // Hello


3、Blob


(1)Blob

Blob 对象表示一个不可变、原始数据的类文件对象(常用于表示二进制数据),它的构造函数如下:

Blob(array, options)


array:一个由 ArrayBuffer、Blob、DOMString 等对象构成的 Array


options:对象类型,包含一些可选属性,包括

type:表示 MIME 类型,默认为 ""

endings:指定包含行结束符 \n 的字符串如何被写入,默认为 transparent


Blob 对象具有以下属性和方法:


  • size:只读属性,表示数据的大小
  • type:只读属性,表示数据的 MIME 类型
  • text():返回一个 Promise,包含 Blob 所有内容的 UTF-8 格式的 USVString
  • arrayBuffer():返回一个 Promise,包含 Blob 所有内容的 Binary 格式的 ArrayBuffer


(2)File


File 对象是一个特殊的 Blob,我们通常会在用 <input> 标签上传文件的场景遇到这个对象


它保存着文件的描述信息以及文件的原始数据,除了继承 Blob 的属性外,File 还具有以下的属性:


  • size:只读属性,表示数据的大小
  • type:只读属性,表示数据的 MIME 类型
  • name:只读属性,表示文件的名称
  • lastModified:只读属性,表示文件的最后修改时间,自 UNIX 时间起始值以来的毫秒数
  • lastModifiedDate:只读属性,表示文件的最后修改时间,Date 对象


4、BlobURL


可以用 URL.createObjectURL() 给 Blob 等对象创建一个 URL,之后通过这个 URL 可以访问原始数据


但是需要注意的是,这些 URL 对象是不会自动释放的,只有当 document 卸载时才会同时释放这些对象


当然我们还有更好的选择,那就是当我们不再需要这些对象时,通过 URL.revokeObjectURL() 主动释放


5、DataURL 与 Blob 的转化


(1)DataURL -> Blob

function dataURLtoBlob(dataURL) {
    return new Promise((resolve, reject) => {
        let [descString, dataString] = dataURL.split(',')
        let mimeType = descString.split('data:')[1].split(';base64')[0]
        let byteData = window
          ? window.atob(dataString)
          : Buffer.from(dataString, 'base64').toString('binary')
        let intArray = new Uint8Array(new ArrayBuffer(byteData.length))
        for (let idx = 0; idx < byteData.length; idx++) {
            intArray[idx] = byteData.charCodeAt(idx)
        }
        let blob = new Blob([intArray], {type: mimeType})
        resolve(blob)
    })
}


(2)Blob -> DataURL

function blobToDataURL(blob) {
    return new Promise((resolve, reject) => {
        blob.arrayBuffer().then((arrayBuffer) => {
            let mimetype = blob.type
            let intArray = new Uint8Array(arrayBuffer)
            let byteData = [].map.call(intArray, (val) => {
                return String.fromCharCode(val)
            }).join('')
            let dataString = window
                ? window.btoa(byteData)
                : Buffer.from(byteData).toString('base64')
            let descString = 'data:' + mimetype + ';base64'
            let dataURL = descString + ',' + dataString
            resolve(dataURL)
        })
    })
}


注意,在上面的解决方案中,blob.arrayBuffer() 的兼容性其实并不是很好

事实上,我们有一个更加简单的解决方案

function blobToDataURL(blob) {
    return new Promise((resolve, reject) => {
        let reader = new FileReader()
        reader.onloadend = function() {
            resolve(reader.result)
        }
        reader.readAsDataURL(blob)
    })
}


6、图片预览


(1)BlobURL

<!DOCTYPE html>
<html>
<head>
    <script>
        function bindEvent() {
            const input = document.querySelector('input[type=file]')
            input.addEventListener('change', uoloadFile)
        }
        function uoloadFile(e) {
            let files = e.target.files;
            if (files.length > 0) {
                let file = files[0]
                document.querySelector('#avatar').src = URL.createObjectURL(file)
            }
        }
    </script>
</head>
<body onload="bindEvent()">
    <input type="file" accept="image/png, image/jpeg" />
    <image id="avatar" />
</body>
</html>


(2)DataURL

<!DOCTYPE html>
<html>
<head>
    <script>
        function bindEvent() {
            const input = document.querySelector('input[type=file]')
            input.addEventListener('change', uoloadFile)
        }
        function uoloadFile(e) {
            let files = e.target.files;
            if (files.length > 0) {
                let file = files[0]
                blobToDataURL(file).then((dataURL) => {
                    document.querySelector('#avatar').src = dataURL
                })
            }
        }
        function blobToDataURL(blob) {
            return new Promise((resolve, reject) => {
                let reader = new FileReader()
                reader.onloadend = function() {
                    resolve(reader.result)
                }
                reader.readAsDataURL(blob)
            })
        }
    </script>
</head>
<body onload="bindEvent()">
    <input type="file" accept="image/png, image/jpeg" />
    <image id="avatar" />
</body>
</html>


(3)实现效果

5556.gif




目录
相关文章
|
1月前
|
存储 安全 API
Next.js 实战 (九):使用 next-auth 完成第三方身份登录验证
这篇文章介绍了next-auth,一个为Next.js设计的身份验证库,支持多种认证方式,如电子邮件和密码、OAuth2.0提供商(如Google、GitHub、Facebook等)以及自定义提供商。文章包含了如何配置Github Provider以及会话管理,并提到了适配器Adapters在next-auth中的作用。最后,文章强调了next-auth的强大功能值得进一步探索。
74 10
|
4月前
|
自然语言处理 JavaScript 前端开发
深入理解JavaScript中的闭包:原理与实战
【10月更文挑战第12天】深入理解JavaScript中的闭包:原理与实战
|
1月前
|
设计模式 数据安全/隐私保护
Next.js 实战 (七):浅谈 Layout 布局的嵌套设计模式
这篇文章介绍了在Next.js框架下,如何处理中后台管理系统中特殊页面(如登录页)不包裹根布局(RootLayout)的问题。作者指出Next.js的设计理念是通过布局的嵌套来创建复杂的页面结构,这虽然保持了代码的整洁和可维护性,但对于特殊页面来说,却造成了不必要的布局包裹。文章提出了一个解决方案,即通过判断页面的skipGlobalLayout属性来决定是否包含RootLayout,从而实现特殊页面不包裹根布局的目标。
90 33
|
1月前
|
移动开发 JavaScript 前端开发
【Html.js——图片折叠效果】折叠手风琴(蓝桥杯真题-1763)【合集】
本项目实现了一个图片折叠手风琴效果,使用jQuery完成。主要包括以下部分: - **介绍**:任务是通过点击图片实现折叠和展开的效果。 - **准备**:内置初始代码,包含 `css/style.css`、`images/` 文件夹、`js/` 文件夹及 `index.html` 等文件。启动 Web Server 服务可运行项目。 - **目标**:完善 `index.js` 文件,使页面达到预期的折叠效果。 - **规定**:严格按步骤操作,保持默认文件结构不变,并在完成后保持 Web 服务正常访问状态。 - **通关代码**:使用 jQuery 实现点击事件,为选中元素添加 `act
42 19
|
4月前
|
JavaScript 前端开发 程序员
前端学习笔记——node.js
前端学习笔记——node.js
84 0
|
1月前
|
中间件 API
Next.js 实战 (八):使用 Lodash 打包构建产生的“坑”?
这篇文章介绍了作者在使用Nextjs15进行项目开发时遇到的部署问题。在部署过程中,作者遇到了打包构建时的一系列报错,报错内容涉及动态代码评估在Edge运行时不被允许等问题。经过一天的尝试和调整,作者最终删除了lodash-es库,并将radash的部分源码复制到本地,解决了打包报错的问题。文章最后提供了项目的线上预览地址,并欢迎读者留言讨论更好的解决方案。
41 10
|
2月前
|
JavaScript 容器
带方向感知功能的js图片遮罩层插件
带方向感知功能的js图片遮罩层插件
|
2月前
|
前端开发 API 开发者
Next.js 实战 (五):添加路由 Transition 过渡效果和 Loading 动画
这篇文章介绍了Framer Motion,一个为React设计的动画库,提供了声明式API处理动画和页面转换,适合创建响应式用户界面。文章包括首屏加载动画、路由加载Loading、路由进场和退场动画等主题,并提供了使用Framer Motion和next.js实现这些动画的示例代码。最后,文章总结了这些效果,并邀请读者探讨更好的实现方案。
|
1月前
|
JavaScript 前端开发 API
Next.js 实战 (六):如何实现文件本地上传
这篇文章介绍了在Next.js中如何实现文件上传到本地的方法。文章首先提到Next.js官方文档中没有提供文件上传的实例代码,因此开发者需要自行实现,通常有两种思路:使用Node.js原生上传或使用第三方插件如multer。接着,文章选择了使用Node.js原生上传的方式来讲解实现过程,包括如何通过哈希值命名文件、上传到指定目录以及如何分类文件夹。然后,文章展示了具体的实现步骤,包括编写代码来处理文件上传,并给出了代码示例。最后,文章通过一个效果演示说明了如何通过postman模拟上传文件,并展示了上传后的文件夹结构。
|
28天前
|
监控 安全 中间件
Next.js 实战 (十):中间件的魅力,打造更快更安全的应用
这篇文章介绍了什么是Next.js中的中间件以及其应用场景。中间件可以用于处理每个传入请求,比如实现日志记录、身份验证、重定向、CORS配置等功能。文章还提供了一个身份验证中间件的示例代码,以及如何使用限流中间件来限制同一IP地址的请求次数。中间件相当于一个构建模块,能够简化HTTP请求的预处理和后处理,提高代码的可维护性,有助于创建快速、安全和用户友好的Web体验。

热门文章

最新文章

  • 1
    当面试官再问我JS闭包时,我能答出来的都在这里了。
    49
  • 2
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    29
  • 3
    Node.js 中实现多任务下载的并发控制策略
    34
  • 4
    【2025优雅草开源计划进行中01】-针对web前端开发初学者使用-优雅草科技官网-纯静态页面html+css+JavaScript可直接下载使用-开源-首页为优雅草吴银满工程师原创-优雅草卓伊凡发布
    26
  • 5
    【JavaScript】深入理解 let、var 和 const
    49
  • 6
    【04】Java+若依+vue.js技术栈实现钱包积分管理系统项目-若依框架二次开发准备工作-以及建立初步后端目录菜单列-优雅草卓伊凡商业项目实战
    47
  • 7
    【03】Java+若依+vue.js技术栈实现钱包积分管理系统项目-若依框架搭建-服务端-后台管理-整体搭建-优雅草卓伊凡商业项目实战
    57
  • 8
    【02】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-ui设计图figmaUI设计准备-figma汉化插件-mysql数据库设计-优雅草卓伊凡商业项目实战
    57
  • 9
    如何通过pm2以cluster模式多进程部署next.js(包括docker下的部署)
    72
  • 10
    【01】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-需求改为思维导图-设计数据库-确定基础架构和设计-优雅草卓伊凡商业项目实战
    57