微信小程序实现图片拖拽调换位置效果 -- 开箱即用

news2025/1/9 1:29:22

在编写类似发布朋友圈功能的功能时,需要实现图片的拖拽排序,删除图片等功能。

一、效果展示在这里插入图片描述

**博主的小程序首页也采用了该示例代码,可以在威信中搜索:我的百宝工具箱
在这里插入图片描述

二、示例代码

1.1、在自己的小程序中创建组件
1.2、组件源码
  • wxml代码
    <view 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}}" mode="aspectFill"/>
        <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;">
        <text>+</text>
      </view>
    </view>
    
  • wxss代码
    .drag-container {
      position: relative;
      left: 30rpx;
      top: 20rpx;
    }
    
    .drag-item {
      position: absolute;
      top: 0;
      left: 0;
    }
    
    .drag-item-transition {
      transition: transform 0.1s
    }
    
    .drag-item-img {
      width: 100%;
      height: 100%;
    }
    
    .drag-item-delete {
      position: absolute;
      top: 0;
      right: 0;
    }
    
    .drag-item-delete_default {
      display: flex;
      width: 21px;
      height: 15px;
      line-height: 10px;
      justify-content: center;
      background-color: rgba(0, 0, 0, 0.7);
      border-radius: 0 0 0 12px;
      color: #FEFEFE;
    }
    
    .drag-upload {
      display: flex;
      justify-content: center;
      align-items: center;
      border: 2px dashed silver;
      width: 100%;
      height: 100%;
      box-sizing: border-box;
      font-size: 70px;
    }
    .drag-upload text{
      margin-top: -20%;
      color: silver;
    }
    
  • js代码
    Component({
      properties: {
        // 每个格子的大小 100*100
        previewSize: {
          type: Number,
          value: 100
        },
        // 默认图片列表
        defaultImgList: {
          type: Array,
          value: [],
          observer(t) {
            if (t?.length && !this.data.dragImgList.length) {
              const e = this.getDragImgList(t);
              this.setUploaPosition(e.length), this.setData({
                dragImgList: e
              })
            }
          }
        },
        // 最大个数
        maxCount: {
          type: Number,
          value: 9
        },
        // 每行列数
        columns: {
          type: Number,
          value: 3
        },
        // 每个格子之间的间隔
        gap: {
          type: Number,
          value: 9
        },
        deleteStyle: {
          type: String,
          value: ""
        }
      },
      data: {
        dragImgList: [],
        containerRes: {
          top: 0,
          left: 0,
          width: 0,
          height: 0
        },
        currentKey: -1,
        currentIndex: -1,
        tranX: 0,
        tranY: 0,
        uploadPosition: {
          tranX: 0,
          tranY: 0
        }
      },
      lifetimes: {
        ready() {
          this.createSelectorQuery().select(".drag-container").boundingClientRect((({
            top: t,
            left: e
          }) => {
            this.setData({
              "containerRes.top": t,
              "containerRes.left": e
            })
          })).exec()
        }
      },
      methods: {
        longPress(t) {
          const e = t.mark.index,
            {
              pageX: a,
              pageY: i
            } = t.touches[0],
            {
              previewSize: s,
              containerRes: {
                top: n,
                left: r
              }
            } = this.data;
          this.setData({
            currentIndex: e,
            tranX: a - s / 2 - r,
            tranY: i - s / 2 - n
          })
        },
        touchMove(t) {
          if (this.data.currentIndex < 0) return;
          const {
            pageX: e,
            pageY: a
          } = t.touches[0], {
            previewSize: i,
            containerRes: {
              top: s,
              left: n
            }
          } = this.data, r = e - i / 2 - n, o = a - i / 2 - s;
          this.setData({
            tranX: r,
            tranY: o
          });
          const h = t.mark.key,
            g = this.getMoveKey(r, o);
          h !== g && this.data.currentKey !== h && (this.data.currentKey = h, this.replace(h, g))
        },
        getMoveKey(t, e) {
          const {
            dragImgList: a,
            previewSize: i,
            columns: s
          } = this.data, n = (t, e) => {
            const a = Math.round(t / i);
            return a >= e ? e - 1 : a < 0 ? 0 : a
          }, r = s * n(e, Math.ceil(a.length / s)) + n(t, s);
          return r >= a.length ? a.length - 1 : r
        },
        replace(t, e) {
          const a = this.data.dragImgList;
          a.forEach((a => {
            t < e ? a.key > t && a.key <= e ? a.key-- : a.key === t && (a.key = e) : t > e && (a.key >= e && a.key < t ? a.key++ : a.key === t && (a.key = e))
          })), this.getListPosition(a)
        },
        getListPosition(t) {
          const {
            previewSize: e,
            columns: a,
            gap: i
          } = this.data, s = t.map((t => (t.tranX = (e + i) * (t.key % a), t.tranY = Math.floor(t.key / a) * (e + i), t)));
          this.setData({
            dragImgList: s
          }), this.updateEvent(s)
        },
        touchEnd() {
          this.setData({
            tranX: 0,
            tranY: 0,
            currentIndex: -1
          }), this.data.currentKey = -1
        },
        updateEvent(t) {
          const e = [...t].sort(((t, e) => t.key - e.key)).map((t => t.src));
          this.triggerEvent("updateImageList", {
            list: e
          })
        },
        async uploadImage() {
          let {
            dragImgList: t,
            maxCount: e
          } = this.data;
          try {
            const a = await wx.chooseMedia({
                count: e - t.length,
                mediaType: ["image"]
              }),
              i = this.getDragImgList(a?.tempFiles?.map((({
                tempFilePath: t
              }) => t)) || [], !1);
            t = t.concat(i), this.setUploaPosition(t.length), this.setData({
              dragImgList: t
            }), this.updateEvent(t)
          } catch (t) {
            console.log(t)
          }
        },
        getContainerRect(t) {
          const {
            columns: e,
            previewSize: a,
            maxCount: i,
            gap: s
          } = this.data, n = t === i ? t : t + 1, r = Math.ceil(n / e);
          return {
            width: e * a + (e - 1) * s,
            height: r * a + s * (r - 1)
          }
        },
        getDragImgList(t, e = !0) {
          let {
            dragImgList: a,
            previewSize: i,
            columns: s,
            gap: n
          } = this.data;
          return t.map(((t, r) => {
            const o = (e ? 0 : a.length) + r;
            return {
              tranX: (i + n) * (o % s),
              tranY: Math.floor(o / s) * (i + n),
              src: t,
              id: o,
              key: o
            }
          }))
        },
        setUploaPosition(t) {
          const {
            previewSize: e,
            columns: a,
            gap: i
          } = this.data, s = {
            tranX: t % a * (e + i),
            tranY: Math.floor(t / a) * (e + i)
          }, {
            width: n,
            height: r
          } = this.getContainerRect(t);
          this.setData({
            uploadPosition: s,
            "containerRes.width": n,
            "containerRes.height": r
          })
        },
        deleteImg(t) {
          const e = t.mark.key,
            a = this.data.dragImgList.filter((t => t.key !== e));
          a.forEach((t => {
            t.key > e && t.key--
          })), this.getListPosition(a), this.setUploaPosition(a.length)
        }
      }
    });
    
  • json代码
    {
      "component": true,
      "usingComponents":{}
    }
    
