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)]
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')
}
HTML5
的拖拽接口有 DragEvent
, DataTransfer
, DataTransferItem
和 DataTransferItemList
DragEvent
是一个表示拖、放交互的一个 DOM event
接口,继承 MouseEvent
和Event
属性
dataTransfer
—— 在拖放交互期间传输的数据,dataTransfer
属性是一个 DataTransfer
对象let box = document.querySelector('.box')
box.ondragstart = function(e) {
console.log(e.dataTransfer)
}
DataTransfer
对象用于保存拖动并放下(drag and drop)过程中的数据,用于从被拖动元素向放置目标传递字符串数据
**Tips:**必须同时设置
effectAllowed
,否则dropEffect
属性无效
DataTransfer.dropEffect
获取当前选定的拖放操作类型或者设置的为一个新的类型。值必须为 none
, copy
, link
或 move
DataTransfer.effectAllowed
提供所有可用的操作类型。取值 none
, copy
, copyLink
, copyMove
, link
, linkMove
, move
, all
or uninitialized
之一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
}
除了 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");
}
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();
}
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();
}
当拖拽发生时,会生成拖拽目标的一个半透明图像,并在拖拽过程中跟踪鼠标指针。这个图像是自动创建的,你可以使用 setDragImage()
方法来自定义拖拽反馈图像
setDragImage(img, xOffset, yOffset)
—— 用于设置自定义的拖动图像
img
设置拖动时半透明的图像,通常是一个
元素,但也可以是
或任何其他元素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)
}
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 移动拖动元素到放置目标
}
当拖拽一个项目到 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')
}
<div class="container">
<ul class="drag-list">
<li draggable="true" class="1">HTMLli>
<li draggable="true" class="2">CSSli>
<li draggable="true" class="3">JavaScriptli>
<li draggable="true" class="4">Vueli>
<li draggable="true" class="5">TypeScriptli>
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>
DataTransferItem
描述了一个拖拽项,在一个拖拽操作*中,*每一个 drag event
都有一个 dataTransfer
属性,它包含一个存有拖拽数据的列表,其中每一项都是一个 DataTransferItem
kind
—— 拖拽项的种类,string
或是 file
type
—— 拖拽项的类型,一般是一个 MIME
类型
getAsFile()
—— 返回一个关联拖拽项的 File
对象,当拖拽项不是一个文件时返回 null
getAsString()
—— 使用拖拽项的字符串作为参数执行指定回调函数
<div class="container">
<ul class="drag-list">
<li draggable="true">HTMLli>
<li draggable="true">CSSli>
<li draggable="true">JavaScriptli>
<li draggable="true">Vueli>
<li draggable="true">TypeScriptli>
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>
DataTransferItemList
对象是一组代表被拖动项的 DataTransferItem
对象的列表
length
—— 列表中拖动项的数量
add()
—— 向拖动项列表中添加新项 File
对象或 string
,该方法返回一个 DataTransferItem
对象
remove()
—— 根据索引删除拖动项列表中的对象
clear()
—— 清空拖动项列表
此列表的拖动数据存储区仅在处理 dragstart
事件时可操作
在处理 drop
事件时,drag
数据存储处于只读模式,而此方法不执行任何操作
DataTransferItem()
—— 返回给定下标的 DataTransferItem
对象
<div class="container">
<ul class="drag-list">
<li draggable="true">HTMLli>
<li draggable="true">CSSli>
<li draggable="true">JavaScriptli>
<li draggable="true">Vueli>
<li draggable="true">TypeScriptli>
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>
HTML5 Geolocation API
用于获得用户的地理位置
地理位置 API 允许用户向 Web 应用程序提供他们的位置,出于隐私考虑,报告地理位置前会先请求用户许可
//判断地理位置是否支持
if ("geolocation" in navigator) {
/* 地理位置服务可用 */
} else {
/* 地理位置服务不可用 */
}
可以调用 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
})
使用 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)
}
获取地理定位成功,则 getCurrentPosition()
方法返回 position
对象。始终会返回 latitude
、longitude
以及 accuracy
属性
属性 | 描述 |
---|---|
coords.latitude | 十进制数的纬度 |
coords.longitude | 十进制数的经度 |
coords.accuracy | 位置精度 |
coords.altitude | 海拔,海平面以上以米计 |
coords.altitudeAccuracy | 位置的海拔精度 |
coords.heading | 方向,从正北开始以度计 |
coords.speed | 速度,以米/每秒计 |
timestamp | 响应的日期/时间 |