likes
comments
collection
share

🔪🔪🔪图片裁剪器✂✂✂一个相当简单好用的图片裁剪器,仅使用Javascript即可完成,可自由缩放大小,移动,实现

作者站长头像
站长
· 阅读数 52

写在开头

嘿嘿!各位早上好吖!👻

七月,对于小编来说是繁忙的,各种琐事缠身😔,但愿能赶紧挺过七月,迎来一个快乐的八月吧,还是开开心心当一条咸鱼的日子过得快乐啊。

还有,七月有了一个新的Flag,准备打卡满一个月的运动,运动对于小编之前来说并没有刻意去做,就是顺其自然(就是太懒😆)。而七月一号那天不知道抽什么风🤡,突然就想着需要开始运动了,那就行动起来吧。。。

小编选择的运动是步行,大概就是每天晚上会花一到两小时到处去走走,每天大概能走个五公里以上吧,快把居住的附近大街小巷给走熟了。

当前,Em...算是坚持住了,希望继续坚持下去吧,拭目以待哈。😋

🔪🔪🔪图片裁剪器✂✂✂一个相当简单好用的图片裁剪器,仅使用Javascript即可完成,可自由缩放大小,移动,实现

回到正题,这次要分享是一个图片裁剪器相关的内容,具体效果如下,请诸君按需食用。

🔪🔪🔪图片裁剪器✂✂✂一个相当简单好用的图片裁剪器,仅使用Javascript即可完成,可自由缩放大小,移动,实现

前置知识

🍊

在开始主题过程之前,咱们先来看一个小知识点,且看:

<!DOCTYPE html>
<html>
<head>
  <style>
    .box {
      width: 600px;
      height: 400px;
      border: 1px solid red;
      position: relative;
    }
    .mask {
      position: absolute;
      top: 0;
      right: 0;
      bottom: 0;
      left: 0;
      background-color: rgba(0, 0, 0, 0.5);
    }
  </style>
</head>
<body>
  <div class="box">
    <div class="mask"></div>
  </div>
</body>
</html>

很简单,有一个 .mask 元素会铺满 .box 元素,这个...就不用过多解释,相信都能理解哈。

🔪🔪🔪图片裁剪器✂✂✂一个相当简单好用的图片裁剪器,仅使用Javascript即可完成,可自由缩放大小,移动,实现

而当我们改变 .mask 元素的样式,如下:

🔪🔪🔪图片裁剪器✂✂✂一个相当简单好用的图片裁剪器,仅使用Javascript即可完成,可自由缩放大小,移动,实现

top/right/bottom/left 等属性可以替换成 inset 属性,即 inset: 10px 10px 10px 10px;inset 属于为它们的简写模式。

可以看到,通过改变 top/right/bottom/left 等属性,咱们也是能控制 .mask 元素的大小位置❗❗❗

如果咱们能动态不断去改变这些属性,那......

这个操作呢,也就是咱们最终案例中的那个框框变化大小与移动的原理所在了,有点意思不?😋

看了网上一些裁剪图片功能,这部分功能大多是通过宽度(width/height)与偏离量(translate)来完成,咱这也算是一个新思路吧。🙊

🍊🍊

再来看这个案例:

<div class="box">
  <div class="mask">
    <div class="mask__view"></div>
  </div>
</div>
.mask {
  position: absolute;
  top: 0px;
  right: 0px;
  bottom: 0px;
  left: 0px;
  background-color: rgba(0, 0, 0, 0.5);
}
.mask__view {
  width: 100%;
  height: 100%;
  background-image: url('https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/8506b8c045b644448b24c93d4ca90119~tplv-73owjymdk6-watermark.image?policy=eyJ2bSI6MywidWlkIjoiMTkwODQwNzkxOTE4NDY3MCJ9&rk3s=e9ecf3d6&x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&x-orig-expires=1720751671&x-orig-sign=1z9wkuIkI5wlSg43cAnqrhBvil8%3D');
  background-size: 100% 100%;
  clip-path: inset(50px 50px 50px 50px);
}

