沃梦达 / IT编程 / 前端开发 / 正文

基于touch.js手势库+zepto.js插件开发图片查看器(滑动、缩放、双击缩放)

首先讲一下所需工具:

首先讲一下所需工具:

  • touch.js:一款轻量级的移动端手势库,用于实现图片的缩放、滑动等手势操作;
  • Zepto.js:一款轻量级的JavaScript库,可用于DOM操作、事件绑定等常见操作。

如果你已经准备好了这些工具,接下来我们就可以开始制作基于touch.js和Zepto.js的图片查看器了。

步骤一、创建HTML结构

首先我们需要先创建出HTML结构,这个结构比较简单,主要就是一个包含图片的div容器。

<div class="image-viewer">
  <img src="example.jpg" alt="example image">
</div>

其中的class可以用于样式设置和JS操作。

步骤二、调用touch.js和Zepto.js库

我们需要在HTML文件中引入touch.js和zepto.js库,代码如下:

<script src="./path/to/touch.js"></script>
<script src="./path/to/zepto.js"></script>

引入之后我们就可以使用库中的方法和函数了。

步骤三、添加基本样式

若要使图片查看器显示正常,我们需要为其添加一些基本样式,主要是设置图片容器的宽度、高度等。

.image-viewer {
  width: 100%;
  height: 100%;
  overflow: hidden;
  position: relative;
}

.image-viewer img {
  max-width: 100%;
  max-height: 100%;
  display: block;
  margin: auto;
}

以上代码主要功能为设置图片容器为相对定位和隐藏溢出部分,同时设置图片为居中显示。

步骤四、编写js代码实现手势操作

接下来我们就开始编写JavaScript代码来实现手势操作。

首先,我们需要给图片容器添加touchstart、touchmove、touchend事件,用于在触摸时实现滑动、缩放等操作。代码如下:

const imgViewer = document.querySelector('.image-viewer');

let initScale = 1; // 初始缩放比例
let curScale = 1; // 当前缩放比例
let prevDistance = 0; // 前一时刻的两个手指的距离
let startX, startY, moveX, moveY, lastMoveX = 0, lastMoveY = 0; // 手指的初始位置和移动距离
let isSingleTap = false; // 是否为单击事件
let isDoubleTap = false; // 是否为双击事件
let lastTapTime = null; // 上一次触摸结束的时间

let isTouchStart = false; // 是否触摸开始

imgViewer.addEventListener('touchstart', function(e) {
  e.preventDefault();
  isTouchStart = true;

  // 判断是否为双击事件
  let currentTapTime = Date.now();
  if (lastTapTime !== null && currentTapTime - lastTapTime < 300) {
    isDoubleTap = true;
  } else {
    isSingleTap = true;
    lastTapTime = currentTapTime;
  }

  // 获取初始位置
  startX = e.touches[0].pageX;
  startY = e.touches[0].pageY;

  // 重置相关值
  lastMoveX = moveX;
  lastMoveY = moveY;
  prevDistance = 0;
});

imgViewer.addEventListener('touchmove', function(e) {
  e.preventDefault();

  // 获取移动距离
  moveX = e.touches[0].pageX - startX + lastMoveX;
  moveY = e.touches[0].pageY - startY + lastMoveY;

  if (e.touches.length > 1) { // 处理双指操作
    isSingleTap = false;

    let distance = Math.sqrt(
      (e.touches[1].pageX - e.touches[0].pageX) ** 2 +
      (e.touches[1].pageY - e.touches[0].pageY) ** 2);

    if (prevDistance !== 0) {
      curScale = curScale * (distance / prevDistance);
      imgViewer.style.transform = `scale(${curScale}) translate(${moveX}px, ${moveY}px)`;
    }
    prevDistance = distance;
  } else { // 处理单指操作
    isDoubleTap = false;
    curScale = initScale;
    imgViewer.style.transform = `scale(${curScale}) translate(${moveX}px, ${moveY}px)`;
  }
});

imgViewer.addEventListener('touchend', function(e) {
  e.preventDefault();
  if (isSingleTap) {
    // 处理单击事件
  } else if (isDoubleTap) {
    // 处理双击事件
  }

  // 重置相关值
  prevDistance = 0;
  isSingleTap = false;
  isDoubleTap = false;

  // 是否触摸结束
  isTouchStart = false;
});

以上代码主要处理了以下事件:

  • touchstart:获取触摸开始的位置,并判断是否为单击或双击事件;
  • touchmove:获取触摸滑动的距离,并实现图片的移动和缩放操作;
  • touchend:处理单击和双击事件,同时重置相关变量。

步骤五、实现双击操作和缩放操作

实现双击操作主要需要在touchstart、touchend事件中对isDoubleTap进行判断,并在touchstart事件中记录下当前时间,用于判断两次触摸间隔是否小于300ms。若是,则视为双击。

imgViewer.addEventListener('touchstart', function(e) {
  // 判断是否为双击事件
  let currentTapTime = Date.now();
  if (lastTapTime !== null && currentTapTime - lastTapTime < 300) {
    isDoubleTap = true;
  } else {
    isSingleTap = true;
    lastTapTime = currentTapTime;
  }

  // ...
});

imgViewer.addEventListener('touchend', function(e) {
  // 处理双击事件
  if (isDoubleTap) {
    if (curScale === initScale) {
      // 如果当前缩放比例为1,则双击放大
      curScale = 2;
      imgViewer.style.transform = `scale(${curScale}) translate(${moveX}px, ${moveY}px)`;
    } else {
      // 如果当前缩放比例大于1,则双击缩小至初始比例
      curScale = initScale;
      imgViewer.style.transform = `scale(${curScale}) translate(0, 0)`;
    }
  }

  // ...
});

