在下面的例子中,我们将要构建一个 Bingo 卡片游戏,每个示例演示 JavaScript 的不同方面,通过每次的改进将会得到最终有效的 Bingo 卡片。

Bingo 卡片的内容

美国 Bingo 卡片是 5 X 5 的方形,5 个列上标明 B-I-N-G-O,格子中包含 1~75 的数字。正中间是一个空格子,常常印着 free。每列可以包含的范围如下:

  • B 列包含数字 1~15
  • I 列包含数字 16~30
  • N 列包含数字 31~45
  • G 列包含数字 46~60
  • O 列包含数字 61~75

原始1、第一个简单的 JavaScript 循环

bingo.html,这个页面建立 Bingo 卡片的框架。

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Make Your Own Bingo</title>
<link rel="stylesheet" href="bingo.css">
<script src="bingo.js"></script>
</head>
<body>
<h1>Create A Bingo Card</h1>
<table>
<tr>
<th>B</th>
<th>I</th>
<th>N</th>
<th>G</th>
<th>O</th>
</tr> <tr>
<td id="square0">&nbsp;</td>
<td id="square5">&nbsp;</td>
<td id="square10">&nbsp;</td>
<td id="square14">&nbsp;</td>
<td id="square19">&nbsp;</td>
</tr> <tr>
<td id="square1">&nbsp;</td>
<td id="square6">&nbsp;</td>
<td id="square11">&nbsp;</td>
<td id="square15">&nbsp;</td>
<td id="square20">&nbsp;</td>
</tr> <tr>
<td id="square2">&nbsp;</td>
<td id="square7">&nbsp;</td>
<td id="free">Free</td>
<td id="square16">&nbsp;</td>
<td id="square21">&nbsp;</td>
</tr> <tr>
<td id="square3">&nbsp;</td>
<td id="square8">&nbsp;</td>
<td id="square12">&nbsp;</td>
<td id="square17">&nbsp;</td>
<td id="square22">&nbsp;</td>
</tr> <tr>
<td id="square4">&nbsp;</td>
<td id="square9">&nbsp;</td>
<td id="square13">&nbsp;</td>
<td id="square18">&nbsp;</td>
<td id="square23">&nbsp;</td>
</tr>
</table>
<p><a href="../111.html" id="reload">Click here</a> to create a new card</p>
</body>
</html>

bingo.css 为 Bingo 卡片添加样式

@charset "utf-8";
/* CSS Document */
body{
background-color: white;
color: black;
font-size: 20px;
font-family: "Lucida Console", Verdana, Arial, Helvetica, sans-serif;
} h1, th{
font-family: Georgia, "Times New Roman", Times, serif;
} h1 {
font-size: 28px;
} table{
border-collapse: collapse;
}
th, td{
padding: 10px;
border: 2px #666 solid;
text-align: center;
width: 20%;
} #free, .pickedBG{
background-color: #f66;
}
.winningBG{
background-image: url(redFlash.gif);
}

我们先看看上面的 HTML 和 CSS 页面,这个是 Bingo 卡片的框架,包含 6 行 5 列的表格,表格的第一行是BINGO字母,且第三行中间是一个 Free 表格,每个单元格都有一个 id 属性,脚本将使用此 id 操纵这些单元格内容。id 采用 square0、square1、square2,直到 square23 分布如下图,在页面的底部,有一个用来生成新卡片的链接。

我们将要用循环语句,最常用的就是 for 循环,这种循环使用一个计数器(counter),计数器是一个变量,它的初值是某个值。在测试条件得不到满足的时候就会结束。

我们将 bingo.html<head> 标签中的 <script> src 属性设置为 bingo01.js

bingo01.js,使用 for 循环将表格内容填写为 1~75 中数,如下:

// JavaScript Document
window.onload = initAll; function initAll(){
for(var i=0; i<24; i++){
var newNum = Math.floor(Math.random() * 75) + 1;
document.getElementById('square' + i).innerHTML = newNum;
}
}

