拖放与地理定位

拖放与地理定位

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 拖放事件

HTML5drag & drop 使用了 DOM event model DOM事件模型以及从 mouse events 鼠标事件继承而来的 drag events 拖放事件

**Tips:**在操作期间,会触发一些事件类型,有一些事件类型可能会被多次触发

**Tips:**当从操作系统向浏览器中拖拽文件时,不会触发 dragstartdragend 事件

事件 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 键)

在拖动目标时触发事件,作用在被拖拽元素上:dragstartdragdragend

释放目标时触发的事件,作用在放置目标元素上:dragenterdragoverdragleavedrop

// 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, DataTransferItemDataTransferItemList

2-1 dataTransfer

DragEvent 是一个表示拖、放交互的一个 DOM event 接口,继承 MouseEventEvent 属性

  • 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, linkmove
  • 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
}

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 设置拖动时半透明的图像,通常是一个 元素,但也可以是 或任何其他元素
  • xOffsetyOffset 相对于图片的横向纵向偏移量
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 属性用来控制拖放操作中用户给予的反馈,它会影响到拖拽过程中浏览器显示的鼠标样式。在 dragenterdragover 事件期间修改 dropEffect 属性,取值 nonecopymovelink

  • 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 —— 允许 copylink 放置行为
  • copyMove —— 允许 copymove 放置行为
  • link —— 允许 link 放置行为
  • linkMove —— 允许 linkmove 放置行为
  • 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 元素中时,浏览器默认不会有任何响应,想要让一个元素变成可释放区域,该元素必须在 ondragoverondrop 中阻止默认的处理并设置事件处理

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">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>

拖放与地理定位_第1张图片

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">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>

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">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>

5. 地理定位

5-1 geolocation对象

HTML5 Geolocation API 用于获得用户的地理位置

地理位置 API 允许用户向 Web 应用程序提供他们的位置,出于隐私考虑,报告地理位置前会先请求用户许可

//判断地理位置是否支持   
if ("geolocation" in navigator) {
  /* 地理位置服务可用 */
} else {
  /* 地理位置服务不可用 */
}

拖放与地理定位_第2张图片

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 对象。始终会返回 latitudelongitude 以及 accuracy 属性

属性 描述
coords.latitude 十进制数的纬度
coords.longitude 十进制数的经度
coords.accuracy 位置精度
coords.altitude 海拔,海平面以上以米计
coords.altitudeAccuracy 位置的海拔精度
coords.heading 方向,从正北开始以度计
coords.speed 速度,以米/每秒计
timestamp 响应的日期/时间

你可能感兴趣的:(html,html,javascript)