专业的编程技术博客社区

网站首页 > 博客文章 正文

手把手教你7个有趣的JavaScript 项目-上「附源码」

baijin 2024-08-15 00:18:22 博客文章 7 ℃ 0 评论



前言

JavaScript是最好的语言之一,尤其是在前端开发中。在本文中,您将找到7个为初学者提供免费源代码的最佳javascript项目。

手把手教你7个有趣的JavaScript 项目-上「附源码」(本篇)

手把手教你7个有趣的JavaScript 项目-下「附源码」


1.使用JavaScript创建待办事项列表应用



如果您是javascript语言的初学者,则待办事项列表应用程序是最好的和最容易的应用程序之一,如果您使用HTML CSS和一点点的javascript,则可以创建此简单的待办事项列表应用程序,您将找到源代码这个js项目的底部。

<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>创建待办事项列表应用</title>
<style type="text/css">
$primary: #313e50;
$grey: #cdcdcd;
$secondary: #1dd2af;

%reset {
    margin: 0;
    padding: 0;
    border: none;
    outline: none;
    background: transparent;
}

%transition {
    transition: all 0.2s ease;
    -webkit-transition: all 0.2s ease;
}

body {
    background: #f1f1f1;
    margin-top: 2rem;
}

/*PEN STYLES*/
.tasker {
    max-width: 400px;
    margin: 0 auto;
    .error {
        display: none;
        background: rgba(237, 28, 36, 0.7);
        color: #fff;
        padding: 14px;
        margin-bottom: 10px;
        border-radius: 5px;
        text-align: center;
    }

    ul {
        @extend %reset;
        background: #fff;
    }

    li,
    .error,
    button,
    input {
        @extend %reset;
        font: 18px/1.25em Helvetica, Arial, Sans-serif;
    }
}

.tasker-header {
    display: inline-flex;
    background: $primary;
    justify-content: space-between;
    width: 100%;
    input,
    button {
        color: #fff;
        box-sizing: border-box;
        font-size: 1.25em;
        padding: 14px;
    }

    input {
        flex-grow: 2;
    }

    button {
        @extend %transition;
        background: $secondary;
        border-left: 1px solid ($secondary * 1.05);
        &:hover {
            background: $secondary * 1.1;
        }
    }
}

.tasker-body {
    .task {
        display: block;
        position: relative;
        padding: 14px 40px 14px 14px;
        border-bottom: 1px solid rgba(0, 0, 0, 0.1);
        &:last-child {
            border-bottom: none;
        }

        &:hover > button {
            opacity: 1;
        }

        &.completed {
            color: $grey;
            text-decoration: line-through;
        }

        input {
            margin-right: 10px;
        }

        button {
            @extend %transition;
            color: $grey;
            margin: 14px;
            position: absolute;
            top: 0;
            right: 0;
            opacity: 0;
            &:hover {
                color: #ed1c24;
            }
        }
    }
}
</style>
</head>
<body>
<!--PEN CODE-->
<div id="tasker" class="tasker">
    <div id="error" class="error">Please enter a task</div>
    <div id="tasker-header" class="tasker-header">
        <input type="text" id="input-task" placeholder="Enter a task">
        <button id="add-task-btn"><i class="fa fa-fw fa-plus"></i>
        </button>
    </div>
    <div class="tasker-body">
        <ul id="tasks"></ul>
    </div>
