原生JS的拖拽属性draggable

本文详细介绍了HTML5中的draggable属性及其用法,包括如何设定元素的拖动性、关键事件如dragstart、dragover、drop的作用以及示例代码。重点讲解了如何在拖放操作中处理元素的移动和放置行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

定义和用法

draggable 属性规定元素是否可拖动。

提示: 链接和图像默认是可拖动的。

提示: draggable 属性经常用于拖放操作。

draggable 属性是 HTML5 新增的。

语法

<element draggable="true|false|auto">

属性值

描述

true

规定元素是可拖动的。

false

规定元素是不可拖动的。

auto

使用浏览器的默认特性。

draggable属性的使用

draggable既然是拖放,那么主要是两个角色比较重要:

(1)被拖动的元素A

(2)A被拖动以后放置的元素B

举例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .one{
      width: 100px;
      height: 100px;
      background-color: red;
    }
    .two{
      width: 200px;
      height: 200px;
      background-color: springgreen;
    }
  </style>
</head>
<body>
  <div class="one" draggable="true">11</div>
  <div class="two">22</div>
  <script>
  </script>
</body>
</html>

效果

现在有两个点:

(1)拖动的元素要赋予draggable属性,属性值为true。

(2)被拖进的元素要在dragover和dragenter事件值中阻止默认行为。

<div class="one" draggable="true">11</div>
<div class="two" ondragover="handleOndragover(event)" ondragenter="handleOndragenter(event)">22</div>
<script>
  function handleOndragover(e){
    e.preventDefault();
  }
  function handleOndragenter(e){
    e.preventDefault();
  }
</script>

此时A元素可以拖入到B元素里面,但是只是视觉效果上的,一旦松开鼠标,就恢复原状了

draggable属性的API

针对被拖拽元素A

(1)dragstart方法

该方法在按下鼠标并且移动鼠标时,会在A上触发该方法。同时鼠标的光标会变成禁用的样子,直到拖动到允许放置A的元素上,禁用的效果就会消失。

而允许放置A的元素,就是刚刚说的在dragover和dragenter中阻止默认行为

举例:当拖动A时,改变A元素的背景颜色为蓝色

<div class="one" draggable="true" ondragstart="handleOndragstart(event)">11</div>
<div class="two" ondragover="handleOndragover(event)" ondragenter="handleOndragenter(event)">22</div>
<script>
  function handleOndragstart(e){
    e.target.style.backgroundColor='blue';
  }
  function handleOndragover(e){
    e.preventDefault();
  }
  function handleOndragenter(e){
    e.preventDefault();
  }
</script>

(2)drag方法

该方法发生在dragstart之后,只要是在拖动过程之中,该方法就会持续触发

<div class="one" draggable="true" ondragstart="handleOndragstart(event)" ondrag="handleOndrag(event)">11</div>
<div class="two" ondragover="handleOndragover(event)" ondragenter="handleOndragenter(event)">22</div>
<script>
  function handleOndragstart(e){
    console.log('ondragstart');
  }
  function handleOndrag(e){
    console.log('ondrag');
  }
  function handleOndragover(e){
    e.preventDefault();
  }
  function handleOndragenter(e){
    e.preventDefault();
  }
</script>

(3)dragend方法

该方法是在拖动结束的时候触发,也就是当你拖拽后,松开鼠标的一瞬间触发

<div class="one" draggable="true" ondragstart="handleOndragstart(event)" ondrag="handleOndrag(event)" ondragend="handleOndragend(event)">11</div>
<div class="two" ondragover="handleOndragover(event)" ondragenter="handleOndragenter(event)">22</div>
<script>
  function handleOndragstart(e){
    console.log('ondragstart');
  }
  function handleOndrag(e){
    console.log('ondrag');
  }

  function handleOndragend(e){
    console.log('ondragend');
  }

  function handleOndragover(e){
    e.preventDefault();
  }
  function handleOndragenter(e){
    e.preventDefault();
  }
</script>

一般我们比较常用的方法就是dragstrat方法,通过在这个方法中将被推拽的元素进行保存下来,再进行后续的操作。

拖入元素B的事件

