第一幕
1. 图片及定位问题
大部分图片使用绝对定位,想把图片放全,放进盒子,且原比例不变,使用百分比来确定宽或高,(另一个不设置,则默认为auto)根据需求选择
2.背景颜色渐变实现
css
`background-image: linear-gradient( #1e2d59, #192e79, #0069aa);`
3.月亮向上滑动的实现
html
<body>
<div class="first">
<!-- 背景星星 -->
<img class="backdropstar" src="img/backdropstart.png" alt="star">
<!-- 提示语 -->
<div class="text-tips">
<img class="words" src="img/words1.png" alt="words1">
<img class="words" src="img/words2.png" alt="words2">
<img class="words" src="img/words3.png" alt="words3">
</div>
<!-- 乐曲界面 -->
<div class="second" id="second">
<!-- 未点击的乐曲 -->
<img src="" alt="">
<img src="img2/musicealternatelytitle.png" class="yindao">
<img src="img2/zhuangtaiqiusi.png" class="zhaung play">
<img src="img2/guanglingsan.png" class="guang play">
<img src="img2/nichangqu.png" class="ni play">
<img src="img2/meihuasannong.png" class="mei play">
<img src="img2/shenrenchang.png" class="shen play">
<img src="img2/yueergao.png" class="yue play">
<img src="img2/xiaoxiangshuiyun.png" class="xiao play">
<audio src="music/zhuangtaiqiusi.mp3" class="musiclist"></audio>
<audio src="music/guanglingsan.mp3" class="musiclist"></audio>
<audio src="music/nichangqu.mp3" class="musiclist"></audio>
<audio src="music/meihuasannong.mp3" class="musiclist"></audio>
<audio src="music/shenrenchang.mp3" class="musiclist"></audio>
<audio src="music/yueergao.mp3" class="musiclist"></audio>
<audio src="music/xiaoxiangshuiyun.mp3" class="musiclist"></audio>
<!-- 点击后的乐曲 -->
<img src="img2/zhuangtaiqiusi-change.png" class="zhaung played" id="zahungp">
<img src="img2/guanglingsan-change.png" class="guang played">
<img src="img2/nichangqu-change.png" class="ni played">
<img src="img2/meihuasannong-change.png" class="mei played">
<img src="img2/shenrenchang-change.png" class="shen played">
<img src="img2/yueergao-change.png" class="yue played">
<img src="img2/xiaoxiangshuiyun-change.png" class="xiao played">
<!-- 放飞天灯 -->
</div>
<!-- 月亮 -->
<div class="moonbox">
<img id="moon" class="moon" src="img/moonbunny.png" alt="moon">
</div>
<!-- 透明月亮滑动块 -->
<div class="fakemoonbutton"></div>
<!-- 背景小山 -->
<div class="bac-mountain">
<img class="mountain" src="img/mountain1.png" alt="mountain">
<img class="mountain2" src="img/mountain2.png" alt="mountain">
</div>
</div>
<!-- script脚本 -->
<script type="text/javascript" src="js/js.js"></script>
</body>
js
// 获取手指初始坐标
var startY = 0;
var middleY = 275;
// 初始化获得盒子原来的位置
var y = 0;
// console.log(movedY);
var lastTop = 0
// 手指触摸
fakemoonbutton.addEventListener('touchstart', function(e) {
// 获取手指初始坐标
// 当前元素offsetTop是相对于父节点的垂直距离
// pageY是touch接口的一个属性:表示触摸的点!!!相对于网页左上角的垂直距离
startY = e.targetTouches[0].pageY;
y = this.offsetTop;
this.style.transition = "none";
});
// 手指按住移动
fakemoonbutton.addEventListener('touchmove', function(e) {
// 计算手指的移动距离:手指移动之后的坐标减去手指初始的坐标
let moveY = e.targetTouches[0].pageY - startY;
lastTop = y + moveY;
// 移动盒子 盒子原来的位置 + 手指移动的距离
moonbox.style.top = lastTop + 'px';
// 输出盒子所在高度
// console.log(lastTop);
// 阻止屏幕滚动的默认行为
e.preventDefault();
});
// 手指离开
fakemoonbutton.addEventListener('touchend', function(e) {
// this.style.boxShadow = '';
if (lastTop >= middleY) {
moonbox.style.top = y + 'px';
moonbox.style.transition = "ease 3s"
console.log('没过中线嗷,给爷爬');
} else {
moonbox.style.top = 0 + 'px';
moonbox.style.transition = "ease 3s"
moon.style.opacity = 0;
moon.style.transition = "ease 3s"
console.log('给爷上天');
textTips.style.display = 'none';
textTips.style.transition = "ease 2s";
second.style.display = 'block';
second.style.transition = "2s";
}
});
月亮滑动有几个bug需要注意
- 月亮滑动的范围
- 月亮点击一次以后,往上移动,没有超过中线,再次滑动,会发现还存在之前的缓慢移动的css动画效果,这不是我们想要的,想想如何解决
- h5单页面应用,第一幕月亮向上滑动后,隐藏月亮和提示语元素,显示第二幕所有元素 js
// 手指离开
fakemoonbutton.addEventListener('touchend', function(e) {
// this.style.boxShadow = '';
if (lastTop >= middleY) {
moonbox.style.top = y + 'px';
moonbox.style.transition = "ease 3s"
console.log('没过中线嗷,给爷爬');
} else {
moonbox.style.top = 0 + 'px';
moonbox.style.transition = "ease 3s"
moon.style.opacity = 0;
moon.style.transition = "ease 3s"
console.log('给爷上天');
textTips.style.display = 'none';
textTips.style.transition = "ease 2s";
second.style.display = 'block';
second.style.transition = "2s";
}
});
第二幕
这些乐曲名都是图片,有白色图片(未播放)和黄色图片(正在播放),使用绝对定位一一进行定位显示
1.实现点击乐曲名,播放音乐
html
<!-- 乐曲界面 -->
<div class="second" id="second">
<!-- 未点击的乐曲 -->
<img src="" alt="">
<img src="img2/musicealternatelytitle.png" class="yindao">
<img src="img2/zhuangtaiqiusi.png" class="zhaung play">
<img src="img2/guanglingsan.png" class="guang play">
<img src="img2/nichangqu.png" class="ni play">
<img src="img2/meihuasannong.png" class="mei play">
<img src="img2/shenrenchang.png" class="shen play">
<img src="img2/yueergao.png" class="yue play">
<img src="img2/xiaoxiangshuiyun.png" class="xiao play">
<audio src="music/zhuangtaiqiusi.mp3" class="musiclist"></audio>
<audio src="music/guanglingsan.mp3" class="musiclist"></audio>
<audio src="music/nichangqu.mp3" class="musiclist"></audio>
<audio src="music/meihuasannong.mp3" class="musiclist"></audio>
<audio src="music/shenrenchang.mp3" class="musiclist"></audio>
<audio src="music/yueergao.mp3" class="musiclist"></audio>
<audio src="music/xiaoxiangshuiyun.mp3" class="musiclist"></audio>
<!-- 点击后的乐曲 -->
<img src="img2/zhuangtaiqiusi-change.png" class="zhaung played" id="zahungp">
<img src="img2/guanglingsan-change.png" class="guang played">
<img src="img2/nichangqu-change.png" class="ni played">
<img src="img2/meihuasannong-change.png" class="mei played">
<img src="img2/shenrenchang-change.png" class="shen played">
<img src="img2/yueergao-change.png" class="yue played">
<img src="img2/xiaoxiangshuiyun-change.png" class="xiao played">
<!-- 放飞天灯 -->
</div>
js
const playMusicList = document.querySelectorAll('.play');
const playedMusicList = document.querySelectorAll('.played');
const MusicList = document.querySelectorAll('.musiclist');
const MusicList2 = document.querySelector('.musiclist2');
var temp = 7;
// 点击播放,进行判断
for (let t = 0; t < playedMusicList.length; t++) {
playMusicList[t].addEventListener('touchstart', function(e) {
if (t !== temp) {
// 这次点击的下标与上次点击的下标进行判断。
// 若相同,则再存,走正常流程显示,播放,隐藏
// 若不同,则证明此时还有一个已经播放的字体,
// 则需要通过遍历把所有播放暂停,所有黄色字体隐藏,白色字体显示,恢复初始状态
// 恢复初始状态后,再走正常流程
for (let p = 0; p < playMusicList.length; p++) {
MusicList[p].pause();
playMusicList[p].style.display = 'block';
playedMusicList[p].style.display = "none";
}
}
temp = t;
// 存住上一次点击的下标
MusicList[t].play();
playMusicList[t].style.display = 'none';
playedMusicList[t].style.display = 'block';
// 这就保证了不管什么时候,页面上只有一个黄色字体正在播放
})
}
// 白色字体播放后,点击黄色字体暂停播放
for (let i = 0; i < playedMusicList.length; i++) {
playedMusicList[i].addEventListener("touchstart", function(e) {
// for
playMusicList[i].style.display = 'block';
playedMusicList[i].style.display = "none";
MusicList[i].pause();
})
}
先尝试实现,点击乐曲名播放对应音乐,图片变化由白变黄
及再次点击实现乐曲暂停,图片变化由黄变白(使用了数组的循环遍历,注意对下标的使用)
然后调试bug,比如,点击一次以后,不去暂停乐曲,直接点击另一个乐曲(这是用户可能会出现的操作)这时候要求,原本播放的音乐暂停,开始播放新的乐曲,并且图片发生变化(原本播放的乐曲现在应该由黄变白)
这部分的具体实现见上面的js代码
还没想通的问题
超过中线时,首先输出‘过中线了’,然后的操作是让月亮和提示语透明度在1s内渐变为0, 接下来执行延迟函数:1s后让月亮和提示语元素消失,让第二幕出现(第二幕原本的display是none,opacity是0)让他的display为block,然后!再接下来的这1s内(这是过了中线的第二秒了)!让他的opacity逐渐为1,这就完成了第二幕逐渐出现的效果,这个道理完全通顺的啊! 实际效果却是第二幕在1s后突然opacity为1的出现在页面上!!!为什么!?
通过实验发现,和second.style.display = 'block'有关只有吧这行代码放在延迟函数的外面让他先执行,后面的渐变动画才会提现出来,但具体原因还需要思考
2.天灯的动画实现(设计css动画的多种使用)
css
@keyframes tiandenghandmove {
from {
transform: translateX(10%);
opacity: 1;
}
to {
transform: translateX(-180%);
opacity: 0;
}
}
.tiandenghandmove {
height: 8%;
position: absolute;
right: 10%;
bottom: 25%;
z-index: 1;
animation: 3s ease-out infinite tiandenghandmove;
}
@keyframes 通过 @keyframes 规则,能够创建动画。创建动画的原理是,将一套 CSS 样式逐渐变化为另一套样式。在动画过程中,能够多次改变这套 CSS 样式。以百分比来规定改变发生的时间,或者通过关键词 "from" 和 "to",等价于 0% 和 100%。0% 是动画的开始时间,100% 动画的结束时间。
animation,请查阅animation的mdn的介绍文档!!!(很清楚)
更多动画相关属性,具体查阅其他博客
第三幕
乐器点击播放,暂停逻辑
可复用的函数:点击进入下一页的函数
原生js代码中想调用其他js文件里的代码,如:html文件需要两个js文件,a.js和b.js,只要在html文件中引入过这两个js文件,a.js中可以直接调用b.js的函数或变量
总结
-
文件名、函数名、样式名 规范化:让这些名字都能简单明了的表达清楚他们代表的意思。比如musicList可变成playMusictImgList,因为他是播放音乐的图片list光给个musicList 就比较不够具体,过几个月再去看可能就会以为这是个音乐列表,代码可读性不够
-
加强对css样式(背景渐变效果,动画效果,point-events:none的使用),布局(图片原比例显示,对于不同设备的自适应!!!使用百分比,而不是固定的像素值),定位(BFC的理解还是不够)的掌握
-
函数拆分化,把单一,可重复使用的功能函数单独拆开,这样有3个好处,需要使用的时候直接调用即可;便于代码的理解,提高可读性;代码出问题的时候有利于排错;
point-events:none的使用
关于月亮藏在山后面,无法点击到的问题,可以使用这个样式,点击就会穿过底部的群山,直接点到月亮上,此时的群山就像下文中所说的海市蜃楼一样