</div>
<!--END PEN CODE-->
<script type="text/javascript">
(function() {
    'use strict';
    var tasker = {
        init: function() {
            this.cacheDom();
            this.bindEvents();
            this.evalTasklist();
        },
        cacheDom: function() {
            this.taskInput = document.getElementById("input-task");
            this.addBtn = document.getElementById("add-task-btn");
            this.tasklist = document.getElementById("tasks");
            this.tasklistChildren = this.tasklist.children;
            this.errorMessage = document.getElementById("error");
        },
        bindEvents: function() {
            this.addBtn.onclick = this.addTask.bind(this);
            this.taskInput.onkeypress = this.enterKey.bind(this);
        },
        evalTasklist: function() {
            var i, chkBox, delBtn;
            //BIND CLICK EVENTS TO ELEMENTS
            for (i = 0; i < this.tasklistChildren.length; i += 1) {
                //ADD CLICK EVENT TO CHECKBOXES
                chkBox = this.tasklistChildren[i].getElementsByTagName("input")[0];
                chkBox.onclick = this.completeTask.bind(this, this.tasklistChildren[i], chkBox);
                //ADD CLICK EVENT TO DELETE BUTTON
                delBtn = this.tasklistChildren[i].getElementsByTagName("button")[0];
                delBtn.onclick = this.delTask.bind(this, i);
            }
        },
        render: function() {
            var taskLi, taskChkbx, taskVal, taskBtn, taskTrsh;
            //BUILD HTML
            taskLi = document.createElement("li");
            taskLi.setAttribute("class", "task");
            //CHECKBOX
            taskChkbx = document.createElement("input");
            taskChkbx.setAttribute("type", "checkbox");
            //USER TASK
            taskVal = document.createTextNode(this.taskInput.value);
            //DELETE BUTTON
            taskBtn = document.createElement("button");
            //TRASH ICON
            taskTrsh = document.createElement("i");
            taskTrsh.setAttribute("class", "fa fa-trash");
            //INSTERT TRASH CAN INTO BUTTON
            taskBtn.appendChild(taskTrsh);

            //APPEND ELEMENTS TO TASKLI
            taskLi.appendChild(taskChkbx);
            taskLi.appendChild(taskVal);
            taskLi.appendChild(taskBtn);

            //ADD TASK TO TASK LIST
            this.tasklist.appendChild(taskLi);

        },
        completeTask: function(i, chkBox) {
            if (chkBox.checked) {
                i.className = "task completed";
            } else {
                this.incompleteTask(i);
            }
        },
        incompleteTask: function(i) {
            i.className = "task";
        },
        enterKey: function(event) {
            if (event.keyCode === 13 || event.which === 13) {
                this.addTask();
            }
        },
        addTask: function() {
            var value = this.taskInput.value;
            this.errorMessage.style.display = "none";

            if (value === "") {
                this.error();
            } else {
                this.render();
                this.taskInput.value = "";
                this.evalTasklist();
            }
        },
        delTask: function(i) {
            this.tasklist.children[i].remove();
            this.evalTasklist();
        },
        error: function() {
            this.errorMessage.style.display = "block";
        }
    };

    tasker.init();
}());
</script>
</body>
</html>

2.使用JavaScript和CSS创建垂直时间轴(里程碑)



您可以使用javascript初学者创建的第二个小项目是时间轴,许多现代网站都使用该时间轴使网站更具交互性和动态性。

<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>CSS创建垂直时间轴(里程碑)</title>
<style type="text/css">
*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  font: normal 16px/1.5 "Helvetica Neue", sans-serif;
  background: #456990;
  color: #fff;
  overflow-x: hidden;
  padding-bottom: 50px;
}  /* INTRO SECTION
–––––––––––––––––––––––––––––––––––––––––––––––––– */

.intro {
  background: #F45B69;
  padding: 100px 0;
}

.container {
  width: 90%;
  max-width: 1200px;
  margin: 0 auto;
  text-align: center;
}

h1 {
  font-size: 2.5rem;
}


/* TIMELINE
–––––––––––––––––––––––––––––––––––––––––––––––––– */

.timeline ul {
  background: #456990;
  padding: 50px 0;
}

.timeline ul li {
  list-style-type: none;
  position: relative;
  width: 6px;
  margin: 0 auto;
  padding-top: 50px;
  background: #fff;
}

.timeline ul li::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: 0;
  transform: translateX(-50%);
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: inherit;
}

.timeline ul li div {
  position: relative;
  bottom: 0;
  width: 400px;
  padding: 15px;
  background: #F45B69;
}

.timeline ul li div::before {
  content: '';
  position: absolute;
  bottom: 7px;
  width: 0;
  height: 0;
  border-style: solid;
}

.timeline ul li:nth-child(odd) div {
  left: 45px;
}

.timeline ul li:nth-child(odd) div::before {
  left: -15px;
  border-width: 8px 16px 8px 0;
  border-color: transparent #F45B69 transparent transparent;
}

.timeline ul li:nth-child(even) div {
  left: -439px;
}

.timeline ul li:nth-child(even) div::before {
  right: -15px;
  border-width: 8px 0 8px 16px;
  border-color: transparent transparent transparent #F45B69;
}

time {
  display: block;
  font-size: 1.2rem;
  font-weight: bold;
  margin-bottom: 8px;
}


/* EFFECTS
–––––––––––––––––––––––––––––––––––––––––––––––––– */

.timeline ul li::after {
  transition: background .5s ease-in-out;
}

.timeline ul li.in-view::after {
  background: #F45B69;
}

.timeline ul li div {
  visibility: hidden;
  opacity: 0;
  transition: all .5s ease-in-out;
}

.timeline ul li:nth-child(odd) div {
  transform: translate3d(200px, 0, 0);
}

.timeline ul li:nth-child(even) div {
  transform: translate3d(-200px, 0, 0);
}

.timeline ul li.in-view div {
  transform: none;
  visibility: visible;
  opacity: 1;
}


/* GENERAL MEDIA QUERIES
–––––––––––––––––––––––––––––––––––––––––––––––––– */

@media screen and (max-width: 900px) {
  .timeline ul li div {
    width: 250px;
  }
  .timeline ul li:nth-child(even) div {
    left: -289px;
    /*250+45-6*/
  }
}

