WebStorage
WebStorage是HTML5提供的可以让前端持久化缓存数据的存储空间。包含两种对象:
sessionStorage: 这一块存储空间存储的数据单浏览器会话生效。重启浏览器即销毁。localStorage: 这一块存储空间存储的数据永久有效。
WebStorage相关API
存数据:
sessionStorage.setItem('name', '张三')
localStorage.setItem('age', '15')
let user = {"id":1,"name":"zs","age":15}
sessionStorage.setItem('user', JSON.stringify(user))
读数据:
sessionStorage.getItem('name') --> '张三'
localStorage.getItem('age') --> '15'
sessionStorage.getItem('user') --> JSON字符串
JSON.parse(sessionStorage.getItem('user')) --> JS对象
删除数据:
sessionStorage.removeItem('name')
localStorage.removeItem('name')
清空数据:
sessionStorage.clear()
localStorage.clear()
退出登录
音频与视频
HTML5提供了相关标签支持在网页中实现音频与视频的播放。
音频标签
音频标签支持的文件格式有:WAV、MP3、ogg。
音频标签的简单使用方法:
<audio src="../assets/xxxx.mp3" controls></audio>
音频标签的标准使用方法:
<audio controls>
<source src="xxx.mp3" type="audio/mpeg"/>
<source src="xxx.wav" type="audio/wav"/>
<source src="xxx.ogg" type="audio/ogg"/>
什么破浏览器,换一个吧~
</audio>
audio的常用属性
<audio controls 是否显示播放器控制面板
src=""
autoplay 是否在加载完毕后自动播放
muted 是否静音
loop 是否单曲循环
preload="预加载模式"></audio>
preload:
none不预加载metadata只预加载元数据auto尽可能的加载音频数据
视频标签
简写方式:
<video src="" 视频文件的链接路径
controls
autoplay
muted
loop
width="" 视频播放器的宽度
height="" 视频播放器的高度
poster="" 海报帧图片路径
></video>
音视频相关的DOM操作
我们可以通过Javascript获取音视频的DOM对象。
可以通过访问对象的属性,调用对象的方法来访问音视频播放状态,控制音视频的播放。
<audio id="audio" src="./let.mp3"></audio>
<script>
let audio = document.getElementById('audio')
audio.duration 属性 返回时长
audio.play() 方法 播放视频
</script>
查看DOM相关文档:
https://www.w3school.com.cn/tags/html_ref_audio_video_dom.asp
音视频相关的DOM操作
我们可以通过Javascript获取音视频的DOM对象。
可以通过访问对象的属性,调用对象的方法来访问音视频播放状态,控制音视频的播放。
<audio id="audio" src="./let.mp3"></audio>
<script>
let audio = document.getElementById('audio')
audio.duration 属性 返回时长
audio.play() 方法 播放视频
</script>
查看DOM相关文档:
https://www.w3school.com.cn/tags/html_ref_audio_video_dom.asp
HTML5 Audio/Video 属性
let audio = document.getElementById('audio')
audio.currentTime
audio.duration
| 属性 | 描述 |
|---|---|
| audioTracks | 返回表示可用音轨的 AudioTrackList 对象 |
| autoplay | 设置或返回是否在加载完成后随即播放音频/视频 |
| buffered | 返回表示音频/视频已缓冲部分的 TimeRanges 对象 |
| controller | 返回表示音频/视频当前媒体控制器的 MediaController 对象 |
| controls | 设置或返回音频/视频是否显示控件(比如播放/暂停等) |
| crossOrigin | 设置或返回音频/视频的 CORS 设置 |
| currentSrc | 返回当前音频/视频的 URL |
| currentTime | 设置或返回音频/视频中的当前播放位置(以秒计) |
| defaultMuted | 设置或返回音频/视频默认是否静音 |
| defaultPlaybackRate | 设置或返回音频/视频的默认播放速度 |
| duration | 返回当前音频/视频的长度(以秒计) |
| ended | 返回音频/视频的播放是否已结束 |
| error | 返回表示音频/视频错误状态的 MediaError 对象 |
| loop | 设置或返回音频/视频是否应在结束时重新播放 |
| mediaGroup | 设置或返回音频/视频所属的组合(用于连接多个音频/视频元素) |
| muted | 设置或返回音频/视频是否静音 |
| networkState | 返回音频/视频的当前网络状态 |
| paused | 设置或返回音频/视频是否暂停 |
| playbackRate | 设置或返回音频/视频播放的速度 |
| played | 返回表示音频/视频已播放部分的 TimeRanges 对象 |
| preload | 设置或返回音频/视频是否应该在页面加载后进行加载 |
| readyState | 返回音频/视频当前的就绪状态 |
| seekable | 返回表示音频/视频可寻址部分的 TimeRanges 对象 |
| seeking | 返回用户是否正在音频/视频中进行查找 |
| src | 设置或返回音频/视频元素的当前来源 |
| startDate | 返回表示当前时间偏移的 Date 对象 |
| textTracks | 返回表示可用文本轨道的 TextTrackList 对象 |
| videoTracks | 返回表示可用视频轨道的 VideoTrackList 对象 |
| volume | 设置或返回音频/视频的音量 |
HTML5 Audio/Video 方法
| 方法 | 描述 |
|---|---|
| play() | 开始播放音频/视频 |
| pause() | 暂停当前播放的音频/视频 |
HTML5 Audio/Video 事件
audio.addEventListener('abort', function (){
当音频/视频的加载已放弃时执行
})
audio.addEventListener('play', function(){
})
audio.addEventListener('pause', function(){
})
| 事件 | 描述 |
|---|---|
| abort | 当音频/视频的加载已放弃时 |
| canplay | 当浏览器可以播放音频/视频时 |
| canplaythrough | 当浏览器可在不因缓冲而停顿的情况下进行播放时 |
| durationchange | 当音频/视频的时长已更改时 |
| emptied | 当目前的播放列表为空时 |
| ended | 当目前的播放列表已结束时 |
| error | 当在音频/视频加载期间发生错误时 |
| loadeddata | 当浏览器已加载音频/视频的当前帧时 |
| loadedmetadata | 当浏览器已加载音频/视频的元数据时 |
| loadstart | 当浏览器开始查找音频/视频时 |
| pause | 当音频/视频已暂停时 |
| play | 当音频/视频已开始或不再暂停时 |
| playing | 当音频/视频在已因缓冲而暂停或停止后已就绪时 |
| progress | 当浏览器正在下载音频/视频时 |
| ratechange | 当音频/视频的播放速度已更改时 |
| seeked | 当用户已移动/跳跃到音频/视频中的新位置时 |
| seeking | 当用户开始移动/跳跃到音频/视频中的新位置时 |
| stalled | 当浏览器尝试获取媒体数据,但数据不可用时 |
| suspend | 当浏览器刻意不获取媒体数据时 |
| timeupdate | 当目前的播放位置已更改时 |
| volumechange | 当音量已更改时 |
| waiting | 当视频由于需要缓冲下一帧而停止 |
实现简易音乐播放器
neteasecloudmusicapi.vercel.app/#/?id=licen…
Canvas
canvas意为“画布”。我们可以使用javascript操作画布上的任何一个像素,从而实现在网页中绘制图像。常用于:
- 网页特效。
- 网页游戏。
- 图形图表。
canvas的基本使用
<canvas id="cvs" width="640" height="360"></canvas>
绘制API:
let cvs = document.getElementById('cvs')
let ctx = cvs.getContext('2d') // 获取绘制Canvas所需要的Context对象
ctx.fillStyle = 'red' // 设置填充颜色
ctx.fillRect() // 填充矩形
绘制填充
ctx.fillStyle = 'red' // 设置填充颜色
ctx.fillRect(x, y, width, height) // 填充矩形
绘制描边
ctx.strokeStyle = 'blue' // 设置描边颜色
ctx.strokeRect(x, y, width, height) // 针对矩形描边
绘制文本
ctx.font = '24px 微软雅黑' // 设置字体
ctx.fillText('文本内容', x, y) // 填充文字
ctx.strokeText('文本内容', x, y) // 针对文字描边
Canvas路径
什么是路径?
将一些连续的点按照顺序连接起来所形成的图形称为路径。 路径没有颜色,可以通过API对路径进行描边。若想要填充路径,需要先闭合路径。
绘制路径的基本写法
- 调用
ctx.beginPath()开启一条新路径。- 调用
ctx.moveTo(x, y)将画笔移动到某一个坐标点。- 调用ctx的相关方法(例如
ctx.lineTo(x, y))绘制路径。- 路径绘制完毕后,调用
stroke()或fill()来进行描边或填充。
Canvas路径
什么是路径?
将一些连续的点按照顺序连接起来所形成的图形称为路径。 路径没有颜色,可以通过API对路径进行描边。若想要填充路径,需要先闭合路径。
绘制路径的基本写法
- 调用
ctx.beginPath()开启一条新路径。- 调用
ctx.moveTo(x, y)将画笔移动到某一个坐标点。- 调用ctx的相关方法(例如
ctx.lineTo(x, y))绘制路径。- 路径绘制完毕后,调用
stroke()或fill()来进行描边或填充。
案例:实现一个画板。
移动端针对网页会触发touch相关事件:
touchstart当开始触摸目标元素时触发touchmove当触摸目标元素并移动时触发touchcancel当触摸目标元素被打断时触发touchend当触摸结束时触发
如何实现一个画板?
- 监听
touchstart, 开始触摸canvas时,开启一条新路径。 - 监听
touchmove,当触摸移动时,获取移动到的坐标位置,绘制路径,描边即可。
绘制路径的其他常用API:
绘制矩形路径
ctx.rect(x, y, width, height) // 仅仅用于绘制透明路径
ctx.stroke()
ctx.fill()
绘制圆弧路径
ctx.beginPath()
// 绘制圆弧 (圆心x, 圆心y, 半径, 起始弧度值, 结束弧度值)
ctx.arc(102, 98, 93, Math.PI*4/3, Math.PI*2)
ctx.lineTo(102, 98)
ctx.fillStyle = 'blue'
ctx.fill()
Canvas动画
动画的本质:每隔很短的一段时间( 30帧/秒 60帧/秒 ),重新绘制界面从而形成动画。
window.setInterval(function(){
微调UI的属性信息
重新绘制UI界面
}, 1000/60)
案例:实现视频播放器的弹幕效果。
- 修改视频播放器案例,添加发送弹幕、文本框等标签。
- 在
Video标签之上盖一层canvas。 - 当点击发送弹幕时,将弹幕内容写在
canvas的右侧。 - 实现动画。
动画卡顿的原因:掉帧导致卡顿(不能保证每秒60帧的刷新率)
window.setInterval()天生的缺陷保证不了每秒60帧的刷新率,所以会出现顿顿感。
如果希望实现丝滑的动画,推荐使用window.requestAnimationFrame(callback)方法。
该方法的作用是:请求显示器在刷新下一帧时执行callback。可以借助于这个方法来完成丝滑的动画,基本调用模式如下:
function draw(){
微调修改ui的属性
执行耗时操作
...
window.requestAnimationFrame(draw)
}
draw()
地理定位
HTML5提供的地理定位相关API可以使得网页获取客户端设备所在的地理位置(经纬度),从而给与用户更好的应用体验。
定位的基础原理
- IP定位
- 运营商基站定位
- GPS卫星定位
HTML5提供了简单的API用于获取当前设备的地理位置:
let geoloc = window.navigator.geolocation
geoloc.getCurrentPosition((msg)=>{}, (err)=>{}, {timeout:5000})
如果定位成功,则会执行第一个方法,并且返回定位结果:
coords: GeolocationCoordinates
accuracy: 42890 精准度
altitude: null 海拔高度
altitudeAccuracy: null 海拔精准度
heading: null
latitude: 39.5377 纬度
longitude: 116.6837 经度
speed: null
timestamp: 1647507799721
第三方的位置服务-高德地图-百度地图-腾讯地图
高德地图
https://lbs.amap.com
使用vant组件库,呈现轮播图。
- 新建脚手架项目。
- 安装vant,配置vant组件库。
- 访问地址:
http://localhost:8080/swipe,看到vant的轮播图效果。
https://vant-contrib.gitee.io/vant/#/zh-CN/quickstart
第三方的位置服务-高德地图-百度地图-腾讯地图
高德地图
https://lbs.amap.com
引入高德地图,初始化地图
基于高德地图插件完成定位
在地图中显示标记点
为标记点添加事件,弹窗
为地图添加控件
调用高德开发的web服务
- 地点检索
- 逆地理编码
- 天气
在vue脚手架中使用高德地图
文件的上传与下载
文件上传流程与协议规范
文件上传流程
- 客户端通过
html给出一些操作方式(点击按钮、拖拽),选择本地图片。点击提交,准备上传。 - 客户端需要与服务端建立
http连接,客户端遵守http协议提交请求数据(请求数据包中可能包含基本表单数据,还可能包含需要上传的二进制文件)。 - 服务端接收请求,遵守
http协议,接收客户端传过来的所有数据,基本表单数据直接读取,文件则以数据流的方式 边读取边存储到服务端某个目录下。 - 文件存储完成后,服务端应该提供一个用于访问刚上传的图片的一个链接地址,返回给客户端,这样客户端可以使用该地址完成后续业务。
文件上传的协议规范
- 文件上传请求必须是
post请求。 - 发请求时,需要在请求数据包中添加
header:Content-Type:multipart/form-data - 客户端在请求数据包中绑定文件数据:key:value (字段名:文件对象),发送请求。
- 服务端接收请求,读取请求中的请求参数,通过key,获取上传的文件数据流,边读取边保存到服务端磁盘中。
实验:下载uploadserver.zip,解压,启动web服务。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5QTTwIsT-1657544301878)(C:\Users\xuming\AppData\Roaming\Typora\typora-user-images\1647594286987.png)]
实现基于elementui组件库中的el-upload组件,实现文件上传。
-
新建脚手架项目。
-
安装配置
elementui。# 执行安装命令 npm i element-ui -Smain.js中引入:// 引入ElementUI import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' // 全量引入所有组件 Vue.use(ElementUI) -
在组件页面中,使用
el-upload组件,实现上传文件操作。
文件的上传与下载
文件上传流程与协议规范
文件上传流程
- 客户端通过
html给出一些操作方式(点击按钮、拖拽),选择本地图片。点击提交,准备上传。 - 客户端需要与服务端建立
http连接,客户端遵守http协议提交请求数据(请求数据包中可能包含基本表单数据,还可能包含需要上传的二进制文件)。 - 服务端接收请求,遵守
http协议,接收客户端传过来的所有数据,基本表单数据直接读取,文件则以数据流的方式 边读取边存储到服务端某个目录下。 - 文件存储完成后,服务端应该提供一个用于访问刚上传的图片的一个链接地址,返回给客户端,这样客户端可以使用该地址完成后续业务。
文件上传的协议规范
- 文件上传请求必须是
post请求。 - 发请求时,需要在请求数据包中添加
header:Content-Type:multipart/form-data - 客户端在请求数据包中绑定文件数据:key:value (字段名:文件对象),发送请求。
- 服务端接收请求,读取请求中的请求参数,通过key,获取上传的文件数据流,边读取边保存到服务端磁盘中。
实现基于elementui组件库中的el-upload组件,实现文件上传。
-
新建脚手架项目。
-
安装配置
elementui。# 执行安装命令 npm i element-ui -Smain.js中引入:// 引入ElementUI import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' // 全量引入所有组件 Vue.use(ElementUI) -
在组件页面中,使用
el-upload组件,实现上传文件操作。<el-upload class="upload-demo" drag action="http://localhost:5000/upload" name="uploadFile" :on-success="handleUploadSuccess" multiple> <i class="el-icon-upload"></i> <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div> <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div> </el-upload>el-upload组件提供的功能很多,详情查阅官方文档。
上传头像流程
- 准备用户表存储用户数据(包括用户头像字段)。加载个人信息时,读取用户表显示用户原始头像。
- 点击头像,选择本地图片上传,服务端保存成功后将会返回一个访问新头像的路径。
- 获取到路径后,需要再次发送请求,更新用户表中的头像数据,从而持久化保存头像路径。
- 下次再登录,再次读取用户表,获取最新的用户数据(包含最新的头像)。
WebSocket
WebSocket可以实现客户端与服务端之间的实时通讯。它是基于web的长连接通讯协议。
网络通讯过程中的长连接与短连接
短连接通讯模式:客户端向服务端发请求建立连接,连接成功后,客户端向服务端发送请求数据包,服务端接收请求处理请求,返回响应数据包后连接断开。客户端接收后处理后续业务。
优点:大量节省服务端连接资源。使得服务端可以为更多的客户端处理业务。
长连接通讯模式:客户端向服务端发请求建立连接,连接成功后,客户端向服务端发送请求数据包,服务端接收请求处理请求,返回响应数据包后连接不断开。客户端接收后处理后续业务。连接将持续保持,这样可以实现随时随地客户端与服务端之间的数据交互。
优点:实现客户端与服务端的即时通讯。用于实现某些必要的业务场景:网页聊天、网页游戏等。
如何使用javascript代码来建立客户端与服务端之间的websocket长连接?
Socket.io
socket.io可以完成 网页中的js(客户端) 与 后台nodejs(服务端)的websocket长连接的建立与数据通讯。
建立websocket连接
服务端
-
新建一个后端项目。(创建一个文件夹
socketserver)下载安装包,安装nodejs。 https://nodejs.org/dist/v16.14.2/node-v16.14.2-x64.msi 换npm源 npm config set registry https://registry.npm.taobao.org -
通过命令行,进入项目目录,初始化
npm项目。cd socketserver npm init -y (将会生一个package.json描述当前项目的基本信息) # 安装socket.io npm install --save socket.io -
编写服务端的核心
index.js文件,监听端口,用接收客户端发过来的websocket连接请求。// index.js const http = require('http').createServer() const socketio = require('socket.io')(http) // socketio提供了on方法用于监听客户端建立websocket连接事件, // 一旦websocket连接建立成功,将会触发connection事件,执行回调方法 socketio.on('connection', function(socket){ // socket对象用于与链接成功的客户端进行数据交互 可以通过socket完成数据的发送与接收 console.log('连接成功,有客户端进来了!'+socket.id) }) http.listen(5050, ()=>{ console.log('服务已经启动...') })
客户端
-
新建
html页面。 通过script标签引入socket.io.js(在node_modules下有该js文件)。node_modules/socket.io/client-dist/socket.io.min.js -
通过
socket.io.js提供的方法,向服务端发请求,请求建立websocket连接。// 向目标地址请求建立websocket连接 let socket = io('http://localhost:5050/')
客户端与服务端之间的通信
-
客户端向服务端发消息
-
客户端发消息
let socket = io('http://localhost:5050/') // 发消息(自定义消息类型,消息内容) socket.emit('textmsg', '你瞅啥?!') -
服务端接收消息
socketio.on('connection', function(socket){ // 监听客户端发过来的消息(消息类型, 回调方法) socket.on('textmsg', function(data){ console.log(data) }) })
-
-
服务端向客户端发消息
-
服务端发消息
socket.on('textmsg', function(data){ socket.emit('textmsg', '消息内容') }) -
客户端接收消息
let socket = io('http://localhost:5050/') socket.on('textmsg', function(data){...})
-
-
服务端向所有客户端广播消息
socketio.emit('textmsg', '兄弟们,抄家伙,干他!')
WebWorker
网页端javascript属于单线程业务模型(.即所有编写的代码都在主线程运行)。 html5的WebWorker使得前端javascript拥有多线程异步处理业务的能力。
若在网页的javascript中编写了一些耗时代码,则主线程在执行这些耗时代码时将会出现页面假死现象。(实际上是因为主线程在执行耗时代码的时候无法及时更新页面的绘制相关属性,导致无论对页面做任何操作都无效)
案例:斐波那契数列。
1 1 2 3 5 8 13 21 34 55 89 ....
递归实现:
function fb(n){
return n<3 ? 1 : fb(n-1) + fb(n-2)
}
所以javascript中的耗时操作将会阻塞主线程,影响ui绘制。,导致界面假死。
可以使用webworker来做这些耗时操作,相当于启动了一个子线程,与主线程并发执行,这样,子线程中执行耗时代码,主线程中绘制ui,两不耽误。
WebWorker的使用
将需要在子线程中执行的代码写入到一个单独的js文件中:
// worker.js
function fb(n){
return n<3 ? 1 : fb(n-1)+fb(n-2)
}
let r = fb(45)
console.log(`n=45的斐波那契数列值:${r}`)
在主线程中,创建WebWorker对象(指定该文件路径),就会自动执行该文件的方法:
let worker = new Worker('worker.js')
上述代码将会创建一个Worker对象,由该对象来异步执行一些耗时操作。但是创建Worker也将会消耗系统资源。所以何时创建Worker对象要慎重考虑。避免创建过多的Worker对客户端系统造成压力。
通常情况下,启动一个worker去做耗时操作即可。必要的时候,主线程向Worker线程发消息,安排新任务。同理,Worker线程也可以向主线程发消息,返回结果。
主线程与Worker线程之间的通信
主线程向worker线程发消息
主线程发消息:
let worker = new Worker(...)
worker.postMessage(45)
worker.postMessage(40)
worker.postMessage(43)
worker线程接收消息:
//worker.js
onmessage = function(e){
console.log(e)
}
worker线程向主线程发消息
worker线程发消息:
//worker2.js
this.postMessage(消息内容)
主线程接收消息:
let worker = new Worker();
worker.onmessage= function(data){
更新UI
}
SVG
SVG是一种图片格式。svg这种图片的本质是一篇符合xml格式的标签文本,由浏览器进行解析并显示。SVG格式图片具备矢量图的特性(放大不失真)。
绘制第一个svg图片
- 新建文件:
circle.svg,依据svg标准,编写svg源代码。 - 在网页中引用该
svg图片。
SVG的使用方式
<img src="vue.svg">
<div style="background-image:url('vue.svg')"></div>
<body>
<svg>
<circle .....></circle>
</svg>
</body>
Canvas 与 SVG 的比较
下表列出了 canvas 与 SVG 之间的一些不同之处。
Canvas
- 依赖分辨率
- 不支持事件处理器
- 弱的文本渲染能力
- 能够以 .png 或 .jpg 格式保存结果图像
- 最适合图像密集型的游戏,其中的许多对象会被频繁重绘
SVG
- 不依赖分辨率
- 支持事件处理器
- 最适合带有大型渲染区域的应用程序(比如谷歌地图)
- 复杂度高会减慢渲染速度(任何过度使用 DOM 的应用都不快)
- 不适合游戏应用
ECharts
一个基于 JavaScript 的开源可视化图表库,用于实现网页端的数据可视化需求。