相关的API
主要有7个api,分别用来描述不同的状态
前提准备
主要实现的点餐功能如下:
- 一个盘子里装了多种菜
- 另一个是小明的菜单
- 小明可以拖动菜品到菜单上
- 小明的菜单中最多可以点三份菜
思考一下我们如何实现这个功能:首先需要两个容器,一个用来装菜品,另一个当作菜单
小明的点菜操作我们可以使用drag相关的api,拖动到菜单上则给菜单添加一个子元素
相关介绍
下面我们把拖拽的物体称为源对象
,放置到位置称为目标对象
dragstart
源对象 开始被拖动时触发的函数,事件对象是源对象,比如我们在这个时候可以给源对象添加一些样式,比如边框高亮,字体加粗等效果,触发一次之后就结束
drag
源对象 在被拖动的时候触发的函数,事件对象是源对象 ,相隔几十毫秒就会触发一次
dragend
源对象被拖拉结束时(释放鼠标键或按下 ESC 键)触发,事件对象是源对象。它与dragstart事件,在同一个节点上触发。不管拖拉是否跨窗口,或者中途被取消,dragend事件总是会触发的
dragenter
源对象进入目标对象时,在目标上触发一次,该事件的target属性是目标对象。通常应该在这个事件的监听函数中,指定是否允许在当前节点放下(drop)拖拉的数据。如果当前节点没有该事件的监听函数,或者监听函数不执行任何操作,就意味着不允许在当前节点放下数据。一般我们可以在源对象刚进入目标对象时监听这个事件,我们可以给目标对象添加高亮效果等
dragover
源对象拖拉到目标对象上方时,在当前节点上持续触发(大概相差几十毫秒),e.target也就是事件对象是目标对象,这个方法类似于drag,都会一直触发。
dragleave
拖拉操作离开目标对象范围时触发,该事件的target属性是目标对象。比如说在点菜时,已经拖到这个框里了,但是又不想点了,又继续滑出去,此时就应该将目标对象之前的样式去掉。
drop
源对象释放到目标对象时,在目标节点上触发。注意,如果目标对象不允许drop,即使在上方松开鼠标键,也不会触发该事件。如果用户按下 ESC 键,取消这个操作,也不会触发该事件。该事件的监听函数负责取出拖拉数据,并进行相关处理。比如我们在点菜时,拖动菜品到盘子里并松手时就说明我们确定点这个菜品,此时就应该复制该节点到盘子里。
注意事项
dragenter和dragover事件的监听函数,用来取出拖拉的数据(即允许放下被拖拉的元素)。由于网页的大部分区域不适合作为放下拖拉元素的目标节点,所以这两个事件的默认设置为当前节点不允许接受被拖拉的元素。如果想要在目标节点上放下的数据,首先必须阻止这两个事件的默认行为
。
<div ondragover="return false">
<div ondragover="event.preventDefault()">
参考代码
还是存在着很多小bug,不过基础功能已经可以实现了
点击查看代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
li {
list-style: none;
border: 1px solid #ccc;
}
.box {
width: 800px;
height: 680px;
margin: 0 auto;
background-color: rgb(235, 230, 230);
}
.dragBox {
display: flex;
width: 100%;
height: 60%;
flex-wrap: wrap;
justify-content: space-around;
align-items: space-between;
}
.dragDiv {
width: 100px;
height: 100px;
border-radius: 100px;
line-height: 100px;
text-align: center;
border: 1px solid rgb(80, 77, 77);
background-color: #7d7a7a;
}
.dragCss {
border: 1px solid blue;
opacity: 0.5;
}
.dropDiv {
display: flex;
justify-content: space-around;
align-items: center;
width: 80%;
height: 30%;
margin: 0 auto;
border: 1px solid #000;
background-color: burlywood;
}
.dropCss {
background-color: yellow;
}
</style>
</head>
<body>
<div class="box">
<h2 style="text-align:center">点餐系统</h2>
<ul class="dragBox">
</ul>
<h2 style="text-align:center">盘子</h2>
<div class="dropDiv"></div>
</div>
</body>
<script>
const foodList = ['火锅', '北京烤鸭', '兰州拉面', '成都冷串串', '重庆酸辣粉', '武汉热干面', '西安肉夹馍', '长沙口味虾', '广东肠粉', '小笼包', '桂林米粉', '柳州螺蛳粉', '天津煎饼果子', '山东煎饼', '东北锅包肉', '福建佛跳墙', '河南烩面', '山西刀削面', '南昌瓦罐汤', '河北驴肉火烧', '手抓饼']
const dropNode = document.querySelector('.dropDiv')
const ul = document.querySelector('.dragBox')
let fragment = document.createDocumentFragment()
foodList.forEach(item => {
let li = document.createElement('li')
li.innerText = item
li.classList.add('dragDiv')
li.draggable = 'true'
fragment.appendChild(li)
})
ul.appendChild(fragment)
// 1.准备工作,先将foodList渲染到ul中
const dragNodes = document.querySelectorAll('.dragDiv')
let dragNode = null
dragNodes.forEach(node => {
node.addEventListener('dragstart', function (e) {
console.log('开始拖拉')
dragNode = e.target
e.target.classList.add('dragCss')
})
node.addEventListener('dragend', function (e) {
e.target.classList.remove('dragCss')
})
})
dropNode.addEventListener('dragenter', function (e) {
dragNode.classList.remove('dragCss')
e.target.classList.add('dropCss')
})
dropNode.addEventListener('dragover', function (e) {
e.preventDefault()
})
dropNode.addEventListener('dragleave', function (e) {
e.target.classList.remove('dropCss')
})
dropNode.addEventListener('drop', function (e) {
if (e.target.children.length > 3) {
e.target.classList.remove('dropCss')
alert('最多只能点四个菜哦~')
return
}
let newNode = dragNode.cloneNode(true)
e.target.classList.remove('dropCss')
e.target.appendChild(newNode)
})
</script>
</html>
// 本人才疏学浅 如有错误 请指出 谢谢!