资讯专栏INFORMATION COLUMN

多功能React影像组件(拖拽、水印、缩放、切换、旋转)

soasme / 3771人阅读

摘要:移动的过程中可以通过拿到元素的坐标,记为。向上滚动放大,向下滚动缩小这里要注意控制最小缩放值。还要注意的是图片在边界的缩放,不然图片可能会移动在屏幕外。代码实现控制滚轮缩放计算缩放后的大小每一次滚轮限制最小不让由于缩小消失在视野中

cxj-react-image 用法如下:

yarn add cxj-react-image
// npm i cxj-react-image
import ImageModal from "cxj-react-image";

 this.next()}            {/* 控制下一张 */}
  prev={() => this.prev()}            {/* 控制上一张 */}
  closeModal={() => this.closeImg()}  {/* 控制modal打开关闭 */}
  option={{
    move: true,                        {/* 控制拖动 */}
    waterMarkText: "多功能图片组件",    {/* 设置水印文字 */}
    rotate: true,                      {/* 控制旋转 */}
    zoom: true                         {/* 控制放大缩小 */}
  }}
/>

更详细的用法请参考 container.js文件

github地址

在线例子

如有帮助,感谢star~ 如有问题,欢迎call me~

交流请加wx: c13266836563



以下为相关实现讲解

拖拽

实现拖拽的思路是计算出dom最后的left跟top。

未移动前可以通过clientX跟offsetLeft拿到dom的x坐标和左边距,记为initX和offLeft

移动的过程中可以通过clientX拿到元素的x坐标,记为moveX

得到公式:left = moveX - initX + offLeft

核心代码如下:

const move = (dv) => {
  // 获取元素
  let x = 0;
  let y = 0;
  let l = 0;
  let t = 0;
  let isDown = false;
  // 鼠标按下事件
  dv.onmousedown = function(e) {
    // 获取x坐标和y坐标
    x = e.clientX;
    y = e.clientY;

    // 获取左部和顶部的偏移量
    l = dv.offsetLeft;
    t = dv.offsetTop;
  
    handleMove();
  };
  // 鼠标移动
  // 再包一层是为了方便注册 避免被替换
  function handleMove() {
    onmousemove = function(e) { 
      // 获取x和y
      let nx = e.clientX;
      let ny = e.clientY;

      // 计算移动后的左偏移量和顶部的偏移量
      let nl = nx - (x - l);
      let nt = ny - (y - t);

      dv.style.left = nl + "px";
      dv.style.top = nt + "px";
    };
  }
};

关于拖拽,有个情况还需要优化:页面上有两个modal,要保证最后点击的modal要覆盖之前点击的modal。

也就是zIndex要控制好,这里用localStorage来保存这个最大的zIndex

imageModalMaxzIndex = localStorage.getItem("imageModalMaxzIndex");
if (dv.style.zIndex != imageModalMaxzIndex) {
  dv.style.zIndex = +imageModalMaxzIndex + 1;
  localStorage.setItem("imageModalMaxzIndex", dv.style.zIndex);
}

水印

前端实现水印,避免私密图片泄露

思路是使用canvas生成文字图片,然后利用以下的css:

background-image:url("${base64Url}");

background-repeat:repeat;

实现水印类:

/**
 * @overview: 水印组件
 */

export default class WaterMark {
  constructor(container, option) {
    this.container = container;
    this.option = {
      width: "200px",
      height: "150px",
      opacity: .7,
      fillStyle: "rgba(47, 205, 227, 0.3)",
      font: "20px microsoft yahei",
      textBaseline: "middle",
      textAlign: "center",
      fillText: "水印",
      ...option
    };
  }
    
