国乐知多少项目实战总结(练手项目)

229 阅读6分钟

第一幕

第一幕效果

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需要注意

  1. 月亮滑动的范围
  2. 月亮点击一次以后,往上移动,没有超过中线,再次滑动,会发现还存在之前的缓慢移动的css动画效果,这不是我们想要的,想想如何解决
  3. 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的函数或变量

总结

  1. 文件名、函数名、样式名 规范化:让这些名字都能简单明了的表达清楚他们代表的意思。比如musicList可变成playMusictImgList,因为他是播放音乐的图片list光给个musicList 就比较不够具体,过几个月再去看可能就会以为这是个音乐列表,代码可读性不够

  2. 加强对css样式(背景渐变效果,动画效果,point-events:none的使用),布局(图片原比例显示,对于不同设备的自适应!!!使用百分比,而不是固定的像素值),定位(BFC的理解还是不够)的掌握

  3. 函数拆分化,把单一,可重复使用的功能函数单独拆开,这样有3个好处,需要使用的时候直接调用即可;便于代码的理解,提高可读性;代码出问题的时候有利于排错;

point-events:none的使用

关于月亮藏在山后面,无法点击到的问题,可以使用这个样式,点击就会穿过底部的群山,直接点到月亮上,此时的群山就像下文中所说的海市蜃楼一样

查阅文档并使用是一种重要的学习能力!!!