咱们给 .mask 元素增加了一个子元素(.mask__view),它占满父元素,并有一个背景图片,并通过 clip-path 属性进行了裁剪。

clip-path 属于不熟悉的小伙伴,可要去好好瞅瞅。传送门

效果如下:

🔪🔪🔪图片裁剪器✂✂✂一个相当简单好用的图片裁剪器,仅使用Javascript即可完成,可自由缩放大小,移动,实现

Em...怎么说呢,inset(50px 50px 50px 50px) 函数可以用来裁剪一个矩形,但要注意,它和我们上面提到的 inset 属性可不是同一个东西,一个是函数,一个是属性。但是呢,在此时的场景下,它们的应用又可以说两者是等同的。

从图可以看到,裁剪后,.mask__view 元素就剩下中间的矩形了,咱们也能瞅到 .mask 元素的淡黑色背景。

然后呢❓这有什么用❓

咱再来增加一个元素,如下:

<div class="box">
  <img style="width: 100%;height: 100%;" src="https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/8506b8c045b644448b24c93d4ca90119~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5qmZ5p-Q5Lq6:q75.awebp?rk3s=f64ab15b&x-expires=1728861933&x-signature=dhZ5gCGrR4wPh7mTEiUucb1TKNI%3D">
  <div class="mask">
    <div class="mask__view"></div>
  </div>
</div>

再来看效果:

🔪🔪🔪图片裁剪器✂✂✂一个相当简单好用的图片裁剪器,仅使用Javascript即可完成,可自由缩放大小,移动,实现

😦 这......

咱增加了一张图片,垫底用,就不会看到黑黑的四边了。

还没完,咱们来动态不断调整 inset() 函数的值:

🔪🔪🔪图片裁剪器✂✂✂一个相当简单好用的图片裁剪器,仅使用Javascript即可完成,可自由缩放大小,移动,实现

这像不像图片裁剪器变化大小时的样子?

好,两个前置小知识就讲到这里了,其实两个原理加起来就是整个图片裁剪器的整个原理过程了。最后,再次提醒,不要把 inset 属性与 inset() 函数搞混了,接下来,咱们就来看看最终案例的整体实现过程。

基础布局与样式

整个 HTML 结构可以分成下面的三个部分,自己瞅瞅哈。😋

<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="./style.css">
</head>
<body>
  <input id="file" type="file" />
  <div id="container" class="container">
    <!-- 底图 -->
    <img id="bgImage" width="100%" height="100%" />
    <!-- 中间预览区 -->
    <div id="mask" class="mask">
      <div id="maskView" class="mask__view"></div>
    </div>
    <!-- 裁剪器 -->
    <div id="cropper" class="cropper">
      <div id="cropperView" class="cropper__view">
        <span class="cropper-dashed dashed-h"></span>
        <span class="cropper-dashed dashed-v"></span>
        <span class="cropper-center"></span>
        <span class="cropper-move"></span>
        <span class="cropper-line line-n"></span>
        <span class="cropper-line line-e"></span>
        <span class="cropper-line line-s"></span>
        <span class="cropper-line line-w"></span>
        <span class="cropper-point point-e"></span>
        <span class="cropper-point point-n"></span>
        <span class="cropper-point point-w"></span>
        <span class="cropper-point point-s"></span>
        <span class="cropper-point point-nw"></span>
        <span class="cropper-point point-ne"></span>
        <span class="cropper-point point-se"></span>
        <span class="cropper-point point-sw"></span>
      </div>
    </div>
  </div>