Math.random() 生成一个 0~1 的随机数,比如 0.123456789。然后与最大值(75)相乘,就会生成 0~75 之间的结果。对结果进行 Math.floor() 操作获得结果的整数部分。

该 bingo01.js 的显示结果如下:

第一个示例产生的卡片还不是有效的 Bingo 卡片,因为 Bingo 卡片对特定列有一些要求。后面的示例将对脚本进行改进,直到产生有效的 Bingo 卡片。


改进2、将值传递给函数

我们继续改进 bingo01.js,并保存为 bingo02.js,如下:

// JavaScript Document
window.onload = initAll; function initAll(){
for(var i=0; i<24; i++){
//我们将i值传递给 setSquare() 函数
setSquare(i);
}
} function setSquare(thisSquare){
var currSquare = "square" + thisSquare;
var newNum = Math.floor(Math.random() * 75) + 1;
document.getElementById(currSquare).innerHTML = newNum;
}

通过将值传递给 setSquare() 函数,使得脚本更加容易阅读和理解了。


改进3、探测对象

在编写脚本时,你可能希望检查浏览器是否有能力理解你要使用的对象。进行这种检查的方法称为对象探测(object detection)。如下:

if (document.getElementById){

如果对象存在,if 语句就为 true,脚本继续执行。但是如果浏览器不理解这个对象,就会返回 false,并执行条件语句 else 部分。

bingo03.js,增加了对象探测功能,如下:

// JavaScript Document
window.onload = initAll; function initAll(){
if(document.getElementById){
//如果 document.getElementById 这个对象存在的话
for(var i=0; i<24; i++){
setSquare(i);
}
}else{
alert('Sorry, your browser doesn\'t support this script!');
}
} function setSquare(thisSquare){
var currSquare = "square" + thisSquare;
var newNum = Math.floor(Math.random() * 75) + 1;
document.getElementById(currSquare).innerHTML = newNum;
}

改进4、处理数组

在这个示例中,我们将使用一个有用的 JavaScript 对象,数组(array)。

数组是一种可以存储一组信息的变量,与变量一眼个,可以使包含任何类型的数据。声明数组时,将数组元素放在括号中,以逗号分隔,如下:

var newCars = new Array("Toyota", "Honda", "Nissan");

在这个示例中,我们要确保 Bingo 卡片是仍然不是有效的,每列虽然具有不同的数字范围,但是一些列中出现重复的数字。

bingo04.js,这个脚本限制了每一列值的范围。

window.onload = initAll;

function initAll(){
if(document.getElementById){
for(var i=0; i<24; i++){
setSquare(i);
}
}else{
alert('Sorry, your browser doesn\'t support this script');
}
} function setSquare(thisSquare){
var currSquare = 'square' + thisSquare;
var colPlace = new Array(0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4);
var colBasis = colPlace[thisSquare] * 15;
var newNum = colBasis + Math.floor(Math.random() * 15) + 1; document.getElementById(currSquare).innerHTML = newNum;
}

该脚本执行后,显示如下:


改进5、处理有返回值的函数、运行时更新数组

我们将一些计算转移到一个函数中,这个函数为 Bingo 卡片上的单元格返回随机数,然后另一个函数使用它返回的结果,这使得整个更加容易理解了。

我们还要纠正一个问题, 避免出现重复的数字,在脚本运行时通过计算修改数组中的值。

bingo05.js,增加了一个 getNewNum 函数,返回一个 0~14 之间的数,新增了一个 usedNums 数组,存放 true / false ,主要是避免重复的数字。

// JavaScript Document
window.onload = initAll;
var usedNums = new Array(76); //已经初始化为 false function initAll(){
if(document.getElementById){
for(var i=0; i<24; i++){
setSquare(i);
}
}else{
alert("Sorry, your browser doesn't support this script");
}
} function setSquare(thisSquare){
var currSquare = 'square' + thisSquare;
var colPlace = new Array(0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4);
var colBasis = colPlace[thisSquare] * 15;
var newNum = colBasis + getNewNum() + 1;
//如果 usedNums[newNum] 为 true ,说明有重复数据,不做任何处理
if(!usedNums[newNum]){
usedNums[newNum] = true;
document.getElementById(currSquare).innerHTML = newNum;
} } function getNewNum(){
return Math.floor(Math.random() * 15);
}

