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

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

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

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

二、示例代码

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"
      }
    }
    

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring框架-IoC的使用(基于XML和注解两种方式)

一、Spring IoC使用-基于XML 1 IoC使用-基于XML 使用SpringIoC组件创建并管理对象 1.1 创建实体类 package com.feng.ioc.bean;import java.util.Date;/*** program: spring-ioc-demo1* description: 学生实体类* author: FF* create: 2024-12-04 18:53**/ public class Stud…

圆通开放平台快递物流查询API对接流程

作为一家深受用户信赖的快递物流服务商&#xff0c;圆通快递通过开放平台为用户提供高效的快递物流查询API。圆通开放平台是将圆通下单、轨迹、工单及基础服多种服务接口通过开放平台赋能客户&#xff0c;帮助客户快速建立全面的物流解决方案的共联平台。平台现有接口文档统一管…

如何防御ARP欺骗 保护IP安全

在数字化浪潮席卷全球的今天&#xff0c;网络安全威胁如同暗流涌动&#xff0c;时刻考验着我们的防范能力。其中&#xff0c;ARP欺骗攻击作为一种隐蔽性强、成本低廉且危害严重的网络攻击手段&#xff0c;成为众多网络安全事件中的一颗“毒瘤”。那么我们究竟是如何防御ARP欺骗…

云数据库 HBase

HBase 是一个分布式、可扩展的列式 NoSQL 数据库&#xff0c;源自 Google 的 Bigtable 论文&#xff0c;并是 Apache Hadoop 生态系统的一部分。它特别适用于需要处理大规模数据集的场景&#xff0c;尤其是那些要求高吞吐量和低延迟的数据访问。HBase 支持分布式存储&#xff0…

泷羽sec学习打卡-shell命令8

声明 学习视频来自B站UP主 泷羽sec,如涉及侵权马上删除文章 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都 与本人无关,切莫逾越法律红线,否则后果自负 关于shell的那些事儿-shell8 until循环(直到为止)case语句func函数定义实践是检验真理的唯一标准 别问&…

车机端同步outlook日历

最近在开发一个车机上的日历助手&#xff0c;其中一个需求就是要实现手机端日历和车机端日历数据的同步。然而这种需求似乎没办法实现&#xff0c;毕竟手机日历是手机厂商自己带的系统应用&#xff0c;根本不能和车机端实现数据同步的。 那么只能去其他公共的平台寻求一些机会&…

从零开始学TiDB(1) 核心组件架构概述

首先TiDB深度兼容MySQL 5.7 1. TiDB Server SQL语句的解析与编译&#xff1a;首先一条SQL语句最先到达的地方是TiDB Server集群&#xff0c;TiDB Server是无状态的&#xff0c;不存储数据&#xff0c;SQL 发过来之后TiDB Server 负责 解析&#xff0c;优化&#xff0c;编译 这…

Linux絮絮叨(三) Ubuntu桌面版添加中文拼音输入法

步骤很详细&#xff0c;直接上教程 一. 配置安装简体拼音输入法 #安装相应的平台支持包 sudo apt install ibus-gtk ibus-gtk3# 安装简体拼音输入法 sudo apt install ibus-pinyin安装完成如果下面的步骤找不到对应输入法可以重启一下&#xff0c;一般不需要 二. 添加简体拼音…

RTCMultiConnection 跨域问题解决

js套件地址 https://github.com/muaz-khan/RTCMultiConnection server套件地址 https://github.com/muaz-khan/RTCMultiConnection-Server 要解决的就是server代码的跨域问题 原装写法&#xff1a; 解决写法&#xff1a; // 喜欢组合语法的自己组 const io new ioServer.S…

在 Zemax 中使用 CAD 镜头的逆向血眼模型

Zemax 中的眼睛模型涉及模拟人眼的光学特性。该模型通常包括代表角膜、晶状体、房水、玻璃体和视网膜的各种成分。 屈光不正的眼睛是具有屈光不正的眼睛&#xff0c;这意味着它不能将光线正确聚焦在视网膜上&#xff0c;导致视力模糊。屈光不正是存在屈光不正的状态&#xff0…

