原生js实现拖拽功能

文章将深入研究原生JavaScript如何实现拖拽功能,探讨技术细节和最佳实践,为前端开发者提供深刻理解和实际应用的知识。

引言

介绍拖拽功能在现代Web应用中的广泛应用,从图形操作到用户交互体验的提升。
引入原生JavaScript实现拖拽的动机。

HTML结构

分析拖拽功能所需HTML结构的特点。
示例:一个简单的任务列表,演示如何通过拖拽实现任务排序。

在这里插入图片描述

基本事件

解析原生JavaScript中拖拽相关的基本事件:ondragstart、ondragenter、ondragend、ondragover。或者mousedown、mousemove、mouseup。
如何监听并响应这些事件。

初始结构样式

html结构

	<div class="drag-box">
        <div class="drag-item" draggable="true">1</div>
        <div class="drag-item" draggable="true">2</div>
        <div class="drag-item" draggable="true">3</div>
        <div class="drag-item" draggable="true">4</div>
        <div class="drag-item" draggable="true">5</div>
        <div class="drag-item" draggable="true">6</div>
        <div class="drag-item" draggable="true">7</div>
        <div class="drag-item" draggable="true">8</div>
    </div>

style结构

<style>
    .drag-item {
        width: 500px;
        height: 80px;
        display: flex;
        align-items: center;
        justify-content: center;
        background: #913291;
        cursor: move;
        margin-bottom: 10px;
        color: #fff;
        border: 1px dashed #913291;
    }
    // 用于拖拽时给的效果,可根据项目所需定制
    .active {
       background: transparent;
        border: 1px dashed #999;
    }
</style>

拖拽的基本实现

通过基本事件实现最简单的拖拽功能。
讨论鼠标位置和元素位置之间的关系,实现元素随鼠标移动。

element.ondragstart = (e) => {
	console.log('拖动开始')
}

element.ondragenter = (e) => {
	console.log('拖动元素进入目标元素时触发')
}

element.ondragend = (e) => {
	console.log('当被鼠标拖动的对象进入其容器范围内时触发此事件')
}

element.ondragover = (e) => {
	console.log('拖动元素在目标元素上方时触发,通常用于防止默认的拖放行为')
}

功能拆分

定义变量

// 获取列表容器
const element = document.querySelector('.drag-box');
// 当前元素
let currentEl;

移动元素开始时,添加移动时定制的特效或影子

// 这里可通过事件委托监听“拖动开始”事件
element.ondragstart = (e) => { 
	currentEl = e.target;
	// 这里的定时器解决拖动元素时也会带上特效或影子的问题
	setTimeout(()=> {
		e.target.classList.add('active')
	}, 0)
}

处理拖拽时的边界情况,防止元素溢出容器

// 防止元素溢出容器或拖动到当前元素
element.ondragenter = (e) => { 
	if(e.target === currentEl || e.target === element) return;
}

拖动完成后移除class效果

// 
element.ondragend = (e) => {
	e.target.classList.remove('active')
}

近一步对处理拖拽做业务处理

const list = [...element.children];
// 自身位置
const currentIndex = list.indexOf(currentEl);
// 目标位置
const targetIndex = list.indexOf(e.target);
if(currentIndex < targetIndex) {
	// 向下拖拽
	element.insertBefore(currentEl, e.target.nextElementSibling);
} else {
	// 向上拖拽
	element.insertBefore(currentEl, e.target)
}

解决只有松开鼠标才是真实变换位置,使用e.preventDefault()阻止拖拽元素的默认行为

element.ondragover = (e) => {
	e.preventDefault();
}

最终完整代码

好了,来看看最终的代码效果,首要目的先理解并消化上面的拆分功能代码

	// 获取列表容器
    const element = document.querySelector('.drag-box');
    // 当前元素
    let currentEl;

    element.ondragstart = (e) => {
        currentEl = e.target;
        setTimeout(()=> {
            e.target.classList.add('active')
        }, 0)
    }

    element.ondragenter = (e) => {
        if(e.target === currentEl || e.target === element) return;
        const list = [...element.children];
        // 自身位置
        const currentIndex = list.indexOf(currentEl);
        // 目标位置
        const targetIndex = list.indexOf(e.target);
        if(currentIndex < targetIndex) {
            // 向下拖拽
            element.insertBefore(currentEl, e.target.nextElementSibling);
        } else {
            // 向上拖拽
            element.insertBefore(currentEl, e.target)
        }
    }

    element.ondragend = (e) => {
        e.target.classList.remove('active')
    }

    element.ondragover = (e) => {
        e.preventDefault();
    }

分析不同浏览器对原生拖拽的兼容性问题。
提供解决方案,确保在各种环境中都能正常运行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值