拖放与地理定位
1. HTML5拖放
1-1 了解拖放
HTML5 提供了 Drag and Drop API,用户可使用鼠标选择可拖拽(draggable)元素,将元素拖拽到可放置(droppable)元素,并释放鼠标按钮以放置这些元素,拖拽操作期间,会有一个可拖拽元素的半透明快照跟随着鼠标指针
让一个元素被拖拽需要添加 draggable 属性
true—— 元素可以被拖动false—— 元素不可以被拖动auto—— 默认值,浏览器定义的默认行为
<div class="main">
<div class="box" draggable="true"></div>
<div class="place-region">请拖到此区域</div>
</div>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0Z2f3MzY-1652241463866)(https://raw.githubusercontent.com/xiaofeilalala/DocsPics/main/imgs/20220509085158.png)]
1-2 拖放事件
HTML5 的 drag & drop 使用了 DOM event model DOM事件模型以及从 mouse events 鼠标事件继承而来的 drag events 拖放事件
**Tips:**在操作期间,会触发一些事件类型,有一些事件类型可能会被多次触发
**Tips:**当从操作系统向浏览器中拖拽文件时,不会触发
dragstart和dragend事件
| 事件 | On 型事件处理程序 | 触发时刻 |
|---|---|---|
| drag | ondrag | 当拖拽元素或选中的文本时触发 |
| dragend | ondragend | 当拖拽操作结束时触发 (比如松开鼠标按键或敲“Esc”键) |
| dragenter | ondragenter | 当拖拽元素或选中的文本到一个可释放目标时触发 |
| dragexit | ondragexit | 当元素变得不再是拖拽操作的选中目标时触发 |
| dragleave | ondragleave | 当拖拽元素或选中的文本离开一个可释放目标时触发 |
| dragover | ondragover | 当元素或选中的文本被拖到一个可释放目标上时触发(每 100 毫秒触发一次) |
| dragstart | ondragstart | 当用户开始拖拽一个元素或选中的文本时触发(见开始拖拽操作 |
| drop | ondrop | 当元素或选中的文本在可释放目标上被释放时触发 |
在 HTML5 中提供了7个与拖放事件,按照触发顺序:
dragstart—— 当用户开始拖拽一个元素或选中的文本时触发drag—— 当拖拽元素或选中的文本时触发dragenter—— 当拖拽元素或选中的文本到一个可释放目标时触发dragover—— 当元素或选中的文本被拖到一个可释放目标上时触发dragleave—— 当拖拽元素或选中的文本离开一个可释放目标时触发drop—— 当元素或选中的文本在可释放目标上被释放时触发dragend—— 当拖拽操作结束时触发 (松开鼠标按键或敲Esc键)
在拖动目标时触发事件,作用在被拖拽元素上:dragstart、drag、dragend
释放目标时触发的事件,作用在放置目标元素上:dragenter、dragover、dragleave、drop
// dragstart 开始拖拽元素时触发
let box = document.querySelector('.box')
let place = document.querySelector('.place-region')
// 拖动目标时触发事件,作用在被拖拽元素上
box.ondragstart = function(e) {
console.log('box dragstart')
}
// drag 拖拽元素触发
box.ondrag = function(e) {
console.log('box drag')
}
// dragend 拖拽结束时触发
place.ondragend = function(e) {
console.log('place dragend')
}
// 释放目标时触发的事件,作用在目标元素上
// dragenter 拖拽到可放置区域时触发
box.ondragenter = function(e) {
console.log('box dragenter')
}
// dragover拖拽到可放置区域时触发
place.ondragover = function(e) {
e.preventDefault();
console.log('place dragover')
}
// dragleave 拖拽元素离开可放置区域触发
place.ondragleave = function(e) {
console.log('place dragleave')
}
// drop 在可放置区域释放拖拽元素时触发
place.ondrop = function(e) {
console.log('place drop')
}
2. 拖放操作
HTML5 的拖拽接口有 DragEvent, DataTransfer, DataTransferItem 和 DataTransferItemList
2-1 dataTransfer
DragEvent 是一个表示拖、放交互的一个 DOM event 接口,继承 MouseEvent 和Event 属性
dataTransfer—— 在拖放交互期间传输的数据,dataTransfer属性是一个DataTransfer对象
let box = document.querySelector('.box')
box.ondragstart = function(e) {
console.log(e.dataTransfer)
}

2-2 拖拽数据
DataTransfer 对象用于保存拖动并放下(drag and drop)过程中的数据,用于从被拖动元素向放置目标传递字符串数据
**Tips:**必须同时设置
effectAllowed,否则dropEffect属性无效
DataTransfer.dropEffect获取当前选定的拖放操作类型或者设置的为一个新的类型。值必须为none,copy,link或moveDataTransfer.effectAllowed提供所有可用的操作类型。取值none,copy,copyLink,copyMove,link,linkMove,move,alloruninitialized之一files—— 包含数据传输中可用的所有本地文件的列表,如果拖动操作不涉及拖动文件,则此属性为空列表items—— 提供一个包含所有拖动数据列表的DataTransferItemList对象types—— 提供dragstart事件中设置的格式的string数组,如果拖动操作不包含数据,则此数组列表将为空,如果拖动操作中包含任何文件,则其中一个类型将是Files
// dropEffect属性 获取当前拖拽元素的操作类型或者设置新的类型
let box = document.querySelector('.box')
box.ondragstart = function(e) {
e.dataTransfer.setData('text/plan', e.target.className)
e.dataTransfer.effectAllowed = 'move'
// 获取允许拖拽元素执行哪几种拖拽效果
console.log(e.dataTransfer.effectAllowed); // move
// 获取所有本地文件的列表
console.log(e.dataTransfer.files); // FileList {length: 0}
}
let place = document.querySelector('.place-region')
place.ondrop = function(e) {
e.preventDefault();
let data = e.dataTransfer.getData('text/plan');
e.target.innerText = '';
e.target.prepend(document.querySelector('.' + data))
// 获取设置的格式
console.log(e.dataTransfer.types); // ['text/plan']
// 获取所有拖动数据列表
console.log(e.dataTransfer.items); // DataTransferItemList {0: DataTransferItem, length: 1}
}
place.ondragover = function(e) {
e.preventDefault();
e.dataTransfer.dropEffect = 'move'
// 获取拖放操作中浏览器鼠标拖动样式
console.log(e.dataTransfer.dropEffect); // none
}
2-3 setData
除了 DataTransfer 的原始属性,我们还使用 setData() 方法,设置自定义拖拽数据项,方法接受两个参数,数据类型和数据值
setData(format, data) —— 设置 DataTransfer 对象指定类型的数据
dataTransfer.setData(format, data),format数据类型,data添加的数据- 数据类型为:“
text/plain” 和 “text/uri-list” - 如果该类型的数据不存在,则将其添加到末尾
- 如果该类型的数据已经存在,则在相同位置替换现有数据
let box = document.querySelector('.box')
box.ondragstart = function(e) {
// setData() 设置对象指定拖放类型
// 两种类型 text/plan text/uri-list
e.dataTransfer.setData('text/plan', e.target.className)
e.dataTransfer.setData('text/plan', 'setData方法')
e.dataTransfer.setData("text/uri-list", "http://www.mozilla.org");
}
2-4 getData
getData(format) —— 检索 DataTransfer 对象指定类型的数据
- 如果该类型的数据不存在或
datatransfer不包含数据,则返回空字符串
let box = document.querySelector('.box')
let place = document.querySelector('.place-region')
box.ondragstart = function(e) {
// setData() 设置对象指定拖放类型
// 两种类型 text/plan text/uri-list
e.dataTransfer.setData('className', e.target.className)
e.dataTransfer.setData('text/plan', 'setData方法')
e.dataTransfer.setData("text/uri-list", "http://www.mozilla.org");
}
// getData() 获取对象指定的拖放类型
place.ondrop = function(e) {
e.preventDefault();
// 获得设置的数据项
console.log(e.dataTransfer.getData('className'))
console.log(e.dataTransfer.getData('text/plan'))
console.log(e.dataTransfer.getData('text/uri-list'))
// 不存在返回空字符串
console.log(e.dataTransfer.getData(''))
}
place.ondragover = function(e) {
e.preventDefault();
}
2-5 clearData
clearData(format) —— 删除 DataTransfer 对象指定类型关联的数据
- 该方法只能在
dragstart事件的处理程序中使用,在拖动操作的数据存储时使用 - 如果此参数为空字符串或未提供,则将删除所有类型的数据
- 如果给定类型的数据不存在,则此方法不执行任何操作
let box = document.querySelector('.box')
let place = document.querySelector('.place-region')
box.ondragstart = function(e) {
// setData() 设置对象指定拖放类型
// 两种类型 text/plan text/uri-list
e.dataTransfer.setData('className', e.target.className)
e.dataTransfer.setData('text/plan', 'setData方法')
e.dataTransfer.setData("text/uri-list", "http://www.mozilla.org");
// clearData 删除指定类型关联的数据
e.dataTransfer.clearData('className');
}
// getData() 获取对象指定的拖放类型
place.ondrop = function(e) {
e.preventDefault();
// 获得设置的数据项
// 返回空字符串指定类型关联的数据已被删除
console.log(e.dataTransfer.getData('className'))
console.log(e.dataTransfer.getData('text/plan'))
console.log(e.dataTransfer.getData('text/uri-list'))
// 不存在返回空字符串
console.log(e.dataTransfer.getData(''))
}
place.ondragover = function(e) {
e.preventDefault();
}
2-6 拖拽图像
当拖拽发生时,会生成拖拽目标的一个半透明图像,并在拖拽过程中跟踪鼠标指针。这个图像是自动创建的,你可以使用 setDragImage() 方法来自定义拖拽反馈图像
setDragImage(img, xOffset, yOffset) —— 用于设置自定义的拖动图像
img设置拖动时半透明的图像,通常是一个<img>元素,但也可以是<canvas>或任何其他元素xOffset,yOffset相对于图片的横向纵向偏移量
let box = document.querySelector('.box')
box.ondragstart = function(e) {
// setDragImage() 设置拖拽时的图像
let img = new Image();
img.src = './assets/zhuang.jpg'
e.dataTransfer.setDragImage(img, 10, 10)
}
2-7 拖拽效果
dropEffect 属性用来控制拖放操作中用户给予的反馈,它会影响到拖拽过程中浏览器显示的鼠标样式。在 dragenter 或 dragover 事件期间修改 dropEffect 属性,取值 none、copy、move 或 link
none—— 被拖动元素不能放置在这里copy—— 被拖动元素应该复制到放置目标link—— 在放置目标建立拖动元素的链接move—— 被拖动元素应该移动到放置目标
let box = document.querySelector('.box')
box.ondragstart = function(e) {
// effectAllowed属性设置拖动元素允许哪种效果
e.dataTransfer.effectAllowed = 'link'
// none 不允许
// copy 允许copy样式
// copylink 允许copy和link样式
// copyMove 允许copy和move样式
// link 允许link样式
// linkMove 允许link与move样式
// move 允许move样式
// all 允许所有样式
// uninitialized 未设置样式默认
}
在 dragstart 事件监听程序中设置 effectAllowed 属性以指定允许拖拽元素执行哪几种拖拽效果
none—— 不允许放下copy—— 允许copy放置行为copyLink—— 允许copy和link放置行为copyMove—— 允许copy和move放置行为link—— 允许link放置行为linkMove—— 允许link和move放置行为move—— 允许move放置行为all—— 允许所有放置行为uninitialized—— 未设置放置行为
let place = document.querySelector('.place-region')
// getData() 获取对象指定的拖放类型
place.ondrop = function(e) {
e.preventDefault();
}
place.ondragover = function(e) {
e.preventDefault();
// dropEffect 属性用来控制拖放操作中鼠标显示的样式
// 在dragenter或dragover事件期间修改dropEffect属性
e.dataTransfer.dropEffect = 'link'
// none 不能放置拖动元素
// copy 复制拖动元素到放置目标
// link 与目标元素建立链接
// move 移动拖动元素到放置目标
}
2-8 放置对象
当拖拽一个项目到 HTML 元素中时,浏览器默认不会有任何响应,想要让一个元素变成可释放区域,该元素必须在 ondragover 和 ondrop 中阻止默认的处理并设置事件处理
let box = document.querySelector('.box')
let place = document.querySelector('.place-region')
box.ondragstart = function(e) {
console.log('dragstart')
}
// 可放置区域必须在元素drop事件与dragover事件取消默认行为
place.ondrop = function(e) {
e.preventDefault();
console.log('drop')
}
place.ondragover = function(e) {
e.preventDefault();
console.log('dragover')
}
2-9 列表拖拽排序
<div class="container">
<ul class="drag-list">
<li draggable="true" class="1">HTML</li>
<li draggable="true" class="2">CSS</li>
<li draggable="true" class="3">JavaScript</li>
<li draggable="true" class="4">Vue</li>
<li draggable="true" class="5">TypeScript</li>
</ul>
</div>
<script>
let dragList = document.querySelector('.drag-list')
let headTitle = document.querySelector('h3')
let placeList = document.querySelector('.place-list')
// 获取当前元素的index索引
function getIndex(elem) {
let index = 0;
if (!elem || !elem.parentNode) {
return -1;
} else {
while (elem = elem.previousElementSibling) {
index++;
}
}
return index;
}
// 当前移动的元素
let current = null;
dragList.ondragstart = function (e) {
current = e.target
}
dragList.ondragover = function (e) {
e.preventDefault();
e.dataTransfer.dropEffect = 'move'
}
dragList.ondrop = function (e) {
e.preventDefault();
if (e.target.nodeName === 'LI' && e.target !== current) {
// 如果current索引小于当前元素则替换位置
if (getIndex(current) < getIndex(e.target)) {
e.target.after(current)
} else {
e.target.before(current)
}
}
}
</script>

3. DataTransferItem
DataTransferItem 描述了一个拖拽项,在一个拖拽操作*中,*每一个 drag event 都有一个 dataTransfer 属性,它包含一个存有拖拽数据的列表,其中每一项都是一个 DataTransferItem
-
kind—— 拖拽项的种类,string或是file -
type—— 拖拽项的类型,一般是一个MIME类型 -
getAsFile()—— 返回一个关联拖拽项的File对象,当拖拽项不是一个文件时返回null -
getAsString()—— 使用拖拽项的字符串作为参数执行指定回调函数
<div class="container">
<ul class="drag-list">
<li draggable="true">HTML</li>
<li draggable="true">CSS</li>
<li draggable="true">JavaScript</li>
<li draggable="true">Vue</li>
<li draggable="true">TypeScript</li>
</ul>
<ul class="place-list">可放置区域</ul>
</div>
<script>
// 获取拖动列表的数量
let dragList = document.querySelectorAll('.drag-list > li');
[...dragList].forEach(list => {
list.addEventListener('dragstart', function (e) {
e.dataTransfer.items.add(this.innerText, 'text/plan');
})
})
let placeList = document.querySelector('.place-list')
placeList.addEventListener('drop', function (e) {
e.preventDefault()
let data = e.dataTransfer.items;
// kind 获取拖拽项种类
console.log(data[0].kind);
// type 获取拖拽类型
console.log(data[0].type);
[...data].forEach(item => {
// 拖拽项为file种类的回调函数
if (item.kind === 'file') {
// 返回一个File对象
console.log(item.getAsFile())
}
if (item.kind === 'string') {
item.getAsString(function (val) {
// 使用拖拽项的字符串作为参数执行指定回调函数
console.log(val)
})
}
})
})
placeList.addEventListener('dragover', function (e) {
e.preventDefault()
})
</script>
4. DataTransferItemList
DataTransferItemList 对象是一组代表被拖动项的 DataTransferItem 对象的列表
-
length—— 列表中拖动项的数量 -
add()—— 向拖动项列表中添加新项File对象或string,该方法返回一个DataTransferItem对象 -
remove()—— 根据索引删除拖动项列表中的对象 -
clear()—— 清空拖动项列表-
此列表的拖动数据存储区仅在处理
dragstart事件时可操作 -
在处理
drop事件时,drag数据存储处于只读模式,而此方法不执行任何操作
-
-
DataTransferItem()—— 返回给定下标的DataTransferItem对象
<div class="container">
<ul class="drag-list">
<li draggable="true">HTML</li>
<li draggable="true">CSS</li>
<li draggable="true">JavaScript</li>
<li draggable="true">Vue</li>
<li draggable="true">TypeScript</li>
</ul>
<ul class="place-list">可放置区域</ul>
</div>
<script>
// 获取拖动列表的数量
let dragList = document.querySelectorAll('.drag-list > li');
[...dragList].forEach(list => {
list.addEventListener('dragstart', function (e) {
e.dataTransfer.items.add(this.innerText, 'text/plan');
if (this.innerText === 'Vue') {
e.dataTransfer.setData('text/paln', 'Vue')
}
if (this.innerText === 'HTML') {
// remove删除拖拽列表中的对象
e.dataTransfer.items.remove(0)
}
if(this.innerText === 'CSS') {
// clear() 清空拖动项列表
e.dataTransfer.items.clear()
}
})
})
let placeList = document.querySelector('.place-list')
placeList.addEventListener('drop', function (e) {
e.preventDefault()
let data = e.dataTransfer.items;
// 拖动列表的length
console.log(data.length)
// drop时无法删除拖拽列表只可读
console.log(data)
})
placeList.addEventListener('dragover', function (e) {
e.preventDefault()
})
</script>
5. 地理定位
5-1 geolocation对象
HTML5 Geolocation API 用于获得用户的地理位置
地理位置 API 允许用户向 Web 应用程序提供他们的位置,出于隐私考虑,报告地理位置前会先请求用户许可
//判断地理位置是否支持
if ("geolocation" in navigator) {
/* 地理位置服务可用 */
} else {
/* 地理位置服务不可用 */
}

5-2 获取当前定位
可以调用 getCurrentPosition() 函数获取用户当前定位位置
该函数会异步地请求获取用户位置,并查询定位硬件来获取最新信息,当定位被确定后定义的回调函数就会被执行
navigator.geolocation.getCurrentPosition(success, error, options);
success—— 成功得到位置信息时的回调函数,使用Position对象作为唯一的参数
// 通过getCurrentPosition()获取当前定位
navigator.geolocation.getCurrentPosition(showPosition)
function showPosition(position) {
console.log(position)
// 通过该函数作为成功获取定位的回调函数
console.log(position.coords.latitude)
console.log(position.coords.longitude)
}
error—— 可选,用于处理错误,获取位置信息失败时的回调函数,使用PositionError对象作为唯一的参数
| 值 | 相关联的常量 | 描述 |
|---|---|---|
1 | PERMISSION_DENIED | 地理位置信息的获取失败,因为该页面没有获取地理位置信息的权限 |
2 | POSITION_UNAVAILABLE | 地理位置获取失败,因为至少有一个内部位置源返回一个内部错误 |
3 | TIMEOUT | 获取地理位置超时,通过定义 PositionOptions.timeout 来设置获取地理位置的超时时长 |
navigator.geolocation.getCurrentPosition(showPosition, showError)
function showError(error) {
switch (error.code) {
case error.PERMISSION_DENIED:
console.log('用户拒绝对获取地理位置的请求')
break;
case error.POSITION_UNAVAILABLE:
console.log('位置信息是不可用的')
break;
case error.TIMEOUT:
console.log('请求用户地理位置超时')
break;
case error.UNKNOWN_ERROR:
console.log('未知错误')
break;
}
}
options—— 可选,一个PositionOptions对象
| 属性 | 描述 | 值 |
|---|---|---|
enableHighAccuracy | 是否使用其最高精度 | false 默认值,设备会通过更快响应、更少的电量等方法来尽可能的节约资源true 提供一个更精确的位置,这会导致较慢的响应时间或者增加电量消耗 |
timeout | 限制返回时间 | Infinity 默认值,一直等待到获取位置为止 |
maximumAge | 可以返回多长时间(单位毫秒)内的缓存位置 | 如果设置为 0, 说明设备不能使用一个缓存位置,而且必须去获取一个真实的当前位置 |
navigator.geolocation.getCurrentPosition(showPosition, showError, {
enableHighAccuracy: true,
timeout: 2000,
maximumAge: 2000
})
5-3 监视定位
使用 watchPosition() 函数可以定时获取用户地理位置信息,在用户设备的地理位置发生改变的时候自动被调用
watchPosition() 与 getCurrentPosition() 接受相同的参数,但回调函数会被调用多次
let watchID = navigator.geolocation.watchPosition(success, error, options);
watchPosition() 函数会返回一个 ID,唯一地标记该位置监视器。您可以将这个 ID 传给 clearWatch() 函数来停止监视用户位置
navigator.geolocation.clearWatch(watchID);
// watchPosition 监视定位当用户位置发生改变时自动调用
let watchID = navigator.geolocation.watchPosition(showPosition, showError, {
enableHighAccuracy: false,
timeout: 5000,
maximumAge: 0
});
// 停止监听
navigator.geolocation.clearWatch(watchID);
function showError() {
console.log('定位失败')
}
function showPosition(position) {
console.log(position.coords.latitude)
console.log(position.coords.longitude)
}
5-4 position对象
获取地理定位成功,则 getCurrentPosition() 方法返回 position 对象。始终会返回 latitude、longitude 以及 accuracy 属性
| 属性 | 描述 |
|---|---|
| coords.latitude | 十进制数的纬度 |
| coords.longitude | 十进制数的经度 |
| coords.accuracy | 位置精度 |
| coords.altitude | 海拔,海平面以上以米计 |
| coords.altitudeAccuracy | 位置的海拔精度 |
| coords.heading | 方向,从正北开始以度计 |
| coords.speed | 速度,以米/每秒计 |
| timestamp | 响应的日期/时间 |
本文详细介绍了HTML5中的拖放功能,包括如何让元素具备拖放能力、拖放事件、dataTransfer对象的使用,以及如何自定义拖拽图像和效果。此外,还探讨了地理定位API,讲解了geolocation对象的使用,如何获取和监视用户的地理位置信息。
914

被折叠的 条评论
为什么被折叠?