@media screen and (max-width: 600px) {
  .timeline ul li {
    margin-left: 20px;
  }
  .timeline ul li div {
    width: calc(100vw - 91px);
  }
  .timeline ul li:nth-child(even) div {
    left: 45px;
  }
  .timeline ul li:nth-child(even) div::before {
    left: -15px;
    border-width: 8px 16px 8px 0;
    border-color: transparent #F45B69 transparent transparent;
  }
}
</style>
</head>
<body>
<section class="intro">
  <div class="container">
    <h1>Vertical Timeline ↓</h1>
  </div>
</section>

<section class="timeline">
  <ul>
    <li>
      <div>
        <time>1934</time> demo1
      </div>
    </li>
    <li>
      <div>
        <time>1937</time> demo1
      </div>
    </li>
    <li>
      <div>
        <time>1940</time> demo1
      </div>
    </li>
    <li>
      <div>
        <time>1943</time> demo1
      </div>
    </li>
    <li>
      <div>
        <time>1946</time> demo1
      </div>
    </li>
    <li>
      <div>
        <time>1956</time> demo1
      </div>
    </li>
    <li>
      <div>
        <time>1957</time> demo1
      </div>
    </li>
    <li>
      <div>
        <time>1967</time>demo1
      </div>
    </li>
    <li>
      <div>
        <time>1977</time> demo1
      </div>
    </li>
    <li>
      <div>
        <time>1985</time> demo1
      </div>
    </li>
    <li>
      <div>
        <time>2000</time> demo1
      </div>
    </li>
    <li>
      <div>
        <time>2005</time> demo1
      </div>
    </li>
  </ul>
</section>
<script type="text/javascript">
(function() {

  'use strict';

  // define variables
  var items = document.querySelectorAll(".timeline li");

  // check if an element is in viewport
  // http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport
  function isElementInViewport(el) {
    var rect = el.getBoundingClientRect();
    return (
      rect.top >= 0 &&
      rect.left >= 0 &&
      rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
      rect.right <= (window.innerWidth || document.documentElement.clientWidth)
    );
  }

  function callbackFunc() {
    for (var i = 0; i < items.length; i++) {
      if (isElementInViewport(items[i])) {
        items[i].classList.add("in-view");
      }
    }
  }

  // listen for events
  window.addEventListener("load", callbackFunc);
  window.addEventListener("resize", callbackFunc);
  window.addEventListener("scroll", callbackFunc);

})();
</script>
</body>
</html>

3.用JavaScript构建一个简单的井字游戏



如果您想构建简单而有趣的东西来练习JavaScript知识,那么使用HTML CSS和JS创建TIC TAC TOE游戏对您来说是个不错的选择,该游戏虽然简单但并不容易,因此您需要专注于该项目的逻辑方面,因为它是该项目最具挑战性的部分。