1.3、在自己的小程序中新建page
1.4、新建page的源码
  • wxml代码
    <view>
    	<wxDragImg
        	defaultImgList="{{imgList}}"
    		previewSize="{{120}}"
    		maxCount="{{9}}"
    		columns="{{3}}"
    		gap="{{10}}"
        	bind:updateImageList="updateImageList">
      </wxDragImg>
    </view>
    
  • js代码
    Page({
      data: {
        imgList: []
      },
      onLoad() {},
      updateImageList(e) {
        console.log(e)
      }
    })
    
  • json代码
    {
      "usingComponents": {
        "wxDragImg": "../wx-drag-img"
      }
    }
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2255142.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

import是如何“占领满屏“

import是如何“占领满屏“的&#xff1f; 《拒绝使用模块重导&#xff08;Re-export&#xff09;》 模块重导是一种通用的技术。在腾讯、字节、阿里等各大厂的组件库中都有大量使用。 如&#xff1a;字节的arco-design组件库中的组件&#xff1a;github.com/arco-design… …

鸿蒙分享(二):引入zrouter路由跳转+封装

码仓库&#xff1a;https://gitee.com/linguanzhong/share_harmonyos 鸿蒙api:12 鸿蒙第三方库地址&#xff1a;OpenHarmony三方库中心仓 zrouter地址&#xff1a;OpenHarmony三方库中心仓 1.引入zrouter 1.打开终端界面&#xff1a;输入 ohpm install hzw/zrouter 2.在项目…

