Javascript

Javascript

一、概述

  • 脚本语言

  • 解释性

  • 解释器作为浏览器一部分

  • 弱类型,定义变量时不需要指定类型。

  • 动态类型,变量类型可以发生变化。

  • 基于原型继承

  • 内置支持类型

作用:给页面添加动态功能。

二、JS组成

  • ECMAScript:js标准语法

  • 文档对象模型(DOM)

  • 浏览器对象模型(BOM)

三、JS的导入

3.1 在页面元素中使用

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title></title>
    </head>
    <body>
        <input type="button" value="点击我试试" οnclick="alert('Hello,world')"/>
    </body>
</html>

3.2 在script标签中使用

script标签可以放在页面大多数位置,但是推荐放到最后,html的外面。

注意:type属性可以不写,如果写,值应该是text/javascript

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title></title>
    </head>
    <body>
        <input type="button" value="点击我试试1" οnclick="fn1()"/>
    </body>
</html>
<script type="text/javascript">
    function fn1(){
        alert('Hello');
    }
</script>

3.3 外部导入

使用script引入外部的js,可以在head中引入,也可在大多数位置引入,推荐写在最后。

注意:

  • type属性可以不写,如果写,值应该是text/javascript

  • 结束标签必须要写,不能直接改成自结束。

  • 不能在中间写js代码。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title></title>
    </head>
    <body>
        <input type="button" value="点击我试试2" οnclick="fn2()"/>
    </body>
</html>
<script type="text/javascript" src="js/common.js" ></script>

四、变量

var作为变量定义的关键字。

弱类型,动态类型,命名规则与Java相似。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
    </body>
</html>
<script>
    var n = 100 // 弱类型
    // 类似Java中的sout
    console.log(n)
    // 动态类型
    n = "hello, world"
    console.log(n)
</script>

五、基本类型

基本类型有5种:

  • Number

  • String

  • Boolean

  • Undefined

  • Null

<script>
    var age = 9; // number
    console.log(typeof(age));
    console.log(age / 2); // 数字不区分小数整数,所以9/2 =4.5
    var name = "mary";
    console.log(typeof(name)); // string
    var flag = true;
    console.log(typeof(flag)); // boolean
    var phone;
    console.log(phone); // undefined
    console.log(typeof(phone)); // undefined
    var person = null;
    console.log(person); // null
    console.log(typeof(person)); // object
</script>

六、引用类型

对象类型:Object类型。

语法:

<script>
    // 使用对象类型
    var obj = new Object();
    obj.name = "张三";
    obj.sex = "男";
    obj.say = function(){
        alert("hello, world");
    }
    console.log(obj.name);
    console.log(obj.sex);
    var n = "name";
    console.log(obj[n]);
    console.log(obj["sex"]);
    obj.say();
    
    // 使用map
    var m = {"name":"李四", sex:"男"} // JSON(JavaScript Object Notation)格式
    console.log(m.name);
    console.log(m.sex);
    console.log(m["name"]);
    console.log(m["sex"]);
</script>

数组类型:

<script>
    // 定义数组,两种方式
    var arr1 = new Array();
    var arr2 = [1,2,3,4];
    // 设置数组的值
    arr1[0] = 5;
    arr1[1] = 10;
    console.log(arr1[1]);
    console.log(arr1.length) // 2
    arr1[10] = "hello";
    console.log(arr1[10]);
    console.log(arr1.length) // 11
    console.log(arr1[5]); // undefined
    
    // js中数组有java中集合的作用
    arr2[arr2.length] = 5;
    console.log(arr2[4]);
    // 通过push添加元素
    arr2.push(10);
    console.log(arr2[5]);
    
    // 循环遍历
    for (var i=0;i<arr2.length;i++) {
        console.log("i==" + arr2[i]);
    }
    // for in循环
    // 注意:i还是下标
    for(var i in arr2){
        console.log("==" + arr2[i]);
    }
    
    // splice可以删除,可以修改,可以添加
    var arr3 = [1,2,3,4,5,6];
//   从下标3开始删除2个元素
//  arr3.splice(3, 2)
// 从下标3开始删除0个元素,添加8和9,相当于添加
//  arr3.splice(3, 0, 8, 9)
// 从下标3开始删除2个元素,添加8和9,相当于修改
    arr3.splice(3, 2, 8, 9)
    console.log(arr3)
</script>

七、运算符

7.1 算术运算符

与Java类似,不同之处在于,js中只有number类型,所以5/2结果为2.5

7.2 赋值运算符

与Java类似

7.3 逻辑运算符

与Java类似

7.4 关系运算符

大多与Java类似

==:比较值是否相等,所以数字2与字符串"2"是相等的。

===:即比较值也要比较类型,所以数字2与字符串"2"不相等。

<script>
    var n = 2;
    var m = "2";
    console.log(n == m) // true
    console.log(n === m) // false
</script>

7.5 三目(三元)运算符

与Java类似

7.6 分支结构

if结构与Java用法一致。

但是判断条件与Java有区别,Java中判断条件必须是布尔值。而JS中0、null、undefine、NaN表示false,其他表示true。

// 以下代码是可以执行的

if(1){

}

注意:NaN是not a number的缩写,表示不是数字。如果变量没有定义,则会报错。

变量没有定义和undefine区别:

var a;
console.log(a); // undefine
console.log(b); // 会报错 b is not define
console.log(a.name); // 会报错

switch与Java一致。

7.7 循环结构

JS中的for的基本用法,while、do-while、break、continue与Java一致。

注意:for循环中一定不要写int i,JS中没有int

for...in循环

var arrstr = ["mary", "jack", "tom", "andy"];
for(var i = 0; i < arrstr.length; i++){
    console.log(arrstr[i]);
}
// 注意for in循环中的变量还是下标,与Java的foreach不同
for(var s in arrstr){
    console.log(arrstr[s]);
}

八、函数

8.1 函数的定义与调用

函数定义的语法:

function 函数名(参数列表){

}

函数调用的语法:

函数名()

注意:在JS中,函数的调用时,如果函数有参数,可以传相应的参数,也可以少传或不传,但是无论如何,传入的参数都是按顺序匹配。

function m1(){
    alert(5);
}
​
function m2(m, n){
    alert(m);
}
​
function m3(m = 10, n){ // 10为默认值,没有传参时值为10
    alert(m);
}
​
function m4(){
    return 5; // 有返回值就return,没有就不用return
}
​
m2(8); // 显示8
m2("hello", 5); // 显示hello
m2(); // 显示undefine
m3(); // 显示10
m3("hello"); // 显示hello
var n = m4(); // 得到函数调用的返回值
alert(n);

8.2 函数变量

类似于Java中方法引用。或者C语言中的方法指针。

var n = m1; // 定义变量,值为一个函数
n(); // 调用该函数
​
​
function m1(){
    alert(5);
}

8.3 函数参数

