JavaScript基础

  变量&数据类型
  运算符
  控制语句
  对象
  DOM节点
  DOM属性
  DOM访问
  DOM事件
  DOM操作
实例练习

JavaScript概述 

JavaScript的历史

  • 1992年Nombas开发出C-minus-minus(C--)的嵌入式脚本语言(最初绑定在CEnvi软件中). 后将其改名ScriptEase.(客户端执行的语言).
  • Netscape(网景)接收Nombas的理念, (Brendan Eich)在其Netscape Navigator 2.0产品中开发出一套livescript的脚本语言.Sun和Netscape共同完成.后改名叫Javascript.
  • 微软随后模仿在其IE3.0的产品中搭载了一个JavaScript的克隆版叫Jscript.
  • 为了统一三家, ECMA(欧洲计算机制造协会)定义了ECMA-262规范. 国际标准化组织及国际电工委员会(ISO/IEC)也采纳 ECMAScript 作为标准(ISO/IEC-16262). 从此, Web 浏览器就开始将 ECMAScript 作为 JavaScript 实现的基础. EcmaScript是规范.

ECMAScript  

尽管 ECMAScript 是一个重要的标准, 但它并不是 JavaScript 唯一的部分. 一个完整的 JavaScript 实现是由以下3个不同部分组成的:

  • 核心(ECMAScript) - JavaScript 的核心 ECMAScript 描述了该语言的语法和基本对象
  • 文档对象模型(DOM, Document Object Model) - 描述了处理网页内容的方法和接口, 整合js, css, html
  • 浏览器对象模型(BOM) Broswer Object Model - 描述了与浏览器进行交互的方法和接口, 整合js和浏览器
JavaScript由三部分组成:ECMAScript、BOM以及DOM
1、核心——ECMAScript:提供核心语言功能

2、文档对象模型——DOM:提供访问和操作网页内容的方法和接口
HTML 和 XML 的应用程序接口(API),用来获取或设置文档中标签的属性,和文档有关, DOM关注的是网页本身的内容. 这里的文档指的是网页, 也就是HTML文档.
DOM把页面映射成一个多层节点结构。
为什么使用DOM?Netscape和微软在开发DHTML方面各持己见,为避免两强割据,浏览器互不兼容的局面,保持Web跨平台的天性,DOM应运而生。

DOM1级:由DOM Core和DOM HTML两部分组成。DOM Core规定如何映射基于XML的文档结构,DOM HTML在DOM Core的基础上扩展,增加了针对HTML的对象和方法。

DOM2级:在原来DOM的基础上扩充了鼠标和用户界面事件、范围、遍历(迭代DOM文档的方法),且通过对象接口增加了对CSS的支持,DOM1级中的DOM Core也经过扩展开始支持XML命名空间。引入了新模块:DOM Views——定义了跟踪不同文档视图的接口;DOM Events——定义了事件和事件处理的接口;DOM Style——定义了基于CSS为元素应用样式的接口;DOM Traversal and Range——定义了遍历和操作文档树的接口。

DOM3级:引入了以统一方式加载和保存文档的方法——在DOM加载和保存(DOM Load and Save)模块中定义;新增了验证文档的方法——在DOM验证(DOM Validation)模块中定义。对DOM Core进行了扩展,开始支持XML 1.0规范,涉及XML Infoset、XPath和XML Base。

3、浏览器对象模型——BOM:提供与浏览器交互的方法和接口
BOM可以访问和操作浏览器窗口,使用BOM可以控制浏览器显示的页面以外的部分。HTML5致力于把很多BOM功能写入正式规范。

从根本上讲,BOM只处理浏览器窗口和框架,但习惯把所有针对浏览器的JavaScript扩展算作BOM的一部分,包括弹出新浏览器窗口的功能,移动、缩放和关闭浏览器窗口的功能,提供浏览器详细信息的navigator对象,提供浏览器所加载页面的详细信息的location对象,提供用户显示器分辨率详细信息的screen对象,对cookie的支持,像XMLHttpRequest和IE的ActiveXObject这样的自定义对象。

BOM是由navigator、history、screen、location、document五个对象组成的。
DOM,BOM

Javascript 在开发中绝大多数情况是基于对象(使用对象, 不是创建, 跟面向对象不同)的, 也是面向对象的. 

 

简单地说,ECMAScript 描述了以下内容:

  • 语法 
  • 类型 
  • 语句 
  • 关键字 
  • 保留字 
  • 运算符 
  • 对象 (封装 继承 多态) 基于对象的语言, 使用对象.

JavaScript的引入方式

//1. 直接编写 - 可以放在<head>标签里, 但是推荐放在<body>标签尾部
    <script>
        alert('hello yuan')
    </script>
//2. 导入文件
    <script src="hello.js"></script> 

 


ECMAScript

变量&数据类型

变量

声明变量时不用声明变量类型, 全都使用var关键字.

var a;

一行可以声明多个变量, 并且可以是不同类型. 

var name="charon", age=20, gender="male";

声明变量时可以不用var, 如果不用var那么它是全局变量. 

function func1(){
    var a = 123;
    b=456
}
func1();
//alert(a);   //a是局部变量, 会报错
alert(b);    //b是全局变量可以alert出来

变量命名, 首字符只能是字母,下划线,$美元符 三选一,且区分大小写,x与X是两个变量

变量还应遵守以下某条著名的命名规则:

// 变量命名, 首字符只能是字母,下划线,$美元符中的一个, 且区分大小写, x与X是两个变量.

Camel 标记法
首字母是小写的, 接下来的字母都以大写字符开头. 例如:
var myTestValue = 0, mySecondValue = "hi";
Pascal 标记法
首字母是大写的, 接下来的字母都以大写字符开头. 例如:
Var MyTestValue = 0, MySecondValue = "hi";
匈牙利类型标记法
在以 Pascal 标记法命名的变量前附加一个小写字母(或小写字母序列), 说明该变量的类型. 例如: i表示整数, s表示字符串
Var iMyTestValue = 0, sMySecondValue = "hi";
命名规则

基础规范

每行结束可以不加分号. 没有分号会以换行符作为每行的结束

注释支持多行注释/* */和单行注释//

使用{}来封装代码块

常量和标识符

常量: 直接在程序中出现的数据值

标识符

  1. 不以数字开头的字母、数字、下划线(_)、美元符号($)组成
  2. 用于表示函数、变量等的名称
  3. 例如:_abc,$abc,abc,abc123是标识符,而1abc不是
  4. JavaScript语言中代表特定含义的词称为保留字,不允许程序再定义为标识符

  

五种数据类型

        

在 ECMAScript 中,变量可以存在两种类型的值,即原始值和引用值.

原始值: 存储在栈(stack)中的原始(基本)数据类型数据段,即它们的值直接存储在变量访问的位置.
引用值: 存储在堆(heap)中的对象,即存储在变量处的值是一个指针(point),指向存储对象的内存处.

(如果一个值是引用类型的, 那么它的存储空间将从堆中分配. 由于引用值的大小会改变, 所以不能把它放在栈中, 否则会降低变量查寻的速度. 相反, 放在变量的栈空间中的值是该对象存储在堆中的地址. 地址的大小是固定的, 所以把它存储在栈中对变量性能无任何负面影响)

1. 数字类型(Number)

最基本的数据类型
不区分整型数值和浮点型数值
所有数字都采用64位浮点格式存储,相当于Java和C语言中的double格式
能表示的最大值是±1.7976931348623157 x 10308 
能表示的最小值是±5 x 10 -324 

   整数:
           在JavaScript中10进制的整数由数字的序列组成
           精确表达的范围是
-9007199254740992 (-253) 到 9007199254740992 (253)
           超出范围的整数, 精确度将受影响
  浮点数:
           使用小数点记录数据, 例如: 3.4, 5.6
           使用指数记录数据, 例如: 4.3e23 = 4.3 x 1023

  16进制和8进制数的表达:
           16进制数据前面加上0x, 八进制前面加0
           16进制数是由0-9, A-F等16个字符组成
           8进制数由0-7等8个数字组成
           16进制和8进制与2进制的换算

2. 字符串(String)

是由Unicode字符、数字、标点符号组成的序列
字符串常量首尾由单引号或双引号括起
JavaScript中没有字符类型
常用特殊字符在字符串中的表达
字符串中部分特殊字符必须加上右划线\
常用的转义字符 \n:换行  \':单引号   \":双引号  \\:右划线

String数据类型的使用

  • 特殊字符的使用方法和效果
  • Unicode的插入方法
var str="\u4f60\u597d\n哈哈哈\"Charon\"";
alert(str);

效果: 
你好
哈哈哈"Charon"
unicode插入方法

3. 布尔型(Boolean)

Boolean类型仅有两个值: true和false, 也代表1和0, 实际运算中true=1,false=0  (true==2; 会返回false)
Boolean值主要用于JavaScript的控制语句,例如
    if (x==1){
      y=y+1;
    }else {
      y=y-1;
    }

4 & 5. Null & Undefined

Undefined 类型

Undefined 类型只有一个值, 即undefined. 当声明的变量未初始化时, 该变量的默认值是 undefined.

当函数无明确返回值时, 返回的也是值 "undefined";

Null 类型

另一种只有一个值的类型是 Null, 它只有一个专用值 null, 即它的字面量. 值 undefined 实际上是从值 null 派生来的, 因此 ECMAScript 把它们定义为相等的, 即 null==undefined; 会返回true.

尽管这两个值相等,但它们的含义不同. undefined 是声明了变量但未对其初始化时赋予该变量的值, null 则用于表示尚未存在的对象. 如果函数或方法要返回的是对象, 那么找不到该对象时, 返回的通常是 null.

var person=new Person()

var person=null

数据类型转换

JavaScript属于松散类型的程序语言
变量在声明的时候并不需要指定数据类型
变量只有在赋值的时候才会确定数据类型
表达式中包含不同类型数据则在计算过程中会强制进行类别转换

数字 + 字符串:数字转换为字符串

