HTML5CORE

音频与视频

HTML5提供了音视频相关标签来实现网页中的音视频播放。

音频标签

浏览器支持的音频格式:mp3wav, 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对象有:HTMLMediaElementHTMLAudioElementHTMLVideoElement

HTMLMediaElement接口是HTMLAudioElementHTMLVideoElement接口的父接口,在其中定义的属性、方法、事件子接口也可以使用。

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>Document</title>
</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>Document</title>
    <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 go</p>
        <img src="../assets/logo.jpg" alt="">
        <input id="range" type="range" min="0" value="0" max="100">
        <div class="time">
          <span class="left">00:00</span>
          <span class="right">03:15</span>
        </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)  // 在画布上用红色填充一个矩形 

绘制填充

 <style>
        canvas{
            border:1px solid #000;
            background-color: rgb(14, 132, 235);
        }
 </style>
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.html</title>
  <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<data.length; i++){
      xs.push(i*barWidth + (2*i+1)*fx)
      ys.push(HEIGHT - data[i] - 20)
      ws.push(barWidth) 
      hs.push(data[i])  //可以等比例缩放
}

Canvas路径

路径(path)是将预先设定好的坐标点按照顺序连接起来所形成的图形。只有通过描边或者填充才可以将路径显示出来。

路径的绘制步骤:

  1. 调用ctx.beginPath()开启一条新路径。
  2. 调用ctx.moveTo(x, y)将画笔移动到指定位置。
  3. 调用相关方法开始绘制路径(ctx.lineTo(x, y)向目标点连线)
  4. 最后通过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>Document</title>
    <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>
案例:写一个画板。(移动端)

涉及到相关移动端触摸事件:

  1. touchstart 开始触摸。
  2. touchmove 触摸移动 。
  3. touchcancel 触摸操作被打断。
  4. 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>Document</title>
    <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>Document</title>
    <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动画

动画的本质 就是每隔一段时间(足够快)重绘界面,并且每次绘制界面时都会有些许不同。由于重绘时间间隔短以及人眼视觉残留现象,出现动画效果。

  <!-- 
        足够快:
           电影 : 每秒24帧
           手机(中等) : 每秒60帧
           旗舰手机 : 每秒120帧(旗舰高刷屏)   
    --> 

window.setInterval(function(){
    修改绘制内容的属性
    重绘界面即可
}, 1000/60)

案例:实现弹幕。

  1. 准备好页面。视频播放器。
  2. 在视频播放器video标签之上,覆盖一层canvas
  3. 发送弹幕即是将弹幕文本写在canvas上。
  4. 弹幕动画即是每隔一段时间(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资源。当前案例中,可以使用一个定时器,来解决所有弹幕的动画更新。所以在页面加载过程中就可以启动定时器,让该定时器加载所有弹幕信息,修改每一个弹幕的属性,重绘每个弹幕内容。

实现思路:

  1. 准备一个dmlist数组,存储所有的弹幕数据。
  2. 发送弹幕时,封装一个弹幕对象:{msg:弹幕内容, x:x坐标, y:y坐标},将该对象存入dmlist数组。
  3. 全局启动唯一一个定时器,每隔1/60秒,加载弹幕数据中的所有弹幕数据,将弹幕的x属性–,重绘该弹幕即可实现动画效果。
<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();
    
3D库

three.js

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值