<html>
    <head>
      <meta charset="utf-8" />
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="description" content="">
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <title>FreeCodeCamp: Tictactoe</title>
<style type="text/css">
@import url(https://fonts.googleapis.com/css?family=Yesteryear);
$app-background-color : #508ABB;
$app-row-height : 100%;
$winAnimStartColor : cyan;
$winAnimEndColor : #508ABB;

// html, body, div, span, a, li, td, th {
//  font-family: 'Lato', sans-serif;
//  font-weight: 300;
//
// }

@-webkit-keyframes winAnim{
    0% {
    background-color: $winAnimStartColor;
  }
  100% {
    background-color: $winAnimEndColor;
  }
}
@-moz-keyframes winAnim{
  0% {
    background-color: $winAnimStartColor;
  }
  100% {
    background-color: $winAnimEndColor;
  }
}
@-o-keyframes winAnim {
  0% {
    background-color: $winAnimStartColor;
  }
  100% {
    background-color: $winAnimEndColor;
  }
}
@keyframes winAnim {
  0% {
    background-color: $winAnimStartColor;
  }
  100% {
    background-color: $winAnimEndColor;
  }
}

@keyframes winAnim {
  0% {
    background-color: $winAnimStartColor;
  }
  100% {
    background-color: $winAnimEndColor;
  }
}

*{
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  outline-style:none;/*IE*/
}

.center-box{
    margin : auto;
    position: absolute;
    top : 0;
    right : 0;
    bottom : 0;
    left : 0;
}

html,body{
    //background-image: linear-gradient(to bottom,#dddbd1,#d2dbdc);
    background-color: #d2dbdc;
    height : 100%;
    width  : 100%;
}

.app{
    @extend .center-box;
    width : 80%;
    height : 70%;
    max-width: 550px;
    background-color : $app-background-color;
    box-shadow: 0 5px 30px -5px rgba(0,0,0, .85);
    border-radius: 10px;
    .app-container,
    .app-row{
        height: $app-row-height;
    }
}
.play-box,.symbol-option{
    font-family: 'Yesteryear', cursive;
}

.play-box{
    border-bottom : 2px solid #fff;
    border-right : 2px solid #fff;
    height : $app-row-height / 3;
    cursor: pointer;
    position: relative;
    &.last-right{
        border-right : none;
    }
    &.last-bottom{
        border-bottom : none;
    }
    &.win {
        -webkit-animation: winAnim .2s ease-out infinite;
      -moz-animation:    winAnim .2s ease-out infinite;
      -o-animation:      winAnim .2s ease-out infinite;
      animation:         winAnim .2s ease-out infinite;
        animation : winAnim .5s infinite;
    }
    .symbol{
        @extend .center-box;
        width: 50%;
        height : 50px;
        text-align: center;
        line-height : 50px;
        font-size: 35px;
        color : white;
    }
}

.modal-content{
    .content{
        padding : 15px;
        text-align: center;
        margin : 0;
        &.body{
            line-height: 2;
        }
    }
    .symbol-options{
        width: 200px;
        margin-top: 10px;
        .symbol-option{
            &:first-child{
                margin-right: 10px;
            }
            &:last-child{
                margin-left: 10px;
            }
        }
    }
    .warning-hr{
        margin: 0;
    }
}
</style>
    </head>

    <body>
        <div class="app">
            <div class="container-fluid app-container">
            <div class="row app-row">
                <div class="col-xs-4 play-box" id="0">
                    <div class="symbol"></div>
                </div>
                <div class="col-xs-4 play-box" id="1">
                    <div class="symbol"></div>
                </div>
                <div class="col-xs-4 play-box last-right" id="2">
                    <div class="symbol"></div>
                </div>
                <div class="col-xs-4 play-box" id="3">
                    <div class="symbol"></div>
                </div>
                <div class="col-xs-4 play-box" id="4">
                    <div class="symbol"></div>
                </div>
                <div class="col-xs-4 play-box last-right" id="5">
                    <div class="symbol"></div>
                </div>
                <div class="col-xs-4 play-box last-bottom" id="6">
                    <div class="symbol"></div>
                </div>
                <div class="col-xs-4 play-box last-bottom" id="7">
                    <div class="symbol"></div>
                </div>
                <div class="col-xs-4 play-box last-right last-bottom" id="8">
                    <div class="symbol"></div>
                </div>
            </div>
            </div>
        </div>

        <div class="modal fade app-modal" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel">
          <div class="modal-dialog modal-size">
            <div class="modal-content">
              <h3 class="content heading">Warning!!!</h3>
              <hr class="warning-hr">
              <div class="content body">
                  Please save your time and don't even think you're smart. <br><strong><em>I'M SMARTER THAN YOU! HA-HA-HA!!!</em></strong> <br>
                  Wana try me? Chose : <br>
                  <div class="center-block symbol-options">
                    <button class="symbol-option btn btn-default btn-md" data-dismiss="modal">X</button> OR <button class="symbol-option btn btn-default btn-md" data-dismiss="modal">O</button>
                  </div>
              </div>
            </div>
          </div>
        </div>
<script src="../js/bundled/tictactoe.bundled.js">
        </script>
    </body>
</html>

4.创建一个JavaScript倒数计时器开始停止重置



许多现代网站和博客都使用倒数计时器来显示倒数,例如,我们通过使用倒数计时器来告诉在线商店的访问者,商品价格将在价格上涨后增加销售量。具体时间。

<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>CSS创建垂直时间轴(里程碑)</title>
<style type="text/css">
 /* Variabes */  
$orange: #ffa600;
$grey:#f3f3f3;
$white: #fff;
$base-color:$orange ;


/* Mixin's */  
@mixin transition {
-webkit-transition: all 0.5s ease-in-out;
-moz-transition: all 0.5s ease-in-out;
transition: all 0.5s ease-in-out;
}
@mixin corners ($radius) {
-moz-border-radius: $radius;
-webkit-border-radius: $radius;
border-radius: $radius; 
-khtml-border-radius: $radius; 
}

body {
background:$base-color;
font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; 
height:100%;
}

.wrapper {
width: 800px;
margin: 30px auto;
color:$white;
text-align:center;
}

h1, h2, h3 {
  font-family: 'Roboto', sans-serif;
  font-weight: 100;
  font-size: 2.6em;
  text-transform: uppercase;
}

#seconds, #tens{
  font-size:2em;
}

button{
@include corners (5px);
background:$base-color;
color:$white;
border: solid 1px $white;
text-decoration:none;
cursor:pointer;
font-size:1.2em;
padding:18px 10px;
width:180px;
margin: 10px;
 outline: none;
  &:hover{
    @include transition;
    background:$white;
    border: solid 1px $white;
    color:$base-color;
    }
} 
</style>
    </head>
