[ 蓝桥杯Web真题 ]-视频弹幕

目录

介绍

准备

目标

效果

规定

思路

解答参考

扩展功能


介绍

弹幕指直接显现在视频上的评论,可以以滚动、停留甚至更多动作特效方式出现在视频上,是观看视频的人发送的简短评论。通过发送弹幕可以给观众一种“实时互动”的错觉,弹幕的出现让观看过程充满乐趣。本题需要在已提供的基础项目中,完成视频弹幕的功能。

准备

开始答题前,需要先打开本题的项目代码文件夹,目录结构如下:

├── effect.gif 
├── css
│   └── index.css
├── video
│   └── video1.webm
├── index.html
└── js└── index.js

其中:

  • index.html 是主页面。
  • js/index.js 是需要补充代码的 js 文件。
  • css/index.css 是样式文件。
  • effect.gif 是完成的效果图。
  • video 是存放视频的文件夹。

注意:打开环境后发现缺少项目代码,请手动输入下述命令进行下载:

cd /home/project
wget -q https://labfile.oss.aliyuncs.com/courses/18213/test6.zip
unzip test6.zip && rm test6.zip

在浏览器中预览 index.html 页面,显示如下所示:

目标

请在 js/index.js 文件中补全代码。具体需求如下:

1.补全 renderBullet 函数中的代码,控制弹幕的显示颜色和移动。功能说明如下:

  • 每个弹幕内容包裹在 span 标签中,作为子节点插入到 #video 元素节点内。

  • 生成的 span 元素节点相对于 #video 元素绝对定位 ,初始位的 left 是 #video 元素的宽,top 是 #video 元素的高内的随机数。注意:需求中所需样式可直接通过已提供的 getEleStyle 方法获取。

  • 弹幕每隔 bulletConfig.time(弹幕配置对象) 时间,向左移动距离为 bulletConfig.speed(弹幕配置对象)。

  • 当弹幕最右端完全移出 #video 元素时,移除 span 元素。

2.补全 #sendBulletBtn 元素的绑定事件,点击发送按钮,输入框中的文字出现在弹幕中,样式不同于普通弹幕(样式红色字体红色框已设置,类名为 create-bullet )。通过调用 renderBullet 方法和正确的传参实现功能。

效果

最终效果可参考文件夹下面的 gif 图,图片名称为 effect.gif(提示:可以通过 VS Code 或者浏览器预览 gif 图片)。

规定

  • 请勿修改 js/index.js 文件外的任何内容。
  • 请严格按照考试步骤操作,切勿修改考试默认提供项目中的文件名称、文件夹路径、class 名、id 名、图片名等,以免造成无法判题通过。

  • 先自己动手做一下吧!传送门


思路

如果想要解决这道题目首先你需要对JS的原生操作能够比较熟悉,这道题目涉及到了子节点的插入以及移除的设置,元素位置的设置。同时需要会利用题目中已经给出的方法,对其进行调用获取我们需要的东西。除此之外还需要你会使用定时器。

解答参考

function renderBullet(bulletConfig, videoEle, isCreate = false) {const spanEle = document.createElement("SPAN");spanEle.classList.add(`bullet${index}`);if (isCreate) {spanEle.classList.add("create-bullet")}// TODO:控制弹幕的显示颜色和移动,每隔 bulletConfig.time 时间,弹幕移动的距离  bulletConfig.speedvideoEle.appendChild(spanEle);//将弹幕插入到视频元素中const videoStyle=getEleStyle(videoEle);//计算视频的宽高spanEle.style.left=videoStyle.width+'px';//设置弹幕的位置leftspanEle.style.top=getRandomNum(videoStyle.height)+'px';//设置弹幕的位置topspanEle.style.color=`rgb(${getRandomNum(255)},${getRandomNum(255)},${getRandomNum(255)})`;//设置弹幕的颜色spanEle.innerHTML=bulletConfig.value;//设置弹幕的文字//设置定时器,每个bulletConfig.time就移动bulletConfig.speed距离let time=setInterval(()=>{spanEle.style.left=parseInt(spanEle.style.left)-bulletConfig.speed+'px';//弹幕离开视线时的条件if(parseInt(spanEle.style.left)<=-getEleStyle(spanEle).width){videoEle.removeChild(spanEle);//移除弹幕clearInterval(time);//清楚定时器}},bulletConfig.time)
}