第七节(2)、T型加减速优化处理【51单片机-TB6600驱动器-步进电机教程】

摘要&#xff1a;本节介绍解决标准T型加减速过程中的两个缺陷&#xff0c;其一是使得初速度任意设置&#xff1b;其二是降低Cn递推计算量&#xff0c;提升速度上限 一. 加速减速过程计算 1.1计算不存在匀速过程 根据基本运动定理&#xff1a; w m a x w 0 a 0 ∗ t n 0 … …

MySQL--用户权限

1.使用root用户登录MySQL客户端&#xff0c;创建一个名为userl的用户&#xff0c;初始密码为123456;创建一个名为user2的用户&#xff0c;无初始密码。然后&#xff0c;分别使用uesr1、user2登录MySQL 客户端。 创建两个用户 使用user1登录 使用user2登录 2.使用root用户登录&a…

最新版Chrome谷歌加载ActiveX控件之金格iWebOffice2015控件

allWebPlugin简介 allWebPlugin中间件是一款为用户提供安全、可靠、便捷的浏览器插件服务的中间件产品&#xff0c;致力于将浏览器插件重新应用到所有浏览器。它将现有ActiveX控件直接嵌入浏览器&#xff0c;实现插件加载、界面显示、接口调用、事件回调等。支持Chrome、Firefo…

实现跨平台 SSH 连接:从 macOS 到 Windows WSL 的完整解决方案20241203

&#x1f310; 实现跨平台 SSH 连接&#xff1a;从 macOS 到 Windows WSL 的完整解决方案 ✨ 引言 随着跨平台开发的普及&#xff0c;开发者经常需要在多系统环境中切换和协作。尤其是在 macOS 和 Windows 混合使用的开发环境中&#xff0c;通过 SSH 远程访问和管理 Windows …

C语言——习题练习(一)

习题&#xff1a; 现在有两种面值的邮票&#xff0c;一种为8角&#xff0c;一种为6角。你要付n角的邮资&#xff08;不能多付也不能少付&#xff09;&#xff0c;请给出邮票张数最少的方案。如果没有正好的方案则输出-1。 输入格式: 只有一行&#xff0c;为若干个整数&#xf…

Redis 数据结结构(一)—字符串、哈希表、列表

Redis&#xff08;版本7.0&#xff09;的数据结构主要包括字符串&#xff08;String&#xff09;、哈希表&#xff08;Hash&#xff09;、列表&#xff08;List&#xff09;、集合&#xff08;Set&#xff09;、有序集合&#xff08;Sorted Set&#xff09;、超日志&#xff08…

短视频矩阵系统saas源码 ---技术源头搭建部署

短视频矩阵系统源码 短视频矩阵系统源码主要有三种框架&#xff1a;Spring、Struts和Hibernate。Spring框架是一个全栈式的Java应用程序开发框架&#xff0c;提供了IOC容器、AOP、事务管理等功能。Struts框架是一个MVC架构的Web应用程序框架&#xff0c;用于将数据模型、Web应用…

李飞飞:Agent AI 多模态交互的前沿探索