<body>
<div class="wrapper">
<h1>Stopwatch</h1>
<h2>Vanilla JavaScript Stopwatch</h2>
<p><span id="seconds">00</span>:<span id="tens">00</span></p>
<button id="button-start">Start</button>
<button id="button-stop">Stop</button>
<button id="button-reset">Reset</button>
</div> 
<script type="text/javascript">
  window.onload = function () {
  
  var seconds = 00; 
  var tens = 00; 
  var appendTens = document.getElementById("tens")
  var appendSeconds = document.getElementById("seconds")
  var buttonStart = document.getElementById('button-start');
  var buttonStop = document.getElementById('button-stop');
  var buttonReset = document.getElementById('button-reset');
  var Interval ;

  buttonStart.onclick = function() {
    
     clearInterval(Interval);
     Interval = setInterval(startTimer, 10);
  }
  
    buttonStop.onclick = function() {
       clearInterval(Interval);
  }
  

  buttonReset.onclick = function() {
     clearInterval(Interval);
    tens = "00";
    seconds = "00";
    appendTens.innerHTML = tens;
    appendSeconds.innerHTML = seconds;
  }
  
   
  
  function startTimer () {
    tens++; 
    
    if(tens < 9){
      appendTens.innerHTML = "0" + tens;
    }
    
    if (tens > 9){
      appendTens.innerHTML = tens;
      
    } 
    
    if (tens > 99) {
      console.log("seconds");
      seconds++;
      appendSeconds.innerHTML = "0" + seconds;
      tens = 0;
      appendTens.innerHTML = "0" + 0;
    }
    
    if (seconds > 9){
      appendSeconds.innerHTML = seconds;
    }
  
  }<script src="../js/bundled/tictactoe.bundled.js">
        </script>

}

 </script>
    </body>
</html>

5.用JavaScript创建一个简单的乒乓球游戏



我可以用JavaScript构建游戏吗?答案是肯定的,使用javascript甚至可以创建复杂的游戏,但是在这种情况下,我们将专注于一个简单的游戏,该游戏可让您练习HTML CSS和javascript技能。

<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>使用js调用设备摄像头并实现拍照</title>
<style type="text/css">
  body {
    text-align: center;
}
  </style>
</head>
<body>
    <script type="text/javascript">
      // Global Variables
var DIRECTION = {
    IDLE: 0,
    UP: 1,
    DOWN: 2,
    LEFT: 3,
    RIGHT: 4
};

var rounds = [5, 5, 3, 3, 2];
var colors = ['#1abc9c', '#2ecc71', '#3498db', '#e74c3c', '#9b59b6'];

// The ball object (The cube that bounces back and forth)
var Ball = {
    new: function (incrementedSpeed) {
        return {
            width: 18,
            height: 18,
            x: (this.canvas.width / 2) - 9,
            y: (this.canvas.height / 2) - 9,
            moveX: DIRECTION.IDLE,
            moveY: DIRECTION.IDLE,
            speed: incrementedSpeed || 9
        };
    }
};

// The paddle object (The two lines that move up and down)
var Paddle = {
    new: function (side) {
        return {
            width: 18,
            height: 70,
            x: side === 'left' ? 150 : this.canvas.width - 150,
            y: (this.canvas.height / 2) - 35,
            score: 0,
            move: DIRECTION.IDLE,
            speed: 10
        };
    }
};