m2(m1);
var n = m1;
m2(n);
​
function m1(){
    alert("hello");
}
​
// 由于函数中m进行函数调用,意味着m参数必须传入一个函数
function m2(m){
    m();
}

8.4 匿名函数

var n = function(){
    alert("hello");
};
​
n();
​
// 将匿名函数传入到函数的参数中
m2(function(){
    alert("world");
});
​
function m2(m){
    m();
}

8.5 函数的返回值

function f1(){
    // 第一种写法,函数中定义函数
    //      var n = function(){
    //          alert("hello");
    //      }
    // 第二种写法,函数中定义函数
    //      function n(){
    //          alert("hello");
    //      }
    //      return n;
​
    // 使用匿名函数
    return function(){
        return function(){
            alert("world");
        }
    }
}
​
var m = f1();
m()();
​
f1()()();

九、弹窗函数

alert(msg)弹出一个确定按钮的窗口。

confirm(msg)弹出一个有确定和取消按钮的窗口。

<script>
    function fn1(){
         if(confirm("确定要删除吗?")){
            alert("你点击了确定")
         }else{
            alert("你点击了取消")
         }
    }
</script>

prompt(msg, default)弹出一个可以输入内容的窗口。

  • msg:提示信息

  • default:输入框中的默认值

  • 返回值为输入的内容,如果没有输入任何内容,点击确定后返回值为空串,如果点击取消,返回null

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title></title>
    </head>
    <body>
        <input type="button" value="输入" οnclick="fn2()"/>
    </body>
</html>
<script>
    function fn2(){
        var r = prompt("请输入姓名", "mary")
        if(r){
            alert("你点击了确定")
         }else{
            alert("你点击了取消或者没有输入任何内容")
         }
    }
</script>

十、系统函数

parseInt():将一个内容转换成整数。

<script>
    var n = 5.5;
    console.log(parseInt(n)); // 将小数转换成整数
    n = "123";
    console.log(parseInt(n) + 1); // 将字符串转换成整数
    n = "235a34563";
    console.log(parseInt(n) + 1); // 236,将字符串转换成整数
    n = "a234";
    console.log(parseInt(n)); // 得到NaN
</script>

parseFloat():将一个内容转换成小数。

<script>
    var n = 5.5;
    console.log(parseFloat(n)); // 将小数转换成小数
    n = "123.3";
    console.log(parseFloat(n) + 1); // 将字符串转换成小数
    n = "235a34563";
    console.log(parseFloat(n) + 1); // 236,将字符串转换成小数
    n = "a234";
    console.log(parseFloat(n)); // 得到NaN
</script>

isNaN():不是数字返回true,是数字返回false

不会关心类型,只会判断值是否不是数字。

<script>
    console.log(isNaN("235a")); // true
    console.log(isNaN("235")); // false
    console.log(isNaN(235)); // false
</script>

十一、事件

鼠标操作:

  • onclick:单击

  • ondbclick:双击

  • onmouseup:按键弹起

  • onmousedown:按键按下

  • onmouseover:当鼠标移入

  • onmouseout:当鼠标移出

  • onmousemove:当鼠标移动

  • onmouseenter:当鼠标移入

  • onmouseleave:当鼠标移出

  • onmousewheel:滚轮滚动

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style>
            div{
                width: 600px;
                height: 240px;
                border: 1px solid #ccc;
                display: none;
            }
        </style>
    </head>
    <body>
        <input type="button" value="手机" οnmοuseοver="fn1()" οnmοuseοut="fn2()"/>
        
        <div id="div1">
            <ul>
                <li>苹果</li>
                <li>华为</li>
                <li>小米</li>
            </ul>
        </div>
    </body>
</html>
<script>
    function fn1(){
        // 得到div1
        document.getElementById("div1").style.display = "block";
    }
    
    function fn2(){
        // 得到div1
        document.getElementById("div1").style.display = "none";
    }
</script>

键盘操作:

  • onkeydown:键盘按下

  • onkeyup:键盘弹起

  • onkeypress:键盘敲击

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style>
            *{
                padding: 0px;
                margin: 0px;
            }
        </style>
    </head>
    <body>
        <div id="div1" style="width: 50px;height: 50px;background-color: red;position: absolute;top: 50px;left: 50px;"></div>
    </body>
</html>
<script>
    var d = document.getElementById("div1");
    document.onkeydown = function(e){
        // 得到按键的编码
//      alert(e.keyCode);
        if(e.keyCode == 37){ // left
            d.style.left = (parseInt(d.style.left) - 5) + "px";
        }else if(e.keyCode == 38){ // up
            d.style.top = (parseInt(d.style.top) - 5) + "px";
        }else if(e.keyCode == 39){ // right
            d.style.left = (parseInt(d.style.left) + 5) + "px";
        }else if(e.keyCode == 40){ // down
            d.style.top = (parseInt(d.style.top) + 5) + "px";
        }
    };
</script>

其他事件:

  • onload:加载完成后执行,写在body标签中表示页面加载完成后执行

  • onsubmit:表单提交事件,写在form标签中

  • onchange:值改变事件,一般用在表单元素中。

  • onblur:失去焦点事件

  • onfocus:获得焦点事件

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body οnlοad="fn1()">
        <form οnsubmit="return fn5()" action="列表.html" method="get">
            <input type="text" οnblur="fn3()" name="username" id="userTxt"  placeholder="请输入用户名"/>
            <span id="span1"></span>
            <br />
            <!--密码框-->
            <input type="password" οnfοcus="fn4()" name="password" id="pwdTxt" value="" placeholder="请输入密码"/><br />
            
            省份:<select id="sel" οnchange="fn2()" name="province">
                <option value="">请选择</option>
                <option value="1">湖北</option>
                <option value="2">湖南</option>
            </select><br />
            城市:<select id="sel1"  name="city">
                
            </select><br />
            <!--提交按钮,点击后会提交表单到action对应的地址-->
            <input type="submit" value="提交"/>
        </form>
    </body>
</html>
<script>
    var u = document.getElementById("userTxt");
    var p = document.getElementById("pwdTxt");
    var s = document.getElementById("sel");
    var s1 = document.getElementById("sel1");
    var span1 = document.getElementById("span1");
    function fn1(){
        u.value = "";
        p.value = "";
        s.value = "";
    }
    
    function fn2(){
        if(s.value == "1"){
            s1.options.length = 0;
            s1.options.add(new Option("武汉", "1"));
            s1.options.add(new Option("鄂州", "2"));
            s1.options.add(new Option("黄石", "3"));
        }else if(s.value == "2"){
            s1.options.length = 0;
            s1.options.add(new Option("长沙", "4"));
            s1.options.add(new Option("株洲", "5"));
            s1.options.add(new Option("岳阳", "6"));
        }
    }
    
    function fn3(){
        if(u.value.length < 6){
            // innerHTML可以显示标签样式
            // innerText只能显示文本
            span1.innerHTML = "<font color='red'>用户名长度不能低于6位<font>";
            // 获得焦点
//          u.focus();
            // 将内容全选
//          u.select();
        }
    }
    
    function fn4(){
        p.value = "123456";
    }
    
    function fn5(){
        if(u.value.length < 6){
            alert("用户名不合法")
            return false
        }
        if(p.value.length < 6){
            alert("密码不合法")
            return false
        }
        if(s.value == ""){
            alert("必须选择一个省份")
            return false
        }
        return true
    }