脚本执行后,显示如下:


改进6、使用 do/while 循环

有时候,需要让代码循环许多次,但是无法确定需要循环多少次。在这种情况下,就要使用 do/while 循环,只要某个条件为 true, 就执行某种操作。

bingo06.js 脚本,在将数字放入单元格之前,首先检查是否已经使用了这个数字。如果这个数字已经使用过了,脚本就将生成新的随机数并重复该过程,直到找到不重复的数字为止,该脚本最终生成了有效的 Bingo 卡片。

// JavaScript Document
window.onload = initAll;
var usedNums = new Array(76); function initAll(){
if(document.getElementById){
for(var i=0; i<24; i++){
setSquare(i);
}
}else{
alert('Sorry, your browser doesn\'t support this script');
}
} function setSquare(thisSquare){
var currSquare = 'square' + thisSquare;
var colPlace = new Array(0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4);
var colBasis = colPlace[thisSquare] * 15;
var newNum; do{
newNum = colBasis + getNewNum() + 1;
}while (usedNums[newNum]);
//检查 usedNums[] 数组中 newNum 上的值,
//从而判断 newNum 是否已经使用过了 document.getElementById(currSquare).innerHTML = newNum;
}

脚本执行后,我们得到了有效的 Bingo 卡片,如下:


改进7、多种方式调用脚本

到目前为止,我们看到的脚本都是在加载页面的时候自动运行的。但是在显示环境中,常常希望用户对脚本有更多的控制能力,甚至允许他们控制脚本在何时运行。

bingo07.js 脚本中,允许我们通过页面底部的链接来重新运行脚本,这样就可以完全在浏览器中生成 Bingo 卡片,而不需要从服务器重新加载页面。这向用户提供了快速的响应,而且不会产生服务器负载。

// JavaScript Document
window.onload = initAll;
var usedNums = new Array(76); function initAll(){
if(document.getElementById){
document.getElementById("reload").onclick = anotherCard;
newCard();
}else{
alert("Sorry, your browser doesn't support this script");
}
} function newCard(){
for(var i=0; i<24; i++){
setSquare(i);
}
} function setSquare(thisSquare){
var currSquare = 'square' + thisSquare;
var colPlace = new Array(0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4);
var colBasis = colPlace[thisSquare] * 15;
var newNum; do{
newNum = colBasis + getNewNum() + 1;
}while(usedNums[newNum]) usedNums[newNum] = true;
document.getElementById(currSquare).innerHTML = newNum;
} function getNewNum(){
return Math.floor(Math.random() * 15);
} function anotherCard(){
for(var i=0; i<usedNums.length; i++){
usedNums[i] = false;
}
newCard();
return false;
//是浏览器不加载 href 中的链接地址
}

其实到了现在,你已经知道如何使用 JavaScript 进行重新加载一部分的页面了,而不需要向服务器请求整个页面,这正是 Ajax 的基本特色。


改进8、组合使用 JavaScript 和 CSS

该示例中我们将演示如何让用户能够操作所生成的 Bingo 卡片。

bingo08.js 脚本中我们将添加一些 JavaScript 来利用 CSS 的功能。

