前端vue3——实现二次元人物拼图校验

文章目录

    • ⭐前言
    • ⭐vue3拖拽实现拼图
      • 💖 思路分解
      • 💖 布局结构
      • 💖 拖拽函数
      • 💖 校验函数
      • 💖 inscode整体代码
    • ⭐运行效果
      • 💖 随机顺序
      • 💖 拖拽中
      • 💖 校验失败
      • 💖 校验通过
    • ⭐总结
    • ⭐结束

yma16-logo

⭐前言

大家好,我是yma16,本文分享关于 前端vue3——实现二次元人物拼图校验。
vue3系列相关文章:
vue3 + fastapi 实现选择目录所有文件自定义上传到服务器
前端vue2、vue3去掉url路由“ # ”号——nginx配置
csdn新星计划vue3+ts+antd赛道——利用inscode搭建vue3(ts)+antd前端模板
认识vite_vue3 初始化项目到打包
python_selenuim获取csdn新星赛道选手所在城市用echarts地图显示
让大模型分析csdn文章质量 —— 提取csdn博客评论在文心一言分析评论区内容
前端vue3——html2canvas给网站截图生成宣传海报
拖拽相关文章
前端——html拖拽原理

前端html拖拽原理
HTML 拖拽的基本原理是通过鼠标事件和 DOM 操作来实现的。

一般来说,拖拽操作包括三个阶段:

  1. 鼠标按下事件:当用户按下鼠标左键时,触发鼠标按下事件。在该事件处理函数中,首先需要记录下被拖拽元素的相关信息,比如该元素的位置、大小和初始鼠标点击位置等。

  2. 鼠标移动事件:当用户按下鼠标左键时并拖动鼠标时,触发鼠标移动事件。在该事件处理函数中,需要根据鼠标当前位置和拖拽元素的初始位置,计算出该元素要被移动的距离,并在 DOM 中更新该元素的位置。

  3. 鼠标松开事件:当用户松开鼠标左键时,触发鼠标松开事件。在该事件处理函数中,需要清除拖拽元素的相关信息,比如初始鼠标点击位置等。

在以上三个阶段中,需要使用的 DOM 操作包括:

  1. 获取 DOM 元素:可以使用 document.getElementById() 或 document.querySelector() 等方法来获取需要拖拽的元素。

  2. 更新元素位置:可以使用元素的 style 属性来修改元素的位置,比如设置元素的 left 和 top 属性。

  3. 创建新元素:可以使用 document.createElement() 方法来创建新的 DOM 元素。

通过以上鼠标事件和 DOM 操作的组合,可以实现基本的 HTML 拖拽功能。

⭐vue3拖拽实现拼图

使用vue3和原生的html drag 实现片的拖拽

💖 思路分解

  1. 拆分图片为4宫格样式
  2. 定义拖拽的样式div对应图片的4宫格
  3. 定义拖拽的div元素,背景图片使用图片拆分的素材
  4. 给元素定义序号
  5. 校验最终的元素序号,判断是否拼图成功

拆分图片
split-image

💖 布局结构

才有左右布局
左侧:拖拽来源区域
右侧:拖拽放入区域
template布局

<template><div class="container-drag"><div style="width: 100%;text-align:center;margin: 10px;"><a-button type="primary" class="random-button" @click="randomDragOrder">随机顺序</a-button></div><div class="container-drag-box"><div class="container-drag-left"><!-- <> --><div v-for="item in state.dragConfig.sourceArray" :key="item.id" class="drag-item-box":id="state.dragConfig.sourceDomPrefix + '-' + item.id"><div class="drag-item" draggable="true" :id="state.dragConfig.dragDomPrefix + '-' + item.id"><!-- 拖拽对象 data-order 校验排序用 --><img :src="item.src" width="280" height="280" :data-order="item.id" /></div></div></div><div class="container-drag-right" id="target-box-id"><!-- 目标对象 data-order 校验排序用--><div v-for="item in state.dragConfig.sourceArray" :key="item" class="target-item-box dropzone":id="state.dragConfig.targetDomPrefix + '-' + item.id" :data-order="item.id"></div></div></div><div style="width: 100%;text-align:center"><a-button type="primary" @click="confirmImg">确定</a-button></div></div>
</template>