针对于拖入元素的事件,它不需要元素具有draggable属性,只要你想,任何元素使用这些方法都是可以的。但要记住上面所说的那两个方法,阻止事件默认行为。

(1)dragenter方法

该方法是指拖拽元素A,在拖入到B之中,B所触发的事件。当然,任何具有draggable属性为true的元素,拖入到B中,都会触发该事件。

<div class="one" draggable="true" ondragstart="handleOndragstart(event)" ondrag="handleOndrag(event)" ondragend="handleOndragend(event)">11</div>
<div class="two" ondragover="handleOndragover(event)" ondragenter="handleOndragenter(event)">22</div>
<script>
  function handleOndragstart(e){
    console.log('ondragstart');
  }
  function handleOndrag(e){
    console.log('ondrag');
  }

  function handleOndragend(e){
    console.log('ondragend');
  }

  function handleOndragover(e){
    e.preventDefault();
  }
  function handleOndragenter(e){
    console.log('ondragenter');
    e.preventDefault();
  }
</script>

切记,这里事件的触发不需要松开鼠标

举例:当A拖入到B中,我们希望A是真正成为B的子元素:

<div class="one" draggable="true" ondragstart="handleOndragstart(event)" ondrag="handleOndrag(event)" ondragend="handleOndragend(event)">11</div>
<div class="two" ondragover="handleOndragover(event)" ondragenter="handleOndragenter(event)">22</div>
<script>
  function handleOndragstart(e) {
    console.log('ondragstart');
  }
  function handleOndrag(e) {
    console.log('ondrag');
  }

  function handleOndragend(e) {
    console.log('ondragend');
  }

  function handleOndragover(e) {
    e.preventDefault();
  }
  function handleOndragenter(e) {
    e.preventDefault();
    e.target.appendChild(document.querySelector('.one'))
  }
</script>

(2)dragover方法

该方法只要是,拖拽元素A在目标元素B中移动,就会持续触发。(就是如果A在B区域内悬浮,就会触发)

function handleOndragover(e) {
  e.preventDefault();
  console.log('ondragover');
}

(3)dragleave方法

该方法指的是拖拽元素A,在从目标元素B中离开的时候,会触发该方法

这里记住,一定是先进入到B,再离开B的时候触发该事件,也就是说要先触发dragenter方法,才能触发dragleave方法

function handleOndragleave(e){
  console.log('ondragleave');
}

(4)drop方法

该方法是指,拖拽元素A被放置了目标元素B中的时候触发,那它和dragenter方法的区别在于,该方法需要鼠标松开才会触发。而这个方法也是最常用的方法。

例:当A拖入到B中,我们希望A是真正成为B的子元素:

function handleOndrop(e){
  console.log('ondrop');
  e.target.appendChild(document.querySelector('.one'))
}

总结

如果要实现拖放,需要具备以下条件

(1)拖动的元素要赋予draggable属性,属性值为true。

(2)最重要的三个事件:dragstart、dragover、drop

  • 被托动元素A需要设置draggable属性、dragstart事件
  • 拖入元素B需要设置dragover、drop事件
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .one {
      width: 100px;
      height: 100px;
      background-color: red;
    }

    .two {
      width: 200px;
      height: 200px;
      background-color: springgreen;
    }
  </style>
</head>

<body>
  <div class="one" draggable="true" ondragstart="handleOndragstart(event)">11</div>
  <div class="two" ondragover="handleOndragover(event)" ondrop="handleOndrop(event)">22</div>
  <script>
    function handleOndragstart(e){
      console.log(e);
    }
    function handleOndragover(e){
      e.preventDefault();
    }
    function handleOndrop(e){
      e.target.appendChild(document.querySelector('.one'))
    }
  </script>
</body>