var Game = {
    initialize: function () {
        this.canvas = document.querySelector('canvas');
        this.context = this.canvas.getContext('2d');

        this.canvas.width = 1400;
        this.canvas.height = 1000;

        this.canvas.style.width = (this.canvas.width / 2) + 'px';
        this.canvas.style.height = (this.canvas.height / 2) + 'px';

        this.player = Paddle.new.call(this, 'left');
        this.paddle = Paddle.new.call(this, 'right');
        this.ball = Ball.new.call(this);

        this.paddle.speed = 8;
        this.running = this.over = false;
        this.turn = this.paddle;
        this.timer = this.round = 0;
        this.color = '#2c3e50';

        Pong.menu();
        Pong.listen();
    },

    endGameMenu: function (text) {
        // Change the canvas font size and color
        Pong.context.font = '50px Courier New';
        Pong.context.fillStyle = this.color;

        // Draw the rectangle behind the 'Press any key to begin' text.
        Pong.context.fillRect(
            Pong.canvas.width / 2 - 350,
            Pong.canvas.height / 2 - 48,
            700,
            100
        );

        // Change the canvas color;
        Pong.context.fillStyle = '#ffffff';

        // Draw the end game menu text ('Game Over' and 'Winner')
        Pong.context.fillText(text,
            Pong.canvas.width / 2,
            Pong.canvas.height / 2 + 15
        );

        setTimeout(function () {
            Pong = Object.assign({}, Game);
            Pong.initialize();
        }, 3000);
    },

    menu: function () {
        // Draw all the Pong objects in their current state
        Pong.draw();

        // Change the canvas font size and color
        this.context.font = '50px Courier New';
        this.context.fillStyle = this.color;

        // Draw the rectangle behind the 'Press any key to begin' text.
        this.context.fillRect(
            this.canvas.width / 2 - 350,
            this.canvas.height / 2 - 48,
            700,
            100
        );

        // Change the canvas color;
        this.context.fillStyle = '#ffffff';

        // Draw the 'press any key to begin' text
        this.context.fillText('Press any key to begin',
            this.canvas.width / 2,
            this.canvas.height / 2 + 15
        );
    },

    // Update all objects (move the player, paddle, ball, increment the score, etc.)
    update: function () {
        if (!this.over) {
            // If the ball collides with the bound limits - correct the x and y coords.
            if (this.ball.x <= 0) Pong._resetTurn.call(this, this.paddle, this.player);
            if (this.ball.x >= this.canvas.width - this.ball.width) Pong._resetTurn.call(this, this.player, this.paddle);
            if (this.ball.y <= 0) this.ball.moveY = DIRECTION.DOWN;
            if (this.ball.y >= this.canvas.height - this.ball.height) this.ball.moveY = DIRECTION.UP;

            // Move player if they player.move value was updated by a keyboard event
            if (this.player.move === DIRECTION.UP) this.player.y -= this.player.speed;
            else if (this.player.move === DIRECTION.DOWN) this.player.y += this.player.speed;

            // On new serve (start of each turn) move the ball to the correct side
            // and randomize the direction to add some challenge.
            if (Pong._turnDelayIsOver.call(this) && this.turn) {
                this.ball.moveX = this.turn === this.player ? DIRECTION.LEFT : DIRECTION.RIGHT;
                this.ball.moveY = [DIRECTION.UP, DIRECTION.DOWN][Math.round(Math.random())];
                this.ball.y = Math.floor(Math.random() * this.canvas.height - 200) + 200;
                this.turn = null;
            }

            // If the player collides with the bound limits, update the x and y coords.
            if (this.player.y <= 0) this.player.y = 0;
            else if (this.player.y >= (this.canvas.height - this.player.height)) this.player.y = (this.canvas.height - this.player.height);

            // Move ball in intended direction based on moveY and moveX values
            if (this.ball.moveY === DIRECTION.UP) this.ball.y -= (this.ball.speed / 1.5);
            else if (this.ball.moveY === DIRECTION.DOWN) this.ball.y += (this.ball.speed / 1.5);
            if (this.ball.moveX === DIRECTION.LEFT) this.ball.x -= this.ball.speed;
            else if (this.ball.moveX === DIRECTION.RIGHT) this.ball.x += this.ball.speed;

            // Handle paddle (AI) UP and DOWN movement
            if (this.paddle.y > this.ball.y - (this.paddle.height / 2)) {
                if (this.ball.moveX === DIRECTION.RIGHT) this.paddle.y -= this.paddle.speed / 1.5;
                else this.paddle.y -= this.paddle.speed / 4;
            }
            if (this.paddle.y < this.ball.y - (this.paddle.height / 2)) {
                if (this.ball.moveX === DIRECTION.RIGHT) this.paddle.y += this.paddle.speed / 1.5;
                else this.paddle.y += this.paddle.speed / 4;
            }

            // Handle paddle (AI) wall collision
            if (this.paddle.y >= this.canvas.height - this.paddle.height) this.paddle.y = this.canvas.height - this.paddle.height;
            else if (this.paddle.y <= 0) this.paddle.y = 0;

            // Handle Player-Ball collisions
            if (this.ball.x - this.ball.width <= this.player.x && this.ball.x >= this.player.x - this.player.width) {
                if (this.ball.y <= this.player.y + this.player.height && this.ball.y + this.ball.height >= this.player.y) {
                    this.ball.x = (this.player.x + this.ball.width);
                    this.ball.moveX = DIRECTION.RIGHT;

                    beep1.play();
                }
            }

            // Handle paddle-ball collision
            if (this.ball.x - this.ball.width <= this.paddle.x && this.ball.x >= this.paddle.x - this.paddle.width) {
                if (this.ball.y <= this.paddle.y + this.paddle.height && this.ball.y + this.ball.height >= this.paddle.y) {
                    this.ball.x = (this.paddle.x - this.ball.width);
                    this.ball.moveX = DIRECTION.LEFT;

                    beep1.play();
                }
            }
        }

        // Handle the end of round transition
        // Check to see if the player won the round.
        if (this.player.score === rounds[this.round]) {
            // Check to see if there are any more rounds/levels left and display the victory screen if
            // there are not.
            if (!rounds[this.round + 1]) {
                this.over = true;
                setTimeout(function () { Pong.endGameMenu('Winner!'); }, 1000);
            } else {
                // If there is another round, reset all the values and increment the round number.
                this.color = this._generateRoundColor();
                this.player.score = this.paddle.score = 0;
                this.player.speed += 0.5;
                this.paddle.speed += 1;
                this.ball.speed += 1;
                this.round += 1;

                beep3.play();
            }
        }
        // Check to see if the paddle/AI has won the round.
        else if (this.paddle.score === rounds[this.round]) {
            this.over = true;
            setTimeout(function () { Pong.endGameMenu('Game Over!'); }, 1000);
        }
    },

    // Draw the objects to the canvas element
    draw: function () {
        // Clear the Canvas
        this.context.clearRect(
            0,
            0,
            this.canvas.width,
            this.canvas.height
        );

        // Set the fill style to black
        this.context.fillStyle = this.color;

        // Draw the background
        this.context.fillRect(
            0,
            0,
            this.canvas.width,
            this.canvas.height
        );

        // Set the fill style to white (For the paddles and the ball)
        this.context.fillStyle = '#ffffff';

        // Draw the Player
        this.context.fillRect(
            this.player.x,
            this.player.y,
            this.player.width,
            this.player.height
        );

        // Draw the Paddle
        this.context.fillRect(
            this.paddle.x,
            this.paddle.y,
            this.paddle.width,
            this.paddle.height
        );

        // Draw the Ball
        if (Pong._turnDelayIsOver.call(this)) {
            this.context.fillRect(
                this.ball.x,
                this.ball.y,
                this.ball.width,
                this.ball.height
            );
        }

        // Draw the net (Line in the middle)
        this.context.beginPath();
        this.context.setLineDash([7, 15]);
        this.context.moveTo((this.canvas.width / 2), this.canvas.height - 140);
        this.context.lineTo((this.canvas.width / 2), 140);
        this.context.lineWidth = 10;
        this.context.strokeStyle = '#ffffff';
        this.context.stroke();

        // Set the default canvas font and align it to the center
        this.context.font = '100px Courier New';
        this.context.textAlign = 'center';

        // Draw the players score (left)
        this.context.fillText(
            this.player.score.toString(),
            (this.canvas.width / 2) - 300,
            200
        );

        // Draw the paddles score (right)
        this.context.fillText(
            this.paddle.score.toString(),
            (this.canvas.width / 2) + 300,
            200
        );

        // Change the font size for the center score text
        this.context.font = '30px Courier New';

        // Draw the winning score (center)
        this.context.fillText(
            'Round ' + (Pong.round + 1),
            (this.canvas.width / 2),
            35
        );

        // Change the font size for the center score value
        this.context.font = '40px Courier';

        // Draw the current round number
        this.context.fillText(
            rounds[Pong.round] ? rounds[Pong.round] : rounds[Pong.round - 1],
            (this.canvas.width / 2),
            100
        );
    },

    loop: function () {
        Pong.update();
        Pong.draw();

        // If the game is not over, draw the next frame.
        if (!Pong.over) requestAnimationFrame(Pong.loop);
    },

    listen: function () {
        document.addEventListener('keydown', function (key) {
            // Handle the 'Press any key to begin' function and start the game.
            if (Pong.running === false) {
                Pong.running = true;
                window.requestAnimationFrame(Pong.loop);
            }

            // Handle up arrow and w key events
            if (key.keyCode === 38 || key.keyCode === 87) Pong.player.move = DIRECTION.UP;

            // Handle down arrow and s key events
            if (key.keyCode === 40 || key.keyCode === 83) Pong.player.move = DIRECTION.DOWN;
        });

        // Stop the player from moving when there are no keys being pressed.
        document.addEventListener('keyup', function (key) { Pong.player.move = DIRECTION.IDLE; });
    },

    // Reset the ball location, the player turns and set a delay before the next round begins.
    _resetTurn: function(victor, loser) {
        this.ball = Ball.new.call(this, this.ball.speed);
        this.turn = loser;
        this.timer = (new Date()).getTime();

        victor.score++;
        beep2.play();
    },

    // Wait for a delay to have passed after each turn.
    _turnDelayIsOver: function() {
        return ((new Date()).getTime() - this.timer >= 1000);
    },

    // Select a random color as the background of each level/round.
    _generateRoundColor: function () {
        var newColor = colors[Math.floor(Math.random() * colors.length)];
        if (newColor === this.color) return Pong._generateRoundColor();
        return newColor;
    }
};