数字 + 布尔值:true转换为1, false转换为0

字符串 + 布尔值:布尔值转换为字符串true或false

var c="10";
alert(typeof (c));   //String
c=+c;    //类型转换
alert(typeof (c));    //Number

强制类型转换函数

函数parseInt: 强制转换成整数   
例如: parseInt("6.12")=6;    parseInt("12a")=12;    parseInt("a12")=NaN;    parseInt("1a2")=1;
(NaN: 当字符串转换数字无效时就是NaN, 属于Number类型)
// ------ NaN特点: -------
    var n=NaN;
    
    alert(n>3);    //false
    alert(n<3);    //false
    alert(n==3);    //false
    alert(n==NaN);    //false
    alert(n!=NaN);    //true, NaN参与的所有的运算都是false,除了!=
// -----------------------
函数parseFloat: 强制转换成浮点数 
例如: parseFloat("6.12")=6.12

函数eval: 将字符串强制转换为表达式并返回结果 
例如: eval("1+1")=2 ; eval("1<2")=true

类型查询函数(typeof)

ECMAScript 提供了 typeof 运算符来判断一个值是否在某种类型的范围内. 可以用这种运算符判断一个值是否表示一种原始类型:如果它是原始类型,还可以判断它表示哪种原始类型.

函数typeof :查询数值当前类型
 (string / number / boolean / object )
例如typeof("test"+3) "string" 例如typeof(null) "object " 例如typeof(true+1) "number" 例如typeof(true-false) "number"

instanceof

typeof只能判断基本的数据类型, 不能判断对象. 所以用instanceof可以判断是否为某个类型的实例对象.

var s = new String("Charon")
alert(typeof(s))    //object
alert(s instanceof String)    //true

 


运算符

算数运算符

加(+), 减(-), 乘(*), 除(/), 余数(% ) 加、减、乘、除、余数和数学中的运算方法一样 例如:9/2=4.5,4*5=20,9%2=1
-除了可以表示减号还可以表示负号 例如:x = -y
+除了可以表示加法运算还可以用于字符串的连接 例如:"abc"+"def"="abcdef"

 递增(++), 递减(--)

i++/++i 都相当于i=i+1, i--/--i 都相当于i=i-1.
i++表示先把i的值给表达式, 再做递增;
++i表示先递增, 再把递增后的值给表达式. i--/--i 同理
   
var i=1;
console.log(i++);   //1
console.log(++i);   //3
console.log(--i);   //2
console.log(i--);   //2
console.log(i);     //1

赋值运算符

简单的赋值运算符由等号(=)实现,只是把等号右边的值赋予等号左边的变量.

配合其他运算符可以简化表达式, 如
var iNum = 10;
iNum += 10;
还有 *=, /=, -=....

 

逻辑运算符(Boolean运算符, 等性运算符, 关系运算符)

等于(==), 不等于(!=), 大于(>), 小于(<), 
大于等于(>=), 小于等于(<=)
与 (&&) 、或(||) 、非(!)
1 && 1 = 1       1 || 1 = 1
1 && 0 = 0 1 || 0 = 1
0 && 0 = 0 0 || 0 = 0

!0=1 !1=0

Boolean运算符 - AND ( && )

如果某个运算数不是原始的 Boolean 型值,逻辑 AND 运算并不一定返回 Boolean 值

  • 如果一个运算数是对象,另一个是 Boolean 值,返回该对象。
  • 如果两个运算数都是对象,返回第二个对象。
  • 如果某个运算数是 null,返回 null。
  • 如果某个运算数是 NaN,返回 NaN。
  • 如果某个运算数是 undefined,发生错误。

Boolean运算符 - OR ( || )    支持短路原则, 即前面为false, 不再检查第二个就直接返回false

与逻辑 AND 运算符相似, 如果某个运算数不是 Boolean 值,逻辑 OR 运算并不一定返回 Boolean 值.

  • 如果一个运算数是对象,并且该对象左边的运算数值均为 false,则返回该对象。
  • 如果两个运算数都是对象,返回第一个对象。
  • 如果最后一个运算数是 null,并且其他运算数值均为 false,则返回 null。
  • 如果最后一个运算数是 NaN,并且其他运算数值均为 false,则返回 NaN。
  • 如果某个运算数是 undefined,发生错误。

Boolean运算符 - NOT ( ! )

逻辑 NOT 运算符返回的一定是 Boolean 值

  • 如果运算数是对象,返回 false
  • 如果运算数是数字 0,返回 true
  • 如果运算数是 0 以外的任何数字,返回 false
  • 如果运算数是 null,返回 true
  • 如果运算数是 NaN,返回 true
  • 如果运算数是 undefined,发生错误

等性运算符 - 等号和非等号         (==和!=处理原始值     ===和!==处理对象)

等号(==), 当且仅当两个运算数相等时, 它返回 true. 非等号(!=)反之亦然.

执行类型转换的规则如下:

  • 如果一个运算数是 Boolean 值,在检查相等性之前,把它转换成数字值。false 转换成 0,true 为 1。 
  • 如果一个运算数是字符串,另一个是数字,在检查相等性之前,要尝试把字符串转换成数字。 
  • 如果一个运算数是对象,另一个是字符串,在检查相等性之前,要尝试把对象转换成字符串。 
  • 如果一个运算数是对象,另一个是数字,在检查相等性之前,要尝试把对象转换成数字。 

在比较时,该运算符还遵守下列规则:

  • 值 null 和 undefined 相等。 
  • 在检查相等性时,不能把 null 和 undefined 转换成其他值。 
  • 如果某个运算数是 NaN,等号将返回 false,非等号将返回 true。 
  • 如果两个运算数都是对象,那么比较的是它们的引用值。如果两个运算数指向同一对象,那么等号返回 true,否则两个运算数不等。 

等性运算符 -全等号和非全等号

全等号(===)和非全等号(!==), 只有在无需类型转换运算数就相等的情况下, 才返回 true.

var sNum = "66";
var iNum = 66;
alert(sNum == iNum);    //输出 "true"
alert(sNum === iNum);    //输出 "false"
alert(sNum !== iNum);    //输出 "true"

关系运算符

比较运算符两侧如果一个是数字类型, 一个是其他类型, 会将其类型转换成数字类型.  

比较运算符两侧如果都是字符串类型, 比较的是最高位的ascii码, 如果最高位相等, 继续取第二位比较.

 

var bResult = "Blue" < "alpha";
alert(bResult);   //输出 true 
// 字符串 "Blue" 小于 "alpha",因为字母 B 的字符代码是 66,字母 a 的字符代码是 97
var bResult = "25" < "3";
alert(bResult);   //输出 "true"
// 两个运算数都是字符串, 所以比较的是它们的字符代码("2" 的字符代码是 50, "3" 的字符代码是 51)
var bResult = "25" < 3;
alert(bResult);    //输出 "false"
// 字符串 "25" 将被转换成数字 25,然后与数字 3 进行比较.
var bResult = "a" < 3;
alert(bResult);   //输出 "false"
// 字母 "a" 不能转换成有意义的数字. 如果对它调用 parseInt() 方法,返回的是 NaN. 根据规则,任何包含 NaN 的关系运算符都要返回 false.

 


控制语句

if 控制语句