// JavaScript Document
window.onload = initAll;
var usedNums = new Array(76); function initAll(){
if(document.getElementById){
document.getElementById("reload").onclick = anotherCard;
newCard();
}else{
alert("Sorry, your browser doesn't support this script");
}
} function newCard(){
for(var i=0; i<24; i++){
setSquare(i);
}
} function setSquare(thisSquare){
var currSquare = 'square' + thisSquare;
var colPlace = new Array(0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4);
var colBasis = colPlace[thisSquare] * 15;
var newNum; do{
newNum = colBasis + getNewNum() + 1;
}while(usedNums[newNum]);
usedNums[newNum] = true;
document.getElementById(currSquare).innerHTML = newNum;
//确保 Bingo 卡片最初状态都是 class 属性都是空字符串
document.getElementById(currSquare).className = "";
//设置 每个 td 的 onmousedown 事件
document.getElementById(currSquare).onmousedown = toggleColor;
} function getNewNum(){
return Math.floor(Math.random() * 15);
} function anotherCard(){
for(var i=0; i<usedNums.length; i++){
usedNums[i] = false;
}
newCard();
return false;
} function toggleColor(evt){
//为了处理 IE 和 非IE 浏览器,如果是 非IE 则会有一个 evt 传递给函数
if(evt){
var thisSquare = evt.target;
}else{
//如果是 IE 浏览器 则必须通过下面的语句获得
var thisSquare = window.event.srcElement;
}
if(thisSquare.className == ""){
thisSquare.className = "pickedBG";
}else{
thisSquare.className = "";
}
/*
//自行通过 this 也可以获取当前元素进行修改,代码如下
if(this.className == ""){
this.className = "pickedBG";
}else{
this.className = "";
}
alert(this.className);
*/
}

脚本执行后,可以通过鼠标点击单元格,点击后的单元格背景变成红色,如下:


改进9、检查状态

用户能够给格子添加标记后,还可以检查格子是否构成了获胜模式。在下面的脚本中,用户选择那些已经被叫过的号码,bingo09.js 脚本会让用户知道什么时候他们获胜了,该脚本使用了复杂的数学计算来判断获胜组合。

// JavaScript Document
window.onload = initAll;
var usedNums = new Array(76); function initAll(){
if(document.getElementById){
document.getElementById("reload").onclick = anotherCard;
newCard();
}else{
alert("Sorry, your browser doesn't support this script");
}
} function newCard(){
for(var i=0; i<24; i++){
setSquare(i);
}
} function setSquare(thisSquare){
var currSquare = 'square' + thisSquare;
var colPlace = new Array(0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4);
var colBasis = colPlace[thisSquare] * 15;
var newNum;
do{
newNum = colBasis + getNewNum() + 1;
}while(usedNums[newNum]);
usedNums[newNum] = true;
document.getElementById(currSquare).innerHTML = newNum;
document.getElementById(currSquare).className = "";
document.getElementById(currSquare).onmousedown = toggleColor;
} function getNewNum(){
return Math.floor(Math.random() * 15);
} function anotherCard(){
for(var i=0; i<usedNums.length; i++){
usedNums[i] = false;
}
newCard();
return false;
} function toggleColor(evt){
if(evt){
var thisSquare = evt.target;
}else{
var thisSquare = window.event.srcElement;
}
if(thisSquare.className == ""){
thisSquare.className = "pickedBG";
}else{
thisSquare.className = "";
}
//此处增加 checkWin 函数,随时检查是否获胜
checkWin();
} function checkWin(){
//存储用户的获胜选项
var winningOption = -1;
//存储已经点击的格子
var setSquares = 0;
//存储获胜组合的数组
var winners = new Array(31, 992, 15360, 507904, 541729, 557328, 1083458, 2162820, 4329736, 8519745, 8659472, 16252928);
//检查每一个格子是否点击过
for(var i=0; i<24; i++){
var currSquare = "square" + i;
if(document.getElementById(currSquare).className != ""){
document.getElementById(currSquare).className = "pickedBG";
//按位运算,或 操作,记录用户点击的组合
setSquares = setSquares | Math.pow(2, i);
}
}
//与 操作,判断是否获胜
for(var i=0; i<winners.length; i++){
if((winners[i] & setSquares) == winners[i]){
winningOption = i;
//i就是用户获胜的状态
}
}
//如果是获胜者,则遍历每个格子,判断改格子是否获胜的格子
if(winningOption > -1){
for(var i=0; i<24; i++){
if(winners[winningOption] & Math.pow(2, i)){
currSquare = "square" + i;
document.getElementById(currSquare).className = "winningBG";
//winningBG 将设置背景为 GIF 动画
}
}
}
}

