前端 JS 经典:图片裁剪上传原理

前言:图片裁剪一般都是用户选择头像时用到,现在很多插件都可以满足这个功能,但是我们不仅要会用插件,还要自己懂的裁剪原理。

1. 流程

流程分为:1. 预览本地图片 2. 选择裁剪区域 3. 上传裁剪图像

2. 如何预览图片

通过 FileReader 构造函数,将本地的图片,转换成 base64 的地址,不通过网络请求,直接预览。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta
      name="viewport"
      content="initial-scale=1.0, user-scalable=no, width=device-width"
    />
    <title>document</title>
    <style>
      .preview {
        width: 500px;
        height: 500px;
        margin: 0 auto;
        object-fit: cover;
      }
    </style>
  </head>
  <body>
    <input type="file" />
    <img class="preview" />
    <script>
      const inp = document.querySelector("input");
      const img = document.querySelector("img");

      inp.onchange = (e) => {
        const file = e.target.files[0];
        const reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = () => {
          img.src = reader.result;
        };
      };
    </script>
  </body>
</html>

3. 上传裁剪后图片

实现思路:上传图片本质是上传文件,我们需要得到一个文件 file 对象,怎么拿到 file 对象呢,通过 canvas 画出裁剪图然后导出为 blob 对象,然后将 blob 对象转为 file 对象我们就可以进行上传了。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta
      name="viewport"
      content="initial-scale=1.0, user-scalable=no, width=device-width"
    />
    <title>document</title>
    <style>
      .preview {
        width: 500px;
        height: 500px;
        margin: 0 auto;
        object-fit: cover;
      }
    </style>
  </head>
  <body>
    <input type="file" />
    <img class="preview" />
    <button>点击上传裁剪图</button>
    <script>
      const inp = document.querySelector("input");
      const img = document.querySelector("img");
      const btn = document.querySelector("button");

      inp.onchange = (e) => {
        const file = e.target.files[0];
        const reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = () => {
          img.src = reader.result;
        };
      };

      function uploadResult({ cutWidth, cutHeight, cutX, cutY }) {
        const cvs = document.createElement("canvas");
        const ctx = cvs.getContext("2d");
        cvs.width = 200;
        cvs.height = 200;
        ctx.drawImage(
          img,
          cutX,
          cutY,
          cutWidth,
          cutHeight,
          0,
          0,
          cvs.width,
          cvs.height
        );
        document.body.appendChild(cvs);
        cvs.toBlob((blob) => {
          const file = new File([blob], "cut.png", { type: "image/png" });

          // 上传 file 对象
          console.log(file);
        });
      }

      btn.onclick = () => {
        uploadResult({
          cutWidth: 100,
          cutHeight: 100,
          cutX: 250,
          cutY: 250,
        });
      };
    </script>
  </body>
</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yqcoder

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值