JavaScript -- 李立超
JavaScript - 李立超
JS = ECMAScript(标准) + DOM + BOM
JS特点:
- 解释型语言
- 动态语言
- 基于原型的面向对象
JS代码需要编写到script中
alert:控制浏览器弹出警告框
alert("你好");
让计算机在页面中输出一个内容
document.write( )可以向body中输出内容
document.write("我是输出的内容");
向控制台输出一个内容
console.log()的作用是向控制台输出内容
console.log("我是向输出台输出的内容");
JS代码从上往下执行代码
3.js编写位置
可以将js代码编写到变迁的onclick属性中,当我们点击按钮时,js代码才会执行
虽然可以卸载标签的属性中,但是它们属于结构与行为耦合,不方便维护,所以不推荐使用
<button onclick="alert('叫你点你就点啊?');">麻烦点我一下</button>
可以将js代码卸载超链接的href属性中,这样当点击超链接时,会执行js代码
<a href="javascript:alert('没完没了了是吧')">你也点我一下</a>
<a href="javascript:;">点了也没用</a>
可以将js代码编写到script标签中(也不推荐使用)
<script type="text/javascript">
alert("我是script标签中的代码");
</script>
可以将js代码编写到外部js文件中,然后通过script标签引入
写到外部文件中可以再不同的页面中同时引用,也可以利用到浏览器的缓存机制
<推荐使用>
<script type="text/javascript" src="js/script.js">
/*src是路径*/
</script>
script标签一旦用于引入外部文件了,就不能再编写代码了,即使编写了浏览器也会忽略,如果需要则可以再创建一个新的script标签用于编写内部代码
4.JS基本语法
JS严格区分大小写,且每一条语句以分号(;)结尾
JS中会忽略多个空格和换行,所以我们可以利用空格和换行对代码进行格式化
5.字面量和变量
字面量:都是不可改变的值,字面量可以直接使用
变量 :可以用来保存字面量,而且变量的值是可以任意改变的,开发中都是通过变量去保存一个字面量,
可以通过变量对字面量进行描述
声明变量:使用var关键字来声明一个变量
var a = 123;
console.log(a);
6.标识符
在JS中所有可以由我们自主命名的都可以称作标识符,例如:变量名、函数名、属性名都属于标识符
命名规则:1.可以含有字母、数字、_、$
2.标识符不能以数字开头
3.标识符不能是ES中的关键字或保留字
4.标识符一般都采用驼峰命名法
7.数据类型
数据类型指的是字面量的类型
在JS中一共有6种数据类型
String 字符串
Number 数值
Boolean 布尔值
Null 空值
Undefined 未定义
Object 对象
String、Numer、Boolean、Null、Undefined属于基本数据类型
Object 属于引用类型
在JS中String字符串需要使用引号引起来
\t 表示制表符
在JS中所有的数值都是Number类型,包括整数和浮点数(小数)
可以使用typeof来检查变量的类型
语法:typeof 变量 比如:(typeof a)
NaN 是一个特殊的数字,表示not a number
a = NaN;
console.log(typeof a); /*类型为number*/
JS使用进行浮点计算,可能得到一个不精确的结果,所以不要使用JS进行对精确度要求比较高的运算
使用typeof检查一个布尔值时,会返回boolean
Null类型的值只有一个,就是null null这个值专门用来表示一个为空的对象
使用typeof检查一个null值时,会返回object
Undefined类型的值只有一个,就是undefined
当声明一个变量,但是并不给变量赋值时,它的值就是undefined
var a = null;
console.log(a);
11.强制类型转换--将其他的数据类型转换为String
方式一:调用被转换数据类型的toString( )方法 //被转换类型.toString( );
该方法不会影响到原变量,它会将转换的结果返回
注意:null和undefined这两个值没有toString方法,如果调用他们的方法,会报错
方式二:
-
调用String( )函数,并将被转换的数据作为参数传递给函数
-
使用String( )函数做强制类型转换时,
对于Number和Boolean实际上就是调用的toString( )方法
但是对于null和undefinded,就不会调用toString( )方法,
它会将 null 直接转换为 "null"
将undefined 直接转换为 "undefined"
/*调用String()函数,来将a转换为字符串*/
a = String(a);
12.强制类型转换--将其他的数据类型转换为Number
转换方式一:使用Number( )函数
字符串 - - >数字
1.如果是纯数字的字符串,则直接将其转换为数字
2.如果字符串中有非数字的内容,则转换为NaN
3.如果字符串时一个空串或者是一个全是空格的字符串, 则转换为0
4.布尔->数字 true转成1 false转成0
5.null ->0
6.undefined -> NaN
var a = "abc";
//调用Number()函数来将a转换为Number类型
a = Number(a);
console.log(typeof a);
console.log(a);
转换方式二:
- 这种方式专门用来对付字符串
- parseInt( )把一个字符串转换为一个整数
- parseFloat( )把一个字符串转换为一个浮点数
a = "123px";
//调用parseInt()函数将a转换为Number
a = parseInt(a);
//parseInt()可以将字符串中的有效的整数内容取出来,然后转换为Number
console.log(typeof a);
console.log(a)
/*parseFloat()作用和parseInt()类似,不同的是它可以获得有效的小数
如果对非String使用parseInt()或parseFloat()
它会先将其转换为String,然后再操作 */
14.将其他的数据类型转换为Boolean
//使用Boolean( )函数
var a = 123;
//调用Boolean()函数来将a转换为布尔值,
//除了0、空串、null、undefined、NaN,其余都是true
//对象也会转化为true
a = Boolean(a);
console.log(typeof a);
console.log(a);
15.运算符也叫操作符
typeof会将该值得类型以字符串的形式返回
当对非Number类型的值进行运算时,会将这些值转换为Number然后再运算(字符串拼接会相加)
任何值和NaN做运算都得NaN
任何值和字符串做加法运算,都会先转换为字符串,然后再和字符串做拼接(可以利用这一特点,来将一个任意的数据类型转换为String。这是一种隐式的类型转换,由浏览器自动完成,实际上它也是调用String( ))
result = 2*null //0
% 取余
16.一元运算符
+,正号不会对数字产生任何影响
-,负号对数字进行取反
对于非Number类型的值,它会先将其转换为Number,然后再运算
可以对一个其他的数据类型使用+,来将其转换为number,原理同Number( )函数
自增(自减同理)
无论a++还是++a,都会立即使原变量的值自增1
不同点:a++和++a的值不同
a++的值等于原变量的值(自增前的值)
++a的值等于新值(自增后的值)
与运算:
如果第一个值为true,则返回第二个值
如果第一个值为false,则返回第一个值
或运算:
如果第一个值为true,则直接返回第一个值
如果第一个值为false,则返回第二个值
任何值和NaN做任何比较都是false
比较两个字符串时,比较的是字符串的字符编码
比较字符编码时,是一位一位进行比较的,如果两位一样则比较下一位
,可以用来排序
比较两个字符串型数字时,一定要转型
字符串中使用转义字符输出Unicode编码
\u四位编码
在网页中使用Unicode编码:
&#编码;这里的编码需要的是10进制
24.相等运算符
用来比较两个值是否相等,如果相等返回true,否则false
使用 == 来做相等运算:当使用==来比较两个值,如果值的类型不同,则会自动进行类型转换,将其转换为相同的类型,然后再比较
undefined衍生自null
所以这两个值做相等判断时,会返回true
NaN不和任何值相等,包括他本身
=== 全等(不全等同理):和相等的区别是,不会做自动的类型转换,如果两个值的类型不同,直接返回false
条件运算符 语法:
html条件表达式?语句1:语句2
//执行流程:条件运算符在执行时,首先对条件表达式进行求值
//如果该值为true,则执行语句1,并返回结果
//如果该值为false,则执行语句2,并返回结果
//获取a和b的最大值
var max = a > b ? a : b;
26.运算符优先级
&&比||优先级高
27.代码块
JS中的代码块只有分组的作用
29.if
如果所有条件都不满足,则执行最后else后面的语句
prompt( )可以弹出一个提示框,该提示框中会带有一个文本框,用户可以在文本框中输入内容,该函数需要一个字符串作为参数,该字符串将会作为提示框的提示文字
用户输入的内容将会作为函数的返回值返回,可以定义一个变量来接收该内容
var score = prompt("请输入小明的成绩:");
31.判断条件是否是NaN:
if(isNaN)
32.练习2
prompt( )函数的返回值是String类型
33.switch语句
switch(条件表达式) {
case 表达式:
语句...
break;
case 表达式;
语句...
break;
default:
语句...
break;
}
switch(){
case score >= 60;
console.log("合格");
break;
default:
console.log("不合格");
break;
}
//网页的换行是<br />
document.write(1+"<br />");
document.write(2+"<br />");
35.循环
while循环
语法:
while(条件表达式){
语句...
//可以使用break终止循环
}
36.计算年利率
var money = 1000;
//定义一个计数器
var count = 0;
while(money < 5000){
money *= 1.05;
count++;
}
console.log(money);
//将prompt放到循环中
while(true) {
var score = prompt("请输入小明的期末成绩:(0~100)");
//判断用户输入的值是否合法
if (score >= 0 && score <=100){
break;
}
alert("请输入有效的分数!")
}
console.log("奇数之和为:"+sum);
37.for
for循环中的三个部分都可以省略,也可以写在外部
取整:
parseInt(i/100); //获取百位数字
判断质数
//创建一个变量来保存当前的数的状态//默认当前num是质数var flag = true;//判断num是否是质数//获取2-num之间的数for(var i=2;i<num;i++){ if(num % i ==0){ flag = false; }} if(flag){ alert(num + "是质数"); }else{ alert("这个不是质数"); }
41.嵌套的for循环
打印金字塔:内层循环可以来决定图形的宽度,执行几次图形的宽度就是多少
break关键字可以用来退出swith或循环语句
不能在if语句中使用break和continue
break会立即终止离他最近的哪个循环语句
可以为循环语句创建一个label,label可以是任意名称,来表示当前的循环
使用break语句时,可以再break后跟着一个label,这样break将会结束指定的循环,而不是最近的
loop1:
for(var i=0;i<5;i++){
console.log("@外层循环"+i)
for(var j=0;j<5;j++){
break loop1;
console.log("内层循环:"+j);
}
}
break:中止当前循环
continue:跳过当次循环
continue默认只会对离他最近的循环起作用
44.测试程序的性能
在程序执行前,开启计时器
console.time("计时器的名字")可以用来开启一个计时器,它需要一个字符串作为参数,这个字符串将会作为计时器的表示
console.time("test");
......
......
......
console.timeEnd("test"); //中止计时器
可以通过Math.sqrt( )对一个数进行开方
var result = Math.sqrt(36);
console.log("result = "+result)
46.对象
JS中的数据类型
String、Number、Boolean、Null、Undefined以上五种类型属于基本数据类型,只要不是上面5种,全都是对象
基本数据类型都是单一的值,值之间没有任何联系
Object 对象:属于一种复合数据类型,在对象中可以保存多个不同数据类型的属性
对象的分类:
1.内建对象
由ES标准中定义的对象,在任何ES的实现中都可以使用
比如Math String Number Boolean Function Object
2.宿主对象
由JS的运行环境提供的对象,目前来讲主要指由浏览器提供的对象,比如DOM BOM
3.自定义对象
由开发人员自己创建的对象
创建对象:使用new关键字调用的函数,是构造函数constructor
构造函数是专门用来创建对象的函数
使用typeof检查一个对象时,会返回object
var obj = new Object();
//console.log(typeof obj);
在对象中不存的值称为属性
向对象添加属性
语法:对象.属性名 = 属性值
//向obj中添加一个name属性
obj.name = "孙悟空";
//向obj中添加一个gender属性
obj.gender = "男";
//向obj中添加一个age属性
obj.age = 18;
console.log(obj);
//对象的属性值可以添加、读取、修改
//删除对象的属性
语法:delete 对象.属性名
delete obj.name;
48.向对象中添加属性
属性名:
对象的属性名不强制要求遵守标识符的规范,如果要使用特殊的属性名,不能采用.的方式来操作,需要使用另一种方式:
语法:对象["属性名"] = 属性值
读取时也需要采用这种方式
使用[ ]这种形式去操作属性,更加的灵活
在[ ]中可以直接传递一个变量,这样变量值是多少就会读取哪个属性(更灵活)
obj["123"] = 789;obj["nihao"] = "你好";var n = "123";//console.log(obj["123"]);console.log(obj[n]);
属性值
JS对象的属性值,可以是任意的数据类型,也可以是一个对象
//创建一个对象
var obj2 = new Object();
obj2.name = "猪八戒"
//将obj2设置为obj的属性
obj.test = obj2;
in 运算符
通过该运算符可以检查一个对象中是否含有指定的属性
如果有,返回true, 没有则返回false
语法:
"属性名" in 对象
//检查obj中是否含有test2属性
console.log("test2" in obj);
引用数据类型:Object
JS中的变量都是保存在栈内存中的,基本数据类型的值直接在栈内存中存储
值与值之间是独立存在的,修改一个变量不会影响其他的变量
变量本身是没有名字的,它只有一段内存地址
基本数据类型和引用数据类型是有区别的
对象是保存到堆内存中的,每创建一个新的对象,就会在堆内存中开辟出一个新的空间
而变量保存的是对象的内存地址(对象的引用),如果两个变量保存的是同一个对象引用,当一个通过一个变量修改属性时,另一个也会收到影响
当比较两个基本数据类型时,比较的是值
而比较两个引用数据类型时,比较的是对象的内存地址
50
对象字面量
//使用对象字面量来创建一个对象
var obj = { };
//等于 console.log(typeof obj);
obj.name = "孙悟空";
//console.log(obj.name);
//使用对象字面量,可以在创建对象时,直接指定对象中的属性
//语法:{属性名:属性值,属性名:属性值......}
//对象字面量的属性名可以加引号也可以不加
//如果要使用一些特殊的名字,则必须加引号
var obj2 = {name:"猪八戒",
age:28,
gender:"男"
test:{name:"沙和尚"}
};
console.log(obj2.test);
//没有属性名就不要写逗号了
51.函数---对象
函数可以封装功能,需要时可以执行
使用typeof检查一个函数对象时,会返回function
//创建一个函数对象
//可以将要封装的代码以字符串的形式传递给构造函数
//封装到函数中的代码不会立即执行,函数中的代码会在函数调用的时候执行
//调用函数的语法:函数对象() fun()
//调用函数时,函数中封装的代码会按照顺序执行
var fun = new Function("console,log('Hello 这是我的第一个函数');");
console.log(typeof fun);
//开发中很少使用构造函数来创建一个函数对象
//使用函数声明来创建一个函数
//语法:
function 函数名([形参1,形参2,...形参N]){
语句
}
//使用函数声明来创建一个函数 第一种(简单)
function fun2(){
console.log("这是我的第二个函数");
alert("哈哈哈哈");
document.write("嘤嘤嘤");
//一个函数可以实现多个功能
}
//调用:
fun2();
console.log(fun2);
//函数表达式 第二种
var fun3 = funtion(){
console.log("我是匿名函数中封装的代码");
}
52.函数的参数
/*定义一个用来求两个数和的函数
可以在函数的()中来指定一个或多个形参(形式参数)
多个形参之间使用 逗号, 隔开,声明形参就相当于在函数内部声明了对应的变量,但是并不赋值*/
function sum(a,b);
{
console.log(a+b);
}
/*在调用函数时,可以在()中指定实参(实际参数)
实参将会赋值给函数中对应的形参*/
sum(1,2);
sum(123,456);
/*调用函数时解析器不会检查实参的类型,所以需要对参数进行类型的检查
调用函数时,解析器也不会检查实参的数量,多余的实参不会被赋值
如果实参的数量少于形参的数量,则没有对应实参的形参将是undefined
函数的实参可以是任意的数据类型*/
51.函数的返回值
创建一个函数,用来计算三个数的和
可以使用return来设置函数的返回值
语法:
return 值
return后的值将会作为函数的执行结果返回,可以定义一个变量,来接收该结果
如果return语句后不跟任何值,就相当于返回undefined
如果函数中不写return,则返回undefined
return后可以跟任意类型的值
function sum(a,b,c)
{
//alert(a+b+c);
var d = a+b+c;
return d;
}
//调用函数
//变量result的值就是函数的执行结果
//函数返回什么result的值就是什么
sum(4,7,8);
定义一个函数,判断一个数字是否是偶数,如果是返回true,否则返回false
function isOu(num)
{
return num % 2 == 0;
}
var result = isOu(2);
console.log("result = "+result);
/*创建一个函数,可以在控制台中输出一个人的信息,可以输出人的name age gender address
实参可以是任意的数据类型,也可以是一个对象
当我们的参数过多时,可以将参数封装到一个对象中,然后通过对象传递*/
function sayHello(o)
{
console.log("o = "+o);
console.log("我是"+o.name+",今年我"+o.age+"岁了,"+"我是一个"+o.gender+"人","我住在"+o.address);
//sayHello("孙悟空", 18, "男","花果山");
}
//创建一个对象
var obj = {
name:"孙悟空",
age:18,
gender:"男",
address:"花果山"
};
//实参可以是一个对象,也可以是一个函数
function()
- 调用函数
- 相当于使用的函数的返回值
function
- 函数对象
- 相当于直接使用函数对象
break退出当前循环
continue跳过当次循环
return结束整个函数
返回值可以是任意的数据类型,也可以是一个对象,函数
function fun3()
{
//在函数内部再声明一个函数
funcion fun4()
{
alert("我是fun4");
}
//将fun4函数对象作为返回值返回
return fun4;
}
a = fun3();
console.log(a);
56.立即执行函数
调用函数:函数对象( )
立即执行函数
函数执行完,立即被调用,这种函数叫做立即执行函数
立即执行函数往往只会执行一次
(function(a,b)
{
console.log("a = "+a);
console.log("b = "+b);
})
(123,456);
对象的属性值可以是任何的数据类型,也可以是个函数
obj,sayName = function( ){
console.log(obj.name);
};
console.log(obj.sayName);
就是说,函数也可以称为对象的属性,如果一个函数作为一个对象的属性保存,那么我们称这个函数是这个对象的方法,调用函数就是调用对象的方法(method)
obj.sayName = function(){ console.log(obj.name);};function fun(){ console.log(obj.name);};//调方法obj.sayName();//调函数fun();//只是名称上的区别
枚举对象中的属性
使用 for...in 造句
语法:
for(var 变量 in 对象)
{
...
}
//for...in语句 对象中有几个属性,循环体就会执行几次
//每次执行时,会将对象中的一个属性的名字赋值给变量
for(var n in obj)
{
console.log("hello");
}
//枚举属性
var obj = {
name:"孙悟空",
age:18,
gender:"男",
address:"花果山"
}
/*枚举对象中的属性
使用for ... in语句*/
for(var n in obj)
{
console.log(obj.[n]); //中括号可以传变量
}
58.作用域
作用域指一个变量的作用范围
在JS中一共有两种作用域:
1,全局作用域
-
直接编写在script标签中的JS代码,都在全局作用域
-
全局作用域在页面打开时创建,在页面关闭时销毁
-
在全局作用域中有一个全局对象window,代表一个浏览器的窗口,我们可以直接使用
-
在全局作用域中:
创建的变量都会作为window对象的属性保存
创建的函数都会作为window对象的方法保存
<插播知识>
变量的声明提前
-
使用var关键字声明的变量,会在所有的代码执行之前被声明
-
但是如果声明变量时不使用var关键字,则变量不会被声明提前
函数的声明提前
-
使用函数声明形式创建的函数 function 函数( )
-
函数声明,会被提前创建
function fun(){ console.log("我是一个fun函数"); }
-
它会在所有的代码执行之前就被创建,所以我们可以再函数声明前来调用函数
-
使用函数表达式创建的函数,不会被声明提前,所以不能在声明前调用
-
函数表达式,不会被提前创建
var fun2 = function(){
console.log("我是fun2函数");
};
- 全局作用域中的变量都是全局变量
- 在页面的任意的部分都可以访问的到
2.函数作用域
调用函数时创建函数作用域,函数执行完毕以后,函数作用域销毁
每调用一次函数就会创建一个新的函数作用域,他们之间是互相独立的
在函数作用域中可以访问到全局作用域的变量
在全局作用域中无法访问到函数作用域的变量
当在函数作用域操作一个变量时,它会先在自身作用域中寻找,如果有就直接使用,如果没有则向上一级作用域中寻找
如果全局作用域中依然没有找到,则会报错ReferenceError
函数作用域也有声明的特性:
使用var关键字声明的变量,会在函数中所有的代码执行之前被声明
函数声明也会在函数中所有的代码执行之前执行
var c = 33;
function fun5(){
console.log("c = "+c);
var c = 10;
}
fun5(); //c = undefined 因为定义的C不在fun5中,而且定义在fun5()中的c是在控制台输出后定义的(perhaps)
在函数中,不使用var声明的变量都会成为局部变量
function fun5()
{
d = 100; //=window.d = 100;
}
定义形参就相当于在函数作用域中声明了变量
61.this(由浏览器传过来的)
解析器在调用函数每次都会向函数内部传递进一个隐含的参数
这个隐含的参数就是this,this指向的是一个对象,
这个对象我们称为函数执行的上下文对象
根据函数的调用方式的不同,this会指向不同的对象
1.以函数的形式调用时,this永远都是window
2.以方法的形式调用时,this就是调用方法的那个对象
63.对象
/*创建一个对象*/
var obj = {
name:"孙悟空",
age:18,
gender:"男",
sayName:function(){
alert(this.name);
}
};
obj.name();
/*使用工厂方法创建对象,通过该方法可以大批量的创建对象*/
function createPerson(name, age, gender){
//创建一个新对象
var obj = new Object();
//向对象中添加属性
obj.name = "孙悟空";
obj.name = 18;
obj.gender = "男"
obj.sayName = function(){
alert(this.name);
};
//将新的对象返回
return obj;
}
var obj2 = createPerson("mike",23,"male");
var obj3 = createPerson("cook",46,"male");
var obj4 = createPerson("dazy",31,"female");
//这种方法只需要传3个属性就可以了
obj3.sayName();
console.log(obj2);
console.log(obj3);
console.log(obj4);
用来创建狗的对象
function createDog(name, age){
//以后创建狗的对象就可以用createDog
var obj = new Object();
obj.name = name;
obj.age = age;
obj.sayHello = function(){
alert("汪汪");
}
return obj;
}
/*使用工厂方法创建的对象,使用的构造函数都是Object
所以创建的对象都是Object这个类型,导致我们无法区分出多种不同类型的对象*/
//创建一个狗的对象
var dog = createDog("旺财",3);
console.log(dog);
console.log(obj4);
构造函数
创建一个构造函数,专门用来创建Person
构造函数就是一个普通的函数,创建方式和普通函数没有区别
不同的是,构造函数习惯首字母大写
构造函数和普通函数的区别: 调用方式不同
普通函数就是直接调用,构造函数需要使用new关键字来调用
/*构造函数的执行流程:
1.立刻创建一个新的对象
2.将新建的对象设置为函数中的this,在构造函数中可以使用this来引用新建的对象
3.逐行执行函数中的代码
4.将新建的对象作为返回值返回*/
function Person(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
this.sayName = function(){
alert(this.name);
//this指的是per,也就是新建的对象
};
}
var per = new Person("孙悟空",18,"男");
//此处per就是Person类的实例
var per2 = new Person("铁憨憨",17,"男");
console.log(per);
使用同一个构造函数创建的对象,我们称为一类对象,也将一个构造函数称为一个类
我们将通过一个构造函数创建的对象,称为是 该类/该构造函数 的实例
/*使用instanceof可以 检查 一个对象是否是一个类的实例
语法:
对象 instanceof 构造函数
如果是,则返回true,否则返回false
console.log(per instanceof Person);
所有的对象都是Object的后代
所以任何对象和Object做instanceof检查时都会返回true
回顾:构造函数就是一个普通的函数,用来创建对象,首字母大写,区分:new
this的情况:
1.当以函数的形式调用时,this是window
2.当以方法的形式调用时,谁调用方法,this就是谁
3.当以构造函数的形式调用时,this就是新创建的那个对象
创建一个Person构造函数
- 在Person构造函数中,为每一个对象都添加了一个sayName方法,目前我们的方法是在构造函数内部创建的,也就是构造函数每执行一次就会创建一个新的sayName方法
- 也就是所有实例的sayName都是唯一的,这样导致了构造函数执行一次就会创建一个新的方法,,,其实完全可以使所有的对象共享同一个方法
function Person(name, age, gender){
this.name = name;
this.age = age;
this.gender = gender;
//向对象中添加一个方法
this.sayName = fun;
}
//将sayName方法在全局作用域中定义
function fun(){
alert("Hello大家好,我是:"+this.name);
}
//向原型中添加sayName方法
Person.prototype.sayName = function (){
alert("Hello大家好,我是:"+this.name);
}
//创建一个Person的实例
var per = new Person("孙悟空",18,"男");
var per = new Person("猪八戒",28,"男");
console.log(per.sayName == per2.sayName); //是同一个
将函数定义在全局作用域,污染了全局作用域的命名空间
原型prototype
我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype,每个函数创建的prototype是不一样的
console.log(MyClass.prototype == Person.prototype); //不一样
//这个属性对应着一个对象,这个对象就是我们所谓的原型对象
如果函数作为普通函数调用,那么这个prototype没有任何作用
当函数以构造函数调用时,它所创建的对象中都会有一个隐含的属性,指向该构造函数的原型对象,我们可以通过__proto__
来访问该属性
function MyClass(){
}
//向MyClass的原型中添加属性a
MyClass.prototype,a = 123;
//向MyClass的原型中添加一个方法
MyClass.prototype.sayHello = function(){
alert("hello");
};
var mc = new MyClass();
//console.log(MyClass.prototype);
console.log(mc.__proto__); 上下指向的是同一个对象
原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中
当我们访问 对象的一个属性或者方法时,它会先在对象自身中寻找,如果有则直接使用,如果没有则会去原型对象中寻找,如果找到则直接使用
原型的作用
- 以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中,这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法
向mc中添加a属性:
mc.a = "我是mc中的a";
console.log(mc.a);
67.原型
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<script type="text/javascript">
/*创建一个构造函数*/
function MyClass(){
}
//向MyClass的原型中添加一个name属性
MyClass.prototype.name = "我是原型中的名字";
var mc = new MyClass();
mc.age = 18;
//console.log(mc.name);
//使用in 检查对象中是否含有某个属性时,如果对象中没有但是原型中有,也会返回true;
//console.log("name" in mc);
//可以使用对象的hasOwnProperty()来检查对象自身中是否含有该属性
//使用该方法只有当对象自身中含有属性时,才会返回true
console.log(mc.hasOwnProperty("name"));
console.log(mc.hasOwnProperty("age"));
/*原型对象也是对象,所以它也有原型
当我们使用一个对象的属性或方法时,会先在自身中寻找
自身中如果有,则直接使用,
如果没有则去原型对象中寻找,如果原型对象中有,则使用
如果没有则去原型的原型中寻找,直到找到Object对象的原型
Object对象的原型没有原型,如果在Object中依然没有找到,则返回undefined*/
</script>
</head>
<body>
</body>
</html>
console.log(mc.hello); //去mc里找hello属性
function Person(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
}
//创建一个Person实例
var per = new Person("孙悟空,18,"男");
//当我们直接在页面中打印一个对象时,实际上是输出的对象的toString()方法的返回值
//如果我们希望在输出对象时不输出[object Object],可以为添加对象添加一个toString()方法
var result = per.toString();
console.log(per.toString());
//修改Person原型的toString
Person.prototype.toString = function(){
return "Person[name="+this.name+",age="+this.age+",gender="+this.gender"]"
}
69.垃圾回收(GC)
/*程序运行过程中,需要一个垃圾回收机制,来处理程序运行过程中产生的垃圾
当一个对象没有任何的变量或属性对它进行引用,此时我们将永远无法操作该对象
此时这种对象就是一个垃圾,这种对象过多会占用大量的内存空间,导致程序运行变慢,所以必须清理垃圾
在JS中拥有自动的垃圾回收机制,会自动将这些垃圾对象从内存中销毁
我们需要做的只是将不再使用的对象设置为null即可*/
var obj = new Object();
obj = null;
70.数组
数组也是对象,它和普通的对象功能类似
- 普通对象使用字符串作为属性名
- 数组使用数字作为索引操作元素
索引:从0开始的整数
数组的存储性能比普通对象好,在开发中我们经常使用数组来存储一些数据
JS--面向对象的语言 (面向对象:1.找对象 2.搞对象)
//创建数组对象var arr = new Array();//使用typeof检查一个数组时,会返回objectconsole.log(typeof arr);/*向数组中添加元素语法:数组[索引] = 值*/arr[0] = 10;console.log(arr);/*如果读取不存在的索引,他不会报错而是返回undefined 对于非连续的数组,使用length会获取到数组的最大索引+1 尽量不要创建非连续的数组*/获取数组的长度:语法:数组.length//向数组的最后一个位置添加元素//语法:数组[数组.length] = 值;
71.数组字面量
//创建一个数组
var arr = new Array();
arr[0] = 123;
arr.hello = "abc";
console.log(arr.hello);
//使用字面量来创建数组
//语法:[]
var arr = [];
//console.log(typeof arr);
//使用字面量创建数组时,可以在创建时就指定数组中的元素
var arr = [1,2,3];
//还可以使用构造函数创建数组,也可以同时添加元素,将要添加的元素作为构造函数的参数来传递
//元素之间使用逗号隔开
var ar2 = new Array(10,20,30);
console.log(arr2);
//创建一个数组只有一个元素10
arr = [10];
//创建一个长度为10的数组
arr2 = new Array(10);
//数组中的元素可以是任意的数据类型,也可以是对象,可以是函数
var obj = {name:"孙悟空"};
arr[arr.length] = obj;
arr = [{name:"mike"},{name:"john"},{name:"draven"}];
console.log(arr[1].name);
72.数组的四个方法
push()
- 该方法可以向数组的末尾添加一个或多个元素,并返回数组的新的长度
- 可以将要添加的元素作为方法的参数传递
- 这样这些元素将会自动添加到数组的末尾
arr.push("我是新添加的元素1","我是新添加的元素2");
pop()
- 该方法可以删除数组的最后一个元素,并将被删除的元素作为返回值返回
arr.pop();
unshift();
- 向数组开头添加一个或多个元素,并返回新的数组长度
arr.unshift("我是要加在最前面的元素");
shift();
- 可以删除数组的第一个元素,并将被删除的元素作为返回值返回
73.数组的遍历(取出数组中所有元素)
var arr = ["111","222","333"];
for(var i=0;i<arr.length;i++)
{
console.log(arr[i]);
}
//创建一个Person对象
var per = new Person("孙悟空",18);
var per2 = new Person("孙11",28);
var per3 = new Person("孙22",8);
var per4 = new Person("孙33",16);
var per = new Person("孙44",39);
//将这些person对象放入到一个数组中
var perArr = [per,per2,per3,per4,per5];
/*创建一个函数,可以将perArr中的满18岁的Person提取出来,然后封装到一个新的数组中并返回
定义arr为形参,
形参,要提取信息的数组*/
function getAdult(arr){
//创建一个新的数组
var newArr = [];
//遍历arr,获取arr中的Person对象,判断Person对象的age是否大于等于18,将大于等于18的对象添加到newArr中
for(var i=0;i<arr.length;i++){
var p = arr[i];
//判断年龄
if(p.age>=18)
{
//将对象放入到新数组中
newArr.push(p);
}
}
//将新的数组返回
return newArr;
}
var result = getAdult(perArr);
75.用 forEach( )来遍历数组(只支持IE8+)
/*forEach()方法需要一个函数作为参数
- 像这种函数,由我们创建,但是不由我们调用的,我们称为回调函数
数组中有几个元素,函数就会执行几次,每次执行时,浏览器会将遍历到的元素以实参的形式传递进来,我们可以来定义形参,来读取这些内容
浏览器会在回调函数中传递三个参数:
第一个参数:当前正在遍历的元素
第二个参数:当前正在遍历的元素的索引
第三个参数:正在遍历的数组*/
arr.forEach(function(value,index,obj){
console.log(value);
});
slice( )
- 从某个已有的数组返回指定的元素
- 该方法不会改变元素数组,而是将截取到的元素封装到一个新数组中返回
需要2个参数:
1.截取开始的位置的索引,包含开启索引
2.截取结束的位置的索引,不包含结束索引
第二个参数可以省略不写,此时会截取从开始索引往后的所有元素
索引可以传递一个负值,负值则从后往前计算(-1是倒数第一个)
var arr = ["111","222","333"];
var result = arr.slice(0,2);
splice( )
- 可以用于删除数组中的指定元素
- 使用splice( )会影响到原数组,会将指定元素从原数组中删除,并将被删除的元素作为返回值返回
参数: 第一个表示开始位置的索引
第二个表示删除的数量
第三个及以后,可以传递一些新的元素,这些元素将会自动插入到开始位置索引前边
var arr = [1,2,3,1,2,3,1,5,3,1,6]
/*去除数组中重复的数字
获取数组中的每一个元素*/
for(var i=0;i<arr.length;i++){
console.log(arr[i]);
/*获取当前元素后的所有元素*/
for(var j=i+1;j<arr.length;j++){
//判断两个元素的值是否相等
if(arr[i] == arr[j]){
//如果相等则证明出现了重复的元素,则删除j对应的元素
arr.splice(j,1);
//当删除了当前j所在的元素以后,后边的元素会自动补位
//此时将不会再比较这个元素,我需要再比较一次j所在位置的元素
//使j自减
j--;
}
}
}
78.concat( )
/*concat()可以连接两个或多个数组,并将新的数组返回,并且还可以传元素 该方法不会对原数组产生影响,*/var arr = ["111","222","333"];var arr2 = ["11","22","33"];var result = arr.concat(arr2);
join( )
-
该方法可以将数组转换为一个字符串
-
该方法不会对原数组产生影响,而是将转换后的字符串作为结果返回
-
在join( )中可以指定一个字符串作为参数,这个字符串将会称为数组中元素的连接符。如果不指定连接符,则默认使用,作为连接符
arr = ["孙悟空","猪八戒","沙和尚"];
result = arr.join("@-@");
console.log(result);
reverse( )
-
该方法用于反转数组
-
会直接修改原数组
arr.reverse();
console.log(arr);
sort( )
- 可以用来对数组中的元素进行排序
- 会直接修改原数组
- 即使对于纯数字的数组,使用sort( )排序时,也会按照Unicode编码来排序
我们可以自己来指定排序的规则,可以在sort( )添加一个回调函数,来指定排序规则
回调函数需要定义两个形参
浏览器将会分别使用数组中的元素作为实参去调用回调函数
使用哪个元素调用不确定,但是肯定的是在数组中a一定在b前边
浏览器会根据回调函数的返回值来决定元素的顺序,如果返回一个大于的0的值,则元素会交换位置,如果返回一个负数,则元素位置不变,如果返回0,也不换位置
arr = ["b","d","e","a","c"];
arr.sort();
arr = [5,4];
arr.sort(function(a,b){
/* if(a>b){
return 1;
}else if(a<b){
return -1;
}else{
return 0;
}
});*/
return a-b;
//return b-a;
console.log(arr);
call( ) 和apply( )0536
-
这两个方法都是函数对象的方法,需要通过函数对象来调用
-
当对函数调用call( )和apply( )都会调用函数执行
-
在调用call( )和apply( )可以将一个对象指定为第一个参数
此时这个对象将会称为函数执行时的this
function fun(){
alert(this.name);
}
var obj = {name:"obj"};
var obj2 = {name:"obj2"};
fun.apply(obj);
call( )方法可以将实参在对象之后依次传递
apply( )方法需要将实参封装到一个数组中统一传递
两个方法都是来指定this的
this的情况:
1.以函数形式调用时,this永远都是window
2.以方法的形式调用时,this是调用方法的对象
3.以构造函数的形式调用时,this是新创建的那个对象
4.使用call和apply调用时,this是指定的那个对象
在调用函数时,浏览器每次都会传递给两个隐含的参数
1.函数的上下文对象 this
2.封装实参的对象arguments
-
arguments是一个 类数组 对象。它也可以通过索引来操作数据,也可以获取长度
-
在调用函数时,我们所传递的实参都会在arguments中保存
-
arguments.length可以用来获取实参的长度
-
我们即使不定义形参,也可以通过arguments来使用实参
arguments[0] 表示第一个实参
arguments[1] 表示第二个实参
function fun(){
console.log(arguments);
}
fun();
81.Date对象
- 在JS中使用Date对象来表示一个时间
197建一个Date对象
如果直接使用构造函数创建一个Date对象,则会封装为当前代码执行的时间*/
var d = new Date();
/*创建一个指定的时间对象
需要在构造函数中传递一个表示时间的字符串作为参数
日期的格式 月/日/年 时:分:秒*/
var d2 = new Date("12/03/2016 11:11:11");
/*getDate()
- 获取当前日期对象是几日*/
var date = d2.getDate();
/*getDay()
- 获取当前日期对象是 周几
- 会返回一个0-6的值,0表示周日,1表示周一
*/
var day = d2.getDay();
/*getMonth()
- 获取当前时间对象的月份
- 会返回一个0-11的值,0表示1月,11表示12月
getFullYear()
- 获取当前日期对象的年份
getTime()
- 获取当前日期对象的时间戳
- 时间戳指的是1970.1.1,0:0:0 到当前日期所花费的毫秒数(1s = 1000ms)
- 计算机底层在保存时间时使用的都是时间戳
/*获取当前的时间戳
利用时间戳来测试代码的执行性能*/
var start = Date.now();
for(var i=0;i<100;i++)
{
console.log(i);
}
var end = Date.now();
console.log(end - start);
82.Math
Math.PI表示圆周率
abs( )绝对值
Math.ceil()
/*可以对一个数进行向上取整,小数位只有有值就会自动进1*/
Math.floor()
/*可以对一个数进行向下取整*/
Math.round()
/*可以对一个数进行四舍五入取整*/
Math.random()
/*可以用来生成一个0-1之间的随机数*/
Math.round(Math.random()*x)
/*可以生成一个0-x之间的随机数*/
Math.round(Math.random()*(y-x)+x)
/*生成一个x-y之间的随机数*/
/*max()可以获取多个数中的最大值
min()可以获取多个数中的最小值*/
var max = Math.max(1,3.6,5,1,3,17);
/*Math.pow(x,y)
返回x的y次幂*/
83.包装类
基本数据类型:String Number Boolean Null Undefined
引用数据类型:Object
在JS中为我们提供了3个包装类,通过这3个包装类可以将基本数据类型的数据转换为对象
String()
- 可以将基本数据类型字符串转换为String对象
Number()
- 可以将基本数据类型的数字转换为Number对象
Boolean()
- 可以将基本数据类型的布尔值转换为Boolean对象
在实际应用中不会使用基本数据类型的对象
如果使用基本数据类型的对象,在做一些比较时可能会带来一些不可预期的结果
/*创建一个Number类型的对象 num = 3;*/
var num = new Number(3);
var str = new String("hello");
var bool = new Boolean(true);
/*向num中添加一个属性*/
num.hello = "abcd";
console.log(num.hello);
/*方法和属性只能添加给对象,不能添加给基本数据类型
当我们对一些基本数据类型的值去调用属性和方法时,
浏览器会临时使用包装类将其转换为对象,然后再调用对象的属性和方法
调用完以后,再将其转换为基本数据类型*/
84.字符串的相关方法
在底层,字符串时以字符数组的形式保存的
length属性
- 可以用来获取字符串的长度
charAt()
- 可以返回字符串中指定位置的字符
- 根据索引获取指定的字符
charCodeAt()
- 获取指定位置字符的编码(返回的是unicode编码)
String.fromCharCode()
//可以根据字符编码去获取字符
result = String.fromCharCode(0x2692);
concat()
/*可以用来链接两个或多个字符串
作用和 + 一样
*/
result = str.concat("你好","再见");
console.log(result);
indexof()
/*- 该方法可以检索一个字符串中是否含有指定内容
- 如果字符串中含有该内容,则会返回其第一次出现的索引
- 如果没有找到指定的内容,则返回-1
- 可以指定一个第二个参数,指定开始查找的位置*/
str = "hello kadfoh";
result = str.indexof("h");
console.log(result);
lastIndexOf();
- 该方法的用法和indexOf()一样
不同的是indexOf是从前往后找,
lastIndexOf是从后往前找
也可以指定开始查找的位置
slice()
result = str.slice(1,4);
/*可以从字符串中截取指定的内容
不会影响到原字符串,而是将截取到的内容返回
参数:
第一个:开始位置的索引(包括开始位置)
第二个:结束位置的索引(不包括结束位置)
如果省略第二个参数,则会截取到后面所有的
也可以传递一个负数作为参数,负数的话将会从后边计算*/
substring()
/*可以用来截取一个字符串,和slice()类似
参数:
第一个:开始截取位置的索引(包括开始位置)
第二个:结束位置的索引(不包括结束位置)
不同点:这个方法不鞥你接受负值,如果传递了一个负值,默认使用0
会自动调整参数的位置,如果第二个参数小于第一个,则自动交换*/
result = str.substring(0,2);
substr()
- 用来截取字符串
- 参数:
1.截取开始位置的索引
2.截取的长度
sblit()
- 可以将一个字符串拆分为一个数组
- 参数:
需要一个字符串作为参数,将会根据该字符串去拆分数组
- 如果传递一个空串作为参数,则会将每个字符都拆分为数组中的一个元素
result = str.split("");
str = "abc,aba,vasd,vsdgdf,dsg,bcxv";
result = str.split(",");
toUpperCase()
- 将一个字符串转换为大写并返回
toLowerCase()
- 将一个字符串转换为小写并返回
85.正则表达式(给计算机看的)
正则表达式用于定义一些字符串的规则
计算机可以根据正则表达式,来检查一个字符串是否复合规则
或者将字符串中复符合规则的内容提取出来
//创建正则表达式的对象
语法:
var 变量 = new RegExp("正则表达式","匹配模式");
//使用typeof检查正则对象,会返回object
var reg = new RegExp("a");
//这个正则表达式可以来检查一个字符串中是否含有a
/*在构造函数中可以传递一个匹配模式作为第二个参数
可以是
i 忽略大小写
g 全局匹配模式*/
var str = "a";
var result = reg.test(str);
/*正则表达式的方法:
test();
- 使用这个方法可以用来检查一个字符串是否复合正则表达式的规则
- 如果符合则返回true,否则返回false*/
var reg = new RegExp("a","i"); //忽略大小写
var str = "a";
var result = reg.test(str);
console.log(reg.test("Abcbc"));
/*使用字面量来创建正则表达式
语法:var 变量 = /正则表达式/匹配模式
使用字面量的方式创建更加简单,使用构造函数创建更加灵活:
reg = /a/i;
*/
/*创建一个正则表达式,检查一个字符串是否有a或b
使用|表示或者的意思*/
var reg = /a|b/;
/*创建一个正则表达式检查一个字符串中是否有字母 reg[a-z]任意小写字母
[]里的内容也是或的关系 reg[A-Z]任意大写字母
[ab] == a|b reg[A-z]任意字母
reg[0-9]任意数字
检查一个字符串中是否含有 abc或adc或aec
reg = /a[bde]c/
[^ ] 除了
reg = /[^ab]/;
87.字符串和正则相关的方法
var str = "12mdasvm3l4mld5av67";
split()
- 可以将一个字符串拆分为一个数组
- 方法中可以传递一个正则表达式作为参数,这样方法将会根据正则表达式去拆分字符串
- 这个方法即使不指定全局匹配,也会全部拆分
/*根据任意字母来将字符串拆分*/
var result = str.split(/[A-z]/);
方法中可以传递一个正则表达式作为参数,这样方法将会根据正则表达式去拆分字符串
search()
- 可以搜索字符串中是否含有指定内容
- 如果搜索到指定内容,则会返回第一次出现的索引,如果没有搜索到,返回-1
- 它可以接受一个正则表达式作为参数,然后会根据正则表达式去检索字符串
- search()只会查找第一个,即使设置全局匹配也没用
str = "hello hola aec afc";
//搜索字符串中是否含有abc或aec或afc
result = str.search(/a[bef]c/);
console.log(result);
/*match()
- 可以根据正则表达式,从一个字符串中将复合条件的内容提取出来
- 默认情况下我们的match只会找到第一个符合要求的内容,找到以后就停止检索
- 我们可以设置正则表达式为全局匹配模式,这样就会匹配到所有的内容
- 可以为一个正则表达式设置多个匹配模式,且顺序无所谓
- match()会将匹配到的内容封装到一个数组中返回,即使只查询到一个结果
*/
str = "1a2b3c4d5c6f";
result = str.match(/[a-z]/gi); //全局匹配+忽略大小写
console.log(result);
/*replace()
- 可以将字符串中指定内容替换为新的内容
- 参数:
1.被替换的内容
2.新的内容
- 默认只会替换第一个
*/
result = str.replace(/a/gi,"@_@");
//把指定文本中的字母全部删除(即用空格代替字母的位置)
result = str.replace(/a-z/gi,"");
console.log(result);
88.创建一个正则表达式检查一个字符串是否含有aaa
通过量词可以设置一个内容出现的次数
- 通过量词可以设置一个内容出现的次数
- 量词只对它前边的一个内容起作用
- {n} 正好出现n次
- {m,n}出现m-n次
- {m,}m次以上
- +,至少一个,相当于
- *,0个或多个,相当于
- ?,0个或1个,相当于
var reg = /a{3}/;
reg = /(ab){3}/;
/*检查一个字符串中是否以a开头
^ 表示开头
$ 表示结尾*/
reg = /^a/;
reg = /a$/;
/*创建一个正则表达式,用来检查一个字符串是否是一个合法手机号*/
var phoneStr = "13556892461";
/*手机号的规则*/
1 3 567890123(11位)
1.以1开头
2.第二位3-9任意数字
3.三位以后任意数字9个
var phoneStr = "13576324521";
var phoneReg = /^1[3-9][0-9]{9}$/;
89.检查一个字符串中是否含有.(需要使用转义字符)
. 表示任意字符
\. 表示.
\\ 表示\
var reg = /\./;
使用构造函数时,由于它的参数是一个字符串,而\
是字符串中转义字符,如果要使用\
则需要使用\\
来代替
\w 任意字母数字下划线
\W 除了字母数字下划线
\b 单词边界
\B 除了单词边界
\d 任意的数字
\D 除了数字
\s 空格
\S 除了空格
reg = /child/;
reg = /\bchild\b/;
console.log(reg.test("hello children"));
//接收一个用户的输入
//var str = prompt("请输入你的用户名:");
var str = " hello ";
//去除掉字符串中的空格
//去除空格就是使用""来替换空格
console.log(str);
//匹配开头和结尾的空格
str = str.replace(/^\s+|\s+$/g,"");
90.邮件的正则
//任意字母下划线. 任意字母数字下划线 @ 任意字母数字.任意字母(2-5位).任意字母(2-5位)
var emailReg = /^\w{3,}(\.\w+)*@[A-z0-9]+(\.[A-z]{2,5}){1,2}$/;
var email = "abc.hello@163.com"
console.log(emailReg.test(email));
91.DOM(文档对象模型)
JS中通过DOM来对HTML文档进行操作,只要理解了DOM就可以随心所欲地操作WEB页面
-
文档
整个的HTML网页文档
-
对象
将网页中的每一个部分都转换成了一个对象
-
模型
对象之间的关系,这样方便我们获取对象
节点
- 节点Node————构成我们网页的最基本的单元,网页中的每一个部分都可以称为是一个节点,比如html标签,文本,属性,注释,整个文档等都是一个节点
- 虽然是节点但是实际上它们的具体类型是不同的
常用的节点分为四类
文档节点:整个HTML文档
元素节点:HTML文档中的HTML标签
属性节点:元素的属性
文本节点:HTML标签中的文本内容
DOM和网页中的元素有一一对应的关系,想找谁先来获取到对象,随后对这个对象进行操作
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<button id="btn" type="button">我是一个按钮</button>
<script type="text/javascript">
/*浏览器已经为我们提供 文档节点 对象。这个对象是window属性
可以在页面中直接使用,文档节点代表的是整个网页*/
//获取到button对象
var btn = document.getElementById("btn");
//修改按钮的文字
btn.innerHTML = "I'm a button";
console.log(btn);
</script>
</body>
</html>
92.事件:用户和浏览器之间的交互行为
比如点击按钮、鼠标移动、关闭窗口
/*我们可以在事件对应的属性中设置一些js代码,这样当事件被触发时,这些代码将会执行
可以为按钮的对应事件绑定处理函数的形式来响应事件,这样当事件被触发的时候,其对应的函数才会被调用
*/
//获取按钮对象
var btn = document.getElementById("btn");
//绑定一个单击事件
//像这种为单击事件绑定的函数,我们称为单击响应函数
btn.onclick = function(){
alert("你继续点");
}
总结:两种绑定方式
1.直接在标签中通过属性绑定
2.获取对象,通过为对象的指定属性去绑定回调函数
/*获取id为btn的按钮*/
var btn = document.getElementById("btn");
/*为按钮绑定一个单击响应函数*/
btn.onclick = function(){
alert("hello");
};
文档的加载
浏览器加载页面时,是按照自上向下的顺序加载的,读取到一行就运行一行
如果将script标签写到页面的上面,在代码执行时,页面还没有加载
将JS代码编写到页面的下部是为了:可以在页面加载完毕以后再执行js代码
onload事件会在整个页面加载完成之后才触发,
/*为window绑定一个onload事件,该事件对应的响应函数将会在页面加载完成之后执行
这样可以确保我们的代码执行时所有的DOM对象已经加载完毕了,不会出现获取不到DOM对象的情况
代码执行时,页面还未加载,DOM对象也未加载,会导致无法获取到DOM对象的情况*/
window.onload = function(){
//获取id为btn的按钮
var btn = document.getElementById("btn");
//为按钮绑定一个单击响应函数
btn.onclick = function(){
alert("hello");
};
};
如果想把script标签写在head里,可以把代码统一写到window.onload对应的函数里,这样可以确保代码是在页面加载完成之后执行,可以正常获取到对象
DOM里的方法
获取元素节点对象(通过document对象调用)
1.getElementById() --通过id属性获取一个元素节点对象
2.getElementsByTagName() --通过标签名获取一组元素节点对象
3.getElementsByName() --通过name属性获取一组元素节点对象
//为id为btn01的按钮绑定一个单击响应函数
var btn01 = document.getElementById("btn01");
btn01.onclick = function(){
//查找#bj节点
var bj = document.getElementById("bj");
//打印bj
//innerHTML 通过这个属性可以获取到元素内部的html代码
alert(bj.innerHTML);
};
//为id为btn02的按钮绑定一个单击相应函数
var btn02 = document.getElementById("btn02");
btn02.onclick = function(){
//查找所有li节点 li是标签名
//getElementByTagName()可以根据标签名来获取一组元素节点对象
//这个方法会给我们返回一个类数组对象,所有查询到的元素会封装到对象中
//即使查询到的元素只有一个,也会封装到数组中返回
var lis = document.getElementByTagName("li");
//打印lis
alert(lis.length); //打印li的长度
//遍历lis
for(var i=0; i<lis.length; i++){
alert(lis[i].innerHTML);
}
}
//为id为btn03的按钮绑定一个单击响应函数
var btn03 = document.getElementById("btn03");
btn03.onclick = function(){
//查找name = gender的所有节点
var inputs = document.getElementsByName("gender");
//alert(inputs.length);
//遍历:
for(var i=0; i<inputs.length;i++){
//alert(inputs[i]); 输出对象
//innerHTML用于获取元素内部的HTML代码
//对于自结束标签,这个属性没有意义
/*如果需要读取元素节点属性,
直接使用 元素.属性值 */
alert(inputs[i].value); 可以读value
alert(inputs[i].name/type); 也可以读name/type
}
};
//class属性不能采用 元素.属性值 来读
//读class属性时需要使用元素.className
95.图片切换的练习
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<style type="text/css">
*{
margin: 0;
padding: 0;
}
#outer
{
width: 175px;
margin: 50px auto;
padding: 10px;
background-color: aquamarine;
/*设置文本居中*/
text-align: center;
}
</style>
<script type="text/javascript">
window.onload = function(){
/*点击按钮切换图片*/
//获取两个按钮
var prev = document.getElementById("prev");
var next = document.getElementById("next");
/*要切换图片就是要修改img图片的src属性
分别为两个按钮绑定单击响应函数*/
//获取img标签
var img = document.getElementsByTagName("img")[0];
//分别为两个按钮绑定单击响应函数*/
prev.onclick = function(){
//alert("上一张");
img.src = "img/1.png";
};
next.onclick = function(){
//alert("下一张");
//切换图片就是修改img的src属性
//要修改一个元素的属性元素,属性 = 属性值
img.src = "img/2.jpg";
};
}
</script>
</head>
<body>
<div id="outer">
<img src="img/1.png" alt="冰棍">
<button id="prev" type="button">一键复活</button>
<button id="next" type="button">一键去世</button>
</div>
</body>
</html>
3张图片
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<style type="text/css">
*{
margin: 0;
padding: 0;
}
#outer
{
width: 175px;
margin: 50px auto;
padding: 10px;
background-color: aquamarine;
/*设置文本居中*/
text-align: center;
}
</style>
<script type="text/javascript">
window.onload = function(){
/*点击按钮切换图片*/
//获取两个按钮
var prev = document.getElementById("prev");
var next = document.getElementById("next");
/*要切换图片就是要修改img图片的src属性
分别为两个按钮绑定单击响应函数*/
//获取img标签
var img = document.getElementsByTagName("img")[0];
//创建一个数组,用来保存图片的路径
var imgArr = ["img/1.png","img/2.jpg","img/3.jpg"];
//创建一个变量,来保存当前正在显示的图片的索引
var index = 1;
//获取id为info的p元素
var info = document.getElementById("info");
//设置提示文字
info.innerHTML = "一共 "+imgArr.length+" 张图片,当前第 "+(index+1)+" 张";
//分别为两个按钮绑定单击响应函数*/
prev.onclick = function(){
//切换到上一张,索引自减
index--;
//判断index是否小于0
if(index < 0){
index = imgArr.length - 1;
}
//alert("上一张");
img.src = imgArr[index];
info.innerHTML = "一共 "+imgArr.length+" 张图片,当前第 "+(index+1)+" 张";
};
next.onclick = function(){
//切换到下一张,index++
index++;
if(index > imgArr.length - 1){
index = 0;
}
//alert("下一张");
//切换图片就是修改img的src属性
//要修改一个元素的属性元素,属性 = 属性值
img.src = imgArr[index];
//当点击按钮以后,应该重新设置信息
info.innerHTML = "一共 "+imgArr.length+" 张图片,当前第 "+(index+1)+" 张";
};
}
</script>
</head>
<body>
<div id="outer">
<p id = "info">
</p>
<img src="img/1.png" alt="冰棍">
<button id="prev" type="button">一键复活</button>
<button id="next" type="button">一键去世</button>
</div>
</body>
</html>
获取元素节点的子节点
通过具体的元素节点调用
1.getElementsByTagName()
方法,返回当前节点的指定标签名后代节点
2.childNodes
属性,表示当前节点的所有子节点
3.firstChild
属性,表示当前节点的第一个子节点
4.lastChild
属性,表示当前节点的最后一个子节点
//为id为btn02的按钮绑定一个单击响应函数
var btn04 = document.getElementById("btn04");
btn04.onclick = function(){
//获取id为city的元素
var city = document.getElementById("city");
//document是整个页面中查询
//查找#city下所有li节点
var lis = city.getElementsByTagName("li");
for(var i=0;i<lis.length;i++)
{
alert(lis[i].innerHTML);
}
}
//为id为btn05的按钮绑定一个单击响应函数
var btn05 = document.getElementById("btn05");
btn05.onclick = function(){
//获取id为city的节点
var city = document.getElementById("city");
//返回#city的所有子节点
/*childNodes属性会获取包括文本节点在内的所有节点
根据DOM,标签间空白也会当成文本节点*/
var cns = city.childNodes;
/*children属性可以获取当前元素的所有子元素*/
alert(cns.length);
}
//为id为btn06的按钮绑定一个单击响应函数
var btn06 = document.getElementById("btn06");
btn06.onclick = function(){
//获取id为phone的元素
var phone = document.getElementById("phone");
//返回#phone的第一个子节点
//firstChild可以获取到当前元素第一个子节点(包括空白文本节点)
var fir = document.firstChild;
//firstElementChild获取当前元素的第一个子元素
fir = phone.firstElementChild;
};
97.获取父节点和兄弟节点
-
通过具体的节点调用
1.parentNode
属性,表示当前节点的父节点
2.previousSibling
属性,表示当前节点的前一个兄弟节点
3.nextSibling
属性,表示当前节点的后一个兄弟节点
/*定义一个函数,专门用来为指定元素绑定单击响应函数
参数:
idStr 要绑定单击响应函数的对象的id属性值
fun 时间的回调函数,当单击元素时,该函数将会被触发*/
function myClick(idStr,fun)
{
var btn = document.getElementById(idStr);
btn.onclick = fun;
}
/*为id为btn07的按钮绑定一个单击响应函数
函数也是对象,是对象就可以作为参数
*/
myClick("btn07",function(){
alert("Hello");
})
//获取id为bj的节点
var bj = document.getElementById("bj");
//返回#bj的父节点
var pn = bj.parentNode;
alert(pn);
/*innerText
- 该属性可以获取到元素内部的文本内容
- 它和innerHTML类似,不同的是它会自动将html去除*/
alert(pn.innerText);
//为id为btn08的按钮绑定一个单击响应函数
myClick("btn08",function(){
//获取id为android的元素
var and = document.getElementById("android");
//返回#android的前一个兄弟节点,(也可能获取到空白的文本)
var ps = and.previousSibling;
var pe = and.previousElementSibling;
//previousElementSibling获取前一个兄弟元素
alert(ps.innerHTML);
})
//读取#username的value属性值
myClick("btn09",function(){
//获取id为username的元素
var um = document.getElementById("username");
//读取um的value属性值
//文本框的value属性值就是文本框中填写的内容
alert(um.value);
});
//设置#username的value属性值
myClick("btn10",function(){
//获取id为username的元素
var um = document.getElementById("username");
um.value = "今天天气真不错";
});
//返回#bj的文本值
myClick("btn11",function(){
//获取id为bj的元素
var bj = documentgetElementById("bj");
alert(bj.innerHTML);
})
//获取bj中的文本节点
alert(bj.firstChild.nodeValue);
window.onload = function(){
//这个没看明白,后期专门回来补一下
//全选按钮,点击按钮以后四个多选框全都被选中
/*1.#checkedAllBtn
为id为checkedAllBtn的按钮绑定一个单击响应函数*/
//获取四个多选框items
var items = document.getElementByName("items");
var checkedAllBtn = document.getElementById("checkedAllBtn");
checkedAllBtn.onclick = function(){
//设置四个多选框变成选中状态
//遍历items
for (vari=0;i<items.length;i++){
//设置四个多选框变成选中状态
items[i];
}
//通过多选框的checked属性可以来获取或设置多选框的选中状态
//alert(items[i].checked);
//设置四个多选框变成选中状态
items[i].checked = true;
}
//将全选/全不选设置为不选中
checkedAllBox.checked = true;
/*全不选按钮
点击按钮,四个多选框都变成没选中的状态*/
//2.#checkedNoBtn
//为id为checkedNoBtn的按钮绑定一个单击响应函数
var checkNoBtn = document.getElementById("checkedNoBtn");
checkedNoBtn.onclick = function(){
for(var i=0;i<items.length;i++){
//将四个多选框设置为未选中状态
items[i].checked = false;
}
//将全选/全不选设置为不选中
checkedAllBox.checked = false;
};
/*反选按钮
点击按钮以后,选中的变成没选中,没选中的变成选中
*/
var checkRevBtn = document.getElementById("checkedRevBtn");
checkedRevBtn.onclick = function(){
for(var i=0;i<items.length;i++){
//判断多选框状态
/*if(items[i].checked){
//证明多选框已选中,则设置为没选中状态
items[i].checked = false;
}else{
//证明多选框没选中,则设置为选中状态
items[i].checked = true;
}*/
items[i].checked = !items[i].checked;
}
//在反选时需要判断四个多选框是否全都选中
};
/*提交按钮:
- 点击按钮以后,将所有选中的多选框的value属性弹出
4.#sendBtn 为sendBtn绑定单击响应函数*/
var sendBtn = document.getElementById("sendBtn");
sendBtn.onclick = function(){
//遍历items
for (var i=0;i<items.length;i++){
//判断多选框是否选中
if(items[i].checked){
alert(items[i].value);
}
}
};
/*5.#checkedAllBox
全选/全不选 多选框
- 当它选中时,其余的也玄宗,当它取消时其余的也取消
- 在事件的响应函数中,响应函数是给谁绑定的,this就是谁
//为checkedAllBox绑定单击响应函数*/
var checkedAllBox = document.getElementById("checkedAllBox");
checkedAllBox.onclick = function(){
//设置多选框的选中状态
for(var i=0;i<items.length;i++){
items[i].checked = this.checked;
}
}
this如果以函数调用,this是window
this如果以方法调用,this是调用方法的对象
100.
/*如果四个多选框全都选中,则checkedAllBox也应该选中
如果四个多选框没都选中,则checkedAllBox也不应该选中*/
//为四个多选框分别绑定单击响应函数
for(var i=0;i<items.length;i++){
items[i].onclick = function(){
//将checkedAllBox设置为选中状态
checkedAllBox.checked = true;
for(var j=0;j<items.length;j++){
//判断4个多选框是否全选
//只要有1个没选中,就不是全选
if(items[j].checked){
//一旦进入判断,则证明不是全选状态
//将checkedAllBox设置为没选中状态
checkedAllBox.checked = false;
//一旦进入判断,则已经得出结果,不用再继续执行循环
}
}
//判断4个多选框是否全选
}
}
}
101.dom查询的其它方法
window,onload = function(){
//在document中有一个属性body,它保存的是body的引用
var body = document.body;
//document.documentElement保存的是html根标签
var html = document.documentElement;
}
/*根据元素的class属性值查询一组元素节点对象
getElementByClassName()可以根据class属性获取一组元素节点对象
但是该方法不支持IE8以下的浏览器*/
var box1 = document.getElementsByClassName("box1");
console.log(box1.length);
/*获取页面中的所有div*/
var divs = document.getElementByTagName("div");
/*ducoment.querySelector() 很强大,可以接受CSS选择器作为参数
- 需要一个选择器的字符串作为参数,可以根据一个CSS选择器来查询一个元素节点对象
- 虽然IE8没有getElementByClassName()但是可以用querySelector()
- 使用该方法总会返回唯一的元素,如果满足条件的元素有多个,name它只会返回第一个*/
var div = document.querySelector(".box1 div");
var box1 = document.querySelector(".box1");
/*document.querySelectorAll()
- 该方法和querySelector()用法类似,不同的是它会将符合条件的元素封装到一个数组中返回
console.log(divs.length);
102.dom增删改查
window.onload = function(){
/*创建一个 广州 节点,添加到#city下*/
myClick("btn01",function(){
/*创建广州节点<li>广州<li>
分2步
1:创建li元素节点
document,createElement()
可以用于创建一个元素节点对象,它需要一个标签名作为参数,将会根据该标签名创建元素对象,并将创建好的对象作为返回值返回*/
var li = document.createElement("li");
/* 2:创建广州文本节点
document.createTextNode()
可以用来创建一个文本节点对象
需要一个文本内容作为参数,将会根据该内容创建文本节点,并将新的节点返回*/
var gzText = document.createTextNode("广州");
/*将gzText设置li的子节点
appendChild()
- 向一个父节点中添加一个新的子节点
- 用法:父节点.appendChild(子节点);*/
li.appendChild(gzText);
//获取id为city的节点
var city = document.getElementById("city");
//将广州添加到city下
city.appendChild(li);
});
/*将 广州 节点插入到#bj前面*/
myClick("btn02",function(){
//创建一个广州
var li = document.createElement("li");
var gzText = document.createTextNode("广州");
li.appendChild(gzText);
//获取id为bj的节点
var bj = document.getElementById("bj");
//获取city
var city = document.getElementById("city");
/*insertBefore()
可以再指定的子节点前插入新的子节点
语法:
父节点.insertBefore(新节点,旧节点);*/
city.insertbefore(li,bj)
});
//使用“广州”节点替换#bj节点
myClick("btn03",function(){
//创建一个广州
var li = document.createElement("li");
var gzText = document.createTextNode("广州");
li.appendChild(gzText);
//获取id为bj的节点
var bj = document.getElementById("bj");
//获取city
var city = document.getElementById("city");
/*replaceChild()
- 可以是用指定的子节点替换已有的子节点
- 语法:父节点.replaceChild(新节点,旧节点);*/
city.replaceChild(li,bj);
});
//删除#bj节点
myClick("btn04",function(){
//获取id为bj的节点
var bj = document.getElementById("bj");
//获取city
var city = document.getElementById("city");
/*removeChild()
- 可以删除一个子节点
- 语法1:父节点.removeChild(子节点);
- 语法2:子节点.parentNode.removeChild(子节点);
});*/
//city.removeChild(bj); 他杀
bj.parentNode.removeChild(bj); 自杀
});
//读取#city内的HTML代码
myClick("btn05",function(){
//获取city
var city = document.getElementById("city");
alert(city.innerHTML);
});
//设置#bj内的HTML代码
myClick("btn06",function(){
//获取bj
var bj = document.getElementById("bj");
bj.innerHTML = "昌平";
});
myClick("btn07",function(){
//向city中添加广州,等同于向ul中添加li,相当于在ul中修改HTML代码
var city = document.getElementById("city");
/*使用innerHTML也可以完成DOM的增删改的相关操作
一般两种方式结合使用*/
//city.innerHTML += "<li>广州</li>";
//创建一个li **推荐使用**
var li = document.createElement("li");
//向li中设置文本
li.innerHTML = "广州";
//将li添加到city中
city.appendChild(li);
});
103.练习 员工信息增删改查
//添加新员工 script部分
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script type="text/javascript">
window.onload = function(){
/*点击超链接后,删除一个员工的信息
需要给每个超链接绑定单击响应函数
获取所有超链接
*/
var allA = document.getElementsByTagName("a");
//为每个超链接都绑定一个单击响应函数
for(var i=0;i<allA.length;i++){
allA[i].onclick = function(){
alert("hello");
/*点击超链接以后需要删除超链接所在的那行
这里我们点击哪个超链接this就是谁
获取当前tr*/
var tr = this.parentNode.parentNode;
//获取要删除的员工的名字
var name = tr.getElementsByTagName("td")[0].innerHTML;
//删除之前弹出的一个提示框
/*confirm()用于弹出一个带有确认和取消按钮的提示框
需要一个字符串作为参数,该字符串会作为提示文字显示出来
用户点击确认返回true,点击取消返回false*/
var flag = confirm("确认删除"+name+"吗?");
//如果用户点击确认
if(flag){
/*删除tr*/
tr.parentNode.removeChild(tr);
}
/*点击超链接以后,超链接会跳转页面,这个是超链接的默认行为
但是此时我们不希望出现默认行为,
可以通过在响应函数的最后return false来取消默认行为*/
return false;
}
}
}
</script>
</head>
<body>
</body>
</html>
//delete new employer
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script type="text/javascript">
//add new employer
/*点击按钮以后,将员工的信息添加到表格中
为提交按钮绑定单击响应函数*/
var addEmpButton = document.getElementById("addEmpButton");
addEmpButton.onclick = function(){
//获取用户填写的员工信息
//获取员工的名字
var name = document.getElementById("empName").value;
//获取员工弄的邮件和薪水
var email = document.getElementById("email").value;
var salary = document.getElementById("salary").value;
//需要将获取到的信息保存到tr中
//创建一个tr
var tr = document.createElement("tr");
//创建四个td
var nameTd = document.createElement("td");
var emailTd = document.createElement("td");
var salaryTd = document.createElement("td");
var aTd = document.createElement("td");
//创建一个a元素
var a = document.createElement("a");
//创建文本节点
var nameText = document.createTextNode(name);
var emailText = document.createTextNode(email);
var salaryText = document.createTextNode(salary);
var delText = document.createTextNode("Delete");
//将文本添加到td中
nameTd.appendChild(nameText);
emailTd.appendChild(emailText);
salaryTd.appendChild(salaryText);
//向a中添加文本
a.appendChild(delText);
//将a添加到td中
aTd.appendChild(a);
//将td添加到tr中
tr.appendChild(nameTd);
tr.appendChild(emailTd);
tr.appendChild(salaryTd);
tr.appendChild(aTd);
//向a中添加href属性
a.href = "javascript:;";
//为新添加的a再绑定一个单击响应函数
a.onclick = = function(){
alert("hello");
/*点击超链接以后需要删除超链接所在的那行
这里我们点击哪个超链接this就是谁
获取当前tr*/
var tr = this.parentNode.parentNode;
//获取要删除的员工的名字
var name = tr.getElementsByTagName("td")[0].innerHTML;
//删除之前弹出的一个提示框
/*confirm()用于弹出一个带有确认和取消按钮的提示框
需要一个字符串作为参数,该字符串会作为提示文字显示出来
用户点击确认返回true,点击取消返回false*/
var flag = confirm("确认删除"+name+"吗?");
//如果用户点击确认
if(flag){
/*删除tr*/
tr.parentNode.removeChild(tr);
}
/*点击超链接以后,超链接会跳转页面,这个是超链接的默认行为
但是此时我们不希望出现默认行为,
可以通过在响应函数的最后return false来取消默认行为*/
return false;
}
//获取table
var employeeTable = document.getElementById("employeeTable");
//获取employeeTable中的<tbody>
var tbody = employeeTable.getElementsByTagName("tbody")[0];
</tbody>
//将tr添加到table中
employeeTable.appendChild(tr);
}
</script>
</head>
<body>
</body>
</html>
//设置tr中的内容 不推荐tr.innerHTML = "<td>"+name+"</td>"+ "<td>"+email+"</td>"+ "<td>"+salary+"</td>"+ "<td><a href='javascript:;'>Delete</a></td>";//获取刚刚添加的a元素,并为其绑定单击响应函数var a = tr.getElementsByTagName("a")[0];a.onclick = delA;
/*for循环会在页面加载完成之后立即执行
而响应函数会在超链接被点击时才执行
当响应函数执行时,for循环早已执行完毕*/
107.使用DOM操作CSS
操作内联样式
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<style type="text/css">
#box1{
width: 200px;
height: 200px;
background-color: red;
}
</style>
<script>
window.onload = function(){
var box1 = document.getElementById("box1");
var btn01 = document.getElementById("btn01");
btn01.onclick = function(){
/*通过JS修改元素样式
语法:
元素.style.样式名 = 样式值
注意:如果CSS的样式名中含有-,
这种名称在JS中是不合法的
需要去掉 - ,然后将 - 后的字母以驼峰方式命名
通过style属性设置的样式都是内联样式
而内联样式有较高的优先级,所以通过JS修改的样式往往会立即显示
但是如果在样式中写了 !important 则此时样式会有最高优先级
即使通过JS也不能覆盖样式,此时将会导致JS修改样式失效
所以尽量不要为样式添加 !important*/
box1.style.width = "500px";
box1.style.height = "500px";
box1.style.backgroundColor = "green";
/*通过style属性设置和读取的都是内联样式
无法读取样式表中的样式*/
}
};
};
</script>
</head>
<body>
<button type="button" id="btn01">点我一下</button>
<div id="box1">
</div>
</body>
</html>
108.获取元素的样式
<!DOCTYPE html><html lang="zh"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title></title> <style type="text/css"> #box1{ width: 100px; height: 100px; background-color: yellow; } </style> <script type="text/javascript"> window.onload = function(){ var box1 = document.getElementById("box1"); btn01.onclick = function(){ //读取box1的宽度 //alert(box1.style.width); /*获取元素的当前显示的样式 语法:元素.currentStyle.样式名 可以用来读取当前元素正在显示的样式 如果当前元素没有设置该样式,则回去它的默认值*/ alert(box1.currentStyle.width); }; }; </script></head><body> <button id="btn01">点击这里</button>; <div id="box1"> </div></body></html>
- getStyle( )方法
110.其他元素属性
/*clientWidth clientHeight 这两个属性可以获取元素的可见宽度和高度 这些属性都是不带px的,返回都是一个数字,可以直接进行计算 会获取元素的宽度和高度,包括内容区和内边距 这些属性都是只读的,没法修改 offsetWidth offsetHeight 获取元素的整个的宽度和高度,包括内容区,内边距和边框 offsetParent 可以用来获取当前元素的定位父元素 会获取到离当前元素最近的开启了定位的祖先元素 如果所有的祖先元素都没有开启定位,则返回body offsetLeft 当前元素相对于其定位元素的水平偏移量 offsetTop 当前元素相对于其定位元素的垂直偏移量 scrollWidth scrollHeight 可以获取元素整个滚动区域的高度 scrollLeft 可以获取水平滚动条滚动的距离 scrollTop 可以获取垂直滚动条滚动的距离 当满足scrollHeight - scrollTop == clientHeight 说明垂直滚动条滚动到底了 当满足scrollWidth - scrollLeft == clientHeight 说明水平滚动条滚动到底 如果为表单项添加disabled="disabled"则表单项将变成不可用的状态
111.事件对象
当鼠标在areaDiv中移动时,在showMsg中来显示鼠标的坐标
//获取两个divvar areaDiv = document.getElementById("areaDiv");var showMsg = document.getElementById("showMsg");/*onmousemove- 该事件将会在鼠标在元素中移动时被触发事件对象当事件的响应函数被触发时,浏览器每次都会将一个事件作为实参传递进响应函数 在事件对象中封装了当前时间相关的一切信息,比如:鼠标的坐标,键盘哪个键被按下,鼠标轮滚动的方向*/areaDiv.onmousemove = function(event){ //在showMsg中显示鼠标的坐标 /*clientX可以获取鼠标指针的水平坐标 clientY可以获取鼠标指针的垂直坐标*/ var x = event.clientX; var y = event.clientY; //在showMsg中显示鼠标的坐标 showMsg.innerHTML = "x = "+x+" , y = "+y;}
112.div跟随鼠标移动
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style type="text/css">
#box1{
width: 100px;
height: 100px;
background-color: red;
/*开启box1的绝对定位
*/
position: absolute;
};
</style>
<script type="text/javascript">
window.onload = function(){
//使div可以跟随鼠标移动
//获取box1
var box1 = document.getElementById("box1");
//绑定鼠标移动事件
document.onmousemove = function(event){
//解决兼容问题
event = event || window.event;
//获取滚动条滚动的距离
var st = document.body.scrollTop;
var sl = document.body.scrollLeft;
//chrome认为浏览器的滚动条是body的,可以通过body.scrollTop来获取
//获取到鼠标的坐标
//var left = event.clientX;
//var top = event.clientY;
/*clientX和clientY
用于获取鼠标在当前的课件窗口的坐标
pageX和pageY可以获取鼠标相对于当前页面的坐标
*/
var left = event.pageX;
var top = event.pageY;
//设置div的偏移量
box1.style.left = left + "px";
box1.style.top = top + "px";
}
};
</script>
</head>
<body style="height: 1000px;width: 2000px;">
<div id="box1"></div>
</body>
</html>
113.事件的冒泡
<!DOCTYPE html><html> <head> <meta charset="utf-8" /> <title></title> <style type="text/css"> #box1{ width: 200px; height: 200px; background-color: seagreen; } #s1{ background-color: yellow; } </style> <script type="text/javascript"> window.onload = function(){ /*事件的冒泡(Bubble) 冒泡指的是事件的向上传导,当后代元素上的事件被触发时, 其祖先元素的相同事件也会被触发 开发中,大部分冒泡都是有用的,如果不希望发生冒泡,可以通过事件对象来取消冒泡*/ //为s1绑定一个单击响应函数 var s1 = document.getElementById("s1"); s1.onclick = function(){ alert("我是span的单击响应函数"); //取消冒泡 //可以将事件对象的cancelBubble设置为true,即可取消冒泡 //此处只是取消span event.cancelBubble = true; }; //为box1绑定一个单击响应函数 var box1 = document.getElementById("box1"); box1.onclick = function(){ alert("我是div的单击响应函数"); }; //为body绑定一个单击响应函数 document.body.onclick = function(){ alert("我是body的单击响应函数"); }; } </script> </head> <body> </div> <div id="box1"> 我是box1 <span id="s1">我是span</span> </div> </body></html>
114.事件的委派
<!DOCTYPE html><html lang="zh"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title></title> <script type="text/javascript"> window.onload = function(){ var btn01 = document.getElementById("u1"); //点击按钮后添加超链接 var btn01 = document.getElementById("btn01"); btn01.onclick = function(){ //创建一个li var li = document.createElement("li"); li.innerHTML = "<a href='javascript:;' class='link'>新建的超链接</a>"; //将li添加到ul中 u1.appendChild(li); } /*为每一个超链接都绑定一个单击响应函数 这里我们为每一个超链接都绑定了一个单击响应函数,这种操作比较麻烦, 而且这些操作只能为已有的超链接设置事件,而新添加的超链接必须重新绑定*/ //获取所有的a var allA = document.getElementsByTagName("a"); //遍历 /*for(var i=0;i<allA.length;i++){ allA[i].onclick = function(){ alert("我是a的单击响应函数"); } }*/ /*我们希望只绑定一次事件,即可应用到多个元素上,即使元素是后添加的 我们可以尝试将其绑定给元素的共同的祖先元素 事件的委派 - 将事件统一绑定给元素的共同的祖先元素,这样当后代元素上的事件触发时, 会一直冒泡到祖先元素,从而通过祖先元素的响应函数来处理事件 事件委派是利用冒泡,通过委派可以减少事件绑定的次数,可以提高程序的性能 */ //为ul绑定一个单击响应函数 u1.onclick = function(event){ event = event || window.event; /* target - event中的target表示的触发事件的对象*/ //alert(event.target); /*如果触发事件的对象是我们期望的元素,则执行,否则不执行*/ if(event.target.className == "link"){ alert("我是ul的单击响应函数"); } //事件给谁绑定的,this就是谁 }; }; </script></head><body> <button id="btn01" type="button">添加超链接</button> <ul id="u1"> <p>我是P</p> <li class="link"> <a href="javascript:;" class="link">超链接一</a> </li> <li class="link"> <a href="javascript:;" class="link">超链接二</a> </li> <li class="link"> <a href="javascript:;" class="link">超链接三</a> </li> </ul></body></html>
115.事件的绑定
<!DOCTYPE html><html> <head> <meta charset="utf-8" /> <title></title> <script type="text/javascript"> window.onload = function(){ /*点击按钮后,弹出一个内容*/ var btn01 = document.getElementById("btn01"); //使用 对象.事件 = 函数 的形式绑定响应函数 //它只能同时为一个元素的一个事件绑定一个响应函数, //如果绑定了多个,则后边会覆盖掉前边的 /*为btn01绑定一个单击响应函数 btn01.onclick = function(){ alert(1); };*/ /*为btn01绑定第二个响应函数 //btn01.onclick = function(){ alert(2); };*/ /* addEventListener() - 通过这个方法也可以伪元素绑定响应函数 - 参数 1.事件的字符串,不需要on 2.回调函数,当事件触发时,该函数会被调用 3.是否在捕获阶段触发事件,需要一个布尔值,一般都传false 使用addEvenListener()可以同时为一个元素的相同事件同时绑定多个相应函数 当事件被触发时,响应函数将会按照函数的绑定顺序执行*/ btn01.addEventListener("click",function(){ alert(1); },false); btn01.addEventListener("click",function(){ alert(2); },false); btn01.addEventListener("click",function(){ alert(3); },false); }; /*定义一个函数,用来为指定元素绑定响应函数*/ /*addEventListener()中的this,是绑定事件的对象 attachEvent()中的this,是window 需要统一两个方法this*/ /*参数: obj 要绑定事件的对象 eventStr 事件的字符串(不要on) callback 回调函数*/ function bind(obj,eventStr,callback){ //大部分浏览器兼容的方式 obj.addEventListener(eventStr,callback,false); // } </script> </head> <body> <button id="btn01" type="button">点这里</button> </body></html>
117.事件的传播
微软认为事件触发时,应该先触发当前元素上的事件,然后再向当前元素的祖先元素上传播。(事件应该在冒泡阶段执行)
网景公司认为事件应该是由外向内传播的,也就是当前事件触发时,应该先触发当前元素的最外层的祖先元素的事件,然后再向内传播给后代元素
最后事件传播分成了三个阶段
-
1.捕获阶段
在捕获阶段时从最外层的祖先元素,向目标元素进行事件的捕获,但是默认此时不会触发事件
-
2.目标阶段
事件捕获到目标元素,捕获结束开始在目标元素上触发事件
-
3.冒泡阶段
事件从目标元素向他的祖先元素传递,一次触发祖先元素上的事件
如果希望在捕获阶段就触发事件,可以将addEventListener()的第三个参数设置为true,一般情况下我们不会希望在捕获阶段触发事件,所以这个参数一般都是false

118.事件的拖拽
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style type="text/css">
#box1{
width: 100px;
height: 100px;
background-color: red;
position: absolute;
}
#box2{
width: 100px;
height: 100px;
background-color: yellow;
position: absolute;
left:200px;
height: 200px;
}
</style>
<script type="text/javascript">
window.onload = function(){
/*拖拽box1这个元素
- 拖拽的流程
1.当鼠标在被拖拽元素上按下 onmousedown
2.当鼠标移动时被拖拽元素跟随鼠标移动 onmousemove
3.当鼠标松开时,被拖拽元素固定在当前位置 onmouseup
}*/
var box1 = document.getElementById("box1");
//为box1绑定一个鼠标按下事件
//当鼠标在被拖拽元素上按下时,开始拖拽 onmousedown
box1.onmousedown = function(event){
event = event || window.event;
//div的偏移量 鼠标.clientX - 元素.offsetLeft
//div的偏移量 鼠标.clientX - 元素.offsetTop
var ol = event.clientX - box1.offsetLeft;
var ot = event.clientY - box1.offsetTop;
//为document绑定一个onmousemove事件
document.onmousemove = function(event){
event = event || window.event;
//当鼠标移动时被拖拽元素跟随鼠标移动 onmousemove
//获取鼠标的坐标
var left = event.clientX - ol;
var top = event.clientY - ot;
//修改box1的位置
box1.style.left = left+"px";
box1.style.top = top+"px";
};
//为元素绑定一个鼠标松开事件
document.onmouseup = function(){
//当鼠标松开时,被拖拽元素固定在当前位置 onmouseup
//取消document的onmousemove事件
document.onmousemove = null;
//取消document的onmouseup事件
document.onmouseup = null;
};
};
};
</script>
</head>
<body>
<div id="box1"></div>
<div id="box2"></div>
</body>
</html>
119.鼠标的滚轮事件
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<script type="text/javascript">
window.onload = function(){
var btn01 = document.getElementById("u1");
//点击按钮后添加超链接
var btn01 = document.getElementById("btn01");
btn01.onclick = function(){
//创建一个li
var li = document.createElement("li");
li.innerHTML = "<a href='javascript:;' class='link'>新建的超链接</a>";
//将li添加到ul中
u1.appendChild(li);
}
/*为每一个超链接都绑定一个单击响应函数
这里我们为每一个超链接都绑定了一个单击响应函数,这种操作比较麻烦,
而且这些操作只能为已有的超链接设置事件,而新添加的超链接必须重新绑定*/
//获取所有的a
var allA = document.getElementsByTagName("a");
//遍历
/*for(var i=0;i<allA.length;i++){
allA[i].onclick = function(){
alert("我是a的单击响应函数");
}
}*/
/*我们希望只绑定一次事件,即可应用到多个元素上,即使元素是后添加的
我们可以尝试将其绑定给元素的共同的祖先元素
事件的委派
- 将事件统一绑定给元素的共同的祖先元素,这样当后代元素上的事件触发时,
会一直冒泡到祖先元素,从而通过祖先元素的响应函数来处理事件
事件委派是利用冒泡,通过委派可以减少事件绑定的次数,可以提高程序的性能
*/
//为ul绑定一个单击响应函数
u1.onclick = function(event){
event = event || window.event;
/*
target
- event中的target表示的触发事件的对象*/
//alert(event.target);
/*如果触发事件的对象是我们期望的元素,则执行,否则不执行*/
if(event.target.className == "link"){
alert("我是ul的单击响应函数");
}
//事件给谁绑定的,this就是谁
};
};
</script>
</head>
<body>
<button id="btn01" type="button">添加超链接</button>
<ul id="u1">
<p>我是P</p>
<li class="link">
<a href="javascript:;" class="link">超链接一</a>
</li>
<li class="link">
<a href="javascript:;" class="link">超链接二</a>
</li>
<li class="link">
<a href="javascript:;" class="link">超链接三</a>
</li>
</ul>
</body>
</html>
122.键盘事件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script type="text/javascript">
/*键盘事件:
onkeydown
- 按键被按下
- 对于onkeydown来说如果一直按着某个按键不松手,则事件会一直触发
- 当onkeydown连续触发时,第一次和第二次之间会间隔稍微长点,防止误操作
onkeyup
- 按键被松开
键盘事件一般都会绑定给一些可以获取到焦点的对象或者是document*/
document.onkeydown = function(event){
event = event || window.event;
/*可以通过keyCode来获取按键的编码
通过它可以判断哪个按键被按下
除了keyCode,事件对象中还提供了几个属性
altKey
ctrlKey
shiftKey
在文本框中输入内容,属于onkeydown的默认行为
数字的keyCode是48-57*/
}
</script>
</head>
<body>
<div style="width: 100px; height: 100px; background-color: red;">
</div>
</body>
</html>
使div可以根据不同的方向键向不同的方向移动
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style type="text/css">
#box1{
width: 100px;
height: 100px;
background-color: red;
position: absolute;
}
</style>
<script type="text/javascript">
//使div可以根据不同的方向键向不同的方向移动
window.onload = function(){
//为document绑定一个按键按下的事件
document.onkeydown = function(event){
event = event || window.event;
//定义一个变量,来表示移动的速度
var speed = 100;
//当用户按了ctrl以后,速度加快
if(event.ctrlKey)
{
speed = 1;
}
switch(event.keyCode){
case 37:
//alert("向左");left值减小
box1.style.left = box1.offsetLeft - speed + "px";
break;
case 39:
box1.style.left = box1.offsetLeft + speed + "px";
//alert("向右");
break;
case 38:
//alert("向上");
box1.style.top = box1.offsetTop - speed + "px";
break;
case 40:
//alert("向下");
box1.style.top = box1.offsetTop + speed + "px";
break;
}
};
};
</script>
</head>
<body>
<div id="box1"></div>
</body>
</html>
124.BOM(浏览器对象模型)
BOM可以使我们通过JS来操作浏览器
在BOM中为我们提供了一组对象,用来完成对浏览器的操作
BOM对象
Window
- 代表的是整个浏览器的窗口,同时window也是网页中的全局对象
Navigator
- 代表当前浏览器的信息,通过该对象可以来识别不同的浏览器
Location
-
代表当前浏览器的地址栏信息,通过Location可以获取地址栏信息
或者操作浏览器跳转页面
History
-
代表浏览器的历史记录,可以通过该对象来操作浏览器的历史记录
该对象不能获取到具体的历史记录,只能操作浏览器向前或向后
而且该操作只在当次访问时有效
Screen
- 代表用户的屏幕的信息,通过该对象可以获取到用户的显示器相关信息(用得少)
这些DOM对象在浏览器中都是作为window对象的属性保存的,可以通过window对象来使用,也可以直接使用
Navigator
使用userAgent来判断浏览器的信息
userAgent是一个字符串,这个字符串中包含有用来描述浏览器信息的内容
不同浏览器有不同的userAgent
//用正则表达式判断浏览器的名称
if(/firefox/i.test(ua)){
alert("这是火狐");
}else if(/chrome/i.test(ua)){
alert("这是chrome");
}
如果通过UserAgent不能判断,还可以通过一些浏览器中特有的对象,来判断浏览器的信息,比如ActiveXObject
if(window.ActiveXObject)
{
alert("你是IE");
}else{
alert("你不是IE");
}
125.History
对象可以用来操作浏览器向前或向后翻页
window.onload = function(){
//获取按钮对象
var btn = document.getElementById("btn");
btn.onclick = function(){
/*length
属性,可以获取到当前访问的链接数量
alert(history.length);*/
/*back()
可以用来回退到上一个页面,作用和浏览器的回退按钮一样
history.back();
forward()
可以跳转下一个页面,作用和浏览器的前进按钮一样
history.forward()'
go()
可以用来跳转到指定的页面
他需要一个整数作为参数
1:表示向前跳转一个页面
2:表示向前跳转两个页面
-1:表示向后跳转一个页面
-2:表示向后跳转两个页面
history.go(-1);*/
};
};
126.Location
//如果直接打印location,则可以获取到地址栏的信息(当前页面的完整路径)
//alert(location);
//如果直接将location属性修改为一个完整路径/相对路径
//则我们页面会自动跳转到该路径,并且会生成相应的历史记录
/*location = "http://www.baidu.com";
location = "01.BOM.html";
assigh()
用来跳转到其他的页面,作用和直接修改location一样
location.assign("http://www.sohu.com");*/
/*
reload()
- 用于重新加载当前页面,作用和刷新按钮一样
- 如果在方法中传递一个true作为参数,则会强制清空缓存刷新页面
location.reload(true);
replace()
- 可以使用一个新的页面替换当前页面,调用完毕也会跳转页面
- 不会生成历史记录
127.定时器
//图片定时显示
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script type="text/javascript">
window.onload = function(){
/*使图片可以自动切换*/
/*获取img标签*/
var img1 = document.getElementById("img1");
//创建一个数组来保存图片的路径
var imgArr = ["img/1.png","img/2.jpg"]
//创建一个变量,用来保存当前图片的索引
var index = 0;
/*开启定时器来自动切换图片*/
setInterval(function(){
/*目前,我们每点击一次按钮,就会开启一个定时器
点击多次会开启多个定时器,会导致图片切换速度过快,
并且我们只能关闭最后一次开启的定时器,
需要在开启定时器之前,将上一个定时器关闭
clearInterval(timer);*/
//使索引自增
index++;
//判断索引是否超过最大索引
if(index >= imgArr.length){
//则将index设置为0
index = 0;
}
//修改img1的src属性
img1.src = imgArr[index];
},100);
img1.src = imgArr[2];
//clearInterval()可以接收任意参数,如果参数是一个有效的定时器标识,
//则停止对应的定时器
//如果参数不是一个有效的表示,则什么也不做
}
</script>
</head>
<body>
<img id="img1" src="img/1.png" >
</body>
</html>
130.延时调用
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<script type="text/javascript">
//开启一个定时器
/*setInterval(function(){
})*/
/*延时调用:
延时调用一个函数不马上执行,而是隔一段时间以后再执行
而且只会执行一次
延时调用和定时调用的区别,定时调用会执行多次,
延时调用只会执行一次
延时调用和定时调用实际上是可以互相代替的,
在开发中可以根据自己的需要去选择*/
var timer = setTimeout(function(){
console.log(num++);
//使用clearTimeout()来关闭一个延时调用
clearTimeout(timer);
},3000);
</script>
<body>
</body>
</html>
131.轮播图
137.类的操作
//定义一个函数,用来向一个元素中添加指定的class属性值
/*参数:
obj 要添加class属性的元素
cn 要添加的class值*/
function addClass(obj , cn){
obj.className += " "+cn;
}
138.二级菜单
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script type="text/javascript" src="js/tools.js"></script>
<script type="text/javascript" >
window.onload = function(){
/*每个菜单都是一个div
当我们div具有collapsed这个类时,div就是折叠的状态
当div没有这个类时,就是展开的状态
点击菜单,切换菜单的显示状态
获取所有的class为menuSpan的元素*/
var menuSpan = document.querySelectorAll(".menuSpan");
//定义一个变量,来保存当前打开的菜单
var openDiv = menuSpan[0].parentNode;
//为span绑定单击响应函数
for(var i=0;i<menuSpan.length;i++)
{
menuSpan[i].onclick = function(){
//this代表当前点击的span
//获取当前span的父元素
var parentDiv = this.parentNode;
//在切换类之前,获取元素的高度
var begin = parentDiv.offsetHeight;
//切换parentDiv的显示
toggleClass(parentDiv,"collapsed");
//在切换类之后,获取元素的高度
var end = parentDiv.offsetHeight;
//动画效果就是将begin向end过渡
/*将元素的高度重置为begin*/
parentDiv.style.height = begin + "px";
//执行动画,从begin向end过渡
move(parentDiv,"height",end,10,function(){
}
//判断openDiv和parentDiv是否相同
if(openDiv != parentDiv && !hasClass(openDiv , "collapsed"))
{
//打开菜单以后,应该关闭之前打开的菜单.
//为了可以统一处理动画过渡效果
//,我们希望将addClass改为toggleClass
//toggleClass 有则移除,没有则加上
//此处toggleClass()不需要有移除的功能
toggleClass(openDiv,"collapsed");
}
//修改openDiv为当前打开的菜单
openDiv = parentDiv;
};
}
}
</script>
</head>
<body>
</body>
</html>
140.JSON
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<script type="text/javascript">
/*JS中的对象只有JS认识
JSON就是一个特殊格式的字符串,这个字符串可以被任意的语言所识别
并且可以转换为任意语言中的对象,JSON在开发中主要用来数据的交互
JSON
- JS Object Notation JS对象表示法
- JSON和JS对象的格式一样,只不过JSON字符串中的属性名必须加双引号
JSON分类:
1.对象{}
2.数组[]
JSON中允许的值:
1.字符串
2.数值
3.布尔值
4.null
5.对象
6.数组
*/
//创建一个对象
var obj = '{"name":"孙悟空","age":"18","gender":"male"}';
var arr = '[1,2,3,"hello",true]';
/*将JSON字符串转换为JS中的对象
在JS中,为我们提供了一个工具类,叫JSON
这个对象可以帮助我们将JSON转换为JS对象,也可以将JS对象转换为JSON
json --> js对象
JSON.parse()
- 可以将以JSON字符串转换为js对象
- 它需要一个JSON字符串作为参数,会将该字符串转换为JS对象并返回
var o = JSON.parse(json);
var o2 = JSON.parse(arr);
var obj3 = {name:"猪八戒" , age:28 , gender:male};*/
/*JS对象 --> JSON
JSON.stringify()
- 可以将一个JS对象转换为JSON字符串
- 需要一个js对象作为参数,会返回一个JSON字符串
*/
var str = JSON.stringify(obj3);
/*eval()
- 这个函数可以用来执行一段字符串形式的JS代码,并将执行结果返回
- 如果使用eval()执行的字符串中含有{},它会将{}当成是代码块
- 如果不希望将其当成代码块解析,则需要在字符串前后各加一个()
- eval()可以直接执行一个字符串中的JS代码,但是在开发中尽量不要使用
*/
var str2 = "alert('hello');"
var obj = eval("("+str+")");
</script>
<body>
</body>
</html>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话