if语句嵌套格式
if (表达式1) {
    语句1;
}else if (表达式2){
    语句2;
}else if (表达式3){
    语句3;
} else{
    语句4;
}
if (x==1){
    y="星期一";
}else if (x==2){
    y="星期二";
...
}else if (x==6){
    y="星期六";
}else if (x==0){
    y="星期日";
}else{
    y="未定义";
             

switch  选择控制语句

switch基本格式
switch (表达式) {
    case 值1:语句1;break;
    case 值2:语句2;break;
    case 值3:语句3;break;
    default:语句4;
}
switch(x){
case 1:y="星期一";    break;
case 2:y="星期二";    break;
case 3:y="星期三";    break;
case 4:y="星期四";    break;
case 5:y="星期五";    break;
case 6:y="星期六";    break;
case 7:y="星期日";    break;
default: y="未定义";
}
              

switchelse if结构更加简洁清晰, 使程序可读性更强, 效率更高.

首先要看一个问题,if 语句适用范围比较广,只要是 boolean 表达式都可以用 if 判断;而 switch 只能对基本类型进行数值比较。两者的可比性就仅限在两个基本类型比较的范围内。
说到基本类型的数值比较,那当然要有两个数。然后重点来了——
if 语句每一句都是独立的,看下面的语句:
if (a == 1) ...
else if (a == 2) ...
这样 a 要被读入寄存器两次,1 和 2 分别被读入寄存器一次。于是你是否发现其实 a 读两次是有点多余的,在你全部比较完之前只需要一次读入寄存器就行了,其余都是额外开销。但是 if 语句必须每次都把里面的两个数从内存拿出来读到寄存器,它不知道你其实比较的是同一个 a。
于是 switch case 就出来了,把上面的改成 switch case 版本:
switch (a) {
        case 0:
                break;
        case 1:
}
                
总结:

1.switch用来根据一个整型值进行多路分支,并且编译器可以对多路分支进行优化
2.switch-case只将表达式计算一次,然后将表达式的值与每个case的值比较,进而选
  择执行哪一个case的语句块
3.if..else 的判断条件范围较广,每条语句基本上独立的,每次判断时都要条件加载
  一次。
所以在多路分支时用switch比if..else if .. else结构要效率高。
为什么switch效率高

for  循环控制语句

for循环基本格式
for (初始化;条件;增量){
    语句1;
    ...
}
for (var i=1;i<7;i++){
    document.write("<H"+i+">hello</H "+i+"> ");
    document.write("<br>");   //效果: 从H1到H6的hello
}
//----------------------------------------------
var arr=[1,"hello",true]
for (var i in arr) {
    console.log(i)    //index
    console.log(arr[i])    //value
}

注意:

<p>Charon</p>
<p>Alan</p>

<script>
    doms=document.getElementsByTagName("p");

    for (var i in doms){
       console.log(i); // 0 1 length item namedItem
       // console.log(doms[i])   //获取DOM对象和所有属性的值
    }

//用上面的for循环可以获取一个DOM元素集, 元素集包含了对象的所有属性

//用下面这种for循环可以获取DOM对象

    for (var i=0;i<doms.length;i++){
        console.log(i) ; // 0 1
        // console.log(doms[i])  //获取DOM对象
    }
</script>
View Code

结论:for(var i in xx)不推荐使用.

while  循环控制语句

while循环基本格式
while (条件){
语句1;
...
}
var i=1;
while (i<=7) {
    document.write("<H"+i+">hello</H "+i+"> ");
    document.write("<br>");
    i++;
}
//循环输出H1到H7的字体大小

 

异常处理

try {
    //这段代码从上往下运行,其中任何一个语句抛出异常该代码块就结束运行
}
catch (e) {
    // 如果try代码块中抛出了异常,catch代码块中的代码就会被执行。
    //e是一个局部变量,用来指向Error对象或者其他抛出的对象
}
finally {
     //无论try中代码是否有异常抛出(甚至是try代码块中有return语句),finally代码块中始终会被执行。
}

注:主动抛出异常 throw Error('xxxx')  

 


ECMA对象

从传统意义上来说, ECMAScript 并不真正具有类. 事实上, 除了说明不存在类, 在 ECMA-262 中根本没有出现"类"这个词. ECMAScript 定义了"对象定义", 逻辑上等价于其他程序设计语言中的类.

var o = new Object();

对象有三种 - 本地对象, 内置对象, 宿主对象:

  • 本地对象(native object)就是由ECMAScript定义的类(引用类型). 
  • 内置对象(built-in object)就是不必明确实例化内置对象, 它已被实例化了. ECMA-262 只定义了两个内置对象, 即 Global 和 Math (它们也是本地对象, 根据定义, 每个内置对象都是本地对象).
  • 宿主对象(host object)就是所有非本地对象, 即 BOM 和 DOM 对象都是宿主对象.

object对象ECMAScript 中的所有对象都由这个对象继承而来;Object 对象中的所有属性和方法都会出现在其他对象中

ToString() :  返回对象的原始字符串表示.
ValueOf() : 返回最适合该对象的原始值. 对于许多对象,该方法返回的值都与 ToString() 的返回值相同.

11种内置对象:

JavaScript中除了nullundefined以外其他的数据类型都被定义成了对象,也可以用创建对象的方法定义变量,StringMathArrayDateRegExp都是JavaScript中重要的内置对象,在JavaScript程序大多数功能都是通过对象实现的.

                     

String对象

创建字符串对象

创建方式1:
var str="hello world";
// 调用字符串的对象属性或方法时自动创建对象,用完就丢弃.

创建方式2:
var str1= new String("hello word");
// 采用new创建字符串对象str, 全局有效.
View Code

String对象的属性

获取字符串的长度: length

var str1="String对象";
var str2="";

alert("str1长度 "+str1.length);
alert("str2长度 "+str2.length);
View Code

String对象的方法

   

 

String对象的方法(1) —— 格式编排方法

格式编排方法返回值列表

书写格式:
String对象提供了一组针对HTML格式的方法,如x.anchor()返回锚定义字符串<a>x</a>,
x.bold()返回粗体表示字符串<b>x</b>,x.sup()返回上标格式字符串<sup>x</sup>.
// -----------------------------------------

var x="charon";
var y="x.italics():"+x.italics();
document.write(y.fontsize(10));
//<font size="10">x.italics():<i>charon</i></font>
View Code

String对象的方法(2)——  大小写转换

var str1="AbcdEfgh"; 

var str2=str1.toLowerCase();
var str3=str1.toUpperCase();
alert(str2);
//结果为"abcdefgh"
alert(str3);
//结果为"ABCDEFGH"
View Code

String对象的方法(3) —— 获取指定字符

书写格式:
x.charAt(index)

x.charCodeAt(index)

x代表字符串对象
index代表字符位置
index从0开始编号
charAt返回index位置的字符
charCodeAt返回index位置的Unicode编码

// ----------------------
var str1="Hello World! 凯伦";

var str2=str1.charAt(14);
var str3=str1.charCodeAt(14);
alert(str2);
//结果为"伦"
alert(str3);
//结果为20262
View Code

String对象的方法(4)——  查询字符串

书写格式:
x.indexOf(findstr, index)
x.lastIndexOf(findstr)
//-------------------------------------
var str1="welcome to the world of JS!";

var str2=str1.indexOf("l");
var str3=str1.lastIndexOf("l");
alert(str2);
// 结果为2
alert(str3);
// 结果为18

//****************************************************

书写格式:
x.match(regexp)
x.search(regexp)

x代表字符串对象
regexp代表正则表达式或字符串
match返回匹配字符串的数组,如果没有匹配则返回null
search返回匹配字符串的首字符位置索引

//-------------------------------------
var str1="welcome to the world of JS!";

var str2=str1.match("world");
var str3=str1.search("world");
alert(str2[0]);
//结果为"world"
alert(str3);
//结果为15
View Code

String对象的方法(5) ——子字符串处理

截取子字符串

书写格式:
x.substr(start, length)
x.substring(start, end)

x代表字符串对象
start表示开始位置
length表示截取长度
end是结束位置加1
第一个字符位置为0

//-------------------------------------
    
var str1="abcdefgh";
var str2=str1.substr(2,4);
var str3=str1.substring(2,4);
alert(str2);
//结果为"cdef"
alert(str3);
//结果为"cd"

//*******************************************************

书写格式:
x.slice(start, end)

//-------------------------------------

var str1="abcdefgh";
var str2=str1.slice(2,4);
var str3=str1.slice(4);
var str4=str1.slice(2,-1);
var str5=str1.slice(-3,-1);
alert(str2);
//结果为"cd"
alert(str3);
//结果为"efgh"
alert(str4);
//结果为"cdefg"
alert(str5);
//结果为"fg"
View Code

替换子字符串

书写格式:
x.replace(findstr,tostr)

//-------------------------------------

var str1="abcdefgh";
var str2=str1.replace("cd","aaa");
alert(str2);
//结果为"abaaaefgh"
View Code

分割字符串

书写格式:
x.split(str)

//-------------------------------------

var str1="一,二,三,四,五,六,日"; 
var strArray=str1.split(",");

alert(strArray[1]);
//结果为"二"
View Code

连接字符串

书写格式:
y=x.concat(addstr)

x代表字符串对象
addstr为添加字符串
返回x+addstr字符串
    
//-------------------------------------

var str1="abcd"; 
var str2=str1.concat("efgh");

alert(str2);
//结果为"abcdefgh" 
View Code

 

Array对象

Array 对象用于在单个的变量中存储多个值.

数组的特性:

  • js中的数组可以装任意类型, 没有任何限制.
  • js中的数组, 长度是随着下标变化的, 即用到多长就有多长.

创建数组对象

创建方式1:
var a=[1,2,3];

创建方式2:
var arr = new Array();     //  创建数组时允许指定元素个数也可以不指定元素个数.
var arr1 = new Array(size);  // 如果仅一个数字参数, 表示的是数组大小, 而不是其元素
    

初始化数组对象:
    var cnweek=new Array(7);
        cnweek[0]="星期日";
        cnweek[1]="星期一";
        ...
        cnweek[6]="星期六";

    也可以直接在建立对象时初始化数组元素, 元素类型允许不同.
    var test=new Array(100,"a",true);
View Code

创建二维数组

var cnweek=new Array(7);
for (var i=0;i<=6;i++){
    cnweek[i]=new Array(2);
}
cnweek[0][0]="星期日";
cnweek[0][1]="Sunday";
cnweek[1][0]="星期一";
cnweek[1][1]="Monday";
...
cnweek[6][0]="星期六";
cnweek[6][1]="Saturday";
View Code

Array对象的属性

获取数组元素的个数:length

var cnweek=new Array(7);
cnweek[0]="星期日";
cnweek[1]="星期一";
cnweek[2]="星期二";
cnweek[3]="星期三";
cnweek[4]="星期四";
cnweek[5]="星期五";
cnweek[6]="星期六";
for (var i=0;i<cnweek.length;i++){
  document.write(cnweek[i]+" | ");
}

document.write(cnweek[7])    //undefined
View Code

Array对象的方法

 

连接数组-join方法

x.join(bystr)

x代表数组对象
bystr作为连接数组中元素的字符串
返回连接后的字符串
与字符串的split功能刚好相反
    
// ---------------------------
var arr1=[1, 2, 3, 4, 5, 6, 7];
var str1=arr1.join("-");

alert(str1);
//结果为"1-2-3-4-5-6-7"
View Code

连接数组-concat方法

x.concat(value,...)

// -------------------

var a = [1,2,3];
var a = new Array(1,2,3);
var b=a.concat(4,5) ;

alert(a.toString());
//返回结果为1,2,3
alert(b.toString());
//返回结果为1,2,3,4,5
View Code

数组排序-reverse sort

x.reverse()
x.sort()

// -----------------------------

var arr1=[32, 12, 111, 444];
//var arr1=["a","d","f","c"];

arr1.reverse();   //颠倒数组元素
alert(arr1.toString());
//结果为444,111,12,32

arr1.sort();    //排序数组元素
alert(arr1.toString());
//结果为111,12,32,444

结果是按每个元素的第一个字符的ascii码的大小来比的

//------------------------------

按数字大小比较:
    var arr6=[4,1,6,6,3,100,2];

    console.log(arr6.sort(mysort));
    //mysort做的是, 如, 比较mysort(4,1)若返回正数,即返回true,就调换位置
    //接着mysort(4,6)返回的为负数, 即返回false, 所以不调换位置, 以此类推

    function mysort(a,b) {
        return a-b;         // 简便写法

//        if (a>b){         // 复杂写法
//            return 1;
//        }else if(a<b){
//            return -1;
//        }else {
//            return 0
//        }

    }
View Code

数组切片-slice

x.slice(start, end)

x代表数组对象
start表示开始位置索引
end是结束位置下一数组元素索引编号
第一个数组元素索引为0
start、end可为负数,-1代表最后一个数组元素
end省略则相当于从start位置截取以后所有数组元素

// --------------------------------------

var arr1=['a','b','c','d','e','f','g','h'];
var arr2=arr1.slice(2,4);
var arr3=arr1.slice(4);
var arr4=arr1.slice(2,-1);

alert(arr2.toString());
//结果为"c,d" 
alert(arr3.toString());
//结果为"e,f,g,h"
alert(arr4.toString());
//结果为"c,d,e,f,g"
View Code

删除子数组

x. splice(start, deleteCount, value, ...)

x代表数组对象
splice的主要用途是对数组指定位置进行删除和插入
start表示开始位置索引
deleteCount删除数组元素的个数
value表示在删除位置插入的数组元素
value参数可以省略

// -----------------------------

var a = [1,2,3,4,5,6,7,8];
a.splice(1,2);
//a变为 [1,4,5,6,7,8]
alert(a.toString());
a.splice(1,1);
 //a变为[1,5,6,7,8]
alert(a.toString());
a.splice(1,0,2,3);
 //a变为[1,2,3,5,6,7,8]
alert(a.toString());
View Code

数组的进出栈操作

x.push(value, ...)  压栈
x.pop()             弹栈      

x代表数组对象
value可以为字符串、数字、数组等任何值
push是将value值添加到数组x的结尾
pop是将数组x的最后一个元素删除

// ---------------------------------

var arr1=[1,2,3];
arr1.push(4,5);
alert(arr1);
//结果为"1,2,3,4,5"
arr1.push([6,7]);
alert(arr1)
//结果为"1,2,3,4,5,6,7"
arr1.pop();
alert(arr1);
//结果为"1,2,3,4,5"
View Code

数组的进出队列操作

x.unshift(value,...)
x.shift()

x代表数组对象
value可以为字符串、数字、数组等任何值
unshift是将value值插入到数组x的开始
shift是将数组x的第一个元素删除

// -------------------------------------

var arr1=[1,2,3];
arr1.unshift(4,5);
alert(arr1);
//结果为"4,5,1,2,3"
arr1. unshift([6,7]);
alert(arr1);
//结果为"6,7,4,5,1,2,3"
arr1.shift();
alert(arr1);
//结果为"4,5,1,2,3"
View Code

 

Date对象

创建Date对象

//方法1:不指定参数
var nowd1=new Date();
alert(nowd1.toLocaleString( ));
//方法2:参数为日期字符串
var nowd2=new Date("2004/3/20 11:12");
alert(nowd2.toLocaleString( ));
var nowd3=new Date("04/03/20 11:12");
alert(nowd3.toLocaleString( ));
//方法3:参数为毫秒数
var nowd3=new Date(5000);
alert(nowd3.toLocaleString( ));
alert(nowd3.toUTCString());

//方法4:参数为年月日小时分钟秒毫秒
var nowd4=new Date(2004,2,20,11,12,0,300);
alert(nowd4.toLocaleString( ));
//毫秒并不直接显示
View Code

Date对象的方法 - 获取日期和时间

getDate()                 获取日
getDay ()                 获取星期
getMonth ()               获取月(0-11)
getFullYear ()            获取完整年份
getYear ()                获取年
getHours ()               获取小时
getMinutes ()             获取分钟
getSeconds ()             获取秒
getMilliseconds ()        获取毫秒
getTime ()                返回累计毫秒数(从1970/1/1午夜)
View Code
function getCurrentDate(){
        //1. 创建Date对象
        var date = new Date(); //没有填入任何参数那么就是当前时间
        //2. 获得当前年份
        var year = date.getFullYear();
        //3. 获得当前月份 js中月份是从0到11.
        var month = date.getMonth()+1;
        //4. 获得当前日
        var day = date.getDate();
        //5. 获得当前小时
        var hour = date.getHours();
        //6. 获得当前分钟
        var min = date.getMinutes();
        //7. 获得当前秒
        var sec = date.getSeconds();
        //8. 获得当前星期
        var week = date.getDay(); //没有getWeek
        // 2018年03月07日 01:40:30 星期三
        return year+"年"+changeNum(month)+"月"+day+"日 "+hour+":"+min+":"+sec+" "+parseWeek(week);
    }

alert(getCurrentDate());

//自动补齐成两位数字的方法
    function changeNum(num){
    if(num < 10){
        return "0"+num;
    }else{
        return num;
    }

}
//将数字 0~6 转换成 星期日到星期六
    function parseWeek(week){
    var arr = ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"];
    //             0      1      2      3 .............
    return arr[week];
}

Date对象的方法 - 设置日期和时间

//setDate(day_of_month)       设置日
//setMonth (month)                 设置月
//setFullYear (year)               设置年
//setHours (hour)         设置小时
//setMinutes (minute)     设置分钟
//setSeconds (second)     设置秒
//setMillliseconds (ms)       设置毫秒(0-999)
//setTime (allms)     设置累计毫秒(从1970/1/1午夜)
    
var x=new Date();
x.setFullYear (1997);    //设置年1997
x.setMonth(7);        //设置月7
x.setDate(1);        //设置日1
x.setHours(5);        //设置小时5
x.setMinutes(12);    //设置分钟12
x.setSeconds(54);    //设置秒54
x.setMilliseconds(230);        //设置毫秒230
document.write(x.toLocaleString( )+"<br>");
//返回1997年8月1日5点12分54秒

x.setTime(870409430000); //设置累计毫秒数
document.write(x.toLocaleString( )+"<br>");
//返回1997年8月1日12点23分50秒
View Code

Date对象的方法 - 日期和时间的转换 

getTimezoneOffset():8个时区×15度×4分/度=480;
返回本地时间与GMT的时间差,以分钟为单位
toUTCString()
返回国际标准时间字符串
toLocalString()
返回本地格式时间字符串
Date.parse(x)
返回累计毫秒数(从1970/1/1午夜到本地时间)
Date.UTC(x)
返回累计毫秒数(从1970/1/1午夜到国际时间)
View Code

 

RegExp对象

在表单验证时使用该对象验证用户填入的字符串是否符合规则.

创建正则对象

var x = new RegExp("正则表达式", "验证/匹配模式")
//匹配模式: g - global        i - 忽略大小写        也可以写gi

创建用户名要求: 首字母必须是英文, 除了第一位其他只能是英文数字和_. 长度最短不能少于6位, 最长不能超过12位

创建方式1:
    var reg1 = new RegExp("^[a-zA-Z][a-zA-Z0-9_]{5,11}$","g");
    // 
    
创建方式2:  /填写正则表达式/匹配模式;
    var reg2 = /^[a-zA-Z][a-zA-Z0-9_]{5,11}$/g;
View Code

正则对象的方法 - 验证字符串

测试一个字符串是否符合正则规则. 返回值是true 和false.

var re_obj=new RegExp("\d+","g");
alert(re_obj.test("asdf3245lsdk"))     //true
View Code

正则对象的方法 - 配合String对象的四个方法

String对象中的四个方法可以与正则结合使用: macth search split replace

var str = "hello world";
    
alert(str.match(/o/g));   //查找字符串中 复合正则的 内容.
alert(str.search(/h/g));   // 0  查找字符串中符合正则表达式的内容位置
alert(str.split(/o/g));    // 按照正则表达式对字符串进行切割. 返回数组;
alert(str.replace(/o/g, "s"));   // hells wsrld  对字符串按照正则进行替换.
View Code

 

Math对象

math对象是内置对象, 所以无需创建即可使用, 在调用时需要打出"Math."前缀.

Math对象的属性和方法

属性:
alert(Math.PI);

方法:

abs(x)    返回数的绝对值。
exp(x)    返回 e 的指数。
floor(x)对数进行下舍入。
log(x)    返回数的自然对数(底为e)。
max(x,y)    返回 x 和 y 中的最高值。
min(x,y)    返回 x 和 y 中的最低值。
pow(x,y)    返回 x 的 y 次幂。
random()    返回 0 ~ 1 之间的随机数。
round(x)    把数四舍五入为最接近的整数。
sin(x)    返回数的正弦。
sqrt(x)    返回数的平方根。
tan(x)    返回角的正切。
View Code

 

Function对象*

功能说明:

  • 可以使用变量、常量或表达式作为函数调用的参数
  • 函数由关键字function定义
  • 函数名的定义规则与标识符一致,大小写是敏感的
  • 返回值必须使用return

Function 类可以表示开发者定义的任何函数.

Function类直接创建函数

创建方式1:
function 函数名 (参数) {
    
函数体;
   return 返回值;
}

创建方式2:
var 函数名 = new Function("参数1" ,"参数n", "function_body");

// ------------方式1--------------

alert(1);
function func1(){
    alert('hello charon!');
    return 8;
}
    ret=func1();
    alert(ret)

// ------------方式2--------------
 
var func1=new Function("name","alert(\"hello\"+name);")
func1("charon")
View Code

注意:js的函数加载执行与python不同,它是整体加载完才会执行,所以执行函数放在函数声明上面或下面都可以

函数属于引用类型, 所以它们也有属性和方法.

Function对象的length属性

属性 length 声明了函数期望的参数个数

alert(func1.length)

Function对象的方法

Function对象也有与所有对象共享的 valueOf() 方法和 toString() 方法. 这两个方法返回的都是函数的源代码, 在调试时尤其有用.

运算符void()作用: 拦截方法的返回值

alert(void(fun1(1,2)))

函数的调用

function func1(a,b){
    alert(a+b);
}

    func1(1,2);  //3
    func1(1,2,3);//3
    func1(1);    //NaN
    func1();     //NaN
    //只要函数名写对即可,参数怎么填都不报错.

//-------------------面试题----------------
 function a(a,b){
    alert(a+b);
}

   var a=1;
   var b=2;
   a(a,b)
// 出错, 因为函数的名字跟后声明的变量的名字一样, 所以函数被变量覆盖了, 而变量不能加()调用, 所以报错
View Code

函数的内置对象arguments

function add(a,b){

        console.log(a+b);//3
        console.log(arguments.length);//2
        console.log(arguments);//[1,2]

    }
    add(1,2)

//    ------------------arguments的用处1 ------------------
    function nxAdd(){
        var result=0;
        for (var num in arguments){
            result+=arguments[num]
        }
        alert(result)

    }

    nxAdd(1,2,3,4,5)

//     ------------------arguments的用处2 ------------------

    function f(a,b,c){
        if (arguments.length!=3){
            throw new Error("function f called with "+arguments.length+" arguments,but it just need 3 arguments")
        }
        else {
            alert("success!")
        }
    }

    f(1,2,3,4,5)
View Code

匿名函数(自执行函数)

f=function () {
   alert(123)
};
f();
//------- 等同于 -------
(function () {
   alert(123)
})();



// 参数
(function (a) {
   alert(a)
})(234);
View Code

 

函数的作用域链和闭包

作用域

在Java/C#中, 代码块做为作用域, 例如if, while等控制语句有自己作用域.

在JavaScript/Python中, 函数做为作用域, 例如if, while等控制语句并没有自己作用域.

if(1==1){
    var s=12;
}
console.log(s);   //12

// ----------------------

function f(){
    var temp=666;
}
f();
console.log(temp);  //Uncaught ReferenceError: temp is not defined
View Code

嵌套函数的作用域:

    var city = 'beijing';

    function func(){
        var city = 'shanghai';
        function inner(){
            var city = 'shenzhen';
            console.log(city);
        }
        inner();
    }
    func();    //shenzhen
例1
    var city = 'beijing';
    function Bar(){
        console.log(city);
    }   
    function func(){
        var city = 'shanghai';
        return Bar;
    }
    var ret = func();
    ret();    //beijing
例2

闭包(closure):

闭包指的是函数可以使用函数之外定义的变量

    var city = 'beijing';
    function func(){
        var city = "shanghai";
        function inner(){
            // var city = "langfang";
            console.log(city);
        }
        return inner;
    }
    var ret = func();
    ret();   //shanghai
例1
var iBaseNum = 10;

function addNum(iNum1, iNum2) {
  function doAdd() {
    return iNum1 + iNum2 + iBaseNum;
  }
  return doAdd();
}
//这里内部函数doAdd()是一个闭包, 因为它将获取外部函数的参数 iNum1 和 iNum2 以及全局变量 iBaseNum 的值. addNum() 的最后一步调用了 doAdd(), 把两个参数和全局变量相加, 并返回它们的和.
例2

作用域链(Scope Chain):

由于JavaScript中的每个函数作为一个作用域, 如果出现函数嵌套函数, 则就会出现作用域链.

xo = 'alex';

function Func(){
    var xo = "seven";
    function inner(){
        var xo = 'alvin'; 
        console.log(xo);
    }
    inner();
}
Func();

如上述代码则出现三个作用域组成的作用域链,如果出现作用域链后,那么寻找变量时候就会出现顺序,对于上述实例:

当执行console.log(xo)时, 其寻找顺序为根据作用域链从内到外的优先级寻找, 如果内层没有就逐步向上找, 直到没找到抛出异常.

JavaScript的作用域链执行前已创建

JavaScript的作用域在被执行之前已经创建,日后再去执行时只需要按照作用域链去寻找即可。

示例一:

xo = 'alex';
 
function Func(){
    var xo = "seven";
    function inner(){
 
        console.log(xo);
    }
    return inner;
}
 
var ret = Func();
ret();
// 输出结果: seven

上述代码,在函数被调用之前作用域链已经存在:

  • 全局作用域 -> Func函数作用域 -> inner函数作用域

当执行【ret();】时,由于其代指的是inner函数,此函数的作用域链在执行之前已经被定义为:全局作用域 -> Func函数作用域 -> inner函数作用域,所以,在执行【ret();】时,会根据已经存在的作用域链去寻找变量。

示例二:

xo = 'alex';
 
function Func(){
    var xo = "eirc";
    function inner(){
 
        console.log(xo);
    }
    xo = 'seven';
    return inner;
}
 
var ret = Func();
ret();
// 输出结果: seven

上述代码和示例一的目的相同,也是强调在函数被调用之前作用域链已经存在:

  • 全局作用域 -> Func函数作用域 -> inner函数作用域

不同的时,在执行【var ret = Func();】时,Func作用域中的xo变量的值已经由 “eric” 被重置为 “seven”,所以之后再执行【ret();】时,就只能找到“seven”。

示例三:

xo = 'alex';<br>
function Bar(){
    console.log(xo);
}
 
function Func(){
    var xo = "seven";
     
    return Bar;
}
 
var ret = Func();
ret();
// 输出结果: alex

上述代码,在函数被执行之前已经创建了两条作用域链:

  • 全局作用域 -> Bar函数作用域
  • 全局作用域 -> Func函数作用域

当执行【ret();】时,ret代指的Bar函数,而Bar函数的作用域链已经存在:全局作用域 -> Bar函数作用域,所以,执行时会根据已经存在的作用域链去寻找。

声明提前:

在JavaScript中如果不创建变量,直接去使用,则报错:

console.log(xxoo);
// 报错:Uncaught ReferenceError: xxoo is not defined

JavaScript中如果创建值而不赋值,则该值为 undefined,如:

var xxoo;
console.log(xxoo);
// 输出:undefined

在函数内如果这么写:

function Foo(){
    console.log(xo);
    var xo = 'seven';
}
 
Foo();
// 输出:undefined

上述代码,不报错而是输出 undefined,其原因是:JavaScript的函数在被执行之前,会将其中的变量全部声明,而不赋值。所以,相当于上述实例中,函数在“预编译”时,已经执行了var xo;所以上述代码中输出的是undefined

     for (var i=1; i<=9; i++) {
        setTimeout( function timer(){ console.log(i);}, 1000 )
     }  //结果: 隔1秒后, 打印9次10

     for (var i=1; i<=9; i++) {
         ( function(){
             var j = i;
             setTimeout( function timer(){ console.log(j);}, 1000 )}
         )();
     }  //结果: 正常打印0-9, 因为以匿名函数的方式执行
思考题

  


BOM对象

BOM(浏览器对象模型), 可以对浏览器窗口进行访问和操作. 使用 BOM, 开发者可以移动窗口、改变状态栏中的文本以及执行其他与页面内容不直接相关的动作. 

BOM使 JavaScript 有能力与浏览器"对话".

BOM对象:

window对象

window对象
    所有浏览器都支持 window 对象。
    概念上讲.一个html文档(或者说浏览器上的一个标签页)对应一个window对象.
    功能上讲: 控制浏览器窗口的.
    使用上讲: window对象不需要创建对象,直接使用即可.

Window 对象方法

alert()            显示带有一段消息和一个确认按钮的警告框。
confirm()          显示带有一段消息以及确认按钮和取消按钮的对话框。
prompt()           显示可提示用户输入的对话框。

open()             打开一个新的浏览器窗口或查找一个已命名的窗口。
close()            关闭浏览器窗口。
setInterval()      按照指定的周期(以毫秒计)来调用函数或计算表达式。
clearInterval()    取消由 setInterval() 设置的 timeout。
setTimeout()       在指定的毫秒数后调用函数或计算表达式。
clearTimeout()     取消由 setTimeout() 方法设置的 timeout。
scrollTo()         把内容滚动到指定的坐标。
View Code
<script>
    acceptInput();
    var num = Math.round(Math.random()*100);
    function acceptInput() {
        //1.让用户输入(prompt)    并接受 用户输入结果
        var userNum = prompt("请输入一个0~100之间的数字!", "0");
        //2.将用户输入的值与 随机数进行比较
        if (isNaN(+userNum)) {
            //用户输入的无效(重复1,2步骤)
            alert("请输入有效数字!");
            acceptInput();
        }
        else if (userNum > num) {
            //大了==> 提示用户大了,让用户重新输入(重复2,3步骤)
            alert("您输入的大了!");
            acceptInput();
        } else if (userNum < num) {
            //小了==> 提示用户小了,让用户重新输入(重复2,3步骤)
            alert("您输入的小了!");
            acceptInput();
        } else {
            //答对了==>提示用户答对了 , 询问用户是否继续游戏(confirm).
            var result = confirm("恭喜您!答对了,是否继续游戏?");
            if (result) {
                //是 ==> 重复123步骤.
                num = Math.round(Math.random() * 100);
                acceptInput();
            } else {
                //否==> 关闭窗口(close方法).
                close();
            }
        }
    }
</script>

setInterval & clearInterval 和 setTimeout & clearTimeout

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<input type="text" id="clock" style="width: 249px">
<input type="button" value="begin" onclick="begin_click()">
<input type="button" value="End" onclick="End()">
<input type="button" value="timeout" onclick="f1()">

<script>
    function Timeout() {
        alert(123);
    }
    function f1() {
        var ID=setTimeout(Timeout,1000);
        //clearTimeout(ID)   //没反应, 因为在执行前已被清除
    }


    function begin() {
        var stime=getTime();
        var ret=document.getElementById("clock");
        ret.value=stime;
    }

    var ID;
    function begin_click() {
         if (ID==undefined){
              begin();
              ID=setInterval(begin,1000);
         }

    }
    function End() {

        clearInterval(ID);
        ID=undefined;
    }
    
    // 获取时间
    function getTime() {
     var date_obj= new Date();
    var year=date_obj.getFullYear();
    var month=date_obj.getMonth()+1;
    var day=date_obj.getDate();
    var hour=date_obj.getHours();
    var minute=date_obj.getMinutes();
    var seconds=date_obj.getSeconds();
    var week=date_obj.getDay();

    return year+"年"+month+"月"+f(day)+"日"+" "+hour+": "+minute+" :"+seconds+" "+num_week(week)
}
    function f(num) {
        if (num<10){
             return "0"+num;
        }
        return num;
    }
    function num_week(n) {
        week = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"]
        return week[n]
    }
</script>
</body>
</html>
View Code

 

History 对象

History 对象属性

History 对象包含用户(在浏览器窗口中)访问过的 URL。

History 对象是 window 对象的一部分,可通过 window.history 属性对其进行访问

属性 length: 返回浏览器历史列表中的 URL 数量

History 对象方法

back()    // 加载 history 列表中的前一个 URL。
forward()    // 加载 history 列表中的下一个 URL。
go()    // 加载 history 列表中的某个具体页面。
<a href="rrr.html">click</a>
<button onclick=" history.forward()">>>></button>
<button onclick="history.back()">back</button>
<button onclick="history.go(-1)">back</button>
View Code

 

Location 对象

Location 对象包含有关当前 URL 的信息.

Location 对象是 Window 对象的一个部分,可通过 window.location 属性来访问.

Location 对象方法

location.assign(URL)
location.reload()
location.replace(newURL)//注意与assign的区别
<input type="button" value="重载" onclick="location.reload()">
<input type="button" value="重载" onclick="location.href='http://www.baidu.com'">
View Code

 


DOM对象

DOM(Document Object Model)定义了访问HTML和XML文档的标准.

DOM是中立于平台和语言的接口, 它允许程序和脚本动态地访问和更新文档的内容, 结构和样式.

DOM 标准被分为3个不同的部分:

  • 核心 DOM - 针对任何结构化文档的标准模型
  • XML DOM - 针对 XML 文档的标准模型, 定义了所有 XML 元素的对象和属性, 以及访问它们的方法
  • HTML DOM - 针对 HTML 文档的标准模型, 定义了所有 HTML 元素的对象和属性, 以及访问它们的方法

HTML DOM就是关于如何获取, 修改, 添加或删除HTML元素的标准.

DOM节点 

在HTML DOM中, 所有事物都是节点. DOM 是被视为节点树的 HTML.

HTML 文档中的所有内容都是节点(NODE):

  • 整个文档是一个文档节点(document对象)
  • 每个 HTML 元素是元素节点(element 对象)
  • HTML 元素内的文本是文本节点(text对象)
  • 每个 HTML 属性是属性节点(attribute对象)
  • 注释是注释节点(comment对象)

节点树中的节点彼此拥有层级关系:

父(parent), 子(child)和同胞(sibling)等术语用于描述这些关系. 父节点拥有子节点, 同级的子节点被称为兄弟节点.

  • 在节点树中, 顶端节点被称为根(root)
  • 每个节点都有父节点, 除了根之外
  • 一个节点可拥有任意数量的子节点
  • 兄弟节点是拥有相同父节点的节点

 

DOM属性

DOM树是为了展示文档中各个对象之间的关系, 用于对象的导航.

节点(自身)属性:

  • attributes - 节点(元素)的属性节点
  • nodeType - 节点类型
  • nodeValue - 节点值
  • nodeName - 节点名称
  • innerHTML - 节点(元素)的文本值

导航属性:

  • parentNode - 节点(元素)的父节点
  • firstChild - 节点下第一个子元素
  • lastChild - 节点下最后一个子元素
  • childNodes - 节点(元素)的子节点 

推荐的导航属性:

  • parentElement - 父节点标签元素  
  • children - 所有子标签    
  • firstElementChild - 第一个子标签元素  
  • lastElementChild - 最后一个子标签元素  
  • nextElementtSibling - 下一个兄弟标签元素  
  • previousElementSibling - 上一个兄弟标签元素
<script>
    var ele=document.getElementById("div1");
    //firstchild
    var ele2=ele.firstChild;
    alert(ele2.nodeName);  //#text, 它的firstchild是div之后的文本
    //lastchild
    var ele3=ele.lastChild;
    alert(ele3.nodeName);   //#text
    //childNodes
    var ele3=ele.childNodes;
    alert(ele3.length);   //5
    //parentNode
    var ele3=ele.parentNode;
    alert(ele3.nodeName);   //BODY


    console.log(ele.nodeName);   //DIV
    console.log(ele.nodeType);   //1
    console.log(ele.nodeValue);   //null

    //--------------- 推荐方式 ------------------------
    var ele=document.getElementById("div1");
    //firstElementChild
    var ele_son=ele.firstElementChild;
    alert(ele_son.nodeName)    //DIV
    //lastElementChild
    var ele_son=ele.lastElementChild;
    alert(ele_son.nodeName);   //P
    //children
    var ele_sons=ele.children;
    alert(ele_sons.length);   //2
    //parentElement
    var ele_son = ele.parentElement;
    alert(ele_son.nodeName);   //BODY

    alert(ele_sons[0]);   //[object HTMLDivElement]
    for (var i=0;i<ele_sons.length;i++){
        console.log(ele_sons[i])
    }


    var ele=document.getElementById("div1").firstElementChild;
    var sib=ele.nextElementSibling;
    alert(sib.nodeName);   //P
    //这些属性都是为了对文档树进行导航;
</script>
View Code

 

DOM访问

访问HTML元素等同于访问节点, 能以不同的方式来访问HTML元素:

全局查找 - 查找整个页面的元素:

  • 通过使用 getElementById() 方法 
  • 通过使用 getElementsByTagName() 方法 
  • 通过使用 getElementsByClassName() 方法 
  • 通过使用 getElementsByName() 方法 

局部查找 - 查找子节点下的元素:

  • 通过使用 getElementsByTagName() 方法 
  • 通过使用 getElementsByClassName() 方法 
<div id="div1">hello
     <div class="div2">hello 2</div>
     <div class="div3" name="alan">hello 3
          <p >hello inner</p>
          <p id="ppp">hello inner2</p>
          <p class="ppp">hello inner3</p>
          <p name="alex">hello inner4</p>
     </div>
     <p>hello p</p>
</div>

<script>
    //--------- 全局查找 -------------
    //通过ID
    var temp=document.getElementById("div1");
    //通过class
    var ele=document.getElementsByClassName("div2")[0];
    var ele2=ele.nextElementSibling;
    alert(ele2.innerHTML);
    //通过tag
    var tag=document.getElementsByTagName("p");
    alert(tag[0].innerHTML)
    //通过Name


    //--------- 局部查找 -------------
    var ele=document.getElementsByClassName("div3")[0];

    //局部查找可以通过 TagName
    var ele2=ele.getElementsByTagName("p");
    alert(ele2.innerHTML)
    alert(ele2.length)

    //局部查找可以通过 class
    var ele4=ele.getElementsByClassName("ppp");
    alert(ele4);


    //局部查找不可以通过 Name
    var ele5=ele.getElementsByName("alex");
    alert(ele5);

    //局部查找不可以通过ID, 因为ID是全局唯一, 无需在局部查找
    var ele3 =ele.getElementById("ppp");
    alert(ele3.innerHTML);
</script>
View Code

注意:

<p>Charon</p>
<p>Alan</p>

<script>
    doms=document.getElementsByTagName("p");

    for (var i in doms){
       console.log(i); // 0 1 length item namedItem
       // console.log(doms[i])   //获取DOM对象和所有属性的值
    }

//用上面的for循环可以获取一个DOM元素集, 元素集包含了对象的所有属性

//用下面这种for循环可以获取DOM对象

    for (var i=0;i<doms.length;i++){
        console.log(i) ; // 0 1
        // console.log(doms[i])  //获取DOM对象
    }
</script>
View Code

 

DOM Event(事件)

DOM允许JavaScript对HTML事件作出反应, 即HTML事件可以触发浏览器中的动作(action). 下面是一个属性列表, 这些属性可插入 HTML 标签来定义事件动作.

onclick        当用户点击某个对象时调用的事件句柄
ondblclick     当用户双击某个对象时调用的事件句柄

onfocus        元素获得焦点      应用场景: 输入框         
onblur         元素失去焦点      应用场景:用于表单验证,用户离开某个输入框时,代表已经输入完了,我们可以对它进行验证.
onchange       域的内容被改变    应用场景:通常用于表单元素,当元素内容被改变时触发.(三级联动)

onkeydown      某个键盘按键被按下      应用场景: 当用户在最后一个输入框按下回车按键时,表单提交.
onkeypress     某个键盘按键被按下并松开
onkeyup        某个键盘按键被松开
onload         一张页面或一幅图像完成加载
onmousedown    鼠标按钮被按下
onmousemove    鼠标被移动
onmouseout     鼠标从某元素移开
onmouseover    鼠标移到某元素之上
onmouseleave 鼠标从元素离 onselect 文本被选中 onsubmit 确认按钮被点击

绑定事件的两种方式(为元素附加事件属性):

<div id="div1" onclick="func1()">hello div
    <p class="ppp">hello p</p>  //事件传播, 点击hello p会alert哈哈再alert不要
</div>

<script>
    var obj=document.getElementsByClassName("ppp")[0];
    obj.onclick=function () {
        alert("哈哈");
    }

    function func1(){
        alert("不要")
    }
    
</script>
View Code

注意1: this & self, void

<div id="abc" onclick="func1(this)">事件绑定方式1</div>
<div id="id123">事件绑定方式2</div>
<script>
    function func1(self){
        console.log(self.id)
    }

//------------------------------------------

    var ele=document.getElementById("id123").onclick=function(){
         console.log(this.id);
    }
</script>
View Code
    <div>haha
        <div>heihei
            <!--this: 当前触发的标签对象-->
            <div onclick="show(this)" ha="123" id="id1">click</div>
            <div onclick="show(this)" ha="456">click</div>
            <div onclick="show(this)" ha="163">click</div>
            <div onclick="show(this)" ha="132">click</div>
            <div onclick="show(this)" ha="752">click</div>
            <p>lala</p>
        </div>
    </div>
    <!--void()使函数不能返回有效值(清除所有返回值)-->
    <a href="javascript:void(0)">不跳转</a>
    <a href="#">跳转</a>
    <a href="javascript:ale()">函数</a>
    <a href="javascript:void(window.open('about:blank'))">Click me</a>

    <script>
        function show(aa) {
            console.log(aa.getAttribute("ha"))
            console.log(aa.getAttribute("id"))
        }
        function ale() {
            alert("charon")
        }
    </script>
View Code

注意2: 事件传播

<div id="abc_1" style="border:1px solid red;width:300px;height:300px;">
    <div id="abc_2" style="border:1px solid red;width:200px;height:200px;"></div>
</div>
    <script type="text/javascript">
    document.getElementById("abc_1").onclick=function(){
        alert('111');
    }
    document.getElementById("abc_2").onclick=function(event){
        alert('222');
        event.stopPropagation();  //阻止事件向外层div传播.
    }
    
</script>
View Code

 

onload:

onload 属性只会给body元素加.
这个属性的触发标志着页面内容被加载完成.
应用场景: 页面加载完立刻执行,那么可以使用该事件属性.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <script>
//          window.onload=function(){
//               var ele=document.getElementById("ppp");
//               ele.onclick=function(){
//                alert(123)
//            };
//          };



          function fun1() {
              var ele=document.getElementById("ppp");
               ele.onclick=function(){
                alert(123)
            };
          }

    </script>
</head>
<body onload="fun1()">

<p id="ppp">hello p</p>

</body>
</html>
View Code

onsubmit:

是当表单在提交时触发. 该属性也只会给form元素使用.

应用场景: 在表单提交前验证用户输入是否正确.如果验证失败.在该方法中我们应该阻止表单的提交.

<form id="form">
            <input type="text"/>
            <input type="submit" value="点我!" />
</form>

<script type="text/javascript">
            //阻止表单提交方式1().
            //onsubmit 命名的事件函数,可以接受返回值. 其中返回false表示拦截表单提交.其他为放行.

            var ele=document.getElementById("form");
            ele.onsubmit=function(event) {
//                alert("验证失败 表单不会提交!");
//                return false;
                
            // 阻止表单提交方式2 event.preventDefault(); ==>通知浏览器不要执行与事件关联的默认动作。
             alert("验证失败 表单不会提交!");
             event.preventDefault();

    }
View Code

onchange:

当内容发生变化时触发. 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<select  onchange="fun3()">
    <option>上海</option>
    <option>北京</option>
    <option>河北</option>
</select>

<script>
    function fun3() {
        alert(1234);
    }
</script>


</body>
</html>
View Code

onkeypress & keycode

获取用户按下的键

<p style="width: 500px;height: 200px;background-color: cyan;" id="showZone"></p>
<script>
    document.onkeydown=function(event){
        var event=event||window.event;

        document.getElementById("showZone").innerHTML=event.keyCode;
    }
</script>
View Code

判断是否为回车键

<input id="chatMsg" name="chatMsg" type="text" size="90" onkeypress="enterHandler(event);"/>

<script>
    function enterHandler(event) {
        //获取用户单击键盘的“键值”
        var keyCode = event.keyCode ? event.keyCode : event.which;
        //如果是回车键
        if (keyCode == 13) {
            alert("hit enter")
        }
    }
</script>
View Code

 

DOM操作 (操作, 查)

查:

1. 直接查找

document.getElementById             // 根据ID获取一个标签
document.getElementsByName          // 根据name属性获取标签集合
document.getElementsByClassName     // 根据class属性获取标签集合
document.getElementsByTagName       // 根据标签名获取标签集合

2. 间接查找 

parentNode          // 父节点
childNodes          // 所有子节点
firstChild          // 第一个子节点
lastChild           // 最后一个子节点
nextSibling         // 下一个兄弟节点
previousSibling     // 上一个兄弟节点
 
parentElement           // 父节点标签元素
children                // 所有子标签
firstElementChild       // 第一个子标签元素
lastElementChild        // 最后一个子标签元素
nextElementtSibling     // 下一个兄弟标签元素
previousElementSibling  // 上一个兄弟标签元素

操作:

1. HTML内容操作

  改变元素内容的最简答的方法是使用 innerHTML, innerText.

2. HTML属性操作  

setAttribute(key,value)   // 设置标签属性
getAttribute(key)         // 获取指定标签属性
 

var atr = document.createAttribute("class");
atr.nodeValue="democlass";
document.getElementById('n1').setAttributeNode(atr);

3. CSS样式操作

var obj = document.getElementById('i1')
 
obj.style.fontSize = "32px";
obj.style.backgroundColor = "red";

4. HTML标签操作

a. 创建

var tag = document.createElement('a');
tag.innerText = "charon";
tag.className = "c1";
tag.href = "http://www.baidu.com";

xxx.appendChild(tag);

b. 删除

获得要删除的元素
获得它的父元素
使用removeChild();方法删除
<script type="text/javascript">
//在第一个div中动态增加一个a标签. 该a标签点击之后跳转到百度首页.
    function addNode(){
        //1.获得 第一个div
        var div = document.getElementById("div_1");
        //2.创建a标签  createElement==>创建一个a标签   <a></a>
        var eleA =  document.createElement("a");
        //3.为a标签添加属性 <a href="http://www.baidu.com"></a>
        eleA.setAttribute("href", "http://www.baidu.com");
        //4.为a标签添加内容 <a href="http://www.baidu.com">百度</a>
        eleA.innerHTML = "百度";    
        //5.将a标签添加到div中
        div.appendChild(eleA);
    }
    //点击后 删除div区域2
    function deleteNode(){
        //1 获得要删除的div区域
            var div = document.getElementById("div_2");
        //2.获得父亲
            var parent = div.parentNode;
        //3 由父亲操刀 
            parent.removeChild(div);
    }
    //点击后 替换div区域3 为一个美女
    function updateNode(){
        //1 获得要替换的div区域3
        var div = document.getElementById("div_3");
        //2创建img标签对象 <img />
        var img = document.createElement("img");
        //3添加属性 <img src="001.jpg" />
        img.setAttribute("src", "001.JPG");
        //4.获得父节点
        var parent = div.parentNode;
        //5.替换
        parent.replaceChild(img, div);
    }
    //点击后 将div区域4 克隆一份 添加到页面底部
    
    function copyNode(){
        //1.获取要克隆的div
        var div = document.getElementById("div_4");
        //2.克隆 参数为true 那么克隆时克隆所有子元素. false 只克隆自己
        var div_copy = div.cloneNode(true);
        //3.获得父亲
        var parent = div.parentNode;
        //4.添加
        parent.appendChild(div_copy);
    }
    
    
</script>
View Code

5. Class操作

className                // 获取所有类名
classList.remove(cls)    // 删除指定类
classList.add(cls)       // 添加类

6. 位置操作

document.documentElement.offsetHeight   // 总文档高度
document.documentElement.clientHeight   // 当前文档占屏幕高度
tag.offsetHeight   // 自身高度 
tag.offsetTop    // 距离上级定位高度 
tag.offsetParent    // 父定位标签 
tag.scrollTop     // 滚动高度

/*
    clientHeight -> 可见区域:height + padding
    clientTop    -> border高度
    offsetHeight -> 可见区域:height + padding + border
    offsetTop    -> 上级定位标签的高度
    scrollHeight -> 全文高:height + padding
    scrollTop    -> 滚动高度
    特别的:
        document.documentElement代指文档根节点
*/
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body style="margin: 0;">
    <div style="height: 900px;">

    </div>
    <div style="padding: 10px;">
        <div id="i1" style="height:190px;padding: 2px;border: 1px solid red;margin: 8px;">
                <p>asdf</p>
                <p>asdf</p>
                <p>asdf</p>
                <p>asdf</p>
                <p>asdf</p>
        </div>
    </div>

    <script>
        var i1 = document.getElementById('i1');

        console.log(i1.clientHeight); // 可见区域:height + padding
        console.log(i1.clientTop);    // border高度
        console.log('=====');
        console.log(i1.offsetHeight); // 可见区域:height + padding + border
        console.log(i1.offsetTop);    // 上级定位标签的高度
        console.log('=====');
        console.log(i1.scrollHeight);   //全文高:height + padding
        console.log(i1.scrollTop);      // 滚动高度
        console.log('=====');

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

7. 提交表单

document.geElementById('form').submit()

 

实例练习

0. title部分跑马灯

<!DOCTYPE html>
<html>
    <head>
        <meta charset='utf-8' >
        <title>欢迎blue shit莅临指导&nbsp;&nbsp;</title>
        <script type='text/javascript'>
            function Go(){
                var content = document.title;
                var firstChar = content.charAt(0)
                var sub = content.substring(1,content.length)
                document.title = sub + firstChar;
            }
            setInterval('Go()',1000);
        </script>
    </head>
    <body>
    </body>
</html>
View Code

1. 输入框

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<input id="ID1" type="text" value="请输入用户名" onblur="Blurs()" onfocus="Focus()">

<script>
function Focus(){

    var input=document.getElementById("ID1");
    // if (input.value=="请输入用户名"){
    //     input.value="";
    // }
    input.value="";
}

function Blurs(){
    var ele=document.getElementById("ID1");
    var val=ele.value;
    if(!val.trim()){
        ele.value="请输入用户名";
    }
}
</script>
</body>
</html>
View Code

2. 弹出框

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        *{
            margin: 0;
        }
        #div1{
            position: fixed;
            width: 100%;
            top: 0;
            left: 0;
            height: 2000px;
            background-color: #b4b4b4;
            z-index: 1000;
        }
        #div2{

            position: fixed;
            width: 100%;
            z-index: 1001;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-color: red;
            opacity: 0.1;
        }

        #div3{

            height: 200px;
            width: 200px;
            background-color: blueviolet;
            position: absolute;
            top: 50%;
            left: 50%;
            z-index: 1002;
            margin-left: -100px;
            margin-top: -100px;

        }

        .hide{
             display: none;
        }
    </style>
