lrz 源码核心篇剖析:如何实现高效、兼容的图片压缩?

写在前面

前面是讲解了lrz基础用法,从6开始讲解源码,使用过lrz的可以直接从6开始看,中间也掺杂了一下我自己开发过程中的踩坑和经验分享,欢迎讨论!

lrz(LocalResizeIMG)是一个前端图片压缩库,主要用于在浏览器中压缩图片并上传。以下是其主要特点和功能:

1.主要功能

  1. 图片压缩:通过调整图片质量和尺寸来减小文件大小。

  2. 保持宽高比:压缩时可保持图片原始宽高比。

  3. 多格式支持:支持常见图片格式如 JPEG、PNG、GIF 等。

  4. 本地处理:图片在本地压缩,不依赖服务器。

  5. 预览功能:压缩后可生成预览图。

2.基本语法: ★ 基础

lrz(file, [options]);
  • file 通过 input:file 得到的文件,或者直接传入图片路径

  • [options] 这个参数允许忽略

    • width {Number} 图片最大不超过的宽度,默认为原图宽度,高度不设时会适应宽度。
    • height {Number} 同上
    • quality {Number} 图片压缩质量,取值 0 - 1,默认为0.7
    • fieldName {String} 后端接收的字段名,默认:file

返回结果

返回值是一个promise对象

  • then(rst)

    • rst.formData 后端可处理的数据
    • rst.file 压缩后的file对象(默认已经丢在rst.formData有一份了),需要注意的是如果压缩率太低的话,这个会是原始的file对象
    • rst.fileLen 生成后的图片的大小,后端可以通过此值来校验是否传输完整
    • rst.base64 生成后的图片base64,后端可以处理此字符串为图片,也直接用于img.src = base64
    • rst.base64Len 生成后的base64的大小,后端可以通过此值来校验是否传输完整 (如果采用base64上传方式)
    • rst.origin 也就是原始的file对象,里面存了一些原始文件的信息,例如大小,日期等。
  • catch(err)

  • always()

3.基本使用:

基本用法一: ★ 常用

document.querySelector('#file').addEventListener('change', function () {
	lrz(this.files[0])
        .then(function (rst) {
            // 处理成功会执行
            console.log(rst);
        })
        .catch(function (err) {
            // 处理失败会执行
        })
        .always(function () {
            // 不管是成功失败,都会执行
        });
});

 基本用法二: 

lrz('./xxx/xx/x.png')
        .then(function (rst) {
             // 处理成功会执行
        })
        .catch(function (err){
            // 处理失败会执行
        })
        .always(function () {
            // 不管是成功失败,都会执行
        });

4.后端处理

方式一  ★ 推荐使用

  • 也就是标准的文件上传方式,而且这种方式传输量也会小一些

  • 前端发送rst.formData给后端

  • 后端接收 rst.file(可配置)字段,接着按常规处理

方式二

  • 发送base64字符串,接着处理字符串为图片即可。

  • 具体请使用关键字base64 转 image 开发语言进行google、baidu。

备注

建议前端发送一下rst.fileLen字段,后端进行校验来防止文件没有完整传送。

5.一个githup上作者写的简单的案例 ★ 了解

document.querySelector('input').addEventListener('change', function () {
    // this.files[0] 是用户选择的文件
    lrz(this.files[0], {width: 1024})
        .then(function (rst) {
            // 把处理的好的图片给用户看看呗

            var img = new Image();
            img.src = rst.base64;

            img.onload = function () {
                document.body.appendChild(img);
            };

            return rst;
        })

        .then(function (rst) {
            // 这里该上传给后端啦

            /* ==================================================== */
            // 原生ajax上传代码,所以看起来特别多 ╮(╯_╰)╭,但绝对能用
            // 其他框架,例如jQuery处理formData略有不同,请自行google,baidu。
            var xhr = new XMLHttpRequest();
            xhr.open('POST', 'http://localhost:5000/');

            xhr.onload = function () {
                if (xhr.status === 200) {
                    // 上传成功
                } else {
                    // 处理其他情况
                }
            };

            xhr.onerror = function () {
                // 处理错误
            };

            xhr.upload.onprogress = function (e) {
                // 上传进度
                var percentComplete = ((e.loaded / e.total) || 0) * 100;
            };

            // 添加参数
            rst.formData.append('fileLen', rst.fileLen);
            rst.formData.append('xxx', '我是其他参数');

            // 触发上传
            xhr.send(rst.formData);
            /* ==================================================== */

            return rst;
        })

        .catch(function (err) {
            // 万一出错了,这里可以捕捉到错误信息
            // 而且以上的then都不会执行

            alert(err);
        })

        .always(function () {
            // 不管是成功失败,这里都会执行
        });
});

 6.源码的解析 ★ 重点·难点

