HTML5
提供了音视频相关标签来实现网页中的音视频播放。
浏览器支持的音频格式:mp3
,wav
, ogg
VSCODE插件 : liveServe
简写方式:
<audio src="音频路径" controls>audio>
案例:01_audio.html
标准方式:
<audio controls>
<source src="letitgo.mp3" type="audio/mpeg" />
<source src="letitgo.wav" type="audio/wav" />
<source src="letitgo.ogg" type="audio/ogg" />
什么破浏览器,换一个吧。
audio>
audio
标签的常用属性
<audio controls 是否显示控制面板
src="" 路径
autoplay 是否自动播放
muted 是否默认静音
loop 是否单曲循环
preload="" 音频预加载模式 none, metadata(元数据:基本信息),auto(尽可能多的加载)
>audio>
支持的视频格式有:mp4
, webm
, ogg
.
简写方式:
<style>
video{
background-color:#000;
}
style>
<video src="视频资源路径"
controls
width="640"
height="360">video>
注意: 目前视频 21: 9
一般 : 16 : 9
黑边会有留白,不用管
audio
/video
标签的DOM
操作<audio id="audio">audio>
<script>
let audio = document.getElementById('audio')
audio.src="1.mp3"
audio.play()
audio.addEventListener('...', ()=>{})
script>
与媒体相关的DOM对象有:HTMLMediaElement
、HTMLAudioElement
、HTMLVideoElement
HTMLMediaElement
接口是HTMLAudioElement
与HTMLVideoElement
接口的父接口,在其中定义的属性、方法、事件子接口也可以使用。
HTMLMediaElement
常用属性
let audio = document.getElementById('audio')
audio.autoplay
audio.currentTime
属性 | 描述 |
---|---|
autoplay | 设置或返回是否在加载完成后随即播放音频/视频 |
currentTime | 设置或返回音频/视频中的当前播放位置(以秒计) |
duration | 返回当前音频/视频的长度(以秒计) |
ended | 返回音频/视频的播放是否已结束 |
loop | 设置或返回音频/视频是否应在结束时重新播放 |
muted | 设置或返回音频/视频是否静音 |
networkState | 返回音频/视频的当前网络状态 |
paused | 设置或返回音频/视频是否暂停 |
playbackRate | 设置或返回音频/视频播放的速度 |
readyState | 返回音频/视频当前的就绪状态 |
src | 设置或返回音频/视频元素的当前来源 |
volume | 设置或返回音频/视频的音量 |
01_audio.html
中测试属性。DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<audio id="audio"
src="../assets/let_it_go.mp3"
controls
loop
preload="auto"
>audio>
<button id="btn">点我输出audio属性button>
<script>
let audio = document.getElementById('audio');
let btn = document.getElementById('btn');
//属性
btn.onclick=function(){
console.log("当前播放位置"+audio.currentTime);
console.log("当前音频时长"+audio.duration);
console.log("当前播放是否结束"+audio.ended);
console.log("是否重新播放"+audio.loop);
}
script>
body>
html>
常用方法
let audio = document.getElementById('audio')
audio.play()
audio.pause()
方法 | 描述 |
---|---|
play() | 开始播放音频/视频 |
pause() | 暂停当前播放的音频/视频 |
常用事件
let audio = document.getElementById('audio')
audio.addEventListener('play', function(){})
事件 | 描述 |
---|---|
abort | 当音频/视频的加载已放弃时 |
error | 当在音频/视频加载期间发生错误时 |
loadeddata | 当浏览器已加载音频/视频的当前帧时 |
loadedmetadata | 当浏览器已加载音频/视频的元数据时 |
pause | 当音频/视频已暂停时 |
play | 当音频/视频已开始或不再暂停时 |
playing | 当音频/视频在已因缓冲而暂停或停止后已就绪时 |
progress | 当浏览器正在下载音频/视频时 |
ratechange | 当音频/视频的播放速度已更改时 |
timeupdate | 当目前的播放位置已更改时 |
volumechange | 当音量已更改时 |
waiting | 当视频由于需要缓冲下一帧而停止 |
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<style>
.container {
width: 400px;
border: 1px solid #ddd;
text-align: center;
padding-bottom: 10px;
}
.container p{
font-size: 1.3em;
font-weight: bold;
text-align: center;
}
.container img{
width: 340px;
height: 340px;
border-radius: 50%;
}
.container input{
width: 340px;
display: block;
margin: 10px auto;
}
.container .time{
width: 340px;
height: 30px;
margin: 0px auto;
}
.container .time .left{
float: left;
}
.container .time .right{
float: right;
}
style>
head>
<body>
<div class="container">
<p>let it gop>
<img src="../assets/logo.jpg" alt="">
<input id="range" type="range" min="0" value="0" max="100">
<div class="time">
<span class="left">00:00span>
<span class="right">03:15span>
div>
<button id="btn_play">播放/暂停button>
<button id="btn_vp">音量+button>
<button id="btn_vm">音量-button>
<button id="btn_05">0.5倍速button>
<button id="btn_1">1倍速button>
<button id="btn_2">2倍速button>
div>
<script>
let player = new Audio(); //创建一个播放器
player.src="../assets/let_it_go.mp3"
// 暂停 播放
let btn_play = document.getElementById('btn_play')
btn_play.addEventListener('click',function(){
// let player = new Audio(); //创建一个播放器
// player.src="../assets/let_it_go.mp3"
// player.play();
//多点几次,可以无限次播放 - 原因: 每点击一次new Audio()
//解决.放到外部
//播放 暂停 - paused 属性
if(player.paused){
player.play()
}else{
player.pause();
}
})
// 控制音量 +
let btn_vp = document.getElementById('btn_vp');
btn_vp.addEventListener('click',function(){
// player.volume+=0.1
console.log(player.volume);
//越界报错
//不能大于1
player.volume = Math.min(player.volume+0.1,1)
})
// 控制音量 -
let btn_vm = document.getElementById('btn_vm')
btn_vm.addEventListener('click',function(){
console.log(player.volume);
// player.volume-=0.1
//不能低于0
player.volume = Math.max(player.volume-0.1,0)
})
// 0.5 倍速
let btn_05 = document.getElementById('btn_05')
btn_05.addEventListener('click',function(){
player.playbackRate = 0.5;
console.log(player.playbackRate)
})
let btn_1 = document.getElementById('btn_1')
btn_1.addEventListener('click',function(){
player.playbackRate = 1;
console.log(player.playbackRate)
})
let btn_2 = document.getElementById('btn_2')
btn_2.addEventListener('click',function(){
player.playbackRate = 2;
console.log(player.playbackRate)
})
script>
body>
html>
// 更新总时长
player.addEventListener('loadedmetadata',function(){
console.log(player.duration);
let dt = player.duration;
let dtstr = moment.unix(dt).format('mm:ss')
end.innerHTML = dtstr;
})
https://neteasecloudmusicapi.vercel.app/#/?id=license
Canvas
HTML5
提供了可以使用Javascript
来绘制图形的HTML
元素:Canvas
画布。
canvas特效
: https://www.html5tricks.com/16-html5-canvas-animation.html
Canvas
基础绘图
Canvas
路径
Canvas
动画
Canvas
的基本使用<canvas id="cvs" width="640" height="360">canvas>
let cvs = document.getElementById('cvs')
let ctx = cvs.getContext('2d') // 获取用于绘制画布的context对象
ctx.fillStyle = "red" // 设置填充颜色
ctx.fillRect(x,y, width,height) // 在画布上用红色填充一个矩形
绘制填充
ctx.fillStyle = "red" // 设置填充颜色
ctx.fillRect(x,y, width,height) // 在画布上用红色填充一个矩形
绘制描边
ctx.strokeStyle = "blue" // 设置描边的颜色
ctx.strokeRect(x, y, width, height)
绘制文本
// 绘制文本
ctx.fillStyle="orange"
ctx.font = '25px 微软雅黑'
ctx.fillText('冰墩墩墩墩墩墩', 50, 70)
案例:绘制柱状图. – 无缝隙
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>02_bar.htmltitle>
<style>
canvas {
border: 1px solid black;
background-color: aliceblue;
}
style>
head>
<body>
<canvas id="cvs" width="450" height="250">canvas>
<script>
let ctx = cvs.getContext('2d') // Context对象
const WIDTH = 450 // 画布的宽
const HEIGHT = 250 // 画布的高
let barWidth = 45 // 柱子的宽度
let data = [120, 200, 150, 80, 70, 110, 130] // 数据
// 通过已知的参数,计算绘制7根柱子所需要的数据
let xs = [] //x坐标
let ys = [] //y坐标
let ws = [] //宽度
let hs = [] //高度
// 整理这些数组数据
for(let i=0; i<data.length; i++){
xs.push(i*barWidth)
ys.push(HEIGHT - data[i])
ws.push(barWidth)
hs.push(data[i]) //可以等比例缩放
}
// 根据已知数据,绘制柱状图
for(let i=0; i<data.length; i++){
// 输出柱子
ctx.fillStyle = "#36D"
ctx.fillRect(xs[i], ys[i], ws[i], hs[i])
// 输出文本
ctx.fillStyle = "#000"
ctx.font = '13px 微软雅黑'
ctx.textAlign = 'center'
ctx.fillText(data[i], xs[i]+barWidth/2, HEIGHT-5)
}
script>
body>
html>
案例 :绘制柱状图. – 有缝隙
let fx = (WIDTH - barWidth*data.length)/(2*data.length)
for(let i=0; i
Canvas
路径路径(path
)是将预先设定好的坐标点按照顺序连接起来所形成的图形。只有通过描边或者填充才可以将路径显示出来。
路径的绘制步骤:
- 调用
ctx.beginPath()
开启一条新路径。- 调用
ctx.moveTo(x, y)
将画笔移动到指定位置。- 调用相关方法开始绘制路径(
ctx.lineTo(x, y)
向目标点连线)- 最后通过
ctx.stroke()
或ctx.fill()
方法进行描边或填充。
案例:绘制三角形。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<style>
canvas{
border:1px solid #000;
background-color:aliceblue;
}
style>
head>
<body>
<canvas id="cvs" width="640" height="360">canvas>
<script>
let cvs = document.getElementById('cvs')
let ctx = cvs.getContext('2d');
ctx.beginPath();
ctx.moveTo(50,100);
ctx.lineTo(100,50);
ctx.lineTo(150,100);
ctx.lineTo(50,100);
ctx.strokeStyle="blue"
ctx.stroke();
ctx.fillStyle="red";
ctx.fill();
script>
body>
html>
涉及到相关移动端触摸事件:
touchstart
开始触摸。touchmove
触摸移动 。touchcancel
触摸操作被打断。touchend
触摸结束。
实现思路:开始触摸时,开启一条新路径,触摸移动时,绘制路径并描边即可。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<style>
canvas{
background-color:aliceblue;
position: absolute;top:0;left:0;
}
style>
head>
<body>
<canvas id="cvs" width="667" height="375">canvas>
<script>
let ctx = cvs.getContext('2d');
cvs.addEventListener('touchstart',function(e){
// console.log(e);
let x = e.touches[0].pageX;
let y = e.touches[0].pageY;
//开启一条新路径
ctx.beginPath();
ctx.moveTo(x,y);
})
cvs.addEventListener('touchmove',function(e){
// console.log(e);
let x = e.touches[0].pageX;
let y = e.touches[0].pageY;
ctx.lineTo(x,y);
ctx.strokeStyle="red"
ctx.stroke();
//清除画板
//ctx.clearRect(20,20,100,50);
})
script>
body>
html>
Canvas
提供了一些绘制路径的常用方法(如何画弧度)ctx.rect()
用于绘制矩形路径
ctx.rect(x, y, width, height)
ctx.arc()
用于绘制圆弧路径
// 绘制圆弧路径
// 参数:(圆心x, 圆心y, 半径, 起始弧度, 结束弧度)
ctx.arc(x, y, radius, startangle, endangle)
案例 : 绘制圆弧
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<style>
canvas{
border:1px solid #000;
background-color: antiquewhite;
}
style>
head>
<body>
<canvas id="cvs" width="640" height="360">canvas>
<script>
let ctx = cvs.getContext('2d');
//绘制矩形路径
ctx.rect(50,50,100,150);
//ctx.fillStyle="red"; 修改颜色
ctx.fill();
//绘制弧形路径 360度 = 2π
//有一条线, 原因, 同一个画笔没结束,需要重新开始一条路径
ctx.beginPath();
ctx.arc(500,200,100,0,Math.PI/2)
//画1/4饼状图
ctx.lineTo(500,200)
ctx.stroke();
ctx.fill();
//画饼状图
ctx.beginPath();
ctx.moveTo(500,300);
ctx.arc(500,200,100,Math.PI/2,Math.PI*2);
ctx.lineTo(500,200)
ctx.fillStyle="Red";
ctx.stroke();
ctx.fill();
script>
body>
html>
Canvas
动画动画的本质 就是每隔一段时间(足够快)重绘界面,并且每次绘制界面时都会有些许不同。由于重绘时间间隔短以及人眼视觉残留现象,出现动画效果。
window.setInterval(function(){
修改绘制内容的属性
重绘界面即可
}, 1000/60)
案例:实现弹幕。
- 准备好页面。视频播放器。
- 在视频播放器
video
标签之上,覆盖一层canvas
。- 发送弹幕即是将弹幕文本写在
canvas
上。- 弹幕动画即是每隔一段时间(1/60秒),重绘弹幕内容,每次重绘,弹幕的位置要有变化。
<style>
canvas{
position:absolute;
top:8px;
left:8px;
/* background-color: red; */
}
style>
<video id="video" src="../assets/let_it_go.mp4">video>
<canvas id="cvs" width="640" height="360">canvas>
<input type="text" name="" id="message" placeholder="请输入弹幕">
<button id="send">发送弹幕button>
定时器不要启动太多,因为非常耗费系统CPU
资源。当前案例中,可以使用一个定时器,来解决所有弹幕的动画更新。所以在页面加载过程中就可以启动定时器,让该定时器加载所有弹幕信息,修改每一个弹幕的属性,重绘每个弹幕内容。
实现思路:
dmlist
数组,存储所有的弹幕数据。{msg:弹幕内容, x:x坐标, y:y坐标}
,将该对象存入dmlist
数组。<script>
let ctx = cvs.getContext('2d');
var dmlist= [];
//处理弹幕
send.addEventListener('click',function(){
//获取文本内容,写入canvas
let msg = message.value;
dmlist.push({
msg:msg,
x:600,
y:Math.ceil(Math.random()*12)*30
})
console.log(dmlist);
// ctx.font='25px 微软雅黑';
// ctx.fillStyle = "#fff";
// ctx.fillText(msg,600,Math.ceil(Math.random()*12)*30);
//不想弹幕覆盖 - 从一组数列中随机生成数列
//[30,60,90,120 ...]
//[30*1,30*2,30*3 ...]
//随机生成 1~12 之间的数字然后乘以30
//0.0000001 - 11.999999999 - 向上取整
//Math.ceil((Math.random()*12)*30
//动画
//定时器: 不合理, 用户多次点击, 会启动很多定时器,占用电脑cpu
// window.setInterval(function(){
// },1000/60)
})
//启动定时器,绘制dmlist中的每一条弹幕(边修改边绘制)
window.setInterval(function(){
//文字连续显示 - 解决
ctx.clearRect(0,0,640,360);
dmlist.forEach(item=>{ //遍历每一条弹幕 == item
//console.log(item);
ctx.font='25px 微软雅黑';
ctx.fillStyle = "#fff";
ctx.fillText(item.msg,item.x--,item.y);
})
},1000/60)
script>
由于window.setInterval()
方法的天生的缺陷,导致无法保证每秒60帧的刷新率。(掉帧),视觉上就感觉卡卡的。
window.setInterval(functino(){ ... }, 1000/60)
window.setInterval
会等待1/60秒执行function,而function的执行也是需要时间的,所以导致无法保证每秒60帧的刷新率,掉帧、卡顿现象就出来了。
所以如果希望绘制流畅动画,推荐使用:
window.requestAnimationFrame(callback)
该方法的作用,是请求显示器绘制动画帧时执行callback
。基本写法结构如下:
function draw(){
执行耗时代码,更新页面属性等..
.................
绘制界面
window.requestAnimationFrame(draw)
}
draw()
//解决掉帧
function draw(){
ctx.clearRect(0,0,640,360);
dmlist.forEach(item=>{ //遍历每一条弹幕 == item
//console.log(item);
ctx.font='25px 微软雅黑';
ctx.fillStyle = "#fff";
ctx.fillText(item.msg,item.x--,item.y);
})
window.requestAnimationFrame(draw);
}
draw();
three.js