</head>
<body>

<div id="div1" >
    <input type="button" value="click" onclick="show()">
</div>
<div id="div2" class="div hide"></div>
<div id="div3" class="div hide">
    <input type="button" value="cancel" onclick="cancel()">
</div>

<script>
    function show() {
         var ele=document.getElementsByClassName("div")
         for (var i=0;i<ele.length;i++){
             ele[i].classList.remove("hide")
        }

    }
    function cancel() {
          var ele=document.getElementsByClassName("div")
        for (var i=0;i<ele.length;i++){
             ele[i].classList.add("hide")
        }

    }
</script>
</body>
</html>
View Code

3. 正反选

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
     <button onclick="select('all');">全选</button>
     <button onclick="select('cancel');">取消</button>
     <button onclick="select('reverse');">反选</button>

     <table border="1" id="Table">
         <tr>
             <td><input type="checkbox"></td>
             <td>111</td>
         </tr>
         <tr>
             <td><input type="checkbox"></td>
             <td>222</td>
         </tr>
         <tr>
             <td><input type="checkbox"></td>
             <td>333</td>
         </tr>
         <tr>
             <td><input type="checkbox"></td>
             <td>444</td>
         </tr>
     </table>


<script>
    function select(choice){
        var ele=document.getElementById("Table");

        var inputs=ele.getElementsByTagName("input");
        for (var i=0;i<inputs.length;i=i+1){

            var ele2=inputs[i];
            if (choice=="all"){
                ele2.checked=true;

            }else if(choice=="cancel"){
                ele2.checked=false;
            }
            else {

                if (ele2.checked){
                    ele2.checked=false;
                }else {
                    ele2.checked=true;
                }
            }

            }
    }
