微信小程序图片拖拽排序组件

这篇具有很好参考价值的文章主要介绍了微信小程序图片拖拽排序组件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

  • 图片拖拽排序是一个比较常用的组件,常用于发帖或者评论等内容上传模块,我借鉴了《一款优雅的小程序拖拽排序组件实现》这篇文章的拖拽思路,封装成wx-drag-img发布到npm
    微信小程序图片拖拽排序组件

  • 实现原理:每个图片初始化我都会封装成一个拖拽的数据结构,然后通过触发touch事件,根据key的变化改变transform位置,从而达到拖拽效果

  • 功能包括图片上传拖拽删除,源码和npm地址我会贴在结尾,如果感觉好的话,欢迎star

  • 我会在下面逐步分析这个组件的实现思路

  • 使用了以下变量文章来源地址https://www.toymoban.com/news/detail-488935.html

// 拖拽数据结构
interface IDragImg {
  src: string; // 图片路径
  key: number; // 
  id: number; // for循环遍历使用, 不会改变, 创建时自增id
  tranX: number; // x轴位移距离
  tranY: number; // y轴位移距离
}

// props
{
  previewSize // 图片大小
  defaultImgList // 初始化图片数组
  maxCount // 图片上传数量限制
  columns // 列数
  gap // 图片间隔
  deleteStyle // 删除样式
}

data: {
  dragImgList: IDragImg[],
  containerRes: {
    top: 0, // 容器距离页面顶部距离 px
    left: 0, // 容器距离页面左边距离 px
    width: 0, // 容器宽度 px
    height: 0, // 容器高度 px
  }, // 拖拽容器属性
  currentKey: -1, // 正在拖拽图片的key
  currentIndex: -1, // 正在拖拽图片的index
  tranX: 0, // 正在拖拽图片移动的x距离
  tranY: 0, // 正在拖拽图片移动的y距离
  uploadPosition: { // upload上传图标位移距离
    tranX: 0,
    tranY: 0,
  }
},

WXML

<view style="width: {{containerRes.width}}px; height: {{containerRes.height}}px;" class="drag-container">
  <view
    wx:for="{{dragImgList}}"
    wx:key="id"
    style="transform: translate({{index === currentIndex ? tranX : item.tranX}}px, {{index === currentIndex ? tranY : item.tranY}}px); z-index: {{index === currentIndex ? 10 : 1}}; width: {{previewSize}}px; height: {{previewSize}}px;"
    class="drag-item drag-item-transition"
    mark:index="{{index}}"
    mark:key="{{item.key}}"
    catch:longpress="longPress"
    catch:touchmove="touchMove"
    catch:touchend="touchEnd"
  >
    <image class="drag-item-img" src="{{item.src}}"/>
    <!-- 删除图标 -->
    <view catch:tap="deleteImg" mark:key="{{item.key}}" class="drag-item-delete">
      <view class="drag-item-delete_default" style="{{deleteStyle}}">x</view>
    </view>
  </view>

  <!-- 上传图片 -->
  <view
    bindtap="uploadImage"
    class="drag-item drag-upload"
    hidden="{{dragImgList.length >= maxCount}}"
    style="transform: translate({{uploadPosition.tranX}}px, {{uploadPosition.tranY}}px); width: {{previewSize}}px; height: {{previewSize}}px;"
  >
    <view class="drag-upload_solt">
      <slot name="upload"></slot>
    </view>
    <view class="drag-upload_default">
      <text>+</text>
    </view>
  </view>
</view>

图片上传

  • 图片上传很简单,就是初始化上传的图片,然后拼接到现有图片,最后修改上传图标位置即可
  • 点击上传区域回调函数uploadImage
/**
 * 上传图片
 */
async uploadImage() {
  let { dragImgList, maxCount } = this.data;
  try {
    const res = await wx.chooseMedia({
      count: maxCount - dragImgList.length,
      mediaType: ['image'],
    });
    // 获取上传图片数据后需要初始化图片拽结构
    const imgList = this.getDragImgList(res?.tempFiles?.map(({ tempFilePath }) => tempFilePath) || [], false);
    dragImgList = dragImgList.concat(imgList);
    // 修改上传区域位置
    this.setUploaPosition(dragImgList.length);
    this.setData({
      dragImgList,
    });
    this.updateEvent(dragImgList);
  } catch (error) {
    console.log(error);
  }
},
  • 上传后需要初始化拖拽的数据结构
/**
 * 根据图片列表生成拖拽列表数据结构
 * @param list 图片src列表
 * @param init 是否是初始化
 */
 getDragImgList(list, init = true) {
  let { dragImgList, previewSize, columns, gap } = this.data;
  return list.map((item, index) => {
    const i = (init ? 0 : dragImgList.length) + index;
    return {
      tranX: (previewSize + gap) * (i % columns),
      tranY: Math.floor(i / columns) * (previewSize + gap),
      src: item,
      id: i,
      key: i,
    };
  });
},
  • 修改上传区域位置
/**
 * 修改上传区域位置
 * @param listLength 数组长度
 */