</script>

十二、DOM操作

当页面加载后,页面上HTML元素,统称为文档对象模型(DOM)。

DOM操作,即使用js对文档对象模型中的元素进行操作。

  • 对HTML元素本身进行增删改查操作

  • 对HTML元素的样式进行操作

12.1 查找HTML元素

主要有三种方法:

  • getElementById(""):通过id属性获取某个元素。

  • getElementsByTagName(""):通过标签名称得到一组元素。

  • getElementsByClassName(""):通过class名称得到一组元素。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style>
            .c2{
                width: 50px;
                height: 50px;
            }
        </style>
    </head>
    <body>
        <input type="checkbox" οnclick="fn2()" id="chk"/><br />
        <input type="checkbox" class="c1 c2"/>
        <input type="checkbox" class="c1"/>
        <input type="checkbox" class="c1"/>
        <input type="checkbox" class="c1"/>
        <input type="checkbox" class="c1"/>
        <input type="checkbox" class="c1"/>
        <input type="checkbox" class="c1"/>
        <!--button标签默认是submit,需要设置type属性-->
        <button type="button" οnclick="fn1()">点击</button>
    </body>
</html>
<script>
    function fn1(){
        var arr = document.getElementsByTagName("input");
        for(i in arr){
            arr[i].checked = true;
        }
    }
    
    function fn2(){
        // 得到复选框是否被勾选的状态
        var c = document.getElementById("chk").checked;
        // 得到class属性中有c1的元素
        var arr = document.getElementsByClassName("c1");
        for(i in arr){
            arr[i].checked = c;
        }
    }
</script>

12.2 修改HTML元素内部内容

有两种方式:

  • innerText:只能显示文本内容,如果有标签会以文本的方式显示。

  • innerHTML:可以显示标签的效果

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <h1 align="center">Hello, world</h1>
        <input type="button" value="点击" οnclick="fn1()"/>
    </body>
</html>
<script>
    function fn1(){
        var arr = document.getElementsByTagName("h1");
        // 只会以文本的方式显示
//      arr[0].innerText = "<font color='red'>AAAA</font>";
        // 可以显示出红色的字体
        arr[0].innerHTML = "<font color='red'>AAAA</font>";
    }
</script>

12.3 修改属性

有两种方式:

  • 对象.属性

  • 通过getAttribute("属性名")获取属性值,通过setAttribute("属性名", "属性值");来设置属性值。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <a id="a1" href="https://www.baidu.com">百度</a>
        <img id="img1" src="img/13.png" width="200px"/><br />
        <input type="button" value="点击" οnclick="fn1()"/>
    </body>
</html>
<script>
    function fn1(){
        var a1 = document.getElementById("a1");
        a1.innerText = "千锋";
        a1.setAttribute("href", "https://www.qfedu.com");
//      a1.href = "https://www.qfedu.com";
        var img1 = document.getElementById("img1");
        img1.src = "img/14.png";
    }
</script>

12.4 修改css

一般可以通过style属性来修改。

注意:在样式的名称可能类似border-width,在js中会使用驼峰式即borderWidth。

但是style只能得到行内的样式,而无法得到内部或外部加载的样式。

如果要想获取非行内样式,IE9以下的版本与其他浏览器有差异。

function getStyle(elem, attr){
    if(window.getComputedStyle){ // w3c标准,支持chrome,firefox,safari,IE9+等
        return window.getComputedStyle(elem)[attr];
    }else if(elem.currentStyle){ // IE其他版本
        elem.currentStyle[attr];
    }else{
        return null;
    }
}
<input type="text" οnblur="fn3()" name="username" id="userTxt"  placeholder="请输入用户名"/>
<img id="img1" style="display: none;" src="img/icon1.png" />
<br />
<!--密码框-->
<input type="password" οnfοcus="fn4()" name="password" id="pwdTxt" value="" placeholder="请输入密码"/><br />
<script>
function fn3(){
    if(u.value.length < 6){
        document.getElementById("img1").style.display = "inline";
    }else{
        document.getElementById("img1").style.display = "none";
    }
}
</script>

12.5 事件的添加和移除

如果直接在标签中写事件,意味着该事件是静态,不能够动态操作。可以通过下面两种方式,动态给元素添加事件:

  • 元素.onXxxx = function(){}

  • 元素.addEventListener(事件名, 函数, 冒泡或捕获)

使用元素.onXxxx = function(){},可以多次赋值,但是后面的事件会覆盖前面的事件。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title></title>
    </head>
    <body>
        <input type="button" value="设置事件1" οnclick="fn1()"/>
        <input type="button" value="设置事件2" οnclick="fn2()"/>
        <input id="btn1" type="button" value="事件2"/>
    </body>
</html>
<script>
    function fn1(){
        var btn1 = document.getElementById("btn1");
        btn1.onclick = function(){
            alert("事件2");
        };
    }
    
    function fn2(){
        var btn1 = document.getElementById("btn1");
        btn1.onclick = function(){
            alert("事件2事件2");
        };
    }
</script>

上面的事件如果都设置了,只会保留后设置的事件。

使用元素.addEventListener(事件名, 函数, 冒泡或捕获), 三个参数含义分别为:

  • 事件名:设置事件的名称,不需要写on,例如点击事件:click

  • 函数:可以写已经定义了的函数名称,也可以写匿名函数

  • 冒泡或捕获:可以不设置此参数,默认为false(冒泡),可以设置为true(捕获)

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title></title>
    </head>
    <body>
        <input type="button" value="设置事件1" οnclick="fn1()"/>
        <input type="button" value="设置事件2" οnclick="fn2()"/>
        <input id="btn1" type="button" value="事件2"/>
    </body>
</html>
<script>
    function fn1(){
        var btn1 = document.getElementById("btn1");
        btn1.addEventListener("click", function(){
            alert("事件2");
        });
    }
    
    function fn2(){
        var btn1 = document.getElementById("btn1");
        btn1.addEventListener("click", function(){
            alert("事件2事件2");
        });
    }
</script>

上面的案例,给元素添加了两次点击事件,当元素点击时,会分别执行两个事件,不会覆盖。

冒泡和捕获:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title></title>
        <style>
            #div1{
                width: 200px;
                height: 200px;
                background-color: orange;
            }
            #div2{
                width: 100px;
                height: 100px;
                background-color: blue;
            }
        </style>
    </head>
    <body>
        <input type="button" value="设置div1事件1" οnclick="fn1()"/>
        <input type="button" value="设置div2事件2" οnclick="fn2()"/>
        <div id="div1">
            <div id="div2">
                
            </div>
        </div>
    </body>