</script>
</body>
</html>
View Code

4. 选择框二级联动

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<select name="province" id="province" onchange="func1(this)"></select>

<select name="city" id="city" onchange=""></select>



<script>
    data = {"福建":["厦门","泉州"],"北京":["朝阳","海淀"],"香港":["九龙","新界"],"深圳":["罗湖","福田"]};

    var pro = document.getElementById("province");
    for(var i in data){    // for i in key
        var option_pro = document.createElement("option");
        option_pro.innerHTML= i;
        pro.appendChild(option_pro);
    }


    function func1(self) {
        var choice = self.options[self.selectedIndex].innerHTML;  //self.options => 获取所有键,返回一个数组
                                                                // self.selectedIndex => 返回当前键的index

        // 清空上次选的键的值,方式一
        city.options.length = 0;

        // 清空上次选的键的值,方式二
        // for(var k=0; k<city.options.length; k++){
        //     city.removeChild(city.options[k--]);  // 因为当remove第一个child, 下个child自动变成第一个, 故需k--. 即每次remove的都是city.options[0]
        // }

        for (var i in data[choice]){    // for i in value
            var option_city = document.createElement("option");
            option_city.innerHTML = data[choice][i];
            city.appendChild(option_city);
        }
    }


</script>
</body>
</html>
View Code

