用面向对象思维实现点击后小球自由落体弹跳——javascript

几天前进行了一场前端实习面试,题目是用面向对象的方法实现点击后小球自由落体弹跳运动,觉得很有意思,现在有空整理一下。

一些简单的CSS样式和基础的HTML

#bg{
    top:0;
    bottom: 0;
    left: 0;
    right: 0;
    position: absolute;
}

.ball{
    position: absolute;
    border-radius: 50%;
    width:50px;
    height:50px;
    background: radial-gradient(circle at 50px 50px, #ffd3d1, #b01700);
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Ball</title>
    <link rel="stylesheet" href="ball.css">
</head>
<body>
<div id="bg"></div>
</body>
<script src="ball.js"></script>
<script>
// 点击事件我写在此处
</script>
</html>

好了,现在开始工作。

  • 首先,我们需要一个Ball类的构造函数
constructor(left, top, ballID) {
    this.ballID = ballID; //小球的ID,为唯一标识符
    this.x = left; //小球的横坐标
    this.y = top; //小球的纵坐标
    this.g = 9.8; //重力加速度
    this.v = 0; //小球的速度
    this.isStop = false; //判断当前运动是否应该停止

    this.createBall(); //创建小球的DOM

    let intervalSetting = window.setInterval(()=>{ //这里使用箭头函数,函数的this指针问题需要注意一下。
        this.move();
        if (this.isStop) {
            clearInterval(intervalSetting);
        }
    }, 1);
}
  • 创建该小球的DOM,设置其位置,添加ball类以让后面添加的小球获取ID
createBall() {
    let ballDiv = document.createElement('div');
    ballDiv.setAttribute('id', this.ballID);
    document.getElementById('bg').appendChild(ballDiv);
    let ballDom = document.getElementById(this.ballID);
    ballDom.classList.add('ball');
    ballDom.style.top = this.y + 'px';
    ballDom.style.left = this.x + 'px';
}
  • 然后是小球的移动
move() {

    // 0.001秒是setInterval的时间间隔,我将其看作是0.001秒内的匀速运动

    if (this.y >= window.innerHeight - 50 && this.v > 0) { // 如果小球下降过程中接触到屏幕底部。小球的直径为50px
        this.rebound(); //小球反弹
    } else { //自由落体
        this.v = this.v + this.g * 4000 * 0.001; // 公式:v = v0 + gt, 1 m = 3779.527559 px,这里约等于4000
    }
    this.y = this.y + this.v * 0.001; // 公式:s = s + vt
    document.getElementById(this.ballID).style.top = this.y + 'px';
}
  • 最后,点击事件和创建对象
document.getElementById('bg').onclick = function (e) {

    let ballID = document.querySelectorAll('.ball').length + 1;
    let ballObj = new Ball(e.clientX, e.clientY, ballID);

};

实现效果:

 


小球 2.0,实现甩球和在墙上反弹


html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Ball Bounce</title>
    <link rel="stylesheet" href="ball.css">
</head>
<body>
<div id="bg"></div>
</body>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script src="ball.js"></script>
<script>

    $('#bg').mousedown(function (e) {
        let ballID = $('.ball').length + 1;
        let ballObj = new Ball(e.clientX-25, e.clientY-25, ballID);

        ballObj.dragDown(e)
    });

</script>
</html>

js

class Ball {
    constructor(left, top, ballID) {
        this.ballID = ballID; //小球的ID,为唯一标识符
        this.x = left; //小球的横坐标
        this.y = top; //小球的纵坐标
        this.g = 9.8; //重力加速度
        this.speedY = 0; //小球的速度
        this.speedX = 0;
        this.isStop = false; //判断当前运动是否应该停止
        this.createBall();
    }

    createBall() {
        let ballDiv = document.createElement('div');
        ballDiv.setAttribute('id', this.ballID);
        $('#bg').append(ballDiv);
        this.ball = $('#' + this.ballID);
        this.ball.addClass('ball').css('left', this.x).css('top', this.y);
    }

    release() {
        let intervalSetting = window.setInterval(() => {
            this.falling();
            if (this.isStop) {
                clearInterval(intervalSetting);
            }
        }, 1);
    }

    falling() {

        // 0.001秒是setInterval的时间间隔,我将其看作是0.001秒内的匀速运动

        if (this.y >= window.innerHeight - 50 && this.speedY > 0) { //触地反弹
            this.rebound('y');
        } else { //自由落体
            this.speedY = this.speedY + this.g * 4000 * 0.001; // 1 m = 3779.527559 px
        }

        if (this.x >= window.innerWidth - 50 || this.x <= 0) {
            this.rebound('x');
        }

        this.y = this.y + this.speedY * 0.001;
        this.x = this.x + this.speedX * 0.001;

        this.ball.css('top', this.y).css('left', this.x);
    }

    rebound(coordinate) {

        if (Math.abs(parseInt(this.speedY)) <= 20 && this.y >= window.innerHeight - 50) { // 当竖直方向速度为零时(这里为了效果写20),且小球位于地面上时
            this.y = window.innerHeight - 50;
            if (Math.abs(parseInt(this.speedX)) <= 10) { // 当水平方向速度也为零
                this.isStop = 1;
            } else { // 当小球在地面上水平滚动
                this.speedX = this.speedX * 0.995; //假设每次损失0.5%的速度
            }
        } else { // 反弹
            if (coordinate === 'y') {
                this.speedY = -this.speedY * 0.9; //假设每次损失10%的速度
            } else {
                this.speedX = -this.speedX * 0.95; //假设每次损失10%的速度
            }
        }
    }

    dragDown() {
        // 将 dragDown 和 dragUp 函数另存一份,解决抬起鼠标后无法移除绑定事件的问题
        this.mouseUp = this.dragUp.bind(this);
        this.mouseMove = this.dragMove.bind(this);

        this.historicX = this.x;
        this.historicY = this.y;

        $(document).on("mousemove", this.ball, this.mouseMove); // 这里必须绑在document上,如果只是绑在小球上,鼠标过快移动会造成小球脱离鼠标轨迹
        $(document).on("mouseup", this.ball, this.mouseUp);
    }

    dragMove(e) {
        this.x = e.clientX - 25;
        this.y = e.clientY - 25;

        if (e.clientX <= 25) {
            this.x = 0;
        } else if (e.clientX >= window.innerWidth - 50) {
            this.x = window.innerWidth - 50;
        }

        if (e.clientY <= 50) {
            this.y = 0;
        } else if (e.clientY >= window.innerHeight - 50) {
            this.y = window.innerHeight - 50;
        }

        this.ball.css('left', this.x);
        this.ball.css('top', this.y);

        this.speedX = (this.x - this.historicX) * 10;
        this.speedY = (this.y - this.historicY);
    }

    dragUp(e) {
        $(document).off('mousemove');
        this.release();
    }
}

效果:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值