首先将题目给已经给我们编写好的span标签插入到视频元素中,这里使用到了appendChild()方法,用于给父元素插入子节点。插入之后,我们设置span的left以及top对应的值,在设置之前我们先使用getEleStyle方法来获取视频的宽高等信息。然后设置span的left为视频的宽度,它的top为视频高度的随机值,那此时就需要再调用题目已经写好了的getRandomNum()方法来获取到随机值。然后记得后面需要加上px。同时设置span的颜色以及文本。

截止我们需要给它增加一个定时器用于弹幕每隔 bulletConfig.time(弹幕配置对象) 时间,向左移动距离为 bulletConfig.speed(弹幕配置对象)。这里用到了setInterval。然后span的left值不断地减少,使用parseInt方法是将后面的px去掉,才能够进行运算。计算之后记得加上px。重要的是需要判断弹幕离开视线的时刻。当弹幕距离左边的距离是它宽度的负数值时刚好弹幕从视频完全移出。此时使用removeChild方法来对其进行移除。同时记得清除定时器。

document.querySelector("#sendBulletBtn").addEventListener('click', () => {// TODO:点击发送按钮,输入框中的文字出现在弹幕中//获取输入框中为文字bulletConfig.value=document.querySelector("#bulletContent").value;//当有输入文字时在进行调用renderBullet方法if( bulletConfig.value){renderBullet(bulletConfig,videoEle,true);}
})

同时,当在输入框输入文字后发送弹幕时,点击发送按钮,调用renderBullet方法。在调用之前,我们先获取输入框中输入的文本,当判断有输入时才进行调用对应的方法,同时第三个参数出传入true,表示新增弹幕。

完整文件代码:(有什么更好地解决方式欢迎评论区交流学习!)

const bullets = ["前方高能","原来如此","这么简单","学到了","学费了","666666","111111","workerman","学习了","别走,奋斗到天明"];/*** @description 根据 bulletConfig 配置在 videoEle 元素最右边生成弹幕,并移动到最左边,弹幕最后消失* @param {Object} bulletConfig 弹幕配置* @param {Element} videoEle 视频元素* @param {boolean} isCreate 是否为新增发送的弹幕,为 true 表示为新增的弹幕* 
*/
function renderBullet(bulletConfig, videoEle, isCreate = false) {const spanEle = document.createElement("SPAN");spanEle.classList.add(`bullet${index}`);if (isCreate) {spanEle.classList.add("create-bullet")}// TODO:控制弹幕的显示颜色和移动,每隔 bulletConfig.time 时间,弹幕移动的距离  bulletConfig.speedvideoEle.appendChild(spanEle);//将弹幕插入到视频元素中const videoStyle=getEleStyle(videoEle);//计算视频的宽高spanEle.style.left=videoStyle.width+'px';//设置弹幕的位置leftspanEle.style.top=getRandomNum(videoStyle.height)+'px';//设置弹幕的位置topspanEle.style.color=`rgb(${getRandomNum(255)},${getRandomNum(255)},${getRandomNum(255)})`;//设置弹幕的颜色spanEle.innerHTML=bulletConfig.value;//设置弹幕的文字//设置定时器,每个bulletConfig.time就移动bulletConfig.speed距离let time=setInterval(()=>{spanEle.style.left=parseInt(spanEle.style.left)-bulletConfig.speed+'px';//弹幕离开视线时的条件if(parseInt(spanEle.style.left)<=-getEleStyle(spanEle).width){videoEle.removeChild(spanEle);//移除弹幕clearInterval(time);//清楚定时器}},bulletConfig.time)
}document.querySelector("#sendBulletBtn").addEventListener('click', () => {// TODO:点击发送按钮,输入框中的文字出现在弹幕中//获取输入框中为文字bulletConfig.value=document.querySelector("#bulletContent").value;//当有输入文字时在进行调用renderBullet方法if( bulletConfig.value){renderBullet(bulletConfig,videoEle,true);}
})function getEleStyle(ele) {// 获得元素的width,height,left,right,top,bottomreturn ele.getBoundingClientRect();
}function getRandomNum(end, start = 0) {// 获得随机数,范围是 从start到 endreturn Math.floor(start + Math.random() * (end - start + 1));
}// 设置 index 是为了弹幕数组循环滚动
let index = 0;
const videoEle = document.querySelector("#video");
// 弹幕配置
const bulletConfig = {isHide: false, // 是否隐藏speed: 5, // 弹幕的移动距离time: 50, // 弹幕每隔多少ms移动一次value:"" // 弹幕的内容
}
let isPlay = false;
let timer; // 保存定时器
document.querySelector("#vd").addEventListener('play', () => {// 监听视频播放事件,当视频播放时,每隔 1000s 加载一条弹幕isPlay = true;bulletConfig.value = bullets[index++];renderBullet(bulletConfig, videoEle);timer = setInterval(() => {bulletConfig.value = bullets[index++];renderBullet(bulletConfig, videoEle);if (index >= bullets.length) {index = 0;}}, 1000);
})document.querySelector("#vd").addEventListener("pause", () => {isPlay = false;clearInterval(timer);
})document.querySelector("#switchButton").addEventListener("change", (e) => {if (e.target.checked) {bulletConfig.isHide = false;} else {bulletConfig.isHide = true;}
})