</body>
</html>
/* style.css */
body {
    padding: 10px;
    margin: 0;
    height: 100vh;
    box-sizing: border-box;
}
.container {
    width: 600px;
    height: 400px;
    box-sizing: border-box;
    position: relative;
    margin-top: 10px;
}
/* 中间预览区 */
.mask {
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.5);
    position: absolute;
    top: 0;
    left: 0;
    display: none;
}
.mask__view {
    width: 100%;
    height: 100%;
    background-size: 100% 100%;
    clip-path: inset(0 0 0 0);
}
/* 裁剪器 */
.cropper {
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    left: 0;
    display: none;
}
.cropper__view {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    user-select: none;
    outline: 1px solid #39f;
}
.cropper-dashed { /* 虚线 */
    border: 0 dashed #eee;
    display: block;
    opacity: .5;
    position: absolute;
}
.cropper-dashed.dashed-h {
    border-bottom-width: 1px;
    border-top-width: 1px;
    height: 33.33333%;
    left: 0;
    top: 33.33333%;
    width: 100%;
}
.cropper-dashed.dashed-v {
    border-left-width: 1px;
    border-right-width: 1px;
    height: 100%;
    left: 33.33333%;
    top: 0;
    width: 33.33333%;
}
.cropper-center { /* 中心点 */
    display: block;
    height: 0;
    left: 50%;
    opacity: .75;
    position: absolute;
    top: 50%;
    width: 0;
}
.cropper-center:after, .cropper-center:before {
    background-color: #eee;
    content: " ";
    display: block;
    position: absolute;
}
.cropper-center:before {
    height: 1px;
    left: -3px;
    top: 0;
    width: 7px;
}
.cropper-center:after {
    height: 7px;
    left: 0;
    top: -3px;
    width: 1px;
}
.cropper-line { /* 四边线 */
    background-color: #39f;
    display: block;
    height: 100%;
    opacity: .1;
    position: absolute;
    width: 100%;
}
.cropper-line.line-e {
    cursor: e-resize;
    right: -3px;
    top: 0;
    width: 5px;
}
.cropper-line.line-n {
    cursor: n-resize;
    height: 5px;
    left: 0;
    top: -3px;
}
.cropper-line.line-w {
    cursor: w-resize;
    left: -3px;
    top: 0;
    width: 5px;
}
.cropper-line.line-s {
    bottom: -3px;
    cursor: s-resize;
    height: 5px;
    left: 0;
}
.cropper-point { /* 六个点 */
    background-color: #39f;
    height: 5px;
    opacity: .75;
    width: 5px;
    display: block;
    position: absolute;
}
.cropper-point.point-e {
    cursor: e-resize;
    margin-top: -3px;
    right: -3px;
    top: 50%;
}
.cropper-point.point-n {
    cursor: n-resize;
    left: 50%;
    margin-left: -3px;
    top: -3px;
}
.cropper-point.point-w {
    cursor: w-resize;
    left: -3px;
    margin-top: -3px;
    top: 50%;
}
.cropper-point.point-s {
    bottom: -3px;
    cursor: s-resize;
    left: 50%;
    margin-left: -3px;
}
.cropper-point.point-ne {
    cursor: ne-resize;
    right: -3px;
    top: -3px;
}
.cropper-point.point-nw {
    cursor: nw-resize;
    left: -3px;
    top: -3px;
}
.cropper-point.point-sw {
    bottom: -3px;
    cursor: sw-resize;
    left: -3px;
}
.cropper-point.point-se {
    bottom: -3px;
    cursor: se-resize;
    opacity: 1;
    right: -3px;
}
.cropper-move { /* 移动区 */
    display: block;
    height: 100%;
    opacity: .1;
    position: absolute;
    width: 100%;
    cursor: move;
    background-color: #fff;
    left: 0;
    top: 0;
}

案例全部的样式都在这里了,有点多,但其实并不复杂,就是为了构建裁剪器的样式,有八个点,四条边框线,中间四条虚线,还有中心点一个叉,大概就是这样。🙈

🔪🔪🔪图片裁剪器✂✂✂一个相当简单好用的图片裁剪器,仅使用Javascript即可完成,可自由缩放大小,移动,实现

具体逻辑实现

由于仅使用了 JS 来完成,所以咱们只能通过原生的API来获取一些 DOM 元素了。🙊

