前端图片上传并且裁切_使用file 获取预览图 并且支持自定义剪切上传

这样就可以过滤掉非图片类型了。但是图片的类型可能也太多了, 有些可能服务器不支持,所以,如果想保守一些,只允许 jpg 和 png 类型,可以写成这样:

<input type="file" accept="image/jpg, image/jpeg, image/png">

或:

<input type="file" accept=".jpg, .jpeg, .png">

OK, 过滤非图片的需求搞定了。但是有时候 ,产品还要求只能从摄像头采集图片,比如需要上传证件照,防止从网上随便找别人的证件上传,那capture 属性就可以派上用场了:

<input type="file" accept="image/*" capture>

这时候,就不能从文件系统中选择照片了,只能从摄像头采集。到了这一步,可能觉得很完美了,但是还有个问题,可能有些变态产品要求默认打开前置摄像头采集图片,比如就是想要你的自拍照片。capture 默认调用的是后置摄像头。默认启用前置摄像头可以设置 capture="user" ,如下:

<input type="file" accept="image/*" capture="user">

好啦,关于选择图片的就讲么这么多了,有个注意的地方是,可能有些配置在兼容性上会有一些问题,所以需要在不同的机型上测试一下看看效果。

下面再来谈谈预览图片的实现。

预览图片

在远古时代,前端并没有预览图片的方法。当时的做法时,用户选择图片之后,立刻把图片上传到服务器,然后服务器返回远程图片的 url 给前端显示。这种方法略显麻烦,而且会浪费用户的流量,因为用户可能还没有确定要上传,你却已经上传了。幸好,远古时代已经离我们远去了,现代浏览器已经实现了前端预览图片的功能。常用的方法有两个,分别是 URL.createObjectURL() 和 FileReader 。虽然他们目前均处在 w3c 规范中的 Working Draft 阶段, 但是大多数的现代浏览器都已经良好的支持了。下面就介绍一下如何使用这两个方法。

1. 使用 URL.createObjectURL 预览

URL.createObjectURL() 静态方法会创建一个 DOMString,其中包含一个表示参数中给出的对象的 URL。这个 URL 的生命周期和创建它的窗口中的 document 绑定。这个新的URL 对象表示指定的 File 对象或 Blob 对象。用法用下:

objectURL = URL.createObjectURL(object);

其中,object 参数指 用于创建 URL 的 File 对象、Blob 对象或者 MediaSource 对象。

对于我们的 input[type=file] 而言, input.files[0] 可以获取到当前选中文件的 File 对象。示例代码如下:

<input id="inputFile" type="file" accept="image/*">
<img src="" id="previewImage" alt="图片预览">
<script>
    const $ = document.getElementById.bind(document);
    const $inputFile = $('inputFile');
    const $previewImage = $('previewImage');
    $inputFile.addEventListener('change', function() {
        const file = this.files[0];
        $previewImage.src = file ? URL.createObjectURL(file) : '';
    }, this);
</script>

具体用法可以参考 MDN上的  URL.createObjectURL(),

2. 使用 FileReader 预览

FileReader 对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。同理的,我们也可以通过 input.files[0] 获取到当前选中的图片的 File 对象。

特别注意,FileReader 和 是异步读取文件或数据的!

下面是使用 FileReader 预览图片的示例:

<input id="inputFile" type="file" accept="image/*">
<img src="" id="previewImage" alt="图片预览">
<script>
    const $ = document.getElementById.bind(document);
    const $inputFile = $('inputFile');
    const $previewImage = $('previewImage');
    $inputFile.addEventListener('change', function() {
        const file = this.files[0];
        const reader = new FileReader();
        reader.addEventListener('load', function() {
            $previewImage.src = reader.result;
        }, false);
        if (file) {
            reader.readAsDataURL(file);
        }
    }, false)
</script>

会发现, FileReader 会相对复杂一些.

更多关于 FileReader 的用法 ,可以参考 MDN 文档 FileReader

两种方法的对比

我个人更加倾向于使用 URL.createObjectURL() 。主要原先它的 API 简洁,同步读取,并且他返回的是一个 URL ,比 FileReaer 返回的base64 更加精简。兼容性上,两者都差不多,都是在 WD 的阶段。性能上的对比, 在 chrome 上, 选择了一张 2M 的图片, URL.createObjectURL() 用时是 0 , 而 FileReader 用时 20ms 左右。0 感觉不太合理,虽然这个方法立刻就会返回一个 URL ,但是我猜测实际上这个 URL 指定的内容还没有生成好,应该是异步生成的,然后才渲染出来的。所以并没有很好的办法来对比他们的性能。