WebStorm快捷键保持跟Idea一致

修改连续行局部多选 在WebStorm中同时按下ctrl alt s&#xff1b; 选择KeyMap 输入Column Selection Mode选择快捷键, 右键选择Add Mouse Shortcut 按下alt 鼠标左键 如果出现占用的情况&#xff0c;直接删除其他使用该快捷键的地方即可&#xff1b; 修改跨行局部多选 在…

如何查看电脑的屏幕刷新率?

1、按一下键盘的 win i 键&#xff0c;打开如下界面&#xff0c;选择【系统】&#xff1a; 2、选择【屏幕】-【高级显示设置】 如下位置&#xff0c;显示屏幕的刷新率&#xff1a;60Hz 如果可以更改&#xff0c;则选择更高的刷新率&#xff0c;有助于电脑使用起来界面更加流…

【AI模型对比】Kimi与ChatGPT的差距:真实对比它们在六大题型中的全面表现!

文章目录 Moss前沿AI语义理解文学知识数学计算天文学知识物理学知识英语阅读理解详细对比列表总结与建议 Moss前沿AI 【OpenAI】获取OpenAI API Key的多种方式全攻略&#xff1a;从入门到精通&#xff0c;再到详解教程&#xff01;&#xff01; 【VScode】VSCode中的智能AI-G…

WPF编写工业相机镜头选型程序

该程序满足面阵和线阵的要求。 前端代码 <Window x:Class"相机镜头选型.MainWindow" Loaded"Window_Loaded"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml…

若依 ruoyi VUE el-select 直接获取 选择option 的 label和value

1、最新在研究若依这个项目&#xff0c;我使用的是前后端分离的方案&#xff0c;RuoYi-Vue-fast(后端) RuoYi-Vue-->ruoyi-ui(前端)。RuoYi-Vue-fast是单应用版本没有区分那么多的modules 自己开发起来很方便&#xff0c;这个项目运行起来很方便&#xff0c;但是需要自定义的…

【深入探索 C++ STL 双端队列 】deque —— 数据时空的双端虫洞,扭曲常规操作的效率边界

STL系列专栏&#xff1a; C STL系列__Zwy的博客-CSDN博客https://blog.csdn.net/bite_zwy/category_12838593.html?spm1001.2014.3001.5482学习C STL的三个境界&#xff0c;会用&#xff0c;明理&#xff0c;能扩展&#xff0c;STL中的所有容器都遵循这个规律&#xff0c;下面…

DevOps系统设计和技术选型

命名是一件痛苦的事情&#xff0c;除非你不想要一个好名字。 我正在做的这个管理系统叫什么合适&#xff0c;或者是什么类型的系统&#xff0c;想去想来不知所措&#xff0c;后来想想这么小的东西纠结什么&#xff0c;先从小的细节一点点来&#xff0c;能用就行&#xff0c;就用…

20241206-Windows 10下使用IDEA 2024.2.3(JDK 18.0.2.1)搭建Hadoop 3.3.6开发环境

Windows 10下使用IDEA 2024.2.3(JDK 18.0.2.1)搭建Hadoop 3.3.6开发环境 1. 配置好本地hadoop之后 2. idea 新建或导入 Maven 项目 3. 编写 pom.xml 文件: 有些版本和项目信息需要根据自己的项目进行调整 JDK 18.0.2.1 Hadoop 3.3.6 <?xml version"1.0" encod…

C#Treeview

创建一个Windows应用程序&#xff0c;在默认窗体中添加一个TreeView控件、一个ImageList控件和一个ContextMenuStrip控件&#xff0c;其中&#xff0c;TreeView控件用来显示部门结构&#xff0c;ImageList控件用来存储TreeView控件中用到的图片文件&#xff0c;ContextMenuStri…

pytorch多GPU训练教程

pytorch多GPU训练教程 文章目录 pytorch多GPU训练教程1. Torch 的两种并行化模型封装1.1 DataParallel1.2 DistributedDataParallel 2. 多GPU训练的三种架构组织方式2.2 数据不拆分&#xff0c;模型拆分&#xff08;Model Parallelism&#xff09;2.3 数据拆分&#xff0c;模型…