拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

HTML5 详解(二):拖拽、History、Geolocation 与全屏 API 实战指南

HTML5 详解(二):拖拽、History、Geolocation 与全屏 API 实战指南
  • 文档
  • 教程
  • 前端

【免费下载链接】Web

千古前端图文教程,超详细的前端入门到进阶知识库。从零开始学前端,做一名精致优雅的前端工程师。

项目地址:https://gitcode.com/gh_mirrors/we/Web
点击查看免费下载

本篇文章是「千古前端图文教程」HTML5 系列的第二篇,聚焦 HTML5 为 Web 应用带来的四个交互能力:拖拽(Drag and Drop)、历史状态管理(History)、地理定位(Geolocation)与全屏(Fullscreen)。通过本篇文章,你将学会用draggable属性与拖拽事件实现元素搬运,用window.history打造无刷新的单页应用,用navigator.geolocation获取用户经纬度并接入地图服务,以及用全屏 API 让任意元素铺满屏幕。本文内容承接 01-HTML/08-HTML5详解.md,并与 01-HTML/11-HTML5详解(三).md 共同构成 HTML5 核心能力全景。

一、拖拽(Drag and Drop)

在传统网页中,元素是无法被鼠标"抓起来"移动的。HTML5 规范引入了原生的拖拽能力:只要为元素增加draggable="true"属性,该元素就可以被用户拖拽。其中图片、链接默认就是开启拖拽的(例如博客园网站里的图片和超链接可以直接拖拽),而普通元素(如div)默认不可拖拽,需要显式声明。

1、拖拽元素(Draggable)

页面中设置了draggable="true"属性的元素,就是拖拽元素。最简单的例子:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="css/font-awesome.min.css"> <style> .box1{ width: 200px; height: 200px; background-color: green; } </style> </head> <body> <!--给 box1 增加拖拽的属性--> <div class="box1" draggable="true"></div> </body> </html>

给box1加上draggable="true"之后,它就变得可以拖拽了。但"拖拽之后要做什么事情"才是关键,这就涉及事件监听。

拖拽元素可以监听的四个事件(应用于拖拽元素本身):

事件触发时机
ondragstart当拖拽开始时调用
ondragleave当鼠标离开拖拽元素时调用
ondragend当拖拽结束时调用
ondrag整个拖拽过程都会调用

代码演示:

<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <style> .box { width: 200px; height: 200px; background-color: green; } </style> </head> <body> <div class="box" draggable="true"></div> <script> var box = document.querySelector('.box'); // 绑定拖拽事件 // 拖拽开始 box.ondragstart = function () { console.log('拖拽开始.'); } // 拖拽离开:鼠标拖拽时离开被拖拽的元素时触发 box.ondragleave = function () { console.log('拖拽离开..'); } // 拖拽结束 box.ondragend = function () { console.log('拖拽结束...'); console.log("---------------"); } box.ondrag = function () { console.log('拖拽'); } </script> </body> </html>

这里用到了document.querySelector('.box')这个 DOM 查询方法,它是 HTML5 DOM 操作的核心 API 之一,配合classList.add/remove可以完成丰富的交互,相关用法在 01-HTML/08-HTML5详解.md 的「DOM 操作」小节有系统讲解。另外注意,示例中事件处理函数里的this指向绑定事件的对象(即.box),关于事件函数中this的指向规则,可参考 04-JavaScript基础/25-this指向.md。

2、目标元素(Drop Target)

想把元素 A 拖拽到元素 B 里,元素 B 就是目标元素。页面中任何一个元素都可以成为目标元素。

目标元素可以监听的四个事件(应用于目标元素):

事件触发时机
ondragenter当拖拽元素进入时调用
ondragover当拖拽元素停留在目标元素上时,会连续一直触发(不管拖拽元素此时是移动还是不动的状态)
ondrop当在目标元素上松开鼠标时调用
ondragleave当鼠标离开目标元素时调用

代码演示:

<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <style> .one { width: 100px; height: 100px; border: 1px solid #000; background-color: green; } .two { position: relative; width: 200px; height: 200px; left: 300px; top: 100px; border: 1px solid #000; background-color: red; } </style> </head> <body> <div class="one" draggable="true"></div> <div class="two"></div> <script> var two = document.querySelector('.two'); //目标元素的拖拽事件 // 当被拖拽元素进入时触发 two.ondragenter = function () { console.log("来了."); } // 当被拖拽元素离开时触发 two.ondragleave = function () { console.log("走了.."); } // 当拖拽元素在 目标元素上时,连续触发 two.ondragover = function (e) { //阻止拖拽事件的默认行为 e.preventDefault(); //【重要】一定要加这一行代码,否则,后面的方法 ondrop() 无法触发。 console.log("over..."); } // 当在目标元素上松开鼠标是触发 two.ondrop = function () { console.log("松开鼠标了...."); } </script> </body> </html>

关键点:event.preventDefault()必不可少。示例中在ondragover里调用了e.preventDefault()来阻止拖拽的默认行为。如果没有这一行,浏览器默认不允许"把元素放下",后面的ondrop()方法根本无法触发——此时连光标形状都会提示"无法在此处放置"。

总结:如果想让拖拽元素在目标元素里做点事情,就必须在ondragover()里加event.preventDefault()这一行代码。preventDefault()是事件对象(Event)提供的标准方法,用来阻止浏览器的默认行为,它与事件绑定的多种方式(如addEventListener)配合使用的细节,可参考 04-JavaScript基础/41-事件的绑定和事件对象Event.md。

3、拖拽练习:把方块拖进目标盒子

理解了拖拽元素与目标元素两套事件体系之后,就可以实现"拖入容器"的完整功能。下面这个完整案例:左侧盒子内有 8 个圆形小方块,每个都可拖拽;拖到右侧的目标盒子中时,方块会被"收纳"进去。

<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <style> .one { width: 400px; height: 400px; border: 1px solid #000; } .one > div, .two > div { width: 98px; height: 98px; border: 1px solid #000; border-radius: 50%; background-color: red; float: left; text-align: center; line-height: 98px; } .two { width: 400px; height: 400px; border: 1px solid #000; position: absolute; left: 600px; top: 200px; } </style> </head> <body> <div class="one"> <div draggable="true">1</div> <div draggable="true">2</div> <div draggable="true">3</div> <div draggable="true">4</div> <div draggable="true">5</div> <div draggable="true">6</div> <div draggable="true">7</div> <div draggable="true">8</div> </div> <div class="two"></div> <script> var boxs = document.querySelectorAll('.one div'); // 临时的盒子 用于存放当前拖拽的元素 var two = document.querySelector('.two'); var temp = null; // 给8个小盒子分别绑定拖拽事件 for (var i = 0; i < boxs.length; i++) { boxs[i].ondragstart = function () { // 保持当前拖拽的元素 temp = this; console.log(temp); } boxs[i].ondragend = function () { // 当拖拽结束 ,清空temp temp = null; console.log(temp); } } // 目标元素的拖拽事件 two.ondragover = function (e) { // 阻止拖拽的默认行为 e.preventDefault(); } // 当在目标元素上松开鼠标是触发 two.ondrop = function () { // 将拖拽的元素追加到 two里面来 this.appendChild(temp); } </script> </body> </html>

这个案例的核心技巧在于用一个临时变量temp在拖拽元素与目标元素之间传递数据:

  1. 在ondragstart中把当前被拖拽的元素保存到temp(temp = this),这里的this正是触发事件的那个小方块;
  2. 在ondragend中清空temp,避免残留引用;
  3. 在目标元素的ondrop中,通过this.appendChild(temp)把暂存的元素追加为目标盒子的子节点,完成"搬运"。

这正是 HTML5 原生拖拽实现"跨容器搬运元素"的典型范式,无需 jQuery 等第三方库,纯原生即可实现类似购物车、选课列表等交互。

二、历史(History)

界面上的所有 JS 操作不会被浏览器记住,刷新或跳转后就无法回到之前的状态。在 HTML5 中,可以通过window.history操作访问历史状态,让一个页面可以有多个历史状态。

window.history对象让我们可以管理历史记录,常用于单页面应用(Single Page Application,SPA)——无刷新地改变网页内容。常用方法如下:

方法作用
window.history.forward()前进
window.history.back()后退
window.history.go()刷新
window.history.go(n)n=1表示前进;n=-1后退;n=0刷新。如果移动的位置超出了访问历史的边界,会静默失败,但不会报错
history.pushState通过 JS 加入一个访问状态(放入历史中的状态数据,可设置 title,但当前浏览器并不支持通过它改变历史状态标题)

pushState是 SPA 路由方案的核心底层能力:它可以在不刷新页面的情况下,向浏览器历史栈中压入一条新的状态记录,配合popstate事件实现地址与内容的同步切换。关于 Vue 生态下的路由实践,可进一步参考 12-Vue基础/13-Vue-router路由.md。

三、地理定位(Geolocation)

在 HTML5 规范中,增加了获取用户地理信息的 API,使得我们可以基于用户位置开发互联网应用,即基于位置服务 LBS(Location Base Service),例如周边商家推荐、路线规划、打卡签到等场景。

1、获取地理信息的方式

浏览器获取用户地理信息主要有以下几种途径,会自动以最优方式去获取:

(1)IP 地址:根据用户的公网 IP 粗略推断所在区域,精度较低。

(2)三维坐标:精度较高,主要包括以下几种定位技术:

  • GPS(Global Positioning System,全球定位系统):依靠卫星定位,精度高,室外可用。
  • Wi-Fi 定位:通过扫描附近 Wi-Fi 热点反推位置,仅限于室内。
  • 手机信号定位:通过运营商的信号塔(基站)定位。

这里顺带介绍一下当前全球在用的第二代全球卫星导航系统(GNSS):

  1. 美国 Global Positioning System(全球定位系统),简称GPS;
  2. 苏联/俄罗斯 GLOBAL NAVIGATION SATELLITE SYSTEM(全球卫星导航系统),简称GLONASS(格洛纳斯);
  3. 欧盟 Galileo satellite navigation system(伽利略卫星导航系统),简称GALILEO(伽利略)(欧洲的说法并不准确,包括中国在内的诸多国家也参与其中);
  4. 中国 BeiDou(COMPASS) Navigation Satellite System(北斗卫星导航系统),简称BDS;
  5. 日本 Quasi-Zenith Satellite System(准天顶卫星系统),简称QZSS;
  6. 印度 India Regional Satellite Navigation System(印度区域卫星导航系统),简称IRNSS。

以上 6 个系统在中国都能使用。

(3)用户自定义数据:由用户手动输入或应用自行维护的位置数据。浏览器会对不同获取方式的优缺点进行比较,自动选择最优方式。

2、隐私机制

HTML5 Geolocation(地理位置定位)规范提供了一套保护用户隐私的机制:必须先得到用户明确许可,才能获取用户的位置信息。当页面调用定位 API 时,浏览器会弹出授权询问框,用户拒绝后定位将无法进行。这是 Web 平台对用户隐私的基本尊重,开发者在设计定位类应用时要提前考虑"用户拒绝授权"的降级方案。

3、API 详解

地理位置相关 API 挂在navigator.geolocation对象上,核心有两个:

  • navigator.getCurrentPosition(successCallback, errorCallback, options):获取一次当前地理信息;
  • navigator.watchPosition(successCallback, errorCallback, options):重复获取当前地理信息(可用于持续跟踪位置变化)。

回调参数说明:

  1. 当成功获取地理信息后,会调用successCallback,并返回一个包含位置信息的对象position(coords即坐标):
    • position.coords.latitude:纬度;
    • position.coords.longitude:经度。
  2. 当获取地理信息失败后,会调用errorCallback,并返回错误信息error。
  3. 可选参数options对象可以调整位置信息数据收集方式,常用的配置项包括enableHighAccuracy(是否开启高精度模式)、timeout(超时时间)与maximumAge(允许缓存的最长时间)等。

完整代码演示:

<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <script> /*navigator 导航*/ //geolocation: 地理定位 // window.navigator.geolocation // 兼容处理 if(navigator.geolocation){ // 如果支持,获取用户地理信息 // successCallback 当获取用户位置成功的回调函数 // errorCallback 当获取用户位置失败的回调函数 navigator.geolocation.getCurrentPosition(successCallback,errorCallback); }else{ console.log('sorry,你的浏览器不支持地理定位'); } // 获取地理位置成功的回调函数 function successCallback(position){ // 获取用户当前的经纬度 // coords坐标 // 纬度latitude var wd=position.coords.latitude; // 经度longitude var jd=position.coords.longitude; console.log("获取用户位置成功!"); console.log(wd+'----------------'+jd); // 40.05867366972477----------------116.33668634275229 } // 获取地理位置失败的回调函数 function errorCallback(error){ console.log(error); console.log('获取用户位置失败!') } </script> </body> </html>

代码要点:先通过if(navigator.geolocation)做兼容性判断,支持才调用getCurrentPosition;成功回调里从position.coords.latitude / longitude取出经纬度。

需要注意的是,不同地图服务对同一地理位置的坐标展示存在坐标系差异(即坐标偏移),示例代码中的注释给出了对照:谷歌地图40.0601398850,116.3434224706、百度地图40.0658210000,116.3500430000、腾讯/高德40.0601486487,116.3434373643。因此在对接具体地图厂商时,通常需要做坐标系的转换或直接使用对方提供的定位能力。

百度地图 API 举例(全景图展示):

<!DOCTYPE html> <html> <head> <title>普通地图&全景图</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=NsGTBiDpgGQpI7KDmYNAPGuHWGjCh1zk"></script> <style type="text/css"> body, html{width: 100%;height: 100%;overflow: hidden;margin:0;font-family:"微软雅黑";} #panorama {height: 100%;overflow: hidden;} </style> </head> <body> <div id="panorama"></div> <script type="text/javascript"> //全景图展示 // 谷歌获取的经纬度 40.05867366972477----------------116.33668634275229 // 百度地图:40.0658210000,116.3500430000 var jd=116.350043; var wd=40.065821; var panorama = new BMap.Panorama('panorama'); panorama.setPosition(new BMap.Point(jd, wd)); //根据经纬度坐标展示全景图 panorama.setPov({heading: -40, pitch: 6}); panorama.addEventListener('position_changed', function(e){ //全景图位置改变后,普通地图中心点也随之改变 var pos = panorama.getPosition(); map.setCenter(new BMap.Point(pos.lng, pos.lat)); marker.setPosition(pos); }); </script> </body> </html>

这里演示了把 Geolocation 得到的经纬度交给百度地图 SDK:new BMap.Point(jd, wd)构造坐标点,BMap.Panorama展示全景图,并通过position_changed事件联动普通地图与标记点。这展示了"浏览器定位 + 地图服务"的经典组合:定位负责拿坐标,地图负责呈现。

四、全屏(Fullscreen)

HTML5 规范允许用户自定义网页上任一元素全屏显示——不限于视频,任何div、图片、图表容器都可以铺满整个屏幕。

1、开启/关闭全屏显示

方法如下(注意规范写法中screen是小写):

requestFullscreen() //让元素开启全屏显示 cancelFullscreen() //让元素关闭全屏显示

考虑到兼容性问题,不同浏览器需要在此基础之上添加私有前缀(注意带前缀的写法中screen是大写):

webkitRequestFullScreen webkitCancelFullScreen mozRequestFullScreen mozCancelFullScreen

其中webkit前缀对应 Chrome、Safari 等 WebKit/Blink 内核浏览器,moz前缀对应 Firefox。

2、检测当前是否处于全屏状态

document.fullScreen

不同浏览器需要加私有前缀:

document.webkitIsFullScreen document.mozFullScreen

3、全屏的伪类

当元素进入全屏状态后,可以通过全屏伪类改变它的样式:

:full-screen .box {} :-webkit-full-screen {} :-moz-full-screen {}

例如:当元素处于全屏状态时,改变它的背景色,就可以用到这些伪类。

4、代码举例

<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <style> .box { width: 250px; height: 250px; background-color: green; margin: 100px auto; border-radius: 50%; } /*全屏伪类:当元素处于全屏时,改变元素的背景色*/ .box:-webkit-full-screen { background-color: red; } </style> </head> <body> <div class="box"></div> <script> var box = document.querySelector('.box'); // box.requestFullscreen(); //直接这样写是没有效果的。之所以无效,应该是浏览器的机制,必须要点一下才可以实现全屏功能。 document.querySelector('.box').onclick = function () { // 开启全屏显示的兼容写法 if (box.requestFullscreen) { //如果支持全屏,那就让元素全屏 box.requestFullscreen(); } else if (box.webkitRequestFullScreen) { box.webkitRequestFullScreen(); } else if (box.mozRequestFullScreen) { box.mozRequestFullScreen(); } } </script> </body> </html>

这个例子有两个值得注意的工程细节:

  1. 全屏必须由用户手势触发:直接调用box.requestFullscreen()是无效的,浏览器安全机制要求全屏操作必须发生在用户交互(如点击)的回调中,所以示例把调用放在了onclick里。
  2. 兼容性分支判断:依次判断requestFullscreen→webkitRequestFullScreen→mozRequestFullScreen,哪个存在就调用哪个,这是处理浏览器前缀 API 的标准写法。
  3. 全屏伪类联动:进入全屏后,圆形的绿色盒子通过:-webkit-full-screen伪类变成红色,直观展示"全屏状态可单独定制样式"。

5、全屏 API 的综合应用:视频播放器

全屏 API 最典型的实战场景是视频播放器。仓库中的 01-HTML/09-HTML5举例:简单的视频播放器.md 就实现了一个完整的 H5 播放器:用video.play()/video.pause()控制播放暂停,用video.ontimeupdate同步进度条与当前时间,并在点击全屏按钮时调用:

// 全屏 extend.onclick=function(){ // 全屏的h5代码 video.webkitRequestFullScreen(); }

这正好是本节全屏 API 的实际落地:把<video>元素全屏展示,获得沉浸式观影体验。可见,全屏 API 与 HTML5 多媒体标签(<video>、<audio>)是天然的搭档,关于多媒体标签的更多属性(controls、autoplay、loop、preload及多格式兼容写法),可回顾 01-HTML/08-HTML5详解.md 的「多媒体」小节。

五、小结:四大 API 的适用场景速查

API核心入口典型场景关键注意事项
拖拽draggable="true"+ondrag*系列事件卡片搬运、拖拽排序、文件拖放目标元素的ondragover里必须preventDefault(),否则ondrop不触发
历史window.history单页应用(SPA)的页面切换go(n)超出边界会静默失败;pushState不改变标题
定位navigator.geolocation.getCurrentPosition/watchPositionLBS 应用、地图导航、打卡签到必须先获得用户授权;不同地图厂商坐标系存在偏移
全屏requestFullscreen()(含 webkit/moz 前缀)视频播放器、图表大屏、沉浸式演示必须由用户手势触发;可用:full-screen伪类定制全屏样式

本文讲解的四个能力都强调"事件驱动 + 用户交互",是 HTML5 从"静态文档"走向"富客户端应用"的重要标志。它们与 01-HTML/11-HTML5详解(三).md 中讲解的 Web 存储(localStorage/sessionStorage)、网络状态监听、应用缓存一起,构成了开发现代 Web 应用所需的基础能力栈。建议读者把本文中的示例逐行敲一遍,再结合 01-HTML/08-HTML5详解.md 中的语义标签、智能表单与多媒体内容,以及 01-HTML/09-HTML5举例:简单的视频播放器.md 的完整工程,形成对 HTML5 的体系化认知。

  • 文档
  • 教程
  • 前端

【免费下载链接】Web

千古前端图文教程,超详细的前端入门到进阶知识库。从零开始学前端,做一名精致优雅的前端工程师。

项目地址:https://gitcode.com/gh_mirrors/we/Web
点击查看免费下载
上一篇:@lingo.dev/_logging 日志基础设施演进实录:Pino 轮转日志、容错设计与供应链安全实践
下一篇:eSearch 开发环境搭建指南:从源码克隆、依赖安装到打包编译

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

返回列表