css配置

<style>
.container-drag {min-width: 800px;
}.random-button {margin: 5px;cursor: pointer;
}.container-drag-box {display: flex;justify-content: space-between;
}.container-drag-left {width: 800px;}.container-drag-right {width: 600px;height: 600px;margin: 0;
}.drag-item-box {display: inline-block;margin: 2px;padding: 0;width: 280px;height: 280px;border: 1px solid rgb(24, 144, 255);overflow: hidden;}.target-item-box {display: inline-block;width: 280px;height: 280px;border: 1px solid rgb(255, 255, 255);box-sizing: border-box;overflow: hidden;margin-right: 5px;margin-bottom: 0;margin-top: 0;
}/* 拖拽对象 */
.drag-item {margin: 0;text-align: center;cursor: pointer;
}/* 拖拽中 */
.dragging {opacity: .5;
}/* 悬浮上方 */
.dragover {background: rgba(0,255,0,.5);
}
</style>

布局效果
box-left

💖 拖拽函数

拖拽对象配置方法drag,dragstart,dragend
放入区域配置方法drop,dragover,dragleave,dragenter

// 拖拽对象
const drag = (event) => {console.log("dragging", event);
}const dragStart = (event) => {// 保存被拖动元素的引用state.dragConfig.dragTarget = event.target;// 设置为半透明event.target.classList.add("dragging");
}const dragEnd = (event) => {// 拖动结束,重置透明度event.target.classList.remove("dragging");
}// 目标对象const dragOver = (event) => {// 阻止默认行为以允许放置event.preventDefault();
}const dragLeave = (event) => {// 在可拖动元素离开潜在放置目标元素时重置该目标的背景if (event.target.classList.contains("dropzone")) {event.target.classList.remove("dragover");}
}const dragEnter = (event) => {// 在可拖动元素进入潜在的放置目标时高亮显示该目标if (event.target.classList.contains("dropzone")) {event.target.classList.add("dragover");}
}const drop = (event) => {// 阻止默认行为(会作为某些元素的链接打开)event.preventDefault();// 将被拖动元素移动到选定的目标元素中if (event.target.classList.contains("dropzone")) {event.target.classList.remove("dragover");// 删除自身state.dragConfig.dragTarget.parentNode.removeChild(state.dragConfig.dragTarget);// 添加元素event.target.appendChild(state.dragConfig.dragTarget);}
}const initDragAction = (sourceElement) => {if (!sourceElement) {return}/* 在放置拖拽对象上触发的事件 */sourceElement.addEventListener("drag", drag);sourceElement.addEventListener("dragstart", dragStart);sourceElement.addEventListener("dragend", dragEnd);
}const initTargetAction = (targetElement) => {if (!targetElement) {return}/* 在放置目标对象上触发的事件 */targetElement.addEventListener("dragover",dragOver,false,);targetElement.addEventListener("dragenter", dragEnter);targetElement.addEventListener("dragleave", dragLeave);targetElement.addEventListener("drop", drop);
}

💖 校验函数

遍历dom节点获取自定义的data-order属性进行校验