var Pong = Object.assign({}, Game);
Pong.initialize();
    </script>
</body>
</html>

本篇未完结,请继续看下一篇:手把手教你7个有趣的JavaScript 项目-下「附源码」


推荐JavaScript经典实例学习资料文章

JavaScript 使用 mediaDevices API 访问摄像头自拍

手把手教你前端代码如何做错误上报「JS篇」

一文让你彻底搞懂移动前端和Web 前端区别在哪里

63个JavaScript 正则大礼包「值得收藏」

提高你的 JavaScript 技能10 个问答题

JavaScript图表库的5个首选

一文彻底搞懂JavaScript 中Object.freeze与Object.seal的用法

可视化的 JS:动态图演示 - 事件循环 Event Loop的过程

教你如何用动态规划和贪心算法实现前端瀑布流布局「实践」

可视化的 js:动态图演示 Promises & Async/Await 的过程

原生JS封装拖动验证滑块你会吗?「实践」

如何实现高性能的在线 PDF 预览

细说使用字体库加密数据-仿58同城

Node.js要完了吗?

Pug 3.0.0正式发布,不再支持 Node.js 6/8

纯JS手写轮播图(代码逻辑清晰,通俗易懂)

JavaScript 20 年 中文版之创立标准

值得收藏的前端常用60余种工具方法「JS篇」

