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

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

⭐前言

大家好,我是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. 校验最终的元素序号,判断是否拼图成功

拆分图片

💖 布局结构

才有左右布局

左侧:拖拽来源区域

右侧:拖拽放入区域

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>

布局效果

💖 拖拽函数

拖拽对象配置方法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.childNodes
    console.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.childNodes
    console.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项目在线运行

⭐运行效果

💖 随机顺序

💖 拖拽中

💖 校验失败

💖 校验通过

拖拽过程截图

⭐总结

拼图校验总结:

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创建复杂的拖放交互,例如可拖动的图形和对象,将元素沿路径拖动等。

⭐结束

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


目录
相关文章
|
2月前
|
存储 人工智能 前端开发
前端大模型应用笔记(三):Vue3+Antdv+transformers+本地模型实现浏览器端侧增强搜索
本文介绍了一个纯前端实现的增强列表搜索应用,通过使用Transformer模型,实现了更智能的搜索功能,如使用“番茄”可以搜索到“西红柿”。项目基于Vue3和Ant Design Vue,使用了Xenova的bge-base-zh-v1.5模型。文章详细介绍了从环境搭建、数据准备到具体实现的全过程,并展示了实际效果和待改进点。
177 2
|
1月前
|
资源调度 前端开发 JavaScript
vite3+vue3 实现前端部署加密混淆 javascript-obfuscator
【11月更文挑战第10天】本文介绍了在 Vite 3 + Vue 3 项目中使用 `javascript-obfuscator` 实现前端代码加密混淆的详细步骤,包括安装依赖、创建混淆脚本、修改 `package.json` 脚本命令、构建项目并执行混淆,以及在 HTML 文件中引用混淆后的文件。通过这些步骤,可以有效提高代码的安全性。
|
2月前
|
监控 JavaScript 前端开发
前端的混合之路Meteor篇(六):发布订阅示例代码及如何将Meteor的响应数据映射到vue3的reactive系统
本文介绍了 Meteor 3.0 中的发布-订阅模型,详细讲解了如何在服务器端通过 `Meteor.publish` 发布数据,包括简单发布和自定义发布。客户端则通过 `Meteor.subscribe` 订阅数据,并使用 MiniMongo 实现实时数据同步。此外,还展示了如何在 Vue 3 中将 MiniMongo 的 `cursor` 转化为响应式数组,实现数据的自动更新。
|
1月前
|
前端开发 JavaScript 安全
vite3+vue3 实现前端部署加密混淆 javascript-obfuscator
【11月更文挑战第7天】本文介绍了在 Vite 3 + Vue 3 项目中使用 `javascript-obfuscator` 实现前端代码加密混淆的详细步骤。包括项目准备、安装 `javascript-obfuscator`、配置 Vite 构建以应用混淆,以及最终构建项目进行混淆。通过这些步骤,可以有效提升前端代码的安全性,防止被他人轻易分析和盗用。
151 0
|
4月前
|
前端开发 JavaScript
在 Vue3 + ElementPlus 项目中使用 computed 实现前端静态分页
本文介绍了在Vue3 + ElementPlus项目中使用`computed`属性实现前端静态分页的方法,并提供了详细的示例代码和运行效果。
197 1
在 Vue3 + ElementPlus 项目中使用 computed 实现前端静态分页
|
4月前
|
前端开发 JavaScript 数据安全/隐私保护
前端JS正则校验密码之3种实现方式
这篇文章展示了三种使用JavaScript正则表达式来校验密码的方法,密码需要满足包含大写字母、小写字母、数字及特殊字符,并在8到16位之间,同时提供了示例代码和实现效果。
155 1
前端JS正则校验密码之3种实现方式
|
4月前
|
JavaScript 前端开发 API
每个前端开发人员都必须知道的 7 个 Vue3 组件库!
每个前端开发人员都必须知道的 7 个 Vue3 组件库!
|
4月前
|
前端开发 Java C++
超简单使用Vite+Vue3构建共享开发和分模块打包的前端项目
使用Vite和Vue3构建支持共享组件和分模块独立打包的前端项目的方法。
528 0
超简单使用Vite+Vue3构建共享开发和分模块打包的前端项目
|
4月前
|
开发框架 前端开发 JavaScript
【Vue 3】一款开箱即用的中后台前端开发框架,开源且免费!!
【Vue 3】一款开箱即用的中后台前端开发框架,开源且免费!!
|
4月前
|
缓存 JavaScript 前端开发
【性能革命!】Vue 3事件监听缓存的奥秘 —— 揭开前端优化的神秘面纱,让应用性能飙升的秘密武器!
【8月更文挑战第7天】随着前端应用日益复杂,性能优化变得至关重要。Vue 3 通过引入事件监听缓存等新特性提升了应用性能。此特性避免了重复注册相同的事件监听器,减少了资源浪费和潜在的内存泄漏问题。在 Vue 3 中,事件监听器首次渲染时注册,并在后续渲染中重用,除非组件状态变更或手动更新。通过一个示例组件展示了如何利用该特性优化性能,包括使用 `watchEffect` 或 `watch` 在状态变化时重新注册监听器。这一机制降低了浏览器负担,减少了内存占用,提高了应用响应速度,尤其对大型应用效果显著。合理运用事件监听缓存能够构建出更加流畅的应用体验。
323 3