</html>
<script>
    function fn1(){
        var div1 = document.getElementById("div1");
        div1.addEventListener("click", function(){
            console.log("div1事件")
        });
    }
    
    function fn2(){
        var div2 = document.getElementById("div2");
        div2.addEventListener("click", function(){
            console.log("div2事件");
        });
    }
</script>

上面的操作,当给元素设置了两次事件后,由于div2在div1中,默认是冒泡,所以当点击div2时,会先执行div2的点击事件,再执行div1的点击事件。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title></title>
        <style>
            #div1{
                width: 200px;
                height: 200px;
                background-color: orange;
            }
            #div2{
                width: 100px;
                height: 100px;
                background-color: blue;
            }
        </style>
    </head>
    <body>
        <input type="button" value="设置div1事件1" οnclick="fn1()"/>
        <input type="button" value="设置div2事件2" οnclick="fn2()"/>
        <div id="div1">
            <div id="div2">
                
            </div>
        </div>
    </body>
</html>
<script>
    function fn1(){
        var div1 = document.getElementById("div1");
        div1.addEventListener("click", function(){
            console.log("div1事件")
        }, true);
    }
    
    function fn2(){
        var div2 = document.getElementById("div2");
        div2.addEventListener("click", function(){
            console.log("div2事件");
        }, true);
    }
</script>

上面将冒泡修改为捕获,所以当点击div2时,会先执行div1的点击事件,再执行div2的点击事件。

事件的移除:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title></title>
        <style>
            #div1{
                width: 200px;
                height: 200px;
                background-color: orange;
            }
            #div2{
                width: 100px;
                height: 100px;
                background-color: blue;
            }
        </style>
    </head>
    <body>
        <input type="button" value="设置div1事件1" οnclick="fn1()"/>
        <input type="button" value="设置div2事件2" οnclick="fn2()"/>
        <input type="button" value="移除事件" οnclick="fn3()"/>
        <div id="div1">
            <div id="div2">
                
            </div>
        </div>
    </body>
</html>
<script>
    function fn1(){
        var div1 = document.getElementById("div1");
        div1.addEventListener("click", function(){
            console.log("div1事件")
        });
    }
    
    function fn2(){
        var div2 = document.getElementById("div2");
        div2.addEventListener("click", function(){
            console.log("div2事件")
        });
    }
    
    function fn3(){
        var div2 = document.getElementById("div2");
        div2.removeEventListener("click", function(){
            console.log("div2事件")
        });
    }
</script>

上面的移除div2事件的代码移除经测试后,无法实现,因为使用的匿名函数,应该改为以下方式:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title></title>
        <style>
            #div1{
                width: 200px;
                height: 200px;
                background-color: orange;
            }
            #div2{
                width: 100px;
                height: 100px;
                background-color: blue;
            }
        </style>
    </head>
    <body>
        <input type="button" value="设置div1事件1" οnclick="fn1()"/>
        <input type="button" value="设置div2事件2" οnclick="fn2()"/>
        <input type="button" value="移除事件" οnclick="fn3()"/>
        <div id="div1">
            <div id="div2">
                
            </div>
        </div>
    </body>
</html>
<script>
    function fn1(){
        var div1 = document.getElementById("div1");
        div1.addEventListener("click", function(){
            console.log("div1事件")
        });
    }
    
    function fn2(){
        var div2 = document.getElementById("div2");
        div2.addEventListener("click", fn4);
    }
    
    function fn4(){
        console.log("div2事件");
    }
    
    function fn3(){
        var div2 = document.getElementById("div2");
        div2.removeEventListener("click", fn4);
    }
</script>

12.6 新建和删除元素

当需要动态的新建和删除元素时,可以使用js来进行处理。

  • 使用document.createElement("标签名"); 创建元素

  • 使用appendChild将元素放入到指定位置。

  • 也可以使用insertBefore来将元素放入到指定的位置。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style>
            #div1{
                width: 400px;
                height: 400px;
                background-color: orange;
            }
        </style>
    </head>
    <body>
        <div id="div1">
            <span id="span1">111</span>
        </div>
        <input type="button" value="添加元素" οnclick="fn1()"/>
    </body>
</html>
<script>
    function fn1(){
        var h = document.createElement("hr");
        // 将h添加到div1的里面的最后
//      var div1 = document.getElementById("div1");
//      div1.appendChild(h);
        
        // 将h添加到span1中的最前面
        var span1 = document.getElementById("span1");
        var refElement=span1.childNodes[0];
        span1.insertBefore(h, refElement);
    }
</script>

删除元素:

  • 元素.remove(); 删除某个元素

  • 父元素.removeChild(子元素); 删除父元素中的某个子元素

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style>
            #div1{
                width: 400px;
                height: 400px;
                background-color: orange;
            }
        </style>
    </head>
    <body>
        <div id="div1">
            <span id="span1">111</span>
            <span id="span2">222</span>
            <span id="span3">333</span>
            <span id="span4">444</span>
        </div>
        <input type="button" value="删除元素" οnclick="fn2()"/>
    </body>
</html>
<script>
    function fn2(){
        // 要删除span
        var span1 = document.getElementById("span1");
//      // 删除自己
//      span1.remove();
        
        var div1 = document.getElementById("div1");
        // 删除子元素
//      div1.removeChild(span1);
    }
</script>

十三、js定时器

  • setTimeout(函数名,延迟时间)多久后,执行相应的函数(仅执行一次)

  • clearTimeout(定时器名):停止

注意:时间单位为毫秒

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <h1 id="aa"></h1>
        <input type="button" value="开始" οnclick="fn1()"/>
        <input type="button" value="停止" οnclick="fn2()"/>
    </body>
</html>
<script>
    var h = document.getElementById("aa");
    var s;
    function fn1(){
        // 1秒后执行fn3
        s = setTimeout(fn3, 1000);
    }
    
    function fn3(){
        var d = new Date();
        h.innerText = d.toLocaleString();
        s = setTimeout(fn3, 1000);
    }
    
    function fn2(){
        // 停止
        clearTimeout(s);
    }
</script>
  • setInterval(函数名,延迟时间)每隔多久后,执行相应的函数(执行多次)

  • clearInterval(定时器名):停止

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <h1 id="aa"></h1>
        <input type="button" value="开始" οnclick="fn1()"/>
        <input type="button" value="停止" οnclick="fn2()"/>
    </body>
</html>
<script>
    var h = document.getElementById("aa");
    var s;
    function fn1(){
        // 每隔1秒后执行fn3
        s = setInterval(fn3, 1000);
    }
    
    function fn3(){
        var d = new Date();
        h.innerText = d.toLocaleString();
    }
    
    function fn2(){
        // 停止
        clearInterval(s);
    }