</html>
### 实现可拖拽功能的方式 #### 原生 JavaScript 的实现方法 通过原生 JavaScript,可以轻松创建一个基础的可拖拽元素。以下是其实现逻辑: 1. **鼠标按下事件 (mousedown)**:当用户点击目标元素时触发此事件,并记录鼠标的初始位置。 2. **鼠标移动事件 (mousemove)**:在文档上监听该事件,计算当前鼠标的位置相对于起始位置的变化量,从而更新元素的位置。 3. **鼠标释放事件 (mouseup)**:停止拖拽操作。 下面是具体的代码示例[^1]: ```javascript document.addEventListener('DOMContentLoaded', () => { const draggableElement = document.querySelector('.draggable'); let isDragging = false; let offsetX, offsetY; draggableElement.addEventListener('mousedown', (e) => { isDragging = true; offsetX = e.clientX - draggableElement.getBoundingClientRect().left; offsetY = e.clientY - draggableElement.getBoundingClientRect().top; }); document.addEventListener('mousemove', (e) => { if (!isDragging) return; draggableElement.style.position = 'absolute'; draggableElement.style.left = `${e.clientX - offsetX}px`; draggableElement.style.top = `${e.clientY - offsetY}px`; }); document.addEventListener('mouseup', () => { isDragging = false; }); }); ``` --- #### Vue.js 中使用 `vue-draggable-plus` 插件 如果项目基于 Vue.js 开发,推荐使用专门用于拖拽场景的插件——`vue-draggable-plus`。然而,在实际开发过程中可能会遇到一些特殊需求,比如部分子元素不应参与拖拽行为。此时可以通过设置特定属性来解决这一问题[^2]。 例如,对于列表项中的按钮或其他交互组件,可通过以下方式禁用其拖拽能力: ```html <template> <draggable v-model="items"> <div class="item" v-for="(item, index) in items" :key="index"> {{ item.name }} <!-- 防止按钮被误认为拖拽手柄 --> <button @click.stop="handleClick(item)" style="pointer-events: none;"> 删除 </button> </div> </draggable> </template> <script> import draggable from 'vuedraggable'; export default { components: { draggable }, data() { return { items: [{ name: 'Item 1' }, { name: 'Item 2' }], }; }, methods: { handleClick(item) { console.log(`删除 ${item.name}`); }, }, }; </script> ``` 上述代码中,`@click.stop` 和 `style="pointer-events: none;"` 被用来阻止默认拖拽行为的发生。 --- #### 使用 Vue3 结合 Draggable 库实现复杂拖拽功能 针对更复杂的业务场景(如支持缩放、动态调整布局等),Vue3 提供了强大的组合式 API 来简化状态管理流程。同时搭配第三方库 draggable,能够快速构建高度灵活的功能模块[^3]。 需要注意的是,为了确保 DOM 更新的一致性和性能优化,建议为每个可拖拽对象绑定唯一 key 值;另外,ECharts 图表需额外处理尺寸适配问题,通常借助于 window.resizeEvent 完成重新渲染工作。 以下是一个综合案例演示: ```html <template> <div ref="container" class="box" :style="{ width: boxWidth + 'px', height: boxHeight + 'px' }"> <draggable v-model="elements" handle=".drag-handle"> <div v-for="(el, idx) in elements" :key="idx" class="element"> <span class="drag-handle"> Drag Me </span> Content of Element {{ el.id }} </div> </draggable> <div id="chart"></div> </div> </template> <script> import draggable from 'vuedraggable'; import * as echarts from 'echarts'; export default { components: { draggable }, data() { return { boxWidth: 400, boxHeight: 300, elements: [ { id: 1 }, { id: 2 }, ], }; }, mounted() { this.initChart(); window.addEventListener('resize', this.handleResize); }, beforeUnmount() { window.removeEventListener('resize', this.handleResize); }, methods: { initChart() { const chartDom = document.getElementById('chart'); const myChart = echarts.init(chartDom); const option = { grid: { containLabel: true }, xAxis: {}, yAxis: {}, series: [{ type: 'bar', data: [5, 20, 36], }], }; myChart.setOption(option); }, handleResize() { this.boxWidth = Math.max(200, window.innerWidth / 2); // 自定义宽度规则 this.boxHeight = Math.min(window.innerHeight - 100, 500); // 自定义高度规则 }, }, }; </script> <style scoped> .box { border: 1px solid black; position: relative; } .element { background-color: lightblue; margin-bottom: 8px; padding: 10px; } .drag-handle { cursor: move; /* 显示拖动手势 */ } </style> ``` --- ### 总结 无论是采用纯前端技术还是依赖框架生态工具链,均可高效完成各类拖拽功能的设计与实施。开发者应依据项目的具体特性选取最合适的方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值