扩展功能

虽然已经实现了题目要求的功能,且提交已经成功通过了。但是我还想要在这个基础上,实现当点击视频播放时是弹幕可以移动,当点击暂停时,弹幕停止移动,继续播放时弹幕能够继续移动。并且当点击切换按钮时,可以控制视频中弹幕的显示以及隐藏。(这部分若感兴趣可以看看)

思路是先声明一个用于接受视频中出现的弹幕的数组。然后再声明两个函数,一个stop,用于当监听到视频的播放为暂停时清除弹幕的定时器,一个为recover,用于当监听当视频点击继续播放时,让弹幕中的定时器都恢复。同时点击切换按钮,为每一个弹幕设置visibility属性来实现实现或者隐藏。修改后的完整代码如下:

const bullets = ["前方高能","原来如此","这么简单","学到了","学费了","666666","111111","workerman","学习了","别走,奋斗到天明"];
let bulletsArray = []; // 存储所有已生成的弹幕/*** @description 根据 bulletConfig 配置在 videoEle 元素最右边生成弹幕,并移动到最左边,弹幕最后消失* @param {Object} bulletConfig 弹幕配置* @param {Element} videoEle 视频元素* @param {boolean} isCreate 是否为新增发送的弹幕,为 true 表示为新增的弹幕* 
*/
// 暂停弹幕移动的函数
function stop() {for (let bullet of bulletsArray) {clearInterval(bullet.timer);}
}
// 恢复弹幕移动的函数
function recover() {for (let bullet of bulletsArray) {bullet.timer = setInterval(() => {bullet.spanEle.style.left = parseInt(bullet.spanEle.style.left) - bullet.bulletConfig.speed + 'px';if (parseInt(bullet.spanEle.style.left) <= -getEleStyle(bullet.spanEle).width) {videoEle.removeChild(bullet.spanEle);clearInterval(bullet.timer);}}, bullet.bulletConfig.time);}
}function renderBullet(bulletConfig, videoEle, isCreate = false) {const spanEle = document.createElement("SPAN");spanEle.classList.add(`bullet${index}`);if (isCreate) {spanEle.classList.add("create-bullet")}videoEle.appendChild(spanEle);const videoStyle = getEleStyle(videoEle);spanEle.style.left = videoStyle.width + 'px';spanEle.style.top = getRandomNum(videoStyle.height) + 'px';spanEle.style.color = `rgb(${getRandomNum(255)},${getRandomNum(255)},${getRandomNum(255)})`;spanEle.innerHTML = bulletConfig.value;const bullet = {spanEle: spanEle,bulletConfig: bulletConfig,timer: null};bulletsArray.push(bullet);bullet.timer = setInterval(() => {if (!bulletConfig.isHide) {spanEle.style.left = parseInt(spanEle.style.left) - bulletConfig.speed + 'px';if (parseInt(spanEle.style.left) <= -getEleStyle(spanEle).width) {videoEle.removeChild(spanEle);clearInterval(bullet.timer);// 移除弹幕后,从数组中删除对应的弹幕对象const indexToRemove = bulletsArray.indexOf(bullet);if (indexToRemove !== -1) {bulletsArray.splice(indexToRemove, 1);}}}}, bulletConfig.time);
}document.querySelector("#sendBulletBtn").addEventListener('click', () => {// TODO:点击发送按钮,输入框中的文字出现在弹幕中//获取输入框中为文字bulletConfig.value=document.querySelector("#bulletContent").value;//当有输入文字时在进行调用renderBullet方法if( bulletConfig.value){renderBullet(bulletConfig,videoEle,true);}
})function getEleStyle(ele) {// 获得元素的width,height,left,right,top,bottomreturn ele.getBoundingClientRect();
}function getRandomNum(end, start = 0) {// 获得随机数,范围是 从start到 endreturn Math.floor(start + Math.random() * (end - start + 1));
}// 设置 index 是为了弹幕数组循环滚动
let index = 0;
const videoEle = document.querySelector("#video");
// 弹幕配置
const bulletConfig = {isHide: false, // 是否隐藏speed: 5, // 弹幕的移动距离time: 50, // 弹幕每隔多少ms移动一次value:"" // 弹幕的内容
}
let isPlay = false;
let timer; // 保存定时器// 暂停/播放事件监听
document.querySelector("#vd").addEventListener("pause", () => {isPlay = false;stop(); // 停止弹幕移动
});document.querySelector("#vd").addEventListener('play', () => {console.log('播放')if (!bulletConfig.isHide) {recover();}// 监听视频播放事件,当视频播放时,每隔 1000s 加载一条弹幕isPlay = true;bulletConfig.value = bullets[index++];renderBullet(bulletConfig, videoEle);timer = setInterval(() => {bulletConfig.value = bullets[index++];renderBullet(bulletConfig, videoEle);if (index >= bullets.length) {index = 0;}}, 1000);
})document.querySelector("#vd").addEventListener("pause", () => {isPlay = false;clearInterval(timer);
})document.querySelector("#switchButton").addEventListener("change", (e) => {if (e.target.checked) {bulletConfig.isHide = false;for (let bullet of bulletsArray) {bullet.spanEle.style.visibility = 'visible';}} else {bulletConfig.isHide = true;for (let bullet of bulletsArray) {bullet.spanEle.style.visibility = 'hidden';}}
})

好啦,本文就先到这里了。我去吃饭了,拜拜~~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/196479.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于STM32的智慧农业项目(物联网专业毕设)附送源码和文档材料+学习路线

文章目录 概要整体架构流程硬件选型软件总体框架技术细节实现效果小结 概要 传统农业存在着产量受到环境因素影响较大的问题&#xff0c;现有的农业监测系统数据太过简单、太过理想化。而随着现代科学的持续发展,一个精准化、自动化的现代智能农产品管理系统将在农业生产中起着…

个人Windows电脑通过Cloudreve+Cpolar搭建PHP云盘系统公网可访问

文章目录 1、前言2、本地网站搭建2.1 环境使用2.2 支持组件选择2.3 网页安装2.4 测试和使用2.5 问题解决 3、本地网页发布3.1 cpolar云端设置3.2 cpolar本地设置 4、公网访问测试5、结语 1、前言 自云存储概念兴起已经有段时间了&#xff0c;各互联网大厂也纷纷加入战局&#…

⭐ Unity + ARKIT 介绍 以及 平面检测的实现

在AR插件中&#xff0c;ARKIT是比较特殊的一个&#xff0c;首先他在很多追踪上的效果要比其他的AR插件要好&#xff0c;但是只能在IOS系统设备上运行。 1.首先ARKIT在最新版Unity已经集成在AR Foundation中&#xff0c;那我们就需要ARSession 和ARSessionOrigin这两个重要组件…

netcore swagger 错误 Failed to load API definition

后端接口报错如下&#xff1a; 前端nswag报错如下&#xff1a; 根据网上查询到的资料说明&#xff0c;说一般swagger这种错误都是控制器里有接口代码异常造成的&#xff0c;通常是接口没有加属性Attribute&#xff0c; 比如[HttpPost("Delete")]、[HttpGet("Del…

chown和chmod

chown和chmod都是在Linux和Unix系统中用于设置文件和文件夹权限的命令&#xff0c;但它们的功能和用途有所不同。 功能&#xff1a;chown主要用于修改文件或文件夹的所有者和所属组&#xff0c;而chmod则主要用于修改文件或文件夹的读写执行权限。用途&#xff1a;如果想要授权…

Vue3 组合式实现 带连接线的Tree型 架构图(一级树形图)

创建组件名称 TreeNodeView.vue <template><div class"tree-node"><div class"node">{{ rootNodeName }}</div><div class"children" :style"childrenLineStyle"><div class"child-node"…

12月4日作业

完成沙发床的多继承 #include <iostream>using namespace std;class Sofa { private:string sit;int *price; public:Sofa() {cout << "Sofa::无参构造函数" << endl;}Sofa(string sit,int price):sit(sit),price((new int(price))){cout <<…

AutoHotKey-study

目录 使用编辑器脚本注意函数解释信息调试方法键盘获取方法脚本练习 最近发现常用键盘的上下左右箭头去操作输入输出问题感觉很不是滋味&#xff0c;不像Linux那样&#xff0c;有vim的使用&#xff0c;就想着有没有什么方法更快捷&#xff0c;更方便的去使用电脑键盘&#xff0…

分享80个菜单导航JS特效,总有一款适合您

分享80个菜单导航JS特效&#xff0c;总有一款适合您 80个菜单导航JS特效下载链接&#xff1a;https://pan.baidu.com/s/1NgNc759Kg1of_8vR7kaj6A?pwd6666 提取码&#xff1a;6666 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;…

pip的基本命令和使用

pip 简介 pip是Python官方的包管理器&#xff0c;可以方便地安装、升级和卸载Python包。 pip 常用命令 显示版本和路径 pip --version获取帮助 pip --help升级pip和升级包 pip install --upgrade pip # Linux/macOS pip install -U pip # windowspip install…

【Cesium】模型平面裁切

const scene viewer.scene;let tileset; let targetY 400.0; let planeEntities []; let selectedPlane; // 选择的切面 let clippingPlanes; // 切面属性// 当鼠标点击切面时&#xff0c;修改相关属性 const downHandler new Cesium.ScreenSpaceEventHandler(viewer.sce…

表达式二叉树的中序遍历:2017年408算法题

算法思想 表达式二叉树的中序遍历即中缀表达式除了根节点和叶结点&#xff0c;遍历到其他结点时在遍历其左子树前加上左括号&#xff0c;在遍历完右子树后加上右括号 算法实现 //中序遍历&#xff0c;deep从1开始&#xff0c;即根节点的深度为1 void midOrder(BTree T,int …

作业12.4

1.沙发床的多继承 #include <iostream>using namespace std; class Sofa { private:string sit; public://无参构造Sofa(){}//有参构造Sofa(string sit):sit(sit){}//拷贝构造Sofa(const Sofa &other):sit(other.sit){}//拷贝赋值Sofa &operator (const Sofa &…

【数据分享】2015-2023年我国区县逐月二手房房价数据(Excel/Shp格式)

房价是一个城市发展程度的重要体现&#xff0c;一个城市的房价越高通常代表这个城市越发达&#xff0c;对于人口的吸引力越大&#xff01;因此&#xff0c;房价数据是我们在各项城市研究中都非常常用的数据&#xff01;之前我们分享过2015-2023年我国地级市逐月房价数据&#x…

基于姿态估计的3D动画生成

在本文中&#xff0c;我们将尝试通过跟踪 2D 视频中的动作来渲染人物的 3D 动画。 在 3D 图形中制作人物动画需要大量的运动跟踪器来跟踪人物的动作&#xff0c;并且还需要时间手动制作每个肢体的动画。 我们的目标是提供一种节省时间的方法来完成同样的任务。 我们对这个问题…

MATLAB学习QPSK之QPSK_MOD_DEMOD_SALIMup分析

学习的背景说明 因为在学习5G物理层&#xff0c;一直很忙&#xff0c;没有时间。最近稍有一点空闲&#xff0c;所以&#xff0c;学习一下算法。 QPSK的算法&#xff0c;虽然说我没有完全学透&#xff0c;大致还是懂的。只能一直没时间用MATLAB来研究一下。 然后看到这个实例&…

YITH WooCommerce Social Login跨境电商网站社交登录高级版插件

点击阅读YITH WooCommerce Social Login跨境电商网站社交登录高级版插件原文 YITH WooCommerce Social Login跨境电商网站社交登录高级版插件让您的用户节省时间并通过他们的社交资料之一登录或注册网站。 您如何从中受益&#xff1a; 用户无需填写表格、插入个人数据&#…

【数据分享】我国12.5米分辨率的地形粗糙度(起伏度)数据(免费获取)

地形数据&#xff0c;也叫DEM数据&#xff0c;是我们在各项研究中最常使用的数据之一。之前我们分享过源于NASA地球科学数据网站发布的12.5米分辨率DEM地形数据&#xff01;基于该数据我们处理得到12.5米分辨率的坡度数据、坡向数据、山体阴影数据&#xff08;均可查看之前的文…

基于Python的6+1号码生成器

&#x1f388; 博主&#xff1a;一只程序猿子 &#x1f388; 博客主页&#xff1a;一只程序猿子 博客主页 &#x1f388; 个人介绍&#xff1a;爱好(bushi)编程&#xff01; &#x1f388; 创作不易&#xff1a;如喜欢麻烦您点个&#x1f44d;或者点个⭐&#xff01; &#x1f…

(C++)盛水最多的容器--双指针法

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能&#xff0c;轻松拿下世界 IT 名企 Dream Offer。https://le…