npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

cxj-react-imagetlb

v0.1.0

Published

cxj-react-image 用法如下:

Readme

cxj-react-image 用法如下:

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

<ImageModal 
  src={imageList[currentImageIndex]}  {/* 当前图片路径 */}
  next={() => 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`;
};