实现缩放操作其实就是在touchmove事件中对curScale进行计算,并实时更新图片的缩放比例和位置。

imgViewer.addEventListener('touchmove', function(e) {
  // 获取移动距离
  moveX = e.touches[0].pageX - startX + lastMoveX;
  moveY = e.touches[0].pageY - startY + lastMoveY;

  if (e.touches.length > 1) { // 处理双指操作
    // ...

    if (prevDistance !== 0) {
      curScale = curScale * (distance / prevDistance);
      imgViewer.style.transform = `scale(${curScale}) translate(${moveX}px, ${moveY}px)`;
    }

    // ...
  } else { // 处理单指操作
    // ...

    curScale = initScale;
    imgViewer.style.transform = `scale(${curScale}) translate(${moveX}px, ${moveY}px)`;

    // ...
  }
});

步骤六、完善单击事件和完整代码

最后,我们需要完善单击事件,通过判断触摸开始和触摸结束的时间间隔来区分单击和长按事件。代码如下:

imgViewer.addEventListener('touchstart', function(e) {
  // 记录触摸开始的时间
  touchStartTime = Date.now();
  // ...
});

imgViewer.addEventListener('touchend', function(e) {
  // 记录触摸结束的时间
  touchEndTime = Date.now();
  // 判断是否为单击事件或长按事件
  if (isTouchStart && touchEndTime - touchStartTime <= 350) {
    // 处理单击事件
  } else if (isTouchStart && touchEndTime - touchStartTime > 350) {
    // 处理长按事件
  }
  // ...
});

完整代码如下:

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>图片查看器</title>
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <style type="text/css">
    .image-viewer {
      width: 100%;
      height: 100%;
      overflow: hidden;
      position: relative;
    }

    .image-viewer img {
      max-width: 100%;
      max-height: 100%;
      display: block;
      margin: auto;
    }
  </style>
</head>

<body>
  <div class="image-viewer">
    <img src="example.jpg" alt="example image">
  </div>
  <script src="./path/to/touch.js"></script>
  <script src="./path/to/zepto.js"></script>
  <script type="text/javascript">
    const imgViewer = document.querySelector('.image-viewer');

    let initScale = 1; // 初始缩放比例
    let curScale = 1; // 当前缩放比例
    let prevDistance = 0; // 前一时刻的两个手指的距离
    let startX, startY, moveX, moveY, lastMoveX = 0, lastMoveY = 0; // 手指的初始位置和移动距离
    let isSingleTap = false; // 是否为单击事件
    let isDoubleTap = false; // 是否为双击事件
    let lastTapTime = null; // 上一次触摸结束的时间

    let isTouchStart = false; // 是否触摸开始
    let touchStartTime, touchEndTime; // 触摸开始和结束的时间

    imgViewer.addEventListener('touchstart', function(e) {
      e.preventDefault();

      // 判断是否为双击事件
      let currentTapTime = Date.now();
      if (lastTapTime !== null && currentTapTime - lastTapTime < 300) {
        isDoubleTap = true;
      } else {
        isSingleTap = true;
        lastTapTime = currentTapTime;
      }

      // 记录触摸开始的位置
      startX = e.touches[0].pageX;
      startY = e.touches[0].pageY;

      // 重置相关值
      lastMoveX = moveX;
      lastMoveY = moveY;
      prevDistance = 0;

      // 记录触摸开始的事件
      touchStartTime = Date.now();

      isTouchStart = true;
    });

    imgViewer.addEventListener('touchmove', function(e) {
      e.preventDefault();

      // 获取移动距离
      moveX = e.touches[0].pageX - startX + lastMoveX;
      moveY = e.touches[0].pageY - startY + lastMoveY;

      if (e.touches.length > 1) { // 处理双指操作
        isSingleTap = false;

        let distance = Math.sqrt(
          (e.touches[1].pageX - e.touches[0].pageX) ** 2 +
          (e.touches[1].pageY - e.touches[0].pageY) ** 2);

        if (prevDistance !== 0) {
          curScale = curScale * (distance / prevDistance);
          imgViewer.style.transform = `scale(${curScale}) translate(${moveX}px, ${moveY}px)`;
        }
        prevDistance = distance;
      } else { // 处理单指操作
        isDoubleTap = false;
        curScale = initScale;
        imgViewer.style.transform = `scale(${curScale}) translate(${moveX}px, ${moveY}px)`;
      }
    });

    imgViewer.addEventListener('touchend', function(e) {
      e.preventDefault();

      // 记录触摸结束的时间
      touchEndTime = Date.now();

      if (isSingleTap) {
        // 处理单击事件
        if (isTouchStart && touchEndTime - touchStartTime <= 350) {
          // 处理单击事件
        }
      } else if (isDoubleTap) {
        // 处理双击事件
        if (curScale === initScale) {
          // 如果当前缩放比例为1,则双击放大
          curScale = 2;
          imgViewer.style.transform = `scale(${curScale}) translate(${moveX}px, ${moveY}px)`;
        } else {
          // 如果当前缩放比例大于1,则双击缩小至初始比例
          curScale = initScale;
          imgViewer.style.transform = `scale(${curScale}) translate(0, 0)`;
        }
      }

      // 重置相关值
      prevDistance = 0;
      isSingleTap = false;
      isDoubleTap = false;

      // 是否触摸结束
      isTouchStart = false;
    });
  </script>
</body>

</html>

以上就是基于touch.js和zepto.js的图片查看器的完整攻略,其中包含了双击、滑动、缩放等多个手势操作,可以应用于各类移动端H5网站和APP开发中。

本文标题为:基于touch.js手势库+zepto.js插件开发图片查看器(滑动、缩放、双击缩放)