现在学习的代码工作中不一定会需要,如果有,也已经做成了产品和库,
前端重点是创造,面试官考验你的能力是会提出最刁钻的问题给你的。
项目效果
原生JS效率是最高的,框架只是提高代码的可读性
favico图标添加
两种方法
1、放到站点的根目录,但涉及网络和部署相关,不推荐
2、link引入
<link rel="shortcut icon" href="./assets//favicon.ico" type="image/x-icon">
音频控件
<audio controls src="./assets//music.mp3"></audio>
滚动原理
快速创建lorem(乱数假文)
lorem在HTML中的应用可以生成随机文本
li*30>lorem4
给body设置text-align: center
text-align: center是可继承的,body→div→ul→li
让它的行盒子元素内容水平居中
控制里层ul的位置
两种思路:
1、margin-top为负(渲染主线程)
但是margin改变会导致reflow(重排)性能低,是在主线程上进行的
2、用JS控制css3的transform实现位移(合成线程)
css属性变化本身是没有动画效果的
transition过渡,是针对数值类的属性来说的
歌词滚动时,当前歌词高亮并放大,并且与进度条位置一致
JS控制哪一个特殊样式,CSS写样式
放大fontsize会影响布局树,用transform:scale 最好
transition写在li.active还是li?
li.active效果消失没有过渡效果
所以加在li里面
实现界面交互效果,切入点是什么?
不是怎么设置元素的属性,怎么监控这个音乐播放器的进度
而是从数据切入,我的手上有什么数据,转换成数组或对象
var lrc = `[00:01.06]难念的经
[00:03.95]演唱:周华健
[00:06.78]
[00:30.96]笑你我枉花光心计
[00:34.15]爱竞逐镜花那美丽
[00:36.75]怕幸运会转眼远逝
[00:39.32]为贪嗔喜恶怒着迷`;
此案例中,给的是字符串,想办法变成数组
分割歌词字符串
理想效果:
[{time: 1.06, words: '难念的经'}, {time: 3.95, words: '演唱:周华健'}]
思路:
- 根据换行符 \n 分割,将每一行都包装成对象
- 遍历每个对象,每个对象由时间和歌词键值对组成
- 歌词时间格式化,统一转换成秒
/**
* 解析歌词字符串
* 得到一个歌词对象的数组
* 每个歌词对象:
* {time: 开始时间, words: 歌词内容}
*/
function parseLrc () {
let lines = lrc.split('\n');
const result = [];
for (let i = 0; i < lines.length; i++) {
let str = lines[i];
let parts = str.split(']');
let timeStr = parts[0].substring(1); //从第一项开始截取
const obj = {
time: parseTime(timeStr),
words: parts[1]
}
result.push(obj);
}
return result;
}
/**
* 时间字符串转换成秒
* @param {*} timeStr
* @returns {Number} 小数
*/
function parseTime (timeStr) {
let parts = timeStr.split(':');
return +parts[0] * 60 + +parts[1];
}
要高亮显示的歌词,决定了ul列表的偏移量
计算出,当前播放器播到第几秒,对应的高亮歌词下标
获取当前播放时间
audio.currentTime;
遍历歌词数组,判断找到比当前时间大的时间,拿到当前的下标 - 1,就是对应的高亮歌词下标
数据少时,直接在ul中appendChild() :
但是这样频繁改动dom树,70个数据就改动了70多次,数据越多性能越低
function createLrcElements () {
for (let i = 0; i < lrcData.length; i++) {
let li = document.createElement('li');
li.textContent = lrcData[i].words;
doms.ul.appendChild(li);
}
}
永远不要率先优化
做代码顺序:数据逻辑→界面逻辑→事件
数据多时 :
利用文档片段过渡
先将li节点插到createDocumentFragment()
再把createDocumentFragment里的东西加到ul里面
function createLrcElements () {
const frag = document.createDocumentFragment();
for (let i = 0; i < lrcData.length; i++) {
let li = document.createElement('li');
li.textContent = lrcData[i].words;
// doms.ul.appendChild(li);
frag.appendChild(li);
}
doms.ul.appendChild(frag);
}
createLrcElements();
let maxOffset = doms.ul.clientHeight - containerHeight;
设置ul 元素的偏移量
- 小于最小值时,让它等于0
- 大于最大值时,它等于最大值
- 高亮之前清除所有的高亮
function setOffset () {
let index = findIndex();
let offset = liHeight * index + liHeight / 2 - containerHeight / 2;
/* 最小值 */
if (offset < 0) {
offset = 0;
}
/* 最大值 */
if (offset > maxOffset) {
offset = maxOffset;
}
doms.ul.style.transform = `translateY(-${offset}px)`;
/* 去掉之前的样式 */
let li = doms.ul.querySelector('.active');
if (li) {
li.classList.remove('active')
}
/* 拿到需要高亮的li标签 */
li = doms.ul.children[index];
if (li) {
li.classList.add('active');
}
}