// 校验
const confirmImg = () => {const rightDom = document.getElementById('target-box-id')console.log('rightDom', rightDom)const rightDomChildNodes = rightDom.childNodesconsole.log('rightDomChildNodes', rightDomChildNodes)if (rightDomChildNodes.length) {// childNodes会出现空文本节点for (let i = 0, length = rightDomChildNodes.length; i < length; ++i) {console.log('childNodes', rightDomChildNodes[i])if (rightDomChildNodes[i].nodeType !== 1) {// 跳过文本节点continue}else if (rightDomChildNodes[i].hasChildNodes) {console.log('childNodes attr', rightDomChildNodes[i])const currentDataOrder = rightDomChildNodes[i].getAttribute('data-order')const imgDataOrder = rightDomChildNodes[i].getElementsByTagName('img')[0].getAttribute('data-order')console.log('currentDataOrder', currentDataOrder)console.log('imgDataOrder', imgDataOrder)if (currentDataOrder !== imgDataOrder) {return message.warn('拼图位置错误:\t第' + currentDataOrder+'张图片')}}else {return message.warn('没有完成拼图,请拖拽图片')}}}else {return message.warn('没有完成拼图,请拖拽图片')}return '恭喜你完成拼图'
}

💖 inscode整体代码

完整的vue代码

<template><div class="container-drag"><div style="width: 100%;text-align:center;margin: 10px;"><a-button type="primary" class="random-button" @click="randomDragOrder">随机顺序</a-button></div><div class="container-drag-box"><div class="container-drag-left"><!-- <> --><div v-for="item in state.dragConfig.sourceArray" :key="item.id" class="drag-item-box":id="state.dragConfig.sourceDomPrefix + '-' + item.id"><div class="drag-item" draggable="true" :id="state.dragConfig.dragDomPrefix + '-' + item.id"><!-- 拖拽对象 data-order 校验排序用 --><img :src="item.src" width="280" height="280" :data-order="item.id" /></div></div></div><div class="container-drag-right" id="target-box-id"><!-- 目标对象 data-order 校验排序用--><div v-for="item in state.dragConfig.sourceArray" :key="item" class="target-item-box dropzone":id="state.dragConfig.targetDomPrefix + '-' + item.id" :data-order="item.id"></div></div></div><div style="width: 100%;text-align:center"><a-button type="primary" @click="confirmImg">确定</a-button></div></div>
</template><script setup>
import { reactive, onMounted } from 'vue'
import { message } from 'ant-design-vue'
const state = reactive({dragConfig: {sourceDomPrefix: 'source-item',targetDomPrefix: 'target-item',dragDomPrefix: 'drag-item',dragTarget: null,sourceImg: '/img/imageSource.png',sourceArray: [{id: 1,src: '/img/image1.png'},{id: 2,src: '/img/image2.png'},{id: 3,src: '/img/image3.png'},{id: 4,src: '/img/image4.png'},]}
})
// 数组随机顺序
const randomDragOrder = () => {const sourceArray = [...state.dragConfig.sourceArray]sourceArray.sort(() => Math.random() - 0.5);state.dragConfig.sourceArray = sourceArray
}// 拖拽对象
const drag = (event) => {console.log("dragging", event);
}const dragStart = (event) => {// 保存被拖动元素的引用state.dragConfig.dragTarget = event.target;// 设置为半透明event.target.classList.add("dragging");
}const dragEnd = (event) => {// 拖动结束,重置透明度event.target.classList.remove("dragging");
}// 目标对象const dragOver = (event) => {// 阻止默认行为以允许放置event.preventDefault();
}const dragLeave = (event) => {// 在可拖动元素离开潜在放置目标元素时重置该目标的背景if (event.target.classList.contains("dropzone")) {event.target.classList.remove("dragover");}
}const dragEnter = (event) => {// 在可拖动元素进入潜在的放置目标时高亮显示该目标if (event.target.classList.contains("dropzone")) {event.target.classList.add("dragover");}
}const drop = (event) => {// 阻止默认行为(会作为某些元素的链接打开)event.preventDefault();// 将被拖动元素移动到选定的目标元素中if (event.target.classList.contains("dropzone")) {event.target.classList.remove("dragover");// 删除自身state.dragConfig.dragTarget.parentNode.removeChild(state.dragConfig.dragTarget);// 添加元素event.target.appendChild(state.dragConfig.dragTarget);}
}const initDragAction = (sourceElement) => {if (!sourceElement) {return}/* 在放置拖拽对象上触发的事件 */sourceElement.addEventListener("drag", drag);sourceElement.addEventListener("dragstart", dragStart);sourceElement.addEventListener("dragend", dragEnd);
}const initTargetAction = (targetElement) => {if (!targetElement) {return}/* 在放置目标对象上触发的事件 */targetElement.addEventListener("dragover",dragOver,false,);targetElement.addEventListener("dragenter", dragEnter);targetElement.addEventListener("dragleave", dragLeave);targetElement.addEventListener("drop", drop);
}// 校验
const confirmImg = () => {const rightDom = document.getElementById('target-box-id')console.log('rightDom', rightDom)const rightDomChildNodes = rightDom.childNodesconsole.log('rightDomChildNodes', rightDomChildNodes)if (rightDomChildNodes.length) {// childNodes会出现空文本节点for (let i = 0, length = rightDomChildNodes.length; i < length; ++i) {console.log('childNodes', rightDomChildNodes[i])if (rightDomChildNodes[i].nodeType !== 1) {// 跳过文本节点continue}else if (rightDomChildNodes[i].hasChildNodes) {console.log('childNodes attr', rightDomChildNodes[i])const currentDataOrder = rightDomChildNodes[i].getAttribute('data-order')const imgDataOrder = rightDomChildNodes[i].getElementsByTagName('img')[0].getAttribute('data-order')console.log('currentDataOrder', currentDataOrder)console.log('imgDataOrder', imgDataOrder)if (currentDataOrder !== imgDataOrder) {return message.warn('拼图位置错误:\t第' + currentDataOrder+'张图片')}}else {return message.warn('没有完成拼图,请拖拽图片')}}}else {return message.warn('没有完成拼图,请拖拽图片')}return '恭喜你完成拼图'
}// 生命周期
onMounted(() => {// 拖拽对象const dragArr = state.dragConfig.sourceArray.map(item => {return state.dragConfig.dragDomPrefix + '-' + item.id})dragArr.forEach(id => {initDragAction(document.getElementById(id))})// 目标对象const sourceArr = state.dragConfig.sourceArray.map(item => {return state.dragConfig.sourceDomPrefix + '-' + item.id})sourceArr.forEach(id => {initTargetAction(document.getElementById(id))})const targetArr = state.dragConfig.sourceArray.map(item => {return state.dragConfig.targetDomPrefix + '-' + item.id})targetArr.forEach(id => {initTargetAction(document.getElementById(id))})
})</script><style>
.container-drag {min-width: 800px;
}.random-button {margin: 5px;cursor: pointer;
}.container-drag-box {display: flex;justify-content: space-between;
}.container-drag-left {width: 800px;}.container-drag-right {width: 600px;height: 600px;margin: 0;
}.drag-item-box {display: inline-block;margin: 2px;padding: 0;width: 280px;height: 280px;border: 1px solid rgb(255, 255, 255);overflow: hidden;}.target-item-box {display: inline-block;width: 280px;height: 280px;border: 1px solid rgb(255, 255, 255);box-sizing: border-box;overflow: hidden;margin-right: 5px;margin-bottom: 0;margin-top: 0;
}/* 拖拽对象 */
.drag-item {margin: 0;text-align: center;cursor: pointer;
}/* 拖拽中 */
.dragging {opacity: .5;
}/* 悬浮上方 */
.dragover {background: rgba(0,255,0,.5);
}
</style>

代码放在inscode vue3项目在线运行

⭐运行效果

💖 随机顺序

random

💖 拖拽中

draging

💖 校验失败

verrify-error

💖 校验通过

verrify-success
拖拽过程截图

drag-process

⭐总结

拼图校验总结:

1.校验的顺序可以用元素的attribute传递位置顺序进行标记
2.拖拽对象的函数使用 拖拽对象配置方法drag,dragstart,dragend 放入区域配置方法drop,dragover,dragleave,dragenter

拖拽总结:

在HTML中,拖放(drag and
drop)是一种用户界面交互的特定形式,其中用户可以拖动元素或数据并将其放置在另一个位置。以下是HTML拖放的一些总结:

  1. 拖放可用于各种用途,例如重新排序列表,将文本或文件拖动到另一个应用程序中,或从文件资源管理器将文件拖动到Web页面中。
  2. 在HTML中,拖放API由一些事件组成,包括dragstart、dragenter、dragover、dragleave、drop和dragend。
  3. 通过使用HTML data属性,可以将数据附加到拖动事件,并在放置事件中访问它们。
  4. 通过使用CSS,可以为用户拖动时显示的元素创建自定义外观。
  5. 在JavaScript中,可以使用dragEvent对象来访问有关拖动和放置事件的详细信息,例如拖动元素的位置和放置元素的位置。
  6. 可以使用HTML5的拖放API创建复杂的拖放交互,例如可拖动的图形和对象,将元素沿路径拖动等。

⭐结束

本文分享到这结束,如有错误或者不足之处欢迎指出!
cute-img

👍 点赞,是我创作的动力!
⭐️ 收藏,是我努力的方向!
✏️ 评论,是我进步的财富!
💖 感谢你的阅读!

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

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

相关文章

苍穹外卖项目笔记(8)— 缓存商品、购物车功能

前言 代码链接&#xff1a; Echo0701/take-out⁤ (github.com) 1 缓存菜品 1.1 问题说明 【注】很多时候系统性能的瓶颈就在于数据库这端 1.2 实现思路 通过 Redis 来缓存数据&#xff0c;减少数据库查询操作 【注】Redis 基于内存来保存数据的&#xff0c;访问 Redis 数据…

LeetCode208.实现Trie(前缀树)

我一开始想题目叫前缀树&#xff0c;是要用树吗&#xff1f;但是不知道用树怎么写&#xff0c;然后我就花了10多分钟&#xff0c;用了HashMap解了。map的key是word&#xff0c;value是一个放了word的所有前缀的set&#xff0c;这样search方法就非常简单了&#xff0c;只要看has…

Leetcode—2048.下一个更大的数值平衡数【中等】

2023每日刷题&#xff08;五十四&#xff09; Leetcode—2048.下一个更大的数值平衡数 实现代码 class Solution { public:int nextBeautifulNumber(int n) {for(int x n 1; ; x) {vector<int> cnt(10, 0);for(int y x; y > 0; y / 10) {cnt[y%10];}bool ok tru…

TP5上传图片压缩尺寸

图片上传&#xff0c;最简单的就是&#xff0c; 方法一&#xff1a; 修改上传限制&#xff0c;不让上传大于多少多少的图片 改一下size即可&#xff0c;默认单位是B换算成M还需要除以两次1024 方法二&#xff1a; 对上传的图片进行缩放&#xff0c;此办法网上找了不少的代码…

HCIP —— BGP 基础 (下)

BGP 的状态机 --- 建立对等体之间的TCP会话&#xff1a;指定建立对等体的对象 六种状态机 Idle状态 Idle 等待状态&#xff08;相当于OSPF的down状态&#xff09;--- 采用TCP单播建邻 Idle 状态下&#xff0c;启动BGP协议后必须指定建立对等体的目标之后&#xff0c;才能进入…

数据结构 | 查漏补缺之哈希表、最短路径、二叉树与森林的转换

哈希表是什么&#xff1f; 或者说 设图采用邻接表的存储结构&#xff0c;写对图的删除顶点和删除边的算法步骤 删除边 删除点 最短路径问题 参考博文 迪杰斯特拉(Dijkstra)算法_dijkstra算法-CSDN博客 Dijkstra(迪杰斯特拉&#xff09;算法 定义一个点为源点&#xff0c;算源…

5G+AI开花结果,助力智慧安检落地

“请带包的乘客过机安检&#xff01;”&#xff0c;深圳地铁、腾讯共同打造的5GAI智慧安检辅助系统亮相福田枢纽站&#xff0c;进一步解放了人力&#xff0c;提高安检效率&#xff0c;为交通安全保驾护航&#xff0c;让智慧出行成为现实。 传统的安检设备均为人工肉眼辨识&…

2023年9月13日 Go生态洞察:WASI支持在Go中的实现

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

21、命令执行

文章目录 一、命令执行概述1.1 基本定义1.2 原理1.3 两个条件1.4 命令执行漏洞产生的原因1.5 管道符号和通用命令符 二、远程命令执行2.1 远程命令执行相关函数2.2 远程命令执行漏洞的利用 三、系统命令执行3.1 相关函数3.2 系统命令执行漏洞利用 四、命令执行漏洞防御 一、命令…

阿里云生态离线数仓

1. 大数据开发治理平台 DataWorks 功能齐全&#xff1a;10多年大数据建设沉淀完整的平台&#xff0c;覆盖数据开发治理的全生命周期 简单易用&#xff1a;全图形化界面&#xff0c;SQL为主的数据开发方式 安全稳定&#xff1a;双11日千万级任务稳定调度&#x…

一:C语言常见概念

一&#xff1a;C语言常见概念 1.认识C语言&#xff1a; ​ C语言是人和计算机交流的语言 ​ C语言是一门面向过程的语言&#xff0c;而C&#xff0c;Java&#xff0c;Python等是一门面向对象的语言 ​ 软件开发&#xff08;项目&#xff09;&#xff1a;面向过程面向对象 …

maven下载安装与配置

文章目录 1. Maven下载2. 配置settings.xml2.1 指定Maven的本地仓库2.2 配置阿里云提供的镜像仓库2.3 配置 Maven 工程的基础 JDK 版本 3. 配置环境变量3.1 检查 JAVA_HOME 配置是否正确3.2 配置 MAVEN_HOME3.3 配置PATH3.4 验证 1. Maven下载 【Maven官网地址】 【Maven下载…

2023五岳杯量子计算挑战赛数学建模思路+模型+代码+论文

赛题思路&#xff1a;12月6日晚开赛后第一时间更新&#xff0c;获取见文末名片 “五岳杯”量子计算挑战赛&#xff0c;是国内专业的量子计算大赛&#xff0c;也是玻色量子首次联合移动云、南方科技大学共同发起的一场“企校联名”的国际竞赛&#xff0c;旨在深度融合“量子计算…

【外观模式】SpringBoot集成mail发送邮件

前言 发送邮件功能&#xff0c;借鉴 刚果商城&#xff0c;根据文档及项目代码实现。整理总结便有了此文&#xff0c;文章有不对的点&#xff0c;请联系博主指出&#xff0c;请多多点赞收藏&#xff0c;您的支持是我最大的动力~ 发送邮件功能主要借助 mail、freemarker以及rocke…

Java 泛型相关知识

什么是泛型? Java 泛型(generics)是JDK5中引入的一种参数化类型特性。 为什么使用泛型,使用泛型的好处? 代码更健壮(只要编译期没有警告,那么运行期就不会出现 ClassCastException)代码更简洁(不用强转)代码更灵活,复用什么是参数化类型: 把类型当参数一样传递<…

React基础语法整理

安装&#xff1a; yarn create react-app reatc-lesson --template typescript yarn create 创建一个react-app的应用 项目名称 typescript 的模板react-app 官方地址 https://create-react-app.bootcss.com/docs/adding-typescriptreact 语法文档 https://zh-hans.react.dev…

基于Vue框架的电子商城购物平台小程序的设计与开发

基于JavaWebSSMVue电子商城购物平台小程序系统的设计和实现 源码获取入口KaiTi 报告/Ren务书Lun文目录前言主要技术系统设计功能截图订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 源码获取入口 KaiTi 报告/Ren务书 一、选题的目的和意义 自从微信推出了微信小程序…

使用命令行移除VSAN中故障磁盘

原创作者&#xff1a;运维工程师 谢晋 使用命令行移除VSAN中故障磁盘 前提故障盘移除 前提 客户有套VSAN环境内有一台服务器的磁盘组出现了一块故障的数据盘&#xff0c;但该盘已经处于完全掉线状态&#xff0c;无法进行正常移除。如下图&#xff1a; 如果遇到这种情况&am…

P9 LinuxC 进程概述 终端启动的程序父进程是终端

前言 &#x1f3ac; 个人主页&#xff1a;ChenPi &#x1f43b;推荐专栏1: 《C_ChenPi的博客-CSDN博客》✨✨✨ &#x1f525; 推荐专栏2: 《Linux C应用编程&#xff08;概念类&#xff09;_ChenPi的博客-CSDN博客》✨✨✨ &#x1f6f8;推荐专栏3: ​​​​​​《链表_ChenP…

【1】一文读懂PyQt简介和环境搭建

目录 1. PyQt简介 1.1. Qt 1.2. PyQt 1.3. 关于PyQt和PySide 2. 通过pip安装PyQt5 3. 无法运行处理 4. VSCode配置PYQT插件 PyQt官网:Riverbank Computing | Introduction 1. PyQt简介 PyQt是一套Python的GUI开发框架,即图形用户界面开发框架。 Python中经常使用的GU…