  draw() {
    const { 
      container, 
      option: {
        width,
        height,
        opacity,
        fillStyle,
        font,
        textBaseline,
        textAlign,
        fillText,
        scrollHeight
      } 
    } = this;
    const canvas = document.createElement("canvas");
    canvas.setAttribute("width", width);
    canvas.setAttribute("height", height);
    canvas.setAttribute("opacity", opacity);
    const ctx = canvas.getContext("2d");
  
    ctx.textAlign = textAlign;
    ctx.textBaseline = textBaseline;
    ctx.font = font;
    ctx.fillStyle = fillStyle;
    ctx.rotate(Math.PI / 180 * 30);
    ctx.fillText(fillText, 80, 10);
        
    var base64Url = canvas.toDataURL();
    const watermarkDiv = document.createElement("div");
    watermarkDiv.setAttribute("style", `
          position:absolute;
          top:0;
          left:0;
          width:100%;
          height:${scrollHeight || "100%"};
          z-index:1000;
          pointer-events:none;
          background-repeat:repeat;
          background-image:url("${base64Url}")`);
  
    if (typeof container === "object") {
      container.style.position = "relative";
      container.insertBefore(watermarkDiv, container.firstChild);
    }
  }
}

这里有一篇文章总结了几种前端水印的方案,推荐给大家 文章

缩放

缩放的话,监听鼠标滚动事件。向上滚动放大,向下滚动缩小;这里要注意控制最小缩放值。

还要注意的是图片在边界的缩放,不然图片可能会移动在屏幕外。

需要做的处理是判断左边界跟图片的宽度。

代码实现:

// 控制滚轮缩放

const zoom = (onWheelEvent, dom) => {
  let e = onWheelEvent;
  let imageModalWidth = parseInt(dom.style.width);
  let modalLeft = parseInt(dom.style.left);
      
  // 计算缩放后的大小 每一次滚轮 100px
  let calcWidth = imageModalWidth - e.deltaY;                 
      
  // 限制最小 width = 400
  if (calcWidth <= 300) {
    return;
  }
    
  // 不让modal由于缩小消失在视野中
  if (modalLeft + calcWidth < 50) {
    return;
  }
      
  dom.style.width = `${calcWidth}px`;
};

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/99806.html

相关文章

  • 基于javascript的拖拽类封装

    摘要:参考了很多别人写的代码,最后终于弄明白了其中的原理,自己也写了一个。效果图如下地址如下拖拽类封装代码使用方法引入和对应的。如果没有为的结构,就创建。鼠标移动时,记录再次计算鼠标位置距离中心位置的的反正切函数。 在公司做一个h5编辑平台,中间需要对元素进行拖拽、放大缩小、旋转等操作,且需要对文本、图片、音乐组件等不同元素都可以具备这些功能。参考了很多别人写的代码,最后终于弄明白了其中的原...

    afishhhhh 评论0 收藏0
  • 用typescript开发手势库 - (1)web开发常用手势有哪些?

    这只是个开头 说在最前面,本文是一个系列文章的开头, 这个系列里我会讲如何用typescript开发一款支持pc和手机端的手势库any-touch, 以及通过jest让你的代码测试覆盖率100%. showImg(https://segmentfault.com/img/bVbp3B0?w=936&h=246); 目录 用TypeScript开发手势库 - (2)tsconfig.json & r...

    raise_yang 评论0 收藏0
  • 超级小的web手势库AlloyFinger发布

    摘要:拥有两个版本,无依赖的独立版和版本。除了对象,也可监听内元素的手势需要引擎内置对象支持绑定相关事件。据不完全统计,目前服务于兴趣部落群动漫腾讯学院腾讯等多个部门团队和项目。也可以在事件回调里根据携带的信息使用去操作。 简介 针对多点触控设备编程的Web手势组件,快速帮助你的web程序增加手势支持,也不用再担心click 300ms的延迟了。拥有两个版本,无依赖的独立版和react版本。...

    ymyang 评论0 收藏0
  • 一言不合造轮子--撸一个ReactTimePicker

    摘要:时间选择的表盘其实有两个,一个是小时的选择,另一个则是分钟的选择。也就是说,第一步选择小时,第二部选择分钟它是一个小时制的时间选择器。而则用于处理拖拽事件,标记着当前是否处于被拖拽状态。 本文的源码全部位于github项目仓库react-times,如果有差异请以github为准。最终线上DEMO可见react-times github page 文章记录了一次创建独立React组件...

    lifesimple 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<