脚本执行后, 我们尝试选择对角线上格子,背景图案闪烁,说明获胜了,如下图:


改进10、处理字符串数组

到目前为止,我们所使用的数组都是由布尔值或者数字组成的,bingo10.js 脚本将演示使用字符串数组综合前面的所有技术,创建一个 Buzzword Bingo 游戏。

//buzzwords 数组至少需要24个元素
var buzzwords = new Array("Aggregate", "Ajax", "API", "Bandwidth", "Beta", "Bleeding edge", "Convergence", "Design pattern", "Disruptive", "DRM", "Enterprise", "Facilitate", "Folksonomy", "Framework", "Impact", "Innovate", "Long tail", "Mashup", "Microformats", "Mobile", "Monetize", "Open social", "Paradigm", "Podcast", "Proactive", "Rails", "Scalable", "Social bookmarks", "Social graph", "Social software", "Spam", "Synergy", "Tagging", "Tipping point", "Truthiness", "User-generated", "Vlog", "Webinar", "Wiki", "Workflow");
var usedWords = new Array(buzzwords.length);
window.onload = initAll; function initAll(){
if(document.getElementById){
document.getElementById("reload").onclick = anotherCard;
newCard();
}else{
alert("Sorry, your browser doesn't support this script");
}
} function newCard(){
for(var i=0; i<24; i++){
setSquare(i);
}
} function setSquare(thisSquare){
do{
var randomWord = Math.floor(Math.random() * buzzwords.length);
}
while(usedWords[randomWord]);
usedWords[randomWord] = true;
var currSquare = 'square' + thisSquare;
document.getElementById(currSquare).innerHTML = buzzwords[randomWord];
document.getElementById(currSquare).className = "";
document.getElementById(currSquare).onmousedown = toggleColor;
} function anotherCard(){
for(var i=0; i<buzzwords.length; i++){
usedWords[i] = false;
}
newCard();
return false;
} function toggleColor(evt){
if(evt){
var thisSquare = evt.target;
}else{
var thisSquare = window.event.srcElement;
}
if(thisSquare.className == ""){
thisSquare.className = "pickedBG";
}else{
thisSquare.className = "";
}
checkWin();
} function checkWin(){
var winningOption = -1;
var setSquares = 0;
var winners = new Array(31, 992, 15360, 507904, 557328, 1083458, 2162820, 4329736, 8519745, 8659472, 16252928); for(var i=0; i<24; i++){
var currSquare = 'square' + i;
if(document.getElementById(currSquare).className != ''){
document.getElementById(currSquare).className = 'pickedBG';
setSquare = setSquare | Math.pow(2, i);
}
} for(var i=0; i<winners.length; i++){
if((winners[i] & setSquare) == winners[i]){
winningOption = i;
}
} if(winningOption > -1){
for(var i=0; i<24; i++){
if(winners[winningOption] & Math.pow(2, i)){
currSquare = 'square' + i;
document.getElementById(currSquare).className = "winningBG";
}
}
}
}

脚本执行后效果如下:


示例代码下载:

Bingo.rar