5. 选择框左右移动

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        #box_L,#choice,#box_R{
            display: inline-block;
        }
    </style>
</head>
<body>
<div id="box_L">
    <select multiple="multiple" size="10" id="left">
        <option>book1</option>
        <option>book2</option>
        <option>book3</option>
        <option>book4</option>
        <option>book5</option>
        <option>book6</option>
    </select>
</div>


<div id="choice">
    <input class="add"     type="button" value="--->" onclick="add()"><br>
    <input class="remove"  type="button" value="<---" onclick="remove();"><br>
    <input class="add-all" type="button" value="===>" onclick="addall()"><br>
    <input class="remove-all" type="button" value="<===" onclick="removeall()">
</div>


<div id="box_R">
    <select multiple="multiple" size="10" id="right">
        <option>book9</option>
    </select>
</div>

<script>
    var right = document.getElementById("right");
    var left = document.getElementById("left");
     function add(){
         // var options=document.getElementById("left").getElementsByTagName("option");
         var options = left.children;
         for (var i=0; i<options.length;i++){
             if(options[i].selected == true){
                 options[i].selected=false;
                 right.appendChild(options[i]);
                 i--;
             }
         }
     }

    function addall(){
         // var options=document.getElementById("left").getElementsByTagName("option");
         var options = left.children;
         for (var i=0; i<options.length;i++){
             var option=options[i];
             right.appendChild(option);
             i--;
         }
     }

    function remove(){
         // var options=document.getElementById("left").getElementsByTagName("option");
         var options = right.children;
         for (var i=0; i<options.length;i++){
             if(options[i].selected == true){
                 options[i].selected=false;
                 left.appendChild(options[i]);
                 i--;
             }
         }
     }

    function removeall(){
         // var options=document.getElementById("left").getElementsByTagName("option");
         var options = right.children;
         for (var i=0; i<options.length;i++){
             var option=options[i];
             left.appendChild(option);
             i--;
         }
     }