1. 设置 __webpack_public_path__ 和 window.URL

__webpack_public_path__ = getJsDir('lrz') + '/';
window.URL = window.URL || window.webkitURL;
  • __webpack_public_path__:设置 Webpack 的公共路径,用于动态加载资源。getJsDir('lrz') 获取当前脚本的路径,并拼接 /

  • window.URL:兼容性处理,确保 window.URL 可用。如果浏览器不支持 window.URL,则回退到 window.webkitURL

2. 引入依赖

var Promise = require('Promise'),
    BlobFormDataShim = require('Blob.FormData.shim'),
    exif = require('exif');
  • Promise:引入 Promise 库,用于处理异步操作。

  • BlobFormDataShim:引入 Blob 和 FormData 的兼容性处理库,用于处理低版本浏览器的兼容性问题。

  • exif:引入 EXIF 库,用于读取图片的元数据(如方向信息)。

3. 用户代理(UA)检测 ★ lrz性能优化的关键一环

var UA = (function (userAgent) {
    var ISOldIOS = /OS (.*) like Mac OS X/g.exec(userAgent),
        isOldAndroid = /Android (\d.*?);/g.exec(userAgent) || /Android\/(\d.*?) /g.exec(userAgent);

    var IOS_VERSION = ISOldIOS ? +ISOldIOS.pop().replace(/_/g, '.') : 0;
    return {
        oldIOS: ISOldIOS ? IOS_VERSION < 8 : false, // 判断是否是 iOS 8 以下
        newIOS: ISOldIOS ? IOS_VERSION >= 13.4 : false, // 判断是否是 iOS 13.4 及以上
        oldAndroid: isOldAndroid ? +isOldAndroid.pop().substr(0, 3) < 4.5 : false, // 判断是否是 Android 4.5 以下
        iOS: /\(i[^;]+;( U;)? CPU.+Mac OS X/.test(userAgent), // 判断是否是 iOS 设备
        android: /Android/g.test(userAgent), // 判断是否是 Android 设备
        mQQBrowser: /MQQBrowser/g.test(userAgent) // 判断是否是 QQ 浏览器
    };
})(navigator.userAgent);
  • 功能:通过 navigator.userAgent 检测当前设备的类型和版本。

  • 返回值:返回一个对象,包含设备的相关信息(如是否是旧版 iOS、是否是 Android 设备等)。

4. Lrz 构造函数

function Lrz(file, opts) {
    var that = this;

    if (!file) throw new Error('没有收到图片,可能的解决方案:https://github.com/think2011/localResizeIMG/issues/7');

    opts = opts || {};

    that.defaults = {
        width: null, // 压缩后的宽度
        height: null, // 压缩后的高度
        fieldName: 'file', // 表单字段名
        ingnoreOrientation: UA.iOS ? UA.newIOS : true, // 是否忽略方向信息
        quality: 0.7 // 压缩质量(0 到 1 之间)
    };

    that.file = file;

    for (var p in opts) {
        if (!opts.hasOwnProperty(p)) continue;
        that.defaults[p] = opts[p]; // 合并用户传入的配置
    }

    return this.init(); // 初始化
}
  • 功能:初始化 Lrz 实例,合并默认配置和用户传入的配置。

  • 参数

    • file:需要压缩的图片文件(可以是 File 对象、Blob 对象或 base64 字符串)。

    • opts:用户传入的配置项。

5. init 方法

Lrz.prototype.init = function () {
    // 1. 保存当前上下文到 `that`,方便在 Promise 和其他函数中访问
    var that = this,

        // 2. 获取传入的文件对象或 base64 字符串
        file = that.file,

        // 3. 判断文件是否是字符串类型(base64 或 URL)
        fileIsString = typeof file === 'string',

        // 4. 判断文件是否是 base64 格式
        fileIsBase64 = /^data:/.test(file),

        // 5. 创建一个新的 Image 对象,用于加载图片
        img = new Image(),

        // 6. 创建一个新的 canvas 对象,用于绘制和压缩图片
        canvas = document.createElement('canvas'),

        // 7. 如果文件是字符串(base64 或 URL),直接使用;否则,将文件对象转换为 Blob URL
        blob = fileIsString ? file : URL.createObjectURL(file);

    // 8. 将 Image 对象、Blob URL 和 canvas 对象保存到实例中,方便后续使用
    that.img = img;
    that.blob = blob;
    that.canvas = canvas;

    // 9. 设置文件名:
    //    - 如果文件是 base64,默认文件名为 'base64.jpg'
    //    - 如果文件是 URL,取 URL 的最后一部分作为文件名
    //    - 如果文件是 File 对象,直接使用 File 对象的 name 属性
    if (fileIsString) {
        that.fileName = fileIsBase64 ? 'base64.jpg' : file.split('/').pop();
    } else {
        that.fileName = file.name;
    }

    // 10. 检查浏览器是否支持 canvas,如果不支持,抛出错误
    if (!document.createElement('canvas').getContext) {
        throw new Error('浏览器不支持canvas');
    }

    // 11. 返回一个 Promise 对象,用于处理异步操作
    return new Promise(function (resolve, reject) {
        // 12. 监听图片加载失败事件
        img.onerror = function () {
            // 13. 如果图片加载失败,抛出错误并 reject Promise
            var err = new Error('加载图片文件失败');
            reject(err);
            throw err;
        };

        // 14. 监听图片加载成功事件
        img.onload = function () {
            // 15. 图片加载成功后,调用 `_getBase64` 方法生成 base64
            that._getBase64()
                .then(function (base64) {
                    // 16. 检查生成的 base64 是否有效(长度是否大于 10)
                    if (base64.length < 10) {
                        // 17. 如果 base64 无效,抛出错误并 reject Promise
                        var err = new Error('生成base64失败');
                        reject(err);
                        throw err;
                    }

                    // 18. 返回有效的 base64
                    return base64;
                })
                .then(function (base64) {
                    // 19. 初始化 FormData 对象
                    var formData = null;

                    // 20. 判断是否需要使用原始文件:
                    //     - 如果压缩后的 base64 比原始文件还大,则使用原始文件
                    if (typeof that.file === 'object' && base64.length > that.file.size) {
                        // 21. 使用原始文件,并创建原生的 FormData 对象
                        formData = new FormData();
                        file = that.file;
                    } else {
                        // 22. 使用压缩后的文件,并创建兼容性的 FormData 对象
                        formData = new BlobFormDataShim.FormData();
                        file = dataURItoBlob(base64);
                    }

                    // 23. 将文件添加到 FormData 中,字段名为配置中的 `fieldName`,文件名为处理后的文件名(后缀改为 .jpg)
                    formData.append(that.defaults.fieldName, file, that.fileName.replace(/\..+/g, '.jpg'));

                    // 24. 返回压缩结果,包括 FormData、文件大小、base64、原始文件等信息
                    resolve({
                        formData: formData, // 压缩后的 FormData
                        fileLen: +file.size, // 压缩后文件的大小
                        base64: base64, // 压缩后的 base64
                        base64Len: base64.length, // base64 的长度
                        origin: that.file, // 原始文件
                        file: file // 压缩后的文件
                    });

                    // 25. 释放内存:
                    //     - 遍历实例属性,将其置为 null
                    //     - 释放 Blob URL
                    for (var p in that) {
                        if (!that.hasOwnProperty(p)) continue;
                        that[p] = null;
                    }
                    URL.revokeObjectURL(that.blob);
                });
        };

        // 26. 如果文件不是 base64,设置图片的跨域属性为匿名(避免跨域问题)
        !fileIsBase64 && (img.crossOrigin = "*");

        // 27. 开始加载图片,将 Blob URL 或 base64 赋值给 img.src
        img.src = blob;
    });
};
  • 功能:初始化图片加载和压缩流程。

  • 步骤

    1. 创建 Image 对象和 canvas 对象。

    2. 加载图片,并在图片加载完成后调用 _getBase64 方法生成 base64。

    3. 根据压缩结果生成 FormData 对象。

    4. 返回压缩后的结果(包括 base64、FormData 等)

6. _getBase64 方法

Lrz.prototype._getBase64 = function () {
    // 1. 保存当前上下文到 `that`,方便在 Promise 和其他函数中访问
    var that = this,

        // 2. 获取之前初始化的 Image 对象
        img = that.img,

        // 3. 获取传入的文件对象或 base64 字符串
        file = that.file,

        // 4. 获取之前初始化的 canvas 对象
        canvas = that.canvas;

    // 5. 返回一个 Promise 对象,用于处理异步操作
    return new Promise(function (resolve) {
        // 6. 使用 try-catch 捕获可能的异常
        try {
            // 7. 读取图片的 EXIF 信息:
            //    - 如果文件是 File 对象,直接读取文件的 EXIF 信息
            //    - 如果文件是 base64 或 URL,读取 Image 对象的 EXIF 信息
            exif.getData(typeof file === 'object' ? file : img, function () {
                // 8. 获取图片的方向信息(Orientation):
                //    - 如果配置中设置了 `ingnoreOrientation` 为 true,则忽略方向信息,设置为 0
                //    - 否则,从 EXIF 中读取方向信息
                that.orientation = that.defaults.ingnoreOrientation ? 0 : exif.getTag(this, "Orientation");

                // 9. 调用 `_getResize` 方法,计算压缩后的图片尺寸
                that.resize = that._getResize();

                // 10. 获取 canvas 的 2D 上下文,用于绘制图片
                that.ctx = canvas.getContext('2d');

                // 11. 设置 canvas 的宽度和高度为压缩后的尺寸
                canvas.width = that.resize.width;
                canvas.height = that.resize.height;

                // 12. 设置 canvas 的背景色为白色:
                //     - 因为 JPEG 格式不支持透明背景,默认背景为黑色,设置为白色可以避免黑色背景
                that.ctx.fillStyle = '#fff';
                that.ctx.fillRect(0, 0, canvas.width, canvas.height);

                // 13. 根据设备类型选择不同的处理方式:
                //     - 如果是旧版 iOS 设备,调用 `_createBase64ForOldIOS` 方法
                //     - 否则,调用 `_createBase64` 方法
                if (UA.oldIOS) {
                    that._createBase64ForOldIOS().then(resolve);
                } else {
                    that._createBase64().then(resolve);
                }
            });
        } catch (err) {
            // 14. 如果发生异常,抛出错误
            throw new Error(err);
        }
    });
};
  • 功能:获取图片的 base64 数据。

  • 步骤

    1. 读取图片的 EXIF 信息(如方向信息)。

    2. 根据方向信息和配置调整图片尺寸。

    3. 调用 _createBase64ForOldIOS 或 _createBase64 生成 base64。

7. _createBase64ForOldIOS 方法

Lrz.prototype._createBase64ForOldIOS = function () {
    // 1. 保存当前上下文到 `that`,方便在 Promise 和其他函数中访问
    var that = this,

        // 2. 获取之前初始化的 Image 对象
        img = that.img,

        // 3. 获取之前初始化的 canvas 对象
        canvas = that.canvas,

        // 4. 获取默认配置
        defaults = that.defaults,

        // 5. 获取图片的方向信息(Orientation)
        orientation = that.orientation;

    // 6. 返回一个 Promise 对象,用于处理异步操作
    return new Promise(function (resolve) {
        // 7. 动态加载 `megapix-image` 库,用于处理旧版 iOS 设备的图片渲染
        require(['megapix-image'], function (MegaPixImage) {
            // 8. 使用 `MegaPixImage` 创建一个新的图片对象
            var mpImg = new MegaPixImage(img);

            // 9. 判断方向信息是否需要旋转:
            //    - 如果方向信息是 5、6、7、8,表示图片需要旋转 90 度或 270 度
            //    - 此时需要交换 canvas 的宽度和高度
            if ("5678".indexOf(orientation) > -1) {
                // 10. 调用 `mpImg.render` 方法,将图片渲染到 canvas 上:
                //     - 设置宽度为 canvas 的高度
                //     - 设置高度为 canvas 的宽度
                //     - 传递方向信息,确保图片正确旋转
                mpImg.render(canvas, {
                    width: canvas.height, // 交换宽度和高度
                    height: canvas.width, // 交换宽度和高度
                    orientation: orientation // 传递方向信息
                });
            } else {
                // 11. 如果方向信息不需要旋转,直接按原尺寸渲染图片
                mpImg.render(canvas, {
                    width: canvas.width, // 使用原宽度
                    height: canvas.height, // 使用原高度
                    orientation: orientation // 传递方向信息
                });
            }

            // 12. 将 canvas 中的图片转换为 base64 格式:
            //     - 使用 `canvas.toDataURL` 方法,生成 JPEG 格式的 base64
            //     - 设置图片质量为配置中的 `quality`
            resolve(canvas.toDataURL('image/jpeg', defaults.quality));
        });
    });
};
  • 功能:针对旧版 iOS 设备生成 base64。

  • 实现:使用 megapix-image 库处理图片,并根据方向信息调整图片。

8. _createBase64 方法

Lrz.prototype._createBase64 = function () {
    // 1. 保存当前上下文到 `that`,方便在 Promise 和其他函数中访问
    var that = this,

        // 2. 获取之前计算的压缩后的图片尺寸
        resize = that.resize,

        // 3. 获取之前初始化的 Image 对象
        img = that.img,

        // 4. 获取之前初始化的 canvas 对象
        canvas = that.canvas,

        // 5. 获取 canvas 的 2D 上下文
        ctx = that.ctx,

        // 6. 获取默认配置
        defaults = that.defaults,

        // 7. 获取图片的方向信息(Orientation)
        orientation = that.orientation;

    // 8. 根据方向信息调整图片:
    //    - 方向信息(Orientation)来自 EXIF 数据,用于处理图片的旋转和翻转
    switch (orientation) {
        case 3:
            // 9. 方向为 3:图片需要旋转 180 度
            ctx.rotate(180 * Math.PI / 180); // 旋转 180 度
            ctx.drawImage(img, -resize.width, -resize.height, resize.width, resize.height); // 绘制图片
            break;
        case 6:
            // 10. 方向为 6:图片需要旋转 90 度
            ctx.rotate(90 * Math.PI / 180); // 旋转 90 度
            ctx.drawImage(img, 0, -resize.width, resize.height, resize.width); // 绘制图片
            break;
        case 8:
            // 11. 方向为 8:图片需要旋转 270 度
            ctx.rotate(270 * Math.PI / 180); // 旋转 270 度
            ctx.drawImage(img, -resize.height, 0, resize.height, resize.width); // 绘制图片
            break;
        case 2:
            // 12. 方向为 2:图片需要水平翻转
            ctx.translate(resize.width, 0); // 平移画布
            ctx.scale(-1, 1); // 水平翻转
            ctx.drawImage(img, 0, 0, resize.width, resize.height); // 绘制图片
            break;
        case 4:
            // 13. 方向为 4:图片需要垂直翻转
            ctx.translate(resize.width, 0); // 平移画布
            ctx.scale(-1, 1); // 水平翻转
            ctx.rotate(180 * Math.PI / 180); // 旋转 180 度
            ctx.drawImage(img, -resize.width, -resize.height, resize.width, resize.height); // 绘制图片
            break;
        case 5:
            // 14. 方向为 5:图片需要水平翻转并旋转 90 度
            ctx.translate(resize.width, 0); // 平移画布
            ctx.scale(-1, 1); // 水平翻转
            ctx.rotate(90 * Math.PI / 180); // 旋转 90 度
            ctx.drawImage(img, 0, -resize.width, resize.height, resize.width); // 绘制图片
            break;
        case 7:
            // 15. 方向为 7:图片需要水平翻转并旋转 270 度
            ctx.translate(resize.width, 0); // 平移画布
            ctx.scale(-1, 1); // 水平翻转
            ctx.rotate(270 * Math.PI / 180); // 旋转 270 度
            ctx.drawImage(img, -resize.height, 0, resize.height, resize.width); // 绘制图片
            break;
        default:
            // 16. 默认情况:不需要旋转或翻转,直接绘制图片
            ctx.drawImage(img, 0, 0, resize.width, resize.height);
    }

    // 17. 返回一个 Promise 对象,用于处理异步操作
    return new Promise(function (resolve) {
        // 18. 判断是否需要使用兼容性处理:
        //     - 如果是旧版 Android 设备、QQ 浏览器或无法获取用户代理信息,使用 `JPEGEncoder` 生成 base64
        if (UA.oldAndroid || UA.mQQBrowser || !navigator.userAgent) {
            // 19. 动态加载 `jpeg_encoder_basic` 库,用于兼容性处理
            require(['jpeg_encoder_basic'], function (JPEGEncoder) {
                // 20. 创建 `JPEGEncoder` 实例
                var encoder = new JPEGEncoder(),

                    // 21. 获取 canvas 中的图片数据
                    img = ctx.getImageData(0, 0, canvas.width, canvas.height);

                // 22. 使用 `JPEGEncoder` 将图片数据编码为 base64
                resolve(encoder.encode(img, defaults.quality * 100));
            });
        } else {
            // 23. 如果不需要兼容性处理,直接使用 `canvas.toDataURL` 生成 base64
            resolve(canvas.toDataURL('image/jpeg', defaults.quality));
        }
    });
};
  • 功能:生成 base64 数据。

  • 实现:根据方向信息调整图片,并使用 canvas.toDataURL 或 JPEGEncoder 生成 base64。

9. _getResize 方法

Lrz.prototype._getResize = function () {
    // 1. 保存当前上下文到 `that`,方便在函数中访问
    var that = this,

        // 2. 获取之前初始化的 Image 对象
        img = that.img,

        // 3. 获取默认配置
        defaults = that.defaults,

        // 4. 获取配置中设置的宽度和高度
        width = defaults.width,
        height = defaults.height,

        // 5. 获取图片的方向信息(Orientation)
        orientation = that.orientation;

    // 6. 初始化返回值 `ret`,表示压缩后的尺寸,默认值为图片的原始尺寸
    var ret = {
        width: img.width,  // 图片的原始宽度
        height: img.height // 图片的原始高度
    };

    // 7. 判断方向信息是否需要交换宽度和高度:
    //    - 如果方向信息是 5、6、7、8,表示图片需要旋转 90 度或 270 度
    //    - 此时需要交换宽度和高度
    if ("5678".indexOf(orientation) > -1) {
        ret.width = img.height;  // 交换宽度和高度
        ret.height = img.width;  // 交换宽度和高度
    }

    // 8. 如果原图的宽度或高度小于设定的宽度或高度,直接返回原图尺寸
    if (ret.width < width || ret.height < height) {
        return ret;
    }

    // 9. 计算图片的宽高比
    var scale = ret.width / ret.height;

    // 10. 如果配置中同时设置了宽度和高度
    if (width && height) {
        // 11. 判断图片的宽高比是否大于设定的宽高比
        if (scale >= width / height) {
            // 12. 如果图片的宽度大于设定的宽度,调整宽度和高度
            if (ret.width > width) {
                ret.width = width; // 设置宽度为设定值
                ret.height = Math.ceil(width / scale); // 根据宽高比计算高度
            }
        } else {
            // 13. 如果图片的高度大于设定的高度,调整高度和宽度
            if (ret.height > height) {
                ret.height = height; // 设置高度为设定值
                ret.width = Math.ceil(height * scale); // 根据宽高比计算宽度
            }
        }
    }
    // 14. 如果只设置了宽度
    else if (width) {
        // 15. 如果图片的宽度大于设定的宽度,调整宽度和高度
        if (width < ret.width) {
            ret.width = width; // 设置宽度为设定值
            ret.height = Math.ceil(width / scale); // 根据宽高比计算高度
        }
    }
    // 16. 如果只设置了高度
    else if (height) {
        // 17. 如果图片的高度大于设定的高度,调整高度和宽度
        if (height < ret.height) {
            ret.width = Math.ceil(height * scale); // 根据宽高比计算宽度
            ret.height = height; // 设置高度为设定值
        }
    }

    // 18. 处理 iOS 设备的限制:
    //     - 如果宽度或高度超过 3264 或 2448,iOS 设备可能无法生成 base64
    //     - 逐步缩小图片尺寸,直到满足条件
    while (ret.width >= 3264 || ret.height >= 2448) {
        ret.width *= 0.8;  // 缩小宽度
        ret.height *= 0.8; // 缩小高度
    }

    // 19. 返回计算后的压缩尺寸
    return ret;
};
  • 功能:计算压缩后的图片尺寸。

  • 实现:根据配置的宽度、高度和图片的原始尺寸,计算压缩后的尺寸。

10. getJsDir 方法

function getJsDir(src) {
    // 1. 初始化变量 `script`,用于保存找到的脚本元素
    var script = null;

    // 2. 判断是否传入了 `src` 参数:
    //    - 如果传入了 `src`,表示需要根据 `src` 查找特定的脚本元素
    //    - 如果没有传入 `src`,表示需要获取当前页面中最后一个脚本元素
    if (src) {
        // 3. 使用 `Array.prototype.filter` 方法遍历页面中的所有脚本元素
        //    - `document.scripts` 返回页面中所有的 `
                    
                    

你可能感兴趣的:(javascript,前端,开发语言)