</script>

案例:倒计时

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <input id="btn1" type="button" value="点击" οnclick="fn4()"/>
    </body>
</html>
<script>
    var btn1 = document.getElementById("btn1");
    function fn4(){
        var n = 10;
        var e = setInterval(function(){
            btn1.disabled = true;
            btn1.value = n--;
            if(n < 0){
                clearInterval(e);
                btn1.disabled = false;
                btn1.value = "点击";
            }
        }, 1000)
    }
</script>

十四、BOM

BOM浏览器对象模型,主要是指使用js操作浏览器。

整个浏览器顶层为window,window下面又有几个常用的对象属性:

  • history

  • location

  • navigator

  • screen

14.1 window对象

是js的顶层对象,表示浏览器的窗口。

所有的函数、变量均属于window。例如:window.alert()、window.document,自定义的函数fn1()也是属于window的,可以写为window.fn1()

window.innerHeight:窗口高度

window.innerWidth:窗口宽度

注意:得到的当前浏览器中的文档区域的宽度和高度。当窗口缩小或放大时,会改变值。

window.open():打开新窗口

window.close():关闭窗口

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <input type="button" value="点击" οnclick="fn1()"/>
        <input type="button" value="打开窗口" οnclick="fn2()"/>
        <input type="button" value="关闭窗口" οnclick="fn3()"/>
    </body>
</html>
<script>
    function fn1(){
        alert(window.innerWidth + "===" + window.innerHeight);
    }
    
    function fn2(){
        // 打开窗口
        window.open("元素的创建和删除.html", "aaa")
    }
    
    function fn3(){
        // 关闭当前窗口
        window.close()
    }
</script>

14.2 当前屏幕对象

screen.availWidth:浏览所能够最大占据屏幕的宽度

screen.availHeight:浏览所能够最大占据屏幕的高度

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <input type="button" value="点击" οnclick="fn1()"/>
    </body>
</html>
<script>
    function fn1(){
        alert(screen.availWidth + "===" + screen.availHeight);
    }
</script>

14.3 location对象

地址栏对象。用来对地址进行操作。能够跳转页面,或者刷新页面。

属性:

  • href:地址

  • hostname:主机名

  • protocol:协议

  • port:端口号

注意:可以通过修改href属性来跳转页面。

方法:

  • reload():刷新页面

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <input type="button" value="点击" οnclick="fn1()"/>
        <input type="button" value="刷新" οnclick="fn2()"/>
        <input type="button" value="跳转页面" οnclick="fn3()"/>
    </body>
</html>
<script>
    function fn1(){
        console.log("href=" + location.href);
        console.log("hostname=" + location.hostname);
        console.log("protocol=" + location.protocol);
        console.log("port=" + location.port);
    }
    
    function fn2(){
        location.reload();
    }
    
    function fn3(){
        // 通过修改href属性来跳转页面
        location.href = "冒泡捕获.html";
    }
</script>

14.4 history对象

history主要是操作浏览器的历史记录。

主要用前进、后退。

back():后退一次

forward():前进一次

go(n):前进或后退n次,n为正数表示前进,n为负数表示后退。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <input type="button" value="跳转页面" οnclick="fn1()"/>
        <input type="button" value="前进" οnclick="fn2()"/>
        <input type="button" value="go前进" οnclick="fn3()"/>
    </body>
</html>
<script>
    function fn1(){
        location.href = "location对象.html";
    }
    
    function fn2(){
        history.forward();
    }
    
    function fn3(){
        history.go(2);
    }
</script>

14.5 navigator对象

查看浏览器的信息。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <input type="button" value="点击" οnclick="fn1()"/>
    </body>
</html>
<script>
    function fn1(){
        console.log("appName=" + navigator.appName);
        console.log("appVersion=" + navigator.appVersion);
        console.log("appCodeName=" + navigator.appCodeName);
        console.log("platform=" + navigator.platform);
        console.log("userAgent=" + navigator.userAgent);
    }
</script>

十五、正则表达式

是用来描述字符模式的对象。

作用:用来检查、搜索、替换字符串的模式。

基本语法:

  • var reg = new RegExp("pattern", "modifier");

  • var reg = /pattern/modifier

15.1 修饰符

i:不区分大小写

g:所有的都会匹配,而不是匹配到一个就停止

m:执行多行匹配

15.2 字符

[abc]:查找字符串中的任意一个字符。

[^abc]:查找不是字符串中的任意一个字符。

[0-9]:匹配一个数字

[a-z]:匹配一个小写字母

[A-Z]:匹配一个大写字母

[A-z]:匹配一个大小写字母

(red|green|blue):匹配其中的一个单词

15.3 元字符

. :匹配任意一个字符,除了换行和行结束符

\w:匹配单词字符,字母数字下划线

\W:匹配非单词字符

\d:匹配数字字符

\D:匹配非数字字符

\s:匹配空白字符

\S:匹配非空白字符

15.4 量词

用来表示数量。

n+:表示至少一个

n*:表示0个到多个

n?:表示0个到1个

n{x}:表示x个

n{x,}:表示x个到多个

n{x,y}:表示x个到y个

^表示开始$表示结束

15.5 使用

  • 正则表达式对象.test("字符串"); 返回true或者false

  • String对象.match("正则");返回一个或多个的匹配

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <input type="text" id="txt1" οnblur="fn1()"/><br />
        <input type="text"/>
    </body>
</html>
<script>
    function fn1(){
        var t = document.getElementById("txt1").value;
        
        // 验证邮箱
        var reg = /^[A-z0-9]+@[A-z0-9]+[\.](com|cn|org|edu|net|gov)$/;
        // 验证手机号
//      var reg = /^1(39|86|30|92|58)[0-9]{8}$/;
        // 验证用户名
//      var reg = /^[\w]{6,16}$/;
        if(reg.test(t)){
            alert("合法")
        }else{
            alert("不合法")
        }
    }
</script>

十六、创建对象的方式

var v = new Date();

16.1 直接使用属性赋值

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
    </body>
</html>
<script>
    function Student(name, age, sex="男"){
        this.name = name;
        this.age = age;
        this.sex = sex;
        
        this.say = function(){
            return "name = " + this.name + ", age = " + this.age + ", sex =" + this.sex;
        }
        
        this.say1 = function(){
            // 定义变量接收this对象当前的引用
            var that = this;            
            
            function Cla(id, name){
                this.id = id;
                this.name = name;
                
                this.say2 = function(){
                    return "id=" + this.id + ", name=" + this.name + ", studentname=" + that.name;
                }
            }
            var c = new Cla(1, "1班");
            return c.say2();
        }
    }
    
    var s = new Student("张三", 20, "女");
    console.log(s.say1());
</script>

16.2 使用prototype