了解 JavaScript (4)– 第一个 Web 应用程序的更多相关文章

  1. 【转载】ASP.NET MVC Web API 学习笔记---第一个Web API程序

    1. Web API简单说明 近来很多大型的平台都公开了Web API.比如百度地图 Web API,做过地图相关的人都熟悉.公开服务这种方式可以使它易于与各种各样的设备和客户端平台集成功能,以及通过 ...

  2. ASP.NET MVC3入门教程之第一个WEB应用程序

    本文转载自:http://www.youarebug.com/forum.php?mod=viewthread&tid=91&extra=page%3D1 上一节,我们已经搭建好了AS ...

  3. ASP.NET MVC Web API 学习笔记---第一个Web API程序

    http://www.cnblogs.com/qingyuan/archive/2012/10/12/2720824.html GetListAll /api/Contact GetListBySex ...

  4. ASP.NET MVC Web API 学习笔记---第一个Web API程序【转】

    http://www.cnblogs.com/qingyuan/archive/2012/10/12/2720824.html 1. Web API简单说明 近来很多大型的平台都公开了Web API. ...

  5. ASP.NET MVC Web API 学习笔记---第一个Web API程序---近来很多大型的平台都公开了Web API

    1. Web API简单说明 近来很多大型的平台都公开了Web API.比如百度地图 Web API,做过地图相关的人都熟悉.公开服务这种方式可以使它易于与各种各样的设备和客户端平台集成功能,以及通过 ...

  6. Windows Azure入门教学系列 (二):部署第一个Web Role程序

    本文是Windows Azure入门教学的第二篇文章. 在第一篇教学中,我们已经创建了第一个Web Role程序.在这篇教学中,我们将学习如何把该Web Role程序部署到云端. 注意:您需要购买Wi ...

  7. 002.Create a web API with ASP.NET Core MVC and Visual Studio for Windows -- 【在windows上用vs与asp.net core mvc 创建一个 web api 程序】

    Create a web API with ASP.NET Core MVC and Visual Studio for Windows 在windows上用vs与asp.net core mvc 创 ...

  8. javascript面向对象创建高级 Web 应用程序

       目录 JavaScript 对象是词典 JavaScript 函数是最棒的 构造函数而不是类 原型 静态属性和方法 闭包 模拟私有属性 从类继承 模拟命名空间 应当这样编写 JavaScript ...

  9. 目前在做的一个web应用程序的前端选型

    最近进入了一个新的项目组,要新起一个项目.这个Web项目是一个企业内部使用的系统,主要用来记录.追踪.管理潜在客户的数据.该系统有以下特点: 需要支持IE10及以上版本: 后端采用micro serv ...

  10. Spring Boot入门教程1、使用Spring Boot构建第一个Web应用程序

    一.前言 什么是Spring Boot?Spring Boot就是一个让你使用Spring构建应用时减少配置的一个框架.约定优于配置,一定程度上提高了开发效率.https://zhuanlan.zhi ...

随机推荐

  1. vim global命令

    global命令格式 : [range]global/{pattern}/{command} global命令在[range]指定的文本范围内(缺省为整个文件)查找{pattern},然后对匹配到的行 ...

  2. 学习Linux所需软件

    一:  VMware虚拟机 二:VMware_Install_Cleaner 虚拟机卸载 三:XShall

  3. iOS UILabel根据字符串长度自动适应宽度和高度

    //这个frame是初设的,没关系,后面还会重新设置其size.     UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0,0, ...

  4. EasyUI DataGrid 配置参数

    var queryParams = $('#SBDiv_1_DateGrid').datagrid('options').queryParams; queryParams.SearchTime = & ...

  5. 内置函数 和 select练习3

    19.  查询选修"3-105"课程的成绩高于"109"号同学成绩的所有同学的记录. select * from score where cno='3-105' ...

  6. 关于collapsed margin(外边距合并)

    这是前面写postion定位时写到最后面的例子的时候发现的一个问题,于是专门写一篇随笔来解释记录一下,毕竟两个知识点同时写在一篇文章里面有点混乱的感觉.. 上篇随笔position定位遇到的问题在这里 ...

  7. springmvc controller junit 测试

    第一次搭建SSM框架,整合SpringMVC完成后进行Controller测试,找资料并解决问题. 下图是我的完整目录: 1 建立UserController类 代码清单 1-1:UserContro ...

  8. console.log 被重写覆盖以后如何恢复

    有时候一些项目中会使用类似如下的方式覆盖掉console对象: var console = {}; console.log = function(){}; console.info = functio ...

  9. [ACM_模拟][ACM_数学] LA 2995 Image Is Everything [由6个视图计算立方体最大体积]

    Description   Your new company is building a robot that can hold small lightweight objects. The robo ...

  10. jenkins2 hello pipeline

    文章来自:http://www.ciandcd.com 文中的代码来自可以从github下载: https://github.com/ciandcd   根据前面的2篇文章,我们已经安装和配置好了je ...