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

文章目录

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

⭐前言

大家好,我是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布局

html 复制代码
<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配置

html 复制代码
<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

javascript 复制代码
// 拖拽对象
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属性进行校验

javascript 复制代码
// 校验
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代码

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

⭐结束

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

👍 点赞,是我创作的动力!

⭐️ 收藏,是我努力的方向!

✏️ 评论,是我进步的财富!

💖 感谢你的阅读!

相关推荐
却尘18 分钟前
Next.js 请求最佳实践 - vercel 2026一月发布指南
前端·react.js·next.js
ccnocare19 分钟前
浅浅看一下设计模式
前端
Lee川23 分钟前
🎬 从标签到屏幕:揭秘现代网页构建与适配之道
前端·面试
Ticnix1 小时前
ECharts初始化、销毁、resize 适配组件封装(含完整封装代码)
前端·echarts
纯爱掌门人1 小时前
终焉轮回里,藏着 AI 与人类的答案
前端·人工智能·aigc
twl1 小时前
OpenClaw 深度技术解析
前端
崔庆才丨静觅1 小时前
比官方便宜一半以上!Grok API 申请及使用
前端
星光不问赶路人1 小时前
vue3使用jsx语法详解
前端·vue.js
天蓝色的鱼鱼1 小时前
shadcn/ui,给你一个真正可控的UI组件库
前端
布列瑟农的星空1 小时前
前端都能看懂的Rust入门教程(三)——控制流语句
前端·后端·rust