发布于:2024 年 11 月 27 日 星期三 北京 #RAG #李飞飞 #Agent #多模态 #大模型 Agent AI在多模态交互方面展现出巨大潜力,通过整合各类技术,在游戏、机器人、医疗等领域广泛应用。如游戏中优化NPC行为,机器人领域实现多模态操作等。然而,其面临数据隐私、偏见、可解释性…

macOS 15.1.1 (24B2091) 系统中快捷键符号及其代表的按键的对照表

以下是 macOS 15.1.1 (24B2091) 系统中快捷键符号及其代表的按键的对照表&#xff1a; 符号按键名称描述⌘Command (Cmd)常用的功能键&#xff0c;用于执行大多数快捷操作。⌥Option (Alt)Option 键&#xff0c;常用于辅助操作和特殊字符输入。⇧ShiftShift 键&#xff0c;常用…

开源即时通讯与闭源即时通讯该怎么选择,其优势是什么?

在选择即时通讯软件时&#xff0c;应根据企业的经营领域来选择适合自身需求的开源或闭源方案。不同领域对开源和闭源即时通讯的理念存在差异&#xff0c;因此总结两个点简要分析这两种选择&#xff0c;有助于做出更明智的决策。 一、开源与闭源的根本区别在于软件的源代码是否…

学习记录:js算法(一百一十七):重新安排行程

文章目录 重新安排行程思路一 重新安排行程 给你一份航线列表 tickets &#xff0c;其中 tickets[i] [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。 所有这些机票都属于一个从 JFK&#xff08;肯尼迪国际机场&#xff09;出发的先生&#xff0c…

如何制作“优美”PPT

目录 1.免费PPT模板网站&#xff1a; 2.免费有较好质量的图片网站&#xff1a; 免费图片资源 免费透明PNG图片资源&#xff1a; 免费icon图片资源&#xff1a; 3.选择好的图片&#xff1a; 图片底色 4.要与不要 千万不要&#xff1a; 一定要&#xff1a; 6.一些建议…

从excel数据导入到sqlsever遇到的问题

1、格式问题时间格式&#xff0c;excel中将日期列改为日期未生效&#xff0c;改完后&#xff0c;必须手动单击这个单元格才能生效&#xff0c;那不可能一个一个去双击。解决方案如下 2、导入之后表字段格式问题&#xff0c;数据类型的用navicat导入之后默认是nvarchar类型的&a…

Python办公—DataMatrix二维条码制作

目录 专栏导读1、库的介绍2、库的安装3、核心代码4、完整代码总结专栏导读 🌸 欢迎来到Python办公自动化专栏—Python处理办公问题,解放您的双手 🏳️‍🌈 博客主页:请点击——> 一晌小贪欢的博客主页求关注 👍 该系列文章专栏:请点击——>Python办公自动化专…

偏标记学习+图像分类

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

pdf转word/markdown等格式——MinerU的部署:2024最新的智能数据提取工具

一、简介 MinerU是开源、高质量的数据提取工具&#xff0c;支持多源数据、深度挖掘、自定义规则、快速提取等。含数据采集、处理、存储模块及用户界面&#xff0c;适用于学术、商业、金融、法律等多领域&#xff0c;提高数据获取效率。一站式、开源、高质量的数据提取工具&…

fedora下Jetbrains系列IDE窗口中文乱码解决方法

可以看到窗口右部分的中文内容为小方块。 进入 Settings - Appearance & Behavior - Appearance - Use custom font : Note Sans Mono CJK SC &#xff0c;设置后如下图&#xff1a;

机器学习详解(2):线性回归之理论学习

文章目录 1 监督学习2 线性回归2.1 简单/多元线性回归2.2 最佳拟合线2.3 成本函数和梯度下降2.4 线性回归的假设2.5 线性回归的评估指标函数 3 总结 机器学习是人工智能的一个分支&#xff0c;主要致力于开发能够从数据中学习并进行预测的算法和统计模型。线性回归是机器学习的…