</script>
</body>
</html>
View Code

6. 滚动高度

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<style>

    body{
        margin: 0px;
    }
    img {
        border: 0;
    }
    ul{
        padding: 0;
        margin: 0;
        list-style: none;
    }
    h1{
        padding: 0;
        margin: 0;
    }
    .clearfix:after {
        content: ".";
        display: block;
        height: 0;
        clear: both;
        visibility: hidden;
    }

    .wrap{
        width: 980px;
        margin: 0 auto;
    }

    .pg-header{
        background-color: #303a40;
        -webkit-box-shadow: 0 2px 5px rgba(0,0,0,.2);
        -moz-box-shadow: 0 2px 5px rgba(0,0,0,.2);
        box-shadow: 0 2px 5px rgba(0,0,0,.2);
    }
    .pg-header .logo{
        float: left;
        padding:5px 10px 5px 0px;
    }
    .pg-header .logo img{
        vertical-align: middle;
        width: 110px;
        height: 40px;

    }
    .pg-header .nav{
        line-height: 50px;
    }
    .pg-header .nav ul li{
        float: left;
    }
    .pg-header .nav ul li a{
        display: block;
        color: #ccc;
        padding: 0 20px;
        text-decoration: none;
        font-size: 14px;
    }
    .pg-header .nav ul li a:hover{
        color: #fff;
        background-color: #425a66;
    }
    .pg-body{

    }
    .pg-body .catalog{
        position: absolute;
        top:60px;
        width: 200px;
        background-color: #fafafa;
        bottom: 0px;
    }
    .pg-body .catalog.fixed{
        position: fixed;
        top:10px;
    }

    .pg-body .catalog .catalog-item.active{
        color: #fff;
        background-color: #425a66;
    }

    .pg-body .content{
        position: absolute;
        top:60px;
        width: 700px;
        margin-left: 210px;
        background-color: #fafafa;
        overflow: auto;
    }
    .pg-body .content .section{
        height: 900px;
        border: 1px solid red;
    }
