1. 地理定位
地理定位:
Geolocation, 使用JS获取浏览器所在的地理坐标信息, 实现LBS( Location Based Service, 基于定位服务 )应用, Ex: 送餐, 打车, 导航等
-
具体地理坐标信息包括:
- 经度:
longitude - 纬度:
latitude - 海拔:
altitude - 速度:
speed
- 经度:
1.1. 如何获取浏览器所在的定位数据
1.1.1. 手机
- 可以使用内置的
GPS芯片获取卫星数据, 精度为米( m ) - 也可以通过手机通信基站, 反向推出用户位置, 精度为千米( km )
1.1.2. PC
- 可以通过用户的
IP地址反向推导出所在位置( 必需有很大的IP地址库 ), 精度在千米( km )
1.1.3. H5 中提供了新的对象, 专用于获取用户所在的位置数据
-
语法:
window.navigator.geolocation { getCurrentPosition: fn, // 用于获取当前的位置信息 watchPosition: fn, // 监视用户位置的改变 clearWatch: fn // 清除定位监视 } // 获取用户定位信息 window.navigator.geolocation.getCurrentPosition( function (pos) { ...... }, // 定位成功后的回调 function (err) { ...... } // 定位失败后的回调 ) -
提示:
PC中的Chrome和Firefox都需要到www.googleapis.com进行IP地址方向解析, 由于国内无法访问该网站, 所以目前在PC中此方法使用价值不大
2. 拖放 API
Drag&Drop: 拖放,H5提供的拖放API, 可以实现类似于桌面软件中的拖放效果, 无需像以前那样使用鼠标事件来代替
2.1. 拖动的源对象 source ( 可能发生移动的 ) 可以触发的事件: 3 个
dragstart: 拖动开始drag: 拖动中dragend: 拖动结束
-
整个拖动过程的组成:
dragstart* 1 +drag*n+dragend* 1 -
Ex: 实现一个可以随鼠标移动而移动的小飞机
<style> body{ position: relative; margin: 0; } body:before{ content: ''; display: table; } .dragTest{ position: absolute; } </style> <body> <img src="images/dragTest.png" class="dragTest" id="dragTest" /> <script type="text/javascript"> let dragTest = document.getElementById('dragTest') // 拖动刚开始事件相对于飞机的偏移量 let startX = 0 let startY = 0 // 拖动开始 dragTest.addEventListener('dragstart', function (e) { // 拖动事件相对于事件源的偏移量 startX = e.offsetX startY = e.offsetY }) // 拖动中 dragTest.addEventListener('drag', function (e) { let x = e.pageX let y = e.pageY // 屏蔽鼠标在即将松手时触发的(0, 0) 坐标 if (0 == x && 0 == y) { return ; } // 修改小飞机的位置 dragTest.style.left = x - startX + 'px' dragTest.style.top = y - startY + 'px' }) // 拖动完毕 dragTest.addEventListener('dragend', function (e) { console.log(e.pageX) console.log(e.pageY) console.log('拖动完毕') }) </script> </body> -
提示:
drag事件中获取拖动事件相对于页面的坐标(e.pageX,e.pageY), 及时修改事件源的位置(left,top), 事件源绝对定位, 父容器相对定位
2.2. 拖放的目标对象 target ( 不会发生移动 ) 可以触发的事件: 4 个
dragenter: 拖动着进入dragover: 拖动着悬停dragleave: 拖动着离开drop: 释放
- 整个拖动过程的组成1:
dragenter* 1 +dragover*n+dragleave* 1 - 整个拖动过程的组成2:
dragenter* 1 +dragover*n+drop* 1
注意:
dragover事件的默认行为是必须触发dragleave, 若不阻止默认行为,drop无法触发
-
Ex: 初始化垃圾桶半透明, 若有飞机拖动着进入, 垃圾桶变为不透明, 飞机离开 / 释放, 垃圾桶变为不透明, 若飞机在垃圾桶释放, 则删除该飞机
<style> body{ text-align: center; } div.container{ min-height: 200px; padding: 10px; border: 1px solid #aaa; } .trash{ opacity: 0.3; } </style> <body> <!-- 垃圾桶 --> <img src="images/trash.png" id="trash" class="trash" /> <!-- 飞机选择 --> <div class="container" id="container"> <img src="images/planRed.png" id="planRed" /> <img src="images/planBlue.png" id="planBlue"/> <img src="images/planYellow.png" id="planYellow" /> </div> <script type="text/javascript"> let trash = document.getElementById('trash') let planContainer = document.getElementById('container') // 全局变量: 记录拖动的是哪个飞机 let draggedPlanId = null // 给飞机添加事件 let planList = document.querySelectorAll('div.container > img') for(let i = 0; i < planList.length; i++) { let planItem = planList[i] planItem.addEventListener('dragstart', function () { draggedPlanId = this.id }) planItem.addEventListener('drag', function () {}) planItem.addEventListener('dragend', function () {}) } // 给拖动目标(垃圾桶) 添加事件 trash.addEventListener('dragenter', function () { this.style.opacity = 1 }) trash.addEventListener('dragover', function (e) { e.preventDefault() }) trash.addEventListener('dragleave', function () { this.style.opacity = 0.3 }) trash.addEventListener('drop', function () { // 修改垃圾桶的透明度 this.style.opacity = 0.3 // 根据 ID 删除飞机 let planId = document.getElementById(draggedPlanId) planContainer.removeChild(planId) }) </script> </body>
2.3. 如何在拖动的源对象 source 和 目标对象 target 间传递数据
-
如何在 7 个事件之间传递参数
- 源对象事件: 3 个
- 目标对象事件: 4 个
2.3.1. 方法一: 使用全局变量 -> 全局对象污染
2.3.2. 方法二: 使用拖动对象的 dataTransfer 属性
说明:
dataTransfer, 用作数据传递 / 转移, 看做"拖拉机"
-
在拖动源对象事件中使用
e.dataTransfer属性保存数据e.dataTransfer.setData('key', 'value')
-
在拖动目标对象事件中使用
e.dataTransfer属性读取数据e.dataTransfer.getData('key')
-
Ex: 实现英雄选择
<style> *{ box-sizing: border-box; } body{ text-align: center; } div.chosen, div.planList{ padding: 5px; border: 1px solid #aaa; } div.chosen{ width: 200px; height: 115px; margin: 0 auto; } div.chosen > img{ width: 100%; } </style> <body> <div class="chosen" id="chosen"> <img src="images/planInit.png" id="planInit" /> </div> <div class="planList" id="planList"> <img src="images/planRed.png" id="planRed" /> <img src="images/planBlue.png" id="planBlue" /> <img src="images/planYellow.png" id="planYellow" /> </div> <script type="text/javascript"> /* 拖动飞机到 chosen 选择区 planInit 飞机隐藏 拖动的飞机进入选择区 */ let planList = document.querySelectorAll('div.planList > img') let planListId = document.getElementById('planList') for(let i = 0; i < planList.length; i++) { let planItem = planList[i] // 飞机项添加拖动事件 planItem.addEventListener('dragstart', function (e) { // 在源对象事件中保存数据 e.dataTransfer.setData('planId', this.id) }) planItem.addEventListener('drag', function (e) { console.log('拖动中') }) planItem.addEventListener('dragend', function (e) { console.log('拖动结束') }) } // 拖放目标事件 let chosen = document.getElementById('chosen') chosen.addEventListener('dragenter', function (e) { console.log('拖动着进入') }) chosen.addEventListener('dragover', function (e) { e.preventDefault() console.log('拖动着悬停') }) chosen.addEventListener('dragleave', function (e) { console.log('拖动着离开') }) chosen.addEventListener('drop', function (e) { let planInit = document.getElementById('planInit') // 隐藏初始化飞机 planInit.style.display = 'none' // 若初始化飞机此时有兄弟元素, 将该兄弟元素放回原处 if (planInit.nextElementSibling) { planListId.appendChild(planInit.nextElementSibling) } // 将当前拖动放到选择区 let planId = e.dataTransfer.getData('planId') let plan = document.getElementById(planId) chosen.appendChild(plan) }) </script> </body>
2.4. 如何在服务器下载的网页中显示客户端图片
-
一般情况下, 网页只能显示服务器上的图片
-
HTML5中, 可以实现用户拖拽一张本地图片显示在服务器端下载的网页中container.addEventListener('drop', function (e) { let filesOne = e.dataTransfer.files[0] let reader = new FileReader() reader.readAsDataURL(filesOne) reader.addEventListener('load', function () { // 读取完成, 数据在 reader.result 中 }) })
2.4.1. H5 中提供的用于文件输入 / 输出( I / O ) 的对象
File: 代表一个文件 / 目录对象FileList: 代表一个文件列表( 类数组对象 )FileReader: 用于从文件中读取内容FileWriter: 用于向文件中写入内容
3. Web Storage
3.1. Web 项目中项目数据的存储位置
-
服务器端存储: 业务数据, Ex: 商品, 用户, 订单, 帖子, 评论, 储户等
-
客户端存储: 客户端专有数据, Ex: 历史记录, 内容定制, 样式偏好等
Cookie技术: 兼容性好, 大小不能超过 4KB, 操作复杂Flash存储: 不推荐使用IndexedDB技术: 可以直接存取对象, 不是H5标准WebStorage技术: 大小不能超过 8MB, 操作简单,H5特性
3.2. H5 的 WebStorage 技术具体分为两个对象:
3.2.1. window.sessionStorage
Session: 会话, 自从浏览器第一次打开某网站的某个页面开始, 不断的请求 - 响应, 直到最后关闭浏览器 -> 整个过程称为浏览器和Web服务器之间的一次会话 -> 一次会话可能出现任意多个页面的请求 - 响应sessionStorage: 会话级数据存储, 本质就是一个存储在浏览器内存中的类数组对象; 专用于存储当前会话中需要保存的数据, 会话结束则数据删除
-
保存数据:
sessionStorage['key'] = value -
读取数据:
let val = sessionStorage['key'] -
查看保存的数据个数:
let count = sessionStorage.length -
保存数据:
sessionStorage.setItem('key', value) -
读取数据:
let val = sessionStorage.getItem('key') -
删除数据:
sessionStorage.removeItem('key') -
清除所有数据:
sessionStorage.clear() -
获取第
i个key:let key = sessionStorage.key(i) -
Ex: 使用
sessionStorage保存登录用户的uName和uId, 供后续的页面使用// index.html <style> div.welcome{ text-align: right; } </style> <body> <div class="welcome" id="welcome"> <a href="login.html">登录</a> </div> <h3>首页</h3> <script type="text/javascript"> let welcome = document.getElementById('welcome') // 读取 sessionStorage 存储的数据 let uName = window.sessionStorage.getItem('uName') if (uName) { welcome.innerHTML = ` 欢迎回来: ${ uName } <a href="logout.html">退出登录</a> ` } </script> </body>// login.html <body> <form action=""> 用户名: <input type="text" name="uName" id="uName" /> 密码: <input type="password" name="uPwd" id="uPwd" /> <input type="button" value="提交登录消息" id="loginBtn" /> </form> <script type="text/javascript"> let loginBtn = document.getElementById('loginBtn') let uNameEl = document.getElementById('uName') let uPwdEl = document.getElementById('uPwd') // 使用 sessionStorage 存储用户登录信息 loginBtn.addEventListener('click', function () { let uName = uNameEl.value let upwd = uNameEl.value window.sessionStorage.setItem('uName', uName) window.sessionStorage['uPwd'] = uPwd // 跳转页面 alert('登录成功! 3 s后将自动跳转到首页') window.setTimeout(function () { window.location.href = 'index.html' }, 3000) }) </script> </body>// logout.html <body> <h3>退出登录</h3> <h4>你已退出登录!</h4> <p>3 s后将自动跳转到首页</p> <script type="text/javascript"> // 清除 sessionStorage 存储的数据 // sessionStorage.removeItem('uName') window.sessionStorage.clear() // 跳转页面 window.setTimeout(function () { window.location.href = 'index.html' }, 3000) </script> </body>
3.2.2. window.localstorage
localStorage: 跨会话级数据存储, 本质就是一个在浏览器硬盘 / 文件中的类数组对象 专用于永久存储当前网站在当前浏览器中的专用数据, 即使关闭浏览器 / 重启电脑数据也不会删除
-
保存数据:
localStorage['key'] = value -
读取数据:
let val = localStorage['key'] -
查看保存的数据个数:
let count = localStorage.length -
保存数据:
localStorage.setItem('key', value) -
读取数据:
let val = localStorage.getItem('key') -
删除数据:
localStorage.removeItem('key') -
清除所有数据:
localStorage.clear() -
获取第
i个key:let key = localStorage.key(i) -
window.onstorage事件: 当localStorage中数据发生改变时自动触发.注意: 该事件只能用于监听
localStorage中的数据变化, 而不能监听sessionStorage中的数据改变 -
Ex: 使用
localStorage存储用户的样式偏好-
创建
index.html,select选择你喜欢的风格// index.html <style> .blue{ color: #33a; background: #ccf; } .pink{ color: #a0a; background: #faf; } .dark{ color: #eee; background: #333; } </style> <body> <h3>首页</h3> <select name="selUserHobby" id="selUserHobby"> <option vlaue="">请选择你喜欢的主题</option> <option value="blue">蓝色天空</option> <option value="pink">芭比公主</option> <option value="dark">暗黑主题</option> </select> <p> <span> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Assumenda dolor dolores impedit minima perspiciatis qui repellendus sint tempora veritatis vitae! Animi eligendi expedita facilis impedit iusto magnam nihil nobis pariatur? </span> </p> <a href="userCenter.html">跳转到用户中心</a> <script type="text/javascript"> let selUserHobby = document.getElementById('selUserHobby') selUserHobby.addEventListener('change', function () { let hobbyTheme = this.value if (0 == hobbyTheme) { return false } // 为 body 添加 class 类 document.body.className = hobbyTheme // 使用 localStorage 存储用户喜好 window.localStorage.setItem('userHobby', hobbyTheme) }) // 读取 localStorage let userHobby = window.localStorage['userHobby'] document.body.className = userHobby </script> </body> -
创建
userCenter.html, 自动呈现首页中选择的样式风格// userCenter.html <style> .blue{ color: #33a; background: #ccf; } .pink{ color: #a0a; background: #faf; } .dark{ color: #eee; background: #333; } </style> <body> <h3>用户中心</h3> <p> <span> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Assumenda dolor dolores impedit minima perspiciatis qui repellendus sint tempora veritatis vitae! Animi eligendi expedita facilis impedit iusto magnam nihil nobis pariatur? </span> </p> <a href="index.html">返回首页</a> <script type="text/javascript"> // 读取 localStorage let userHobby = window.localStorage.getItem('userHobby') document.body.className = userHobby // 监听 localStorage 中的数据变化 window.addEventListener('storage', function () { // 读取存储的数据 let userHobby = window.localStorage['userHobby'] document.body.className = userHobby }) </script> </body>
-
4. 网页游戏如何按照特定顺序绘制没有特定加载顺序的图片
// 全局的变量: 记录所有图片的总加载进度
let progress = 0
// 加载图片
let imgPan = new Image()
imgPan.src = 'img/pan.png'
imgPan.onload = function () {
console.log('1 - 圆盘加载成功')
progress += 75
if (100 == progress) { // 查看总权重是否已满
startDraw()
}
}
// 加载图片
let imgPin = new Image()
imgPin.src = 'img/pin.png'
imgPin.onload = function () {
console.log('2 - 指针加载完成')
progress += 25
if (100 == progress) {
startDraw()
}
}