function Student(name, age, sex="男"){
    this.name = name;
    this.age = age;
    this.sex = sex;
}
​
Student.prototype = {
    say:function(){
        return "name = " + this.name + ", age = " + this.age + ", sex =" + this.sex;
    },
​
    say1:function(){
        // 定义变量接收this对象当前的引用
        var that = this;            
​
        function Cla(id, name){
            this.id = id;
            this.name = name;
​
            this.say2 = function(){
                return "id=" + this.id + ", name=" + this.name + ", studentname=" + that.name;
            }
        }
        var c = new Cla(1, "1班");
        return c.say2();
    }
};
​
var s = new Student("张三", 20, "女");
console.log(s.say1());

注意:多个方法用逗号隔开。此处是键值对。

16.3 简单的单例模式

var Stu = (function(){
    function Student(){
        console.log("构造函数被调用")
    }
    
    var instance;
    
    var _static = {
        name: "Stu",
​
        getInstance : function(){
            if(!instance){
                instance = new Student();
            }
            return instance;
        }
    }
​
    return _static;
})();
​
var s = Stu.getInstance()

十七、画布和绘制

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <link rel="stylesheet" type="text/css" href="css/canvas.css"/>
        <script src="js/canvas.js" type="text/javascript" charset="utf-8"></script>
    </head>
    <body>
        <canvas id="myCanvas"></canvas>
    </body>
</html>
window.onload = function(){
    // 得到canvas(画布)
    var canvas = document.getElementById("myCanvas");
    // 设置画布的大小
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    // 设置背景颜色
    canvas.style.backgroundColor = "black";
    // 得到上下文(画笔)
    var context = canvas.getContext("2d");
    
    var i = 0;
    // 循环执行画圆
    setInterval(function(){
        context.clearRect(0,0, canvas.width, canvas.height);
        // 开始画画
        context.beginPath();
        // 设置实心画笔的颜色
        context.fillStyle = "#" + Math.floor(Math.random() * 0xffffff).toString(16);
        // 设置空心画笔颜色
        //context.strokeStyle = "#FFFFFF";
        // 画一个宽度为50,高度为50的矩形
    //  context.rect(100,100,200,100);
        // 画线
    //  context.moveTo(100,100);
    //  context.lineTo(200,200);
    //  context.lineTo(100, 200);
    //  context.lineTo(0,100);
        // 画圆
        context.arc(200+i*20,200+i*20,100,0,Math.PI * 2,false);
        // 结束画画
        context.closePath();
        // 填充实心内容
        context.fill();
        // 填充空心内容
        // context.stroke();
        // i递增
        //i++;
    }, 200);
    
};
// 绘制图片
window.onload = function(){
    var canvas = document.createElement("canvas");
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    canvas.style.backgroundColor = "#333333";
    document.body.appendChild(canvas);
    
    var context = canvas.getContext("2d");
    
    // 创建一个图片对象
    var img = new Image();
    img.src = "img/2.png";
    
    // 绘制图片
    // 延时执行
    setTimeout(function(){
        //5个参数时含义 图片,x坐标,y坐标, 宽度,高度
        /*
        1、图片,2、图片中的起始x,3、图片中的起始y
        4、图片中取得的宽度,5、图片中取得的高度
        6、在画布中显示的x、7、在画布中显示的y
        8、在画布中显示的宽度、9、在画布中显示的高度
         */
        context.drawImage(img, 100, 100, 500, 500);
    }, 500);
};

十八、案例

18.1 案例1-模拟喷泉

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <script src="js/particle.js" type="text/javascript" charset="utf-8"></script>
        <style type="text/css">
            body{
                margin: 0px;
            }
        </style>
    </head>
    <body>
    </body>
</html>
window.onload = function(){
    // 创建一个画布对象
    var canvas = document.createElement("canvas");
    // 设置大小和颜色
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    canvas.style.backgroundColor = "#333333";
    // 将画布放置到body里
    document.body.appendChild(canvas);
    // 得到画笔
    var context = canvas.getContext("2d");
    // 定义一个存放所有粒子的数组
    var particles = [ ];
    
    // 调用显示粒子
    showParticle();
    
    // 创建并显示粒子的方法
    function showParticle(){
        // 循环操作
        setInterval(function(){
            // 清空画布
            context.clearRect(0,0,canvas.width, canvas.height);
            // 创建粒子
            var p = new Particle(canvas.width * 0.5, canvas.height * 0.5);
            // 将粒子装入存放粒子的数组
            particles.push(p);
            // 循环更新所有粒子的位置
            for (var i = 0;i<particles.length;i++) {
                // 更新位置
                particles[i].updateData();
            }
        }, 50);
    }
    
    function Particle(x, y){
        // 原坐标
        this.x = x;
        this.y = y;
        // 初始出现的改变的y的值
        this.yVal = -5;
        // 改变的x的值
        this.xVal = Math.random() * 8 - 4;
        // 定义一个下降的重力加速度
        this.g = 0.1;
        // 更新位置
        this.updateData = function(){
            // X值的变化
            this.x = this.x + this.xVal;
            // Y值的变化
            this.y = this.y + this.yVal;
            // 每次改变Y值速度的变化
            this.yVal = this.yVal + this.g;
            // 生成一个随机颜色
            context.fillStyle = "#" + Math.floor(Math.random() * 0xffffff).toString(16);
            // 将更新位置后的圆绘制出来
            this.draw();
        };
        
        // 绘图的方法
        this.draw = function(){
            // 开始画图
            context.beginPath();
            // 画圆
            context.arc(this.x, this.y,5,0,Math.PI * 2, false);
            // 结束画图
            context.closePath();
            // 填充
            context.fill();
        };
    }
};

18.2 俄罗斯方块

俄罗斯方块.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>俄罗斯方块</title>
        <link rel="stylesheet" href="css/common.css" />
    </head>
    <body>
        <canvas id="tetris" width="320" height="640"></canvas>
        <canvas id="nextShape" width="200" height="160"></canvas>
        <canvas id="score" width="200" height="160"></canvas>
    </body>
    <script type="text/javascript" src="js/common.js" ></script>
</html>

common.css

*{
    padding: 0;
    margin: 0;
}
​
body{
    background: url(../img/bg.png);
}
​
​
#tetris{
    border: 2px solid white;
    border-radius: 5px;
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    margin: auto;
}
​
#nextShape{
    position: absolute;
    left: 40px;
    bottom: 160px;
    border-radius: 5px;
    background: orange;
}
​
#score{
    position: absolute;
    left: 40px;
    top: 160px;
    border-radius: 10px;
    background: orange;
}

common.js