</style>
<body onscroll="ScrollEvent();">
<div class="pg-header">
    <div class="wrap clearfix">
        <div class="logo">
            <a href="#">
                <img src="http://core.pc.lietou-static.com/revs/images/common/logo_7012c4a4.pn">
            </a>
        </div>
        <div class="nav">
            <ul>
                <li>
                    <a  href="#">首页</a>
                </li>
                <li>
                    <a  href="#">功能一</a>
                </li>
                <li>
                    <a  href="#">功能二</a>
                </li>
            </ul>
        </div>

    </div>
</div>
<div class="pg-body">
    <div class="wrap">
        <div class="catalog" id="catalog">
            <div class="catalog-item" auto-to="function1"><a>第1张</a></div>
            <div class="catalog-item" auto-to="function2"><a>第2张</a></div>
            <div class="catalog-item" auto-to="function3"><a>第3张</a></div>
        </div>
        <div class="content" id="content">
            <div menu="function1" class="section">
                <h1>第一章</h1>
            </div>
            <div menu="function2" class="section">
                <h1>第二章</h1>
            </div>
            <div menu="function3" class="section" style="height: 200px;">
                <h1>第三章</h1>
            </div>
        </div>
    </div>

</div>
    <script>
        function ScrollEvent(){
            var bodyScrollTop = document.body.scrollTop;
            if(bodyScrollTop>50){
                document.getElementsByClassName('catalog')[0].classList.add('fixed');
            }else{
                document.getElementsByClassName('catalog')[0].classList.remove('fixed');
            }

            var content = document.getElementById('content');
            var sections = content.children;
            for(var i=0;i<sections.length;i++){
                var current_section = sections[i];

                // 当前标签距离顶部绝对高度
                var scOffTop = current_section.offsetTop + 60;

                // 当前标签距离顶部,相对高度
                var offTop = scOffTop - bodyScrollTop;

                // 当前标签高度
                var height = current_section.scrollHeight;

                if(offTop<0 && -offTop < height){
                    // 当前标签添加active
                    // 其他移除 active

                    // 如果已经到底部,现实第三个菜单
                    // 文档高度 = 滚动高度 + 视口高度

                    var a = document.getElementsByClassName('content')[0].offsetHeight + 60;
                    var b = bodyScrollTop + document.documentElement.clientHeight;
                    console.log(a+60,b);
                    if(a == b){
                        var menus = document.getElementById('catalog').children;
                        var current_menu = document.getElementById('catalog').lastElementChild;
                        current_menu.classList.add('active');
                        for(var j=0;j<menus.length;j++){
                            if(menus[j] == current_menu){

                            }else{
                                menus[j].classList.remove('active');
                            }
                        }
                    }else{
                        var menus = document.getElementById('catalog').children;
                        var current_menu = menus[i];
                        current_menu.classList.add('active');
                        for(var j=0;j<menus.length;j++){
                            if(menus[j] == current_menu){

                            }else{
                                menus[j].classList.remove('active');
                            }
                        }
                    }
                    break;
                }
            }
        }
    </script>
</body>
</html>
View Code

 

 

 

 

posted @ 2018-03-05 12:25  Charonnnnn  阅读(141)  评论(0)    收藏  举报