<script>
document.addEventListener("DOMContentLoaded", () => {
  const file = document.getElementById("file");
  const bgImage = document.getElementById("bgImage");
  const mask = document.getElementById("mask");
  const maskView = document.getElementById("maskView");
  const cropper = document.getElementById("cropper");
  const cropperView = document.getElementById("cropperView");
  
  // 监听图片上传
  file.addEventListener("change", (e) => {
    const target = e.target.files[0];
    const imgURL = URL.createObjectURL(target);
    bgImage.src = imgURL;
    maskView.style.backgroundImage = `url('${imgURL}')`;
    bgImage.onload = () => {
      createCropper();
    };
  });

  let initDimention = [50, 50, 50, 50];
  const TOP = 0, RIGHT = 1, BOTTOM = 2, LEFT = 3;
  
  /** @name 生成裁剪器 **/
  function createCropper() {
    mask.style.display = "block";
    cropper.style.display = "block";
    setDimention(initDimention);
  }

  /** @name 设置裁剪器尺寸 **/
  function setDimention(dimention) {
    // inset也可以换成top/right/bottom/left
    cropperView.style.inset = `${dimention[TOP]}px ${dimention[RIGHT]}px ${dimention[BOTTOM]}px ${dimention[LEFT]}px`;
    maskView.style.clipPath = `inset(${dimention[TOP]}px ${dimention[RIGHT]}px ${dimention[BOTTOM]}px ${dimention[LEFT]}px)`;
  }
});
</script>

setDimention 方法用于控制裁剪器的大小与移动,我们只要传入 dimention 参数就行,该参数是一个数组([0, 0, 0, 0]),固定有四项,代表 top/right/bottom/left 属性的值。

dimention 参数的值,与上一次相比,有一项或者两项值变化时,即是裁剪器的大小变化了;如果四项值都变化了,则是裁剪器移动了。😶

效果如下:

🔪🔪🔪图片裁剪器✂✂✂一个相当简单好用的图片裁剪器,仅使用Javascript即可完成,可自由缩放大小,移动,实现

布局这样子就算是完成了,比较简单哈,但裁剪器还无法操作,还有两个功能需要我们来实现,咱们一个一个来看。

大小变化

先来瞅瞅如何才能实现拖动裁剪器四周就能改变裁剪器的大小呢❓

先来给边框四周的元素(四条边框线、八个点)添加事件:

// 是否在拖动中
let dragging = false;
// 记录鼠标按下的位置
let startPoint = [0, 0];
// 当前裁剪器的实时尺寸
let currentDimention = [];
// 记录裁剪器开始的尺寸
let startDimention = [];

/** @name 生成裁剪器 **/
function createCropper() {
  mask.style.display = "block";
  cropper.style.display = "block";
  setDimention(initDimention);

  // 边框四周:四条边框线、八个点
  const elements = [...document.querySelectorAll(".cropper-line"), ...document.querySelectorAll(".cropper-point")];
  elements.forEach(ele => {
    // 添加鼠标按下事件
    ele.addEventListener("mousedown", e => {
      dragging = true;
      // 记录鼠标初始位置
      const { clientX, clientY } = e;
      startPoint[0] = clientX;
      startPoint[1] = clientY;
      // 记录裁剪器初始尺寸,注意浅拷贝一下
      startDimention = [...initDimention];
      // 记录裁剪器实时尺寸
      currentDimention = initDimention;
    });
  });
}

咱们存了四个变量,主要是标记是否开始拖动中、鼠标信息、裁剪器尺寸等,都是后续要用的一些变量,这里就先给全存上了。

咱监听了鼠标按下事件(mousedown),那就肯定还有 mousemovemouseup 事件要处理的😗,且看:

// 鼠标移动事件
document.body.addEventListener("mousemove", e => {
  if (!dragging) return;
  const { clientX, clientY } = e;
  // // 计算鼠标拖动的距离
  let diffX = clientX - startPoint[0];
  let diffY = clientY - startPoint[1];
  
  // 假设是拖动了顶部边框
  currentDimention[TOP] = startDimention[TOP] + diffY;

  setDimention(currentDimention);
});

// 鼠标按键抬起事件
document.body.addEventListener("mouseup", () => {
  dragging = false;
});