setUploaPosition(listLength) {
  const { previewSize, columns, gap } = this.data;
  const uploadPosition = {
    tranX: listLength % columns * (previewSize + gap),
    tranY: Math.floor(listLength / columns) * (previewSize + gap),
  };
  const { width, height } = this.getContainerRect(listLength);
  this.setData({
    uploadPosition,
    ['containerRes.width']: width,
    ['containerRes.height']: height,
  });
},
  • 图片数量改变后就要重新获取容器宽高了
/**
 * 改变图片数量后获取容器宽高
 * @parma listLength 数组长度
 */
getContainerRect(listLength) {
  const { columns, previewSize, maxCount, gap } = this.data;
  const number = listLength === maxCount ? listLength : listLength + 1;
  const row = Math.ceil(number / columns)
  return {
    width: columns * previewSize + (columns - 1) * gap,
    height: row * previewSize + gap * (row - 1),
  };
},
  • updateEvent
/**
 * updateEvent
 * @describe 上传删除拖拽后触发事件把列表数据发给页面
 */
updateEvent(dragImgList) {
  const list = [...dragImgList].sort((a, b) => a.key - b.key).map((item) => item.src);
    this.triggerEvent('updateImageList', {
      list,
  });
},

图片删除

  • 首先从图片列表中删除所需图片,然后修改列表,把大于所选图片key的key全部减一,最后计算剩余图片位置和上传图标位置
/**
 * 删除图片
 */
deleteImg(e) {
  const key = e.mark.key;
  const list = this.data.dragImgList.filter((item) => item.key !== key);
  // 大于删除图片key的key全部减1
  list.forEach((item) => {
    item.key > key && item.key--;
  });
  // 获取
  this.getListPosition(list);
  this.setUploaPosition(list.length);
},
/**
 * 计算数组的位移位置
 * @param list 拖拽图片数组
 */
getListPosition(list) {
  const { previewSize, columns, gap } = this.data;
  const dragImgList = list.map((item) => {
    item.tranX = (previewSize + gap) * (item.key % columns);
    item.tranY = Math.floor(item.key / columns) * (previewSize + gap);
    return item;
  })
  this.setData({
    dragImgList,
  });
  this.updateEvent(dragImgList);
},

图片拖拽

初始化

  • 初始化只需获取容器的位置信息即可,因为拖拽组件不一定是在页面的左上角,所以需要知道容器的位置信息
lifetimes: {
  ready() {
    this.createSelectorQuery()
      .select(".drag-container")
      .boundingClientRect(({ top, left }) => {
        this.setData({
          ['containerRes.top']: top,
          ['containerRes.left']: left,
        });
      }).exec();
  }
},

longPress

  • 这里采用longPress,而不是touchStart的原因,一是为了优化体验,二是touchStart与删除按钮冲突
/**
 * 长按图片
 */
longPress(e) {
  const index = e.mark.index;
  const { pageX, pageY } = e.touches[0];
  const { previewSize, containerRes: { top, left } } = this.data;
  this.setData({
    currentIndex: index,
    tranX: pageX - previewSize / 2 - left,
    tranY: pageY - previewSize / 2 - top,
  });
},

touchMove

  • touchMove首先计算出位移距离,然后根据位移距离求出停放位置的key,如果不一样就修改位置
  • touchMove
/**
 * touchMove
 */
touchMove(e) {
  // 如果currentIndex < 0,说明并没有触发longPress
  if (this.data.currentIndex < 0) {
    return;
  }
  const { pageX, pageY } = e.touches[0];
  const { previewSize, containerRes: { top, left } } = this.data;
  const tranX = pageX - previewSize / 2 - left;
  const tranY = pageY - previewSize / 2 - top;
  this.setData({
    tranX,
    tranY
  });
  // 对比当前移动的key和停放位置的key,如果不一样就修改位置
  const currentKey = e.mark.key;
  const moveKey = this.getMoveKey(tranX, tranY);

  // 当移动的key和正在停放位置的key相等,就无须处理
  if (currentKey === moveKey || this.data.currentKey === currentKey) {
    return;
  }
  this.data.currentKey = currentKey;
  this.replace(currentKey, moveKey);
},
  • getMoveKey
/**
 * 计算移动中的key
 * @param tranX 正在拖拽图片的tranX
 * @param tranY 正在拖拽图片的tranY
 */
getMoveKey(tranX, tranY) {
  const { dragImgList: list, previewSize, columns } = this.data;
  const _getPositionNumber = (drag, limit) => {
    const positionNumber = Math.round(drag / previewSize);
    return positionNumber >= limit ? limit - 1 : positionNumber < 0 ? 0 : positionNumber;
  }
  const endKey = columns * _getPositionNumber(tranY, Math.ceil(list.length / columns)) + _getPositionNumber(tranX, columns);
  return endKey >= list.length ? list.length - 1 : endKey;
},
  • replace
/**
 * 生成拖拽后的新数组
 * @param start 拖拽起始的key
 * @param end 拖拽结束的key
 */