箭头函数和常规函数之间的 5 个区别

通过发布/订阅的设计模式搞懂 Node.js 核心模块 Events

「前端篇」不再为正则烦恼

「速围」Node.js V14.3.0 发布支持顶级 Await 和 REPL 增强功能

深入细品浏览器原理「流程图」

JavaScript 已进入第三个时代,未来将何去何从?

前端上传前预览文件 image、text、json、video、audio「实践」

深入细品 EventLoop 和浏览器渲染、帧动画、空闲回调的关系

推荐13个有用的JavaScript数组技巧「值得收藏」

前端必备基础知识:window.location 详解

不要再依赖CommonJS了

犀牛书作者:最该忘记的JavaScript特性

36个工作中常用的JavaScript函数片段「值得收藏」

Node + H5 实现大文件分片上传、断点续传

一文了解文件上传全过程(1.8w字深度解析)「前端进阶必备」

【实践总结】关于小程序挣脱枷锁实现批量上传

手把手教你前端的各种文件上传攻略和大文件断点续传

字节跳动面试官:请你实现一个大文件上传和断点续传

谈谈前端关于文件上传下载那些事【实践】

手把手教你如何编写一个前端图片压缩、方向纠正、预览、上传插件

最全的 JavaScript 模块化方案和工具

「前端进阶」JS中的内存管理

JavaScript正则深入以及10个非常有意思的正则实战

前端面试者经常忽视的一道JavaScript 面试题

一行JS代码实现一个简单的模板字符串替换「实践」

JS代码是如何被压缩的「前端高级进阶」

前端开发规范:命名规范、html规范、css规范、js规范

【规范篇】前端团队代码规范最佳实践

100个原生JavaScript代码片段知识点详细汇总【实践】

关于前端174道 JavaScript知识点汇总(一)

关于前端174道 JavaScript知识点汇总(二)

关于前端174道 JavaScript知识点汇总(三)

几个非常有意思的javascript知识点总结【实践】

都2020年了,你还不会JavaScript 装饰器?

JavaScript实现图片合成下载

70个JavaScript知识点详细总结(上)【实践】

70个JavaScript知识点详细总结(下)【实践】

开源了一个 JavaScript 版敏感词过滤库

送你 43 道 JavaScript 面试题

3个很棒的小众JavaScript库,你值得拥有

手把手教你深入巩固JavaScript知识体系【思维导图】

推荐7个很棒的JavaScript产品步骤引导库

Echa哥教你彻底弄懂 JavaScript 执行机制

一个合格的中级前端工程师需要掌握的 28 个 JavaScript 技巧

深入解析高频项目中运用到的知识点汇总【JS篇】

JavaScript 工具函数大全【新】

从JavaScript中看设计模式(总结)

身份证号码的正则表达式及验证详解(JavaScript,Regex)

浏览器中实现JavaScript计时器的4种创新方式

Three.js 动效方案

手把手教你常用的59个JS类方法

127个常用的JS代码片段,每段代码花30秒就能看懂-【上】

深入浅出讲解 js 深拷贝 vs 浅拷贝

手把手教你JS开发H5游戏【消灭星星】

深入浅出讲解JS中this/apply/call/bind巧妙用法【实践】

手把手教你全方位解读JS中this真正含义【实践】

书到用时方恨少,一大波JS开发工具函数来了

干货满满!如何优雅简洁地实现时钟翻牌器(支持JS/Vue/React)

手把手教你JS 异步编程六种方案【实践】

让你减少加班的15条高效JS技巧知识点汇总【实践】

手把手教你JS开发H5游戏【黄金矿工】

手把手教你JS实现监控浏览器上下左右滚动

JS 经典实例知识点整理汇总【实践】

2.6万字JS干货分享,带你领略前端魅力【基础篇】

2.6万字JS干货分享,带你领略前端魅力【实践篇】

简单几步让你的 JS 写得更漂亮

恭喜你获得治疗JS this的详细药方

谈谈前端关于文件上传下载那些事【实践】

面试中教你绕过关于 JavaScript 作用域的 5 个坑

Jquery插件(常用的插件库)

【JS】如何防止重复发送ajax请求

JavaScript+Canvas实现自定义画板

Continuation 在 JS 中的应用「前端篇」

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表