注意,这两个事件是要在 document 上监听的,原因嘛,你懂的。😋

咱们假设了当我们拖动的是顶部边框,效果如下:

🔪🔪🔪图片裁剪器✂✂✂一个相当简单好用的图片裁剪器,仅使用Javascript即可完成,可自由缩放大小,移动,实现

感觉还行吧?🙈

那么,可以推导出其他方向的边框,如下:

currentDimention[TOP] = startDimention[TOP] + diffY;
currentDimention[RIGHT] = startDimention[RIGHT] - diffX;
currentDimention[LEFT] = startDimention[LEFT] + diffX;
currentDimention[BOTTOM] = startDimention[BOTTOM] - diffY;

注意, rightbottom 是要减去鼠标移动的距离。

🔪🔪🔪图片裁剪器✂✂✂一个相当简单好用的图片裁剪器,仅使用Javascript即可完成,可自由缩放大小,移动,实现

现在,可不能直接把四个边框的赋值都加上,要不裁剪器就会变成移动的操作,不信你可以自个尝试看看。😁

接下来,我们得来确定拖动的是那个方向的边框,对应使用上面一边的赋值就行啦。

那么,如何来确定是那个方向的边框进行了拖动呢❓

方式有很多,最简单的是,当我们在按下鼠标的时候,进行标记就行了。当然,这是完全可以的,这种方式我们放到下面的"另一个版本实现"中实现,先来瞅瞅小编的这种:

// ...
// 记录哪个方向的边框进行了拖动,top=1; right=-1; bottom=-1; left=1;
let direction = [0, 0, 0, 0];

function createCropper() {
  // ...
  const moveElement = document.querySelector(".cropper-move");
  moveElement.addEventListener("mousemove", e => {
    if (dragging) return;
    const { clientX, clientY } = e;
    const { x: moveElementX, y: moveElementY} = moveElement.getBoundingClientRect();
    // dx越大越右,dy越大越向下
    const dx = clientX - moveElementX;
    const dy = clientY - moveElementY;
    
    // 靠近边框的距离,如当鼠标靠近顶部边框小于5时,意味想要拖动的顶部边框
    const threshold = 5;
    if (dy <= threshold) {
      // 顶部边框拖动
      direction[TOP] = 1;
      direction[BOTTOM] = 0;
    } else if (dy >= moveElement.clientHeight - threshold) {
      // 底部边框拖动
      direction[TOP] = 0;
      direction[BOTTOM] = -1;
    } else {
      // 不会是顶部或者底部的边框
      direction[TOP] = 0;
      direction[BOTTOM] = 0;
    }
    
    if (dx <= threshold) {
      // 左边边框拖动
      direction[LEFT] = 1;
      direction[RIGHT] = 0;
    } else if (dx >= moveElement.clientWidth - threshold) {
      // 右边边框拖动
      direction[LEFT] = 0;
      direction[RIGHT] = -1;
    } else {
      direction[LEFT] = 0;
      direction[RIGHT] = 0;
    }
  });
  
  // ...
}

咱们给 .cropper-move 元素添加一个 mousemove 事件,通过鼠标位置与元素位置计算出鼠标是接近于哪个方向的边框,从而能推导出哪个方向的边框可能将进行拖动的操作。

并且,使用了 direction 变量进行了记录,它是一个只有四项的数组。

🔪🔪🔪图片裁剪器✂✂✂一个相当简单好用的图片裁剪器,仅使用Javascript即可完成,可自由缩放大小,移动,实现

为什么要使用一个 direction 数组变量来记录拖动的边框呢❓

因为假设当 direction = [1, -1, 0, 0] 的时,咱们是能推导出是右上角的端点进行了拖动,这样就不用考虑端点的情况了,是不是稍微有点妙吧?😋

而这也是为什么一开始要使用只有四项的数组来存储裁剪器尺寸(currentDimention/startDimention/...)的原因了,两者其实是呼应的。😯

现在等于是有了拖动的目标标记,来看看拖动具体的处理过程:

currentDimention[TOP] = startDimention[TOP] + direction[TOP] * diffY;
currentDimention[RIGHT] = startDimention[RIGHT] + direction[RIGHT] * diffX;
currentDimention[BOTTOM] = startDimention[BOTTOM] + direction[BOTTOM] * diffY;
currentDimention[LEFT] = startDimention[LEFT] + direction[LEFT] * diffX;

直接将 currentDimention[TOP] = startDimention[TOP] + diffY; 替换成上面这四行即可,因为使用了乘法,当拖动 TOP 方向的时候,其他方向都是 0 ,乘完后就没了。😎

🔪🔪🔪图片裁剪器✂✂✂一个相当简单好用的图片裁剪器,仅使用Javascript即可完成,可自由缩放大小,移动,实现

现在四边与端点处都可以正常拖动变化大小了。

只是好像还有点奇怪,裁剪器会变成了一条线?这不是我们所期望的,咱们可以希望它能有一个最小的宽度与高度限制🚫。

其实就是处理一些边界情况,直接贴出最终的结果吧,如下:

// 最小宽度与高度
const minWidth = 30;
const minHeight = 30;
currentDimention[TOP] = Math.min(
  Math.max(startDimention[TOP] + direction[TOP] * diffY, 0),
  cropper.clientHeight - currentDimention[BOTTOM] - minHeight
);
currentDimention[RIGHT] = Math.min(
  Math.max(startDimention[RIGHT] + direction[RIGHT] * diffX, 0),
  cropper.clientWidth - currentDimention[LEFT] - minWidth
);
currentDimention[BOTTOM] = Math.min(
  Math.max(startDimention[BOTTOM] + direction[BOTTOM] * diffY, 0),
  cropper.clientHeight - currentDimention[TOP] - minHeight
);
currentDimention[LEFT] = Math.min(
  Math.max(startDimention[LEFT] + direction[LEFT] * diffX, 0),
  cropper.clientWidth - currentDimention[RIGHT] - minWidth
);

稍微有点复杂,细细瞅瞅看哈。

贴个辅助计算图:

🔪🔪🔪图片裁剪器✂✂✂一个相当简单好用的图片裁剪器,仅使用Javascript即可完成,可自由缩放大小,移动,实现

移动

好了,拖动改变大小整体大概就是这样了。接下来就是移动的操作,有了前面的铺垫,移动就很好解决了。

上述,咱们在前置知识讲过,在某些场景下,通过同时改变元素 top/right/bottom/left 四个属性就能控制其移动。

换成当前的情况,本质就是同时去改变 currentDimention 数组四个值,就能让裁剪器移动起来了。

来看看是如何做的:

// ...
// 是否在拖动中
let moving = false;

function createCropper() {
  // ...
  const moveElement = document.querySelector(".cropper-move");
  moveElement.addEventListener("mousemove", e => {
    // ...
    
    if (!direction.some((e) => e)) {//当 direction=[0, 0, 0, 0] 证明没有靠近边框,可能要进行移动了
      direction[TOP] = 1;
      direction[BOTTOM] = -1;
      direction[LEFT] = 1;
      direction[RIGHT] = -1;
      moving = true;
    } else {
      moving = false;
    }
  });
  
  // 四条边框线、八个点、移动元素moveElement
  const elements = [moveElement, ...document.querySelectorAll(".cropper-line"), ...document.querySelectorAll(".cropper-point")];
  // ...
}

document.body.addEventListener("mouseup", () => {
  dragging = false;
  moving = false;
});

moveElement 元素也添加 mousedown 事件,然后判断是边框的拖动还是想要移动,去改变 direction 的值。

移动效果:

🔪🔪🔪图片裁剪器✂✂✂一个相当简单好用的图片裁剪器,仅使用Javascript即可完成,可自由缩放大小,移动,实现

呃...有点问题吧,靠边的时候变小了?😐

这是因为没处理边界的情况,导致移动到边的时候裁剪器会变小。

解决:

// 鼠标移动事件
document.body.addEventListener("mousemove", e => {
  // ...
  
  // 处理移动的边框情况
  if (moving) {
    diffX = Math.min(
      Math.max(diffX, -startDimention[LEFT]),
      startDimention[RIGHT]
    );
    diffY = Math.min(
      Math.max(diffY, -startDimention[TOP]),
      startDimention[BOTTOM]
    );
  }
  
  // 最小宽度与高度
  // ...
});

这样就算是大功告成。😌

另一版本实现(推荐)

上面,咱们讲过"如何来确定是那个方向的边框进行了拖动呢❓"还有其他的方式,现在来看看是如何做的,也比较推荐这种方式,上面那种就当做是一个"过客"吧(快忘记快忘记)。🙊

<span class="cropper-line line-n" data-action="top"></span>
<span class="cropper-line line-e" data-action="right"></span>
<span class="cropper-line line-s" data-action="bottom"></span>
<span class="cropper-line line-w" data-action="left"></span>

<span class="cropper-point point-nw" data-action="top-left"></span>
<span class="cropper-point point-ne" data-action="top-right"></span>
<span class="cropper-point point-se" data-action="bottom-right"></span>
<span class="cropper-point point-sw" data-action="bottom-left"></span>

咱们先给四个边框与四个端点添加 data-* 信息。

修改 createCropper 方法:

/** @name 生成裁剪器 **/
function createCropper() {
  mask.style.display = "block";
  cropper.style.display = "block";
  setDimention(initDimention);

  const moveElement = document.querySelector(".cropper-move");

  // 四条边框线、八个点、移动元素moveElement
  const elements = [moveElement, ...document.querySelectorAll(".cropper-line"), ...document.querySelectorAll(".cropper-point")];
  elements.forEach(ele => {
    // 添加鼠标按下事件
    ele.addEventListener("mousedown", e => {
      dragging = true;
      const { clientX, clientY } = e;
      startPoint[0] = clientX;
      startPoint[1] = clientY;
      currentElement = ele;
      currentDimention = initDimention;
      startDimention = [...initDimention];
      
      // 当是移动元素时,改变direction变量
      if(ele === moveElement) {
        direction[TOP] = 1;
        direction[BOTTOM] = -1;
        direction[LEFT] = 1;
        direction[RIGHT] = -1;
        moving = true;
      }
      const action = ele.dataset.action;
      switch(action) {
        // 四条线
        case 'top':  direction[TOP] = 1; direction[BOTTOM] = 0; break;
        case 'right':  direction[LEFT] = 0;direction[RIGHT] = -1; break;
        case 'bottom':  direction[TOP] = 0;direction[BOTTOM] = -1; break;
        case 'left':  direction[LEFT] = 1;direction[RIGHT] = 0; break;
        // 四个端点
        case 'top-right':  direction[TOP] = 1;direction[RIGHT] = -1; break;
        case 'top-left':  direction[TOP] = 1;direction[LEFT] = 1; break;
        case 'bottom-left':  direction[BOTTOM] = -1;direction[LEFT] = 1; break;
        case 'bottom-right':  direction[BOTTOM] = -1;direction[RIGHT] = -1; break;
      }
    });
  });
}
// 鼠标按键抬起事件
document.body.addEventListener("mouseup", () => {
  dragging = false;
  moving = false;
  direction[TOP] = 0;
  direction[BOTTOM] = 0;
  direction[LEFT] = 0;
  direction[RIGHT] = 0;
});

主要修改了两个地方,把 .cropper-move 元素的 mousemove 事件给移除掉了,通过 data-* 来确定是那个方向的边框进行了拖动。

在鼠标抬起(mouseup)事件中做一些重置操作。

完整源码

传送门 👈👈👈


至此,本篇文章就写完啦,撒花撒花。

🔪🔪🔪图片裁剪器✂✂✂一个相当简单好用的图片裁剪器,仅使用Javascript即可完成,可自由缩放大小,移动,实现

希望本文对你有所帮助,如有任何疑问,期待你的留言哦。 老样子,点赞+评论=你会了,收藏=你精通了。

转载自:https://juejin.cn/post/7391160093565829160
评论
请登录