replace(start, end) {
  const dragImgList = this.data.dragImgList;
  dragImgList.forEach((item) => {
    if (start < end) {
      if (item.key > start && item.key <= end) item.key--;
      else if (item.key === start) item.key = end;
    } else if (start > end) {
      if (item.key >= end && item.key < start) item.key++;
      else if (item.key === start) item.key = end;
    }
  });
  this.getListPosition(dragImgList);
},

touchEnd

  • touchEnd用于重置数据
/**
 * touchEnd
 */
touchEnd() {
  this.setData({
    tranX: 0,
    tranY: 0,
    currentIndex: -1,
  });
  this.data.currentKey = -1;
},

总结

  • repo
  • npm

参考资料

  • 一款优雅的小程序拖拽排序组件实现

到了这里,关于微信小程序图片拖拽排序组件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 微信小程序 实现最简单的组件拖拽

    最近在自主学习微信小程序的开发;对于零基础入门(没有学习过前端)的我,查阅了许多微信小程序拖拽的实现,大部分要么实现起来太复杂了,要么封装组件太复杂了,附带了拖拽之后排序等功能;因此写下这篇个人觉得最好理解的 微信小程序元素拖拽的实现; 这边采用了

    2024年02月09日
    浏览(67)
  • 微信小程序中的拖拽和缩放图片功能

    在现代的移动应用开发中,拖拽和缩放功能变得越来越重要。它们不仅使应用程序更具交互性,还为用户提供了更直观、更高效的使用体验。微信小程序作为一个流行的开发平台,也提供了这样的功能。以下是在微信小程序中实现拖拽和缩放图片的步骤和注意事项。 1.设置图

    2024年03月14日
    浏览(50)
  • 基于movable-view的微信小程序拖拽排序(含源码)

    目录 一、前言与效果展示 二、源码 1.目录结构 2.drag.wxml文件 3.drag.wxss文件 (1)drag.less (2)drag.wxss  不会使用less的就用这个 4.drag.js文件 5.drag.json文件 三、结语         最近在做一个账本,里面有个功能需要“拖拽排序”,网上的代码我也看不太懂,打算自己写一个。微信

    2024年02月03日
    浏览(44)
  • 微信小程序使用image组件显示图片的方法

    本文实例讲述了微信小程序使用image组件显示图片的方法。分享给大家供大家参考,具体如下: 1、效果展示 2、关键代码 ① index.wxml 代码如下: image style=\\\"width: 300px; height: 300px; margin:10px;\\\" mode=\\\"scaleToFill\\\" src=\\\"{{imageSrc}}\\\"/image ② index.js Page({ data:{ // text:\\\"这是一个页面\\\" imageSrc:\\\'../..

    2024年02月12日
    浏览(92)
  • 微信小程序 怎么插入图片?image组件的使用教程。

    这期我们来学学怎么在小程序中插入图片         是小程序中一个图片的组件         image组件有一个默认宽度和高度(宽300px,高240px)         支持 JPG、PNG、SVG、WEBP、GIF 等格式,2.3.0 起支持云文件ID。 我们先添加一个image组件给他一个边框看看他的默认情况  我们从

    2023年04月09日
    浏览(65)
  • 基于vue element-ui 封装上传图片组件 功能:上传,删除,预览,上传图片水印,拖拽排序,上传进度条等

    我们在开发后台时肯定避免不了上传图片的功能 例如: 上传图片回显 上传完成 : 预览查看 , 删除等 如果是图片列表,还可能让你拖动图片排序 有的后台项目可能要给图片添加水印,添加标记 有的后台可能要炫酷一点 添加进度条功能 现在我们要完成上面的一系列功能,这里我

    2024年02月16日
    浏览(59)
  • 小程序封装拖拽菜单组件(uniapp拖拽排序,自定义菜单)

    使用movable-area作为可移动区域,并在内部循环渲染列表项view,绑定touch事件。 在mounted生命周期函数内获取区域movable-area的dom信息,记录列表项的坐标信息。 在methods中定义了列表项的touchstart、touchmove和touchend事件的方法,用于实现列表项的拖拽移动和位置变更。 watch监听列表项数

    2023年04月20日
    浏览(32)
  • 【微信小程序】图片上传组件“mp-uploader“(weui)

       wxml    json    js    weui 是微信官方提供的一款小程序插件,是一套基于样式库 weui-wxss 开发的小程序扩展组件库,同微信原生视觉体验一致的UI组件库,由微信官方设计团队和小程序团队设计。官方文档:https://wechat-miniprogram.github.io/weui/docs/。   图片上传组件

    2024年02月11日
    浏览(53)
  • 微信小程序---图片裁剪、旋转、预览、上传功能实现(已经封装成组件,需要的到资源下载)

    1、可以拍摄或选择本地图片上传图片数据 2、图片上传数据可以进行裁剪、选择、取消、裁剪后预览、上传以及限制大小,还可以缩放操作,需要的可以解除限制即可 1、点击图片上传按钮时,跳转页面到cropper进行图片选择剪切 wx.navigateTo({       url: `/pages/cropper/cropper?d

    2023年04月26日
    浏览(76)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包