// 定义一个俄罗斯方块的类 Tetris
var Tetris = (function() {
    // 定义存放形状矩阵的数组
    var layouts = [
        [
            [1, 1, 0],
            [0, 1, 1]
        ],
        [
            [0, 1, 1],
            [1, 1, 0]
        ],
        [
            [1, 0, 0],
            [1, 1, 1]
        ],
        [
            [0, 0, 1],
            [1, 1, 1]
        ],
        [
            [0, 1, 0],
            [1, 1, 1]
        ],
        [
            [1, 1, 1, 1]
        ],
        [
            [1, 1],
            [1, 1]
        ]
    ];
    
    // 分数
    var score = 0;
    // 行数
    var row = 20;
    // 列数
    var col = 10;
​
    // 构造函数
    function Tetris() {
        // 创建游戏面板对象
        this.board = new Board();
        // 创建提示方块的对象
        this.nextShape = new NextShape();
        // 绘制提示的头部内容
        this.nextShape.drawHeader();
        
        this.score = new Score();
        this.score.drawHeader();
        
        // 回调
        KeyBoard.call(this);
        // 调用自己的初始化方法
        this.init();
    }
    
    Tetris.prototype = {
        init: function() {
            // 调用添加键盘监听事件的方法
            this.addEventHandlers();
            var self = this;
            // 在图片源加载到内存的时候才能绘制出图片
            this.board.shape.block.image.onload = function() {
                // 初始化board对象
                self.board.init();
                // 定时器 刷新canvas画布
                self.timer = setInterval(function() {
                    self.board.tick();
                }, 1000);
            }
        }
    }
​
    // 创建游戏面板的类 Board
    function Board() {
        // 获取面板类的canvas画布
        this.canvas = document.getElementById("tetris");
        // 获取画笔
        this.ctx = this.canvas.getContext("2d");
        // 当前方块
        this.shape = new Shape();
        // 下一个方块
        this.nextShape = new Shape();
        
        // 存放已经下落的方块
        this.list;
    }
    // 原型 定义方法
    Board.prototype = {
        // 定义初始化的方法
        init: function() {
            this.initList();
            this.drawGridLine();
            this.shape.init();
            // 调用形状类的绘制形状的方法
            this.shape.drawShape(this.ctx);
            // 初始化下一个形状
            this.nextShape.init();
            // 绘制下一个形状
            window.Tetris.nextShape.drawNextShape(this.nextShape);
            window.Tetris.score.drawScore();
            
        },
        // 初始化list
        initList: function() {
            this.list = [];
            for (var i = 0; i < row; i++) {
                this.list[i] = [];
                for (var j = 0; j < 10; j++) {
                    this.list[i][j] = 0;
                }
            }
        },
        // 把下落的块堆积起来的方法
        addShapeToList: function() {
            for (var y = 0; y < this.shape.layout.length; y++) {
                for (var x = 0; x < this.shape.layout[0].length; x++) {
                    // 判断形状的某个位置上是否有方块
                    if (this.shape.layout[y][x] > 0) {
                        // 有方块就保存到list二位数组中,其值为方块的颜色值加1
                        this.list[this.shape.currentY + y][this.shape.currentX + x] = this.shape.color + 1;
                    }
                }
            }
        },
        // 绘制已存在的方块的方法
        drawList: function() {
            for (var y = 0; y < row; y++) {
                for (var x = 0; x < col; x++) {
                    // 判断list中该位置上是否存在方块
                    if (this.list[y][x] > 0) {
                        this.ctx.drawImage(this.shape.block.image, (this.list[y][x] - 1) * 32, 0, 32, 32, x * 32, y * 32, 32, 32);
                    }
                }
            }
        },
        // 定义画网格线条的方法
        drawGridLine: function() {
            // 循环绘制横线
            for (var i = 0; i < row; i++) {
                this.ctx.strokeStyle = "#ffffff";
                this.ctx.beginPath();
                this.ctx.moveTo(0, i * 32);
                this.ctx.lineTo(320, i * 32);
                this.ctx.closePath();
                this.ctx.stroke();
            }
            // 循环绘制竖线
            for (var i = 0; i < col; i++) {
                this.ctx.strokeStyle = "#ffffff";
                this.ctx.beginPath();
                this.ctx.moveTo(i * 32, 0);
                this.ctx.lineTo(i * 32, 640);
                this.ctx.closePath();
                this.ctx.stroke();
            }
        },
        // 定义方块自动下落的方法
        tick: function() {
            if (this.validMove(0, 1)) {
                // 方块的Y坐标自动增加1
                this.shape.currentY++;
                this.refresh();
            } else {
                this.addShapeToList();
                // 添加形状之后,调用消除方块的方法
                this.clearLineBlock();
                window.Tetris.score.drawScore();
​
                // 表示方块下落到最下面
                this.shape = this.nextShape;
                // 重新随机产生方块
                this.nextShape = new Shape();
                this.nextShape.init();
                window.Tetris.nextShape.drawNextShape(this.nextShape);
                
                this.refresh();
            }
        },
        // 定义刷新画布的方法
        refresh: function() {
            // 清除画布
            this.ctx.clearRect(0, 0, 32*col, 32*row);
            this.drawGridLine();
            this.drawList();
            this.shape.drawShape(this.ctx);
        },
        // 碰撞检测的方法  
        // x 表示方块在横向上的移动        
        // y 表示方块在纵向上的移动
        validMove: function(x, y) {
            // 方块下一个位子的横坐标
            var offsetX = this.shape.currentX + x;
            // 方块下一个位子的纵坐标
            var offsetY = this.shape.currentY + y;
            // 判断方块是否掉出画布
            if (offsetY + this.shape.layout.length > row) {
                // 返回 false 表示无效的移动
                return false;
            }
            // 左右边界的碰撞检测
            if (offsetX < 0 || offsetX + this.shape.layout[0].length > col) {
                return false;
            }
            // 方块与方块之间的碰撞检测
            for (var y = 0; y < this.shape.layout.length; y++) {
                for (var x = 0; x < this.shape.layout[0].length; x++) {
                    if (this.list[offsetY + y][offsetX + x] > 0 && this.shape.layout[y][x] > 0) {
                        if(offsetY == 1){
                            clearInterval(window.Tetris.timer);
                            alert("游戏结束");
                        }
                        return false;
                    }
                }
            }
​
            return true;
        },
        // 消除一行或多行的方块
        clearLineBlock: function() {
            // 循环遍历 list数组
            for (var y = row - 1; y > 0; y--) {
                //  假设该行全部有方块,可以消除
                var flag = true;
                for (var x = 0; x < col; x++) {
                    // 如果该行元素存在空的,则假设不成立
                    if (this.list[y][x] == 0) {
                        flag = false;
                    }
                }
                // 如果标记为true,说明该行可以消除
                if (flag) {
                    for (var i = y; i > 0; i--) {
                        for (var j = 0; j < col; j++) {
                            // 消除一行方块,把上一行的数据往下挪
                            this.list[i][j] = this.list[i - 1][j];
                        }
                    }
                    // 因为数据往下挪,所以该行还得遍历
                    score += 100;
                    y++;
                }
​
            }
        }
    }
​
    // 定义形状类
    function Shape() {
        // 创建方块对象
        this.block = new Block();
        // 存放形状的矩阵
        this.layout;
        // 形状的颜色
        this.color;
        // 当前X坐标
        this.currentX;
        // 当前Y坐标
        this.currentY;
    }
    Shape.prototype = {
        init: function() {
            // 初始化矩阵    
            this.layout = layouts[Math.floor(Math.random() * 7)];
            // 初始化颜色
            this.color = Math.floor(Math.random() * 7);
            // 初始化横纵坐标
            this.currentX = Math.floor((col - this.layout[0].length) / 2);
            this.currentY = 0;
        },
        // 绘制形状的方法
        drawShape: function(ctx) {
            //  两层循环遍历二维数组  
            //  this.layout.length表示矩阵的高度       
            //  this.layout[0].length表示矩阵的宽度
            for (var y = 0; y < this.layout.length; y++) {
                for (var x = 0; x < this.layout[0].length; x++) {
                    if (this.layout[y][x] > 0) {
                        ctx.drawImage(this.block.image, this.color * 32, 0, 32, 32, (this.currentX + x) * 32, (this.currentY + y) * 32, 32, 32);
                    }
                }
            }
        }
    }
​
    // 定义方块类
    function Block() {
        // 创建图片对象
        this.image = new Image();
        // 指定图片源
        this.image.src = "img/blocks.png";
//      // 绘制方块的方法
//      this.drawBlock = function(ctx) {
//          // 绘制图片的方法
//          /*  第一个参数:图片源
//           *  第二、三个参数:截取图片的起始点
//           *  第四、五个参数:截取图片的大小
//           *  第六、七个参数:绘制在canvas上的起始点
//           *  第八、九个参数:绘制在canvas上的大小
//           */
//          ctx.drawImage(this.image, 32, 0, 32, 32, 64, 0, 32, 32);
//      }
    }
​
    // 键盘监听的类
    function KeyBoard() {
        var self = this;
        var keys = {
            37: "left",
            38: "top",
            39: "right",
            40: "bottom"
        }
​
        // 添加监听 事件的方法
        this.addEventHandlers = function() {
                // 添加键盘的监听事件
                document.addEventListener("keydown", this.keyPress, true);
            }
            //  监听键盘事件的方法
        this.keyPress = function(event) {
                // ASCII码
                //          alert(event.keyCode);
                // 判断按下的键是不是上下左右四个键
                if (keys[event.keyCode]) {
                    self.keyPressEvent(keys[event.keyCode]);
                }
            }
            // 键盘按下之后的任务代码方法
        this.keyPressEvent = function(code) {
            switch (code) {
                // 方块向左移动
                case "left":
                    if (this.board.validMove(-1, 0)) {
                        this.board.shape.currentX--;
                        this.board.refresh();
                    }
                    break;
                case "top":
                    // 矩阵变形的操作
                    var lay = [];
                    for (var x = 0; x < this.board.shape.layout[0].length; x++) {
                        lay[x] = [];
                        for (var y = 0; y < this.board.shape.layout.length; y++) {
                            lay[x][y] = this.board.shape.layout[this.board.shape.layout.length - y - 1][x];
                        }
                    }
                    // 变形之后的偏移量
//                  var offsetX = this.board.shape.currentX + lay[0].length;
//                  var offsetY = this.board.shape.currentY + lay.length;
//                  // 正确的坐标
//                  var xZuoBiao = this.board.shape.currentX;
//                  var yZuoBiao = this.board.shape.currentY;
//                  
//                  if (offsetX > col) {
//                      xZuoBiao = col - lay[0].length;
//                  }
//                  if (offsetY > row) {
//                      yZuoBiao = row - lay.length;
//                  }
                    
                    if(lay[0].length + this.board.shape.currentX > col){
                        return;
                    }
                    
//                  // 变形之后的矩阵和已存在的方块之间的碰撞检测
                    for(var y=0;y<lay.length;y++){
                        for(var x=0;x<lay[0].length;x++){
                            if(this.board.list[this.board.shape.currentY+y][this.board.shape.currentX+x] >0 && lay[y][x] > 0){
                                return;
                            }
                        }
                    }
//                  
//                  this.board.shape.currentX = xZuoBiao;
//                  this.board.shape.currentY = yZuoBiao;
​
                    this.board.shape.layout = lay;
                    this.board.refresh();
                    break;
                case "right":
                    if (this.board.validMove(1, 0)) {
                        this.board.shape.currentX++;
                        this.board.refresh();
                    }
                    break;
                case "bottom":
                    if (this.board.validMove(0, 1)) {
                        this.board.shape.currentY++;
                        this.board.refresh();
                    }
                    break;
            }
        }
    }
    
    // 下一个方块提示的类
    function NextShape(){
        this.canvas = document.getElementById("nextShape");
        this.ctx = this.canvas.getContext("2d");
    }
    
    NextShape.prototype = {
        // 绘制提示的头部
        drawHeader:function(){
            this.ctx.fillStyle = "black";
            // 设置字体
            this.ctx.font = "26px April";
            // 设置文字对齐方式
            this.ctx.textAlign = "center";
            // 绘制文本,文本内容,x坐标,y坐标
            this.ctx.fillText("Next",100,40);
            // 绘制矩形
            this.ctx.fillRect(5,60,190,95);
            this.ctx.fill();
        },
        // 绘制提示的方块
        drawNextShape:function(shape){
            // 把显示形状的位置重新绘制成黑色
            this.ctx.fillStyle = "black";
            this.ctx.fillRect(5,60,190,95);
            this.ctx.fill();
            
            for(var y=0;y<shape.layout.length;y++){
                for(var x=0;x<shape.layout[0].length;x++){
                    if(shape.layout[y][x] > 0){
                        this.ctx.drawImage(shape.block.image,shape.color*32,0,32,32,40+x*32,80+y*32,32,32);
                    }
                }
            }
        }
    }
    
    // 得分的类
    function Score(){
        this.canvas = document.getElementById("score");
        this.ctx = this.canvas.getContext("2d");
    }
    Score.prototype = {
        // 绘制提示的头部
        drawHeader:function(){
            this.ctx.fillStyle = "black";
            // 设置字体
            this.ctx.font = "26px April";
            // 设置文字对齐方式
            this.ctx.textAlign = "center";
            // 绘制文本,文本内容,x坐标,y坐标
            this.ctx.fillText("Score",100,40);
            // 绘制矩形
            this.ctx.fillRect(5,60,190,95);
            this.ctx.fill();
        },
        drawScore:function(){
            
            // 把显示形状的位置重新绘制成黑色
            this.ctx.fillStyle = "black";
            this.ctx.fillRect(5,60,190,95);
            
            this.ctx.fillStyle = "white";
            this.ctx.font = "26px April";
            this.ctx.textAlign = "center";
            this.ctx.fillText(score,100,100);
            
            this.ctx.fill();
            
        }
    }
    
    // 返回Tetris类的一个对象
    return new Tetris();
})();

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wxf11211

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值