如果想要学习更多关于图片预览,可以阅读以下两篇文章:

  • 使用FileReader实现前端图片预览
  • js图片/视频预览 - URL.createObjectURL()

裁剪图片

关于图片的裁剪,很自然的会想到使用 canvas ,确实是要通过  canvas, 但是如果全部我们自己来实现,可能需要做比较多的工作,所以为了省力,我们可以站在巨人的肩膀上。比较优秀的图片裁剪库是 cropperjs , 该库可以对图片进行缩放、移动和旋转。

cropperjs 的详细配置这里就不展开了 ,需要的可以自己去看文档就好。下面我们就以这个库为基础,实现一个裁剪人脸的例子:

<input id="inputFile" type="file" accept="image/*">
<img class="preview-image" id="previewImage" src="" alt="">
<!-- cropper裁剪框 -->
<div class="cropper" id="cropper">
    <div class="inner">
        <div class="face-container">
            <img class="cropper-image" id="cropperImage">
        </div>
        <div class="tips">请将面部区域置于人脸框架内</div>
        <div class="toolbar">
            <div class="btn" id="confirm">确认</div>
        </div>
    </div>
</div>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.6/cropper.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.6/cropper.min.js"></script>

<style>
    .preview-image,
    .cropper-image {
        max-width: 100%;
    }
    .cropper {
        display: none;
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        background: #ccc;
        font-size: 0.27rem;
        text-align: center;
    }
    .inner {
        height: 100%;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
    }
    .face-container {
        position: relative;
        width: 320px;
        height: 320px;
        margin: 50px auto;
    }
    .cropper-modal {
        background: url('https://ok.166.net/gameyw-misc/opd/squash/20191028/152551-m37snfsyu1.png') center no-repeat;
        background-size: 100% 100%;
        opacity: 1;
    }
    .cropper-bg {
        background: none;
    }
    .cropper-view-box {
        opacity: 0;
    }
    .tips {
        font-size: 16px;
    }
    .toolbar {
        display: flex;
        justify-content: center;
        margin: 50px 0;
    }
    .btn {
        width: 150px;
        line-height: 40px;
        font-size: 20px;
        text-align: center;
        color: #fff;
        background: #007fff;
    }
</style>

<script>
    const $ = document.getElementById.bind(document);
    const $cropper = $('cropper');
    const $inputFile = $('inputFile');
    const $previewImage = $('previewImage');
    const $cropperImage = $('cropperImage');
    const $confirmBtn = $('confirm')
    let cropperInstance = null;
    // 选择图片后,显示图片裁剪框
    $inputFile.addEventListener('change', function() {
        const file = this.files[0];
        if (!file) return;
        $cropperImage.src = URL.createObjectURL(file);
        showCropper();
    }, false);
    // 点击确认按钮,将裁剪好的图片放到 img 标签显示。
    $confirmBtn.addEventListener('click', function() {
        const url = cropperInstance.getCroppedCanvas().toDataURL("image/jpeg", 1.0);
        $cropper.style.display = 'none';
        $previewImage.src = url;
    }, false);
    function showCropper() {
        $cropper.style.display = 'block';
        cropperInstance && cropperInstance.destroy();
        cropperInstance = new Cropper($cropperImage, {
            viewMode: 1,
            aspectRatio: 1,
            autoCropArea: 1,
            dragMode: 'move',
            guides: false,
            highlight: false,
            cropBoxMovable: false,
### 最后

**[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://bbs.csdn.net/topics/618166371)**

**给大家分享一些关于HTML的面试题。**

![](https://img-blog.csdnimg.cn/img_convert/aa962b0d0c0dc8b25357024b6d59ffa3.webp?x-oss-process=image/format,png)
![](https://img-blog.csdnimg.cn/img_convert/429d85bab019b94469ef8553aa7a4080.webp?x-oss-process=image/format,png)



false,
            highlight: false,
            cropBoxMovable: false,
### 最后

**[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://bbs.csdn.net/topics/618166371)**

**给大家分享一些关于HTML的面试题。**

[外链图片转存中...(img-8ZBcvz5G-1714566991765)]
[外链图片转存中...(img-25kjqlNv-1714566991767)]



  • 7
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值