初识JS
shift+alt+a多行注释
js的输入输出:
prompt()输入的
alert()输出的,展示给用户的
console.log()控制台显示
js是弱语言,动态语言,变量的类型是可以变的,根据右边具体的值来变
比如
var x=10;//数字型
x='hello'//变成字符串型
//这种也是可以的
数据类型的转换
八进制就是在数字面前写0
var num = 010;
console.log(num);
//就是8
//16进制就是,前面加0x
var num = 0x9;//9十进制
var num = 0xa;//10十进制
数字型有最大值和最小值
然后还有三个特殊的
1.无穷大(Infinity)
2.无穷小(-Infinity)
3.NaN(非数值)
isNaA()//这个方法用来判断非数字,并且返回一个值,如果是数字,返回的是false,如果不是数字,返回的是true
字符串型String
1.检测字符串的长度
var str = 'zhangyujie';
console.log(str.length);
2.字符串的拼接 +
console.log('zhangyujie'+2.5);//zhangyujie2.5
console.log('zhangyujie'+'is good');// zhangyujieis good
console.log('3'+2.5);//32.5
console.log(3+2.5);//5.5
布尔型
var flag = true;
console.log(flag+1);//为2
//参加加法运算,true视为1,false是为0
1.true
2.false
3.undefined
4.null
typeof用来检测数据类型
var num = 10;
console.log(typeof num);
还可以通过浏览器控制台的颜色来判断是什么类型的
比如在蓝色是数字型,黑色是字符型,浅灰色是布尔型
数据类型的转换
因为在表单和prompt接收到的数据都是字符型,需要数字型才能进行操作
数字型转换为字符型
1.toString()
2.利用String()
3.利用+拼接字符串的方法(隐式转换)
var num = 12;
var str = num.toString();
var str1= String(num);
console.log(num);
console.log(str1);
console.log(str);
字符型转换为数字型
1.pareseInt()方法,取整数,然后还可以直接去掉px,如果开头是字母就不能转换了
str = '123.56'
console.log(parseInt('23.5'));//23
console.log(parseInt(str));//123
console.log(parseInt('120px'));//打印出120
2.parseFloat()方法,取小数点,也能去掉px
3.Number()
4.利用算数运算,-,*,/隐式转换
console.log('12'-0)//12整数
console.log('12'-'1')//11
第二天看运算符
运算符
/除
%余
例:3%5结果为3
浮点数运算里面会有问题,例如,解决方法以后学习
console.log(0.1 + 0.2);//0.30000000000000004
console.log(0.07 * 100 );//7.000000000000001
所以0.1+0.2不等于0.3
以后进行计算,避开浮点数,会出现精度问题,因为二进制的转换
表达式和返回值
表达式都会有个返回值给我们
console.log('1+1')//2就是返回值,1+1就是表达式
递增递减运算符
++,–必须写在变量的前面或者后面,如果单独使用效果一样,并且还会有些区别
前置递增:顺序是,先加1 后返回值
后置递增:先返回原值,后自加,例如
var age =10;
console.log(age);//10
console.log(age++ + 10);//20
console.log(age);11
//例子
var e =10;
var f = e++ + ++e;
console.log(f);//22
比较运算符
需要注意的是
==有默数据转换
===全等,必须一模一样
比如
console.log(18==18);//true
console.log(18=='18');//true
console.log(18==='18');//false
console.log(18===18);//true
逻辑运算符
&&与
||或
!非
短路运算(逻辑中断)
如果左边的值已经确定结果了,就不再计算右边的结果了
&&如果左边的值为1,就得到表达式2的值作为结果
如果表达式为假(如果有空或者否定为假,其余都为真,0,” , null undefined NaN),则返回式为假false
console.log(123 && 456);//456
console.log(0 && 456);//0
逻辑或短路运算
如果表达式1结果为真,则返回的是表达式1 如果表达式1 结果为假,则返回表达式2
赋值运算符
=
+=
-=
*=
/=
运算符
小括号
一元运算符
算数运算符
关系运算符
相等运算符
逻辑运算符
赋值运算符
逗号运算符
js流程控制
能够使用if分支语句
#3 多分支语句
if
else if
就是多分支了
判断成绩的案例
var score = prompt("请输入分数");
if (score >= 90) {
alert("优秀");
} else if (score >= 80) {
alert("良好");
} else if (score >= 70) {
alert("中等");
} else if (score >= 60) {
alert("及格");
} else {
alert("不及格");
}
三元表达式
语法结构:条件表达式?表达式1:表达式2
执行思路,如果条件表达式结构为真,则返回表达式1的值,如果为假则返回表达式2的值
例子,小于10在前面补0
var score = prompt("请输入一个数字");
var res;
res = score >=10?score:0+score;
console.log(res);
switch语句
switch(条件表达式){
case value1:
执行语句1;
break;
case value2:
执行语句2;
break;
default:
执行语句3;
break;
}
swtich里面的条件表达式,一般写成一个变量
num的值和case里面的值相匹配的时候必须是全等,必须的值数据类型一致才可以。就是===
break没说一定要写,但是最好写,如果当前的case里面没有break,则不会退出switch,继续执行下一个case
switch(1){
case 1:
console.log('1');
case 2:
console.log('2');
case 3:
console.log('3');
}//这样会把1,2,3都打印出来
if else和switch两个一般可以相互替换。
如果能确定值的情况下,用switch比较合适。
如果是范围的清空,if else比较合适。
分支多的时候swtich效率会更好一些,分支结构少的时候,if else效率更高
循环结构
循环的目的:可以重复执行某些代码,让程序更简单更高效
for (var i=0;i<10;i++){
alert('我错了')
}
句法结构:
1.for
循环体,中值条件,一起组成循环语句
//for循环重复执行某些代码,通常跟计数,次数有关系
for (初始化变量;条件表达式;操作表达式) {
循环体;
}
//打印100行你好
for (var i = 0; i<100;i++){
console.log('你好');
}
1-100的的累加和
var sum = 0;
for (var i = 1; i<=100;i++){
sum +=i;
}
console.log(sum);
九九乘法表
var str = ''
var res;
for (var row = 1;row<10;row++){
for (var col = 1;col<=row;col++){
res =col + "*" + row + "=" + col*row+" ";
str +=res;
}
str = str + '\n';
}
console.log(str);
/*
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*4=4 2*4=8 3*4=12 4*4=16
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81 */
2.while
while(条件表达式) {
//循环体
}
//执行思路 当条件表达式结果为true 执行循环体,否则退出循环
和for循环差不多,小心死循环,一定要有计数器初始化变量,和操作表达式
3.do while
do {
//循环体
} while(条件表达式){
//要先执行一次循环体,再来判断条件,如果条件判断为假
4.continue
continue继续跳出本次循环,继续下一次循环
5.break
可以退出整个循环,立马就退出
数组
把一组数据存在一个变量下。是一组数据的结合。
创建数组
1.
2.利用new关键字创建数组
var a = new Array();//创建一个空数组
3.利用数组字面量创建数组
1.使用数组字面量方式创建空的数组
var 数组名 = [];
2.使用数组字面量方式创建带值得数组
var 数组名 = ['小白','小黑','小红'];//这种方式用的更加多,数组里面得数据一定要逗号分隔。
数组里面得数据的元素类型是任意的。
访问数组元素
1.数组的索引,下标,用来访问数组元素的序号。
索引从0 开始
使用方式
var a = [1,2,3] ;
console.log(a[0]);
2.遍历数组
遍历:把数组每一个元素从头到尾都访问一次。
var a = [1,2,3] ;
for (var i=0 ; i<3 ; i++) {
console.log(a[i]);
}
增加数组元素
1.新增数组元素,修改length长度
var a = ['helo', 'world', 'this', 'is', 'a', 'test'];
a.length = 9//这样多出来的两个就变为空
2.修改数组索引
var arr1 = ['2','2','3','4'];
arr1[4]='5'//追加数组元素
//如果索引的已经存在了,则会被替换
3.push这个方法可以增加数组
var a = [];
for (var i = 0; i < 10; i++) {
a.push(i);
}
console.log(a);//给一个空数组存入1-9的数
4.冒泡算法
//把一系列数组按照一定的数据排列显示,从小到大,从大到小
//一次比较两个元素,如果顺序错误就交换
var a = [5,4,3,2,1];
for (var i = 0; i < a.length-1; i++) {
for(var j=0; j < a.length-i-1; j++) {
if(a[j] > a[j+1]) {
if (a[j] > a[j+1]) {
var temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
}
}
console.log(a);
函数
函数是封装了一段重复执行调用的代码块,目的是让大量的代码重复使用
函数的使用
1.函数的声明
function 函数名() {
函数体
}
//function 声明函数的关键字全部小写
//函数名一般是动词
//函数不调用,自己不执行
2.函数的调用
调用函数的时候要加小括号。
function hanshu(){
console.log('函数')
}
hanshu();
3.带参数的函数
function 函数名(形参1,形参2。。。){
}
函数名(实参1,实参2....)
//形参可以接收实参,函数的参数可以有,也可以没有,不限个数
js里面的形参和实参不匹配也没事
function helo(num1,num2){
var res = num1+num2;
console.log(res);
}
helo(1,2);//正常情况,结果为3
helo(1);//一个实参,多余的形参定义为undefined,最终的结果为NaN
helo(1,2,3);//三个实参,还是3
//尽量相匹配
4.函数的返回值
输出语句一定要返回,函数内部一定不要有输出语句。
用return来实现
function hanshu(){
函数体
return 需要返回的结果;
}
//只要函数遇到return 就把后面的结果返回函数的调用者 函数名()=return 后面的结果
代码验证
function cook(){
return 666;
}
cook();
console.log(cook());
return 终止函数
return语句后面的代码不会执行
function helo(num1,num2){
var res = num1+num2;
return res;
alert('我不会执行');
}
helo(1,2);
return只能返回一个值
return num1,num2;//返回的是num2
但是如果想返回多个值,就把结果写进数组,返回数组就可以了
return [num1,num2];
函数如果有return,则返回return后面的值,如果没有return,则返回undefined
return:不仅可以退出循环,还可以结束函数的代码
break就不行,只能退出循环
判断是否是质数
var num = Number(prompt("Enter a number: "));
function number(num){
for(var i=2;i<num;i++){
if(num%i==0){
return("Not a prime number");
}
}
return "Prime number";
}
console.log(number(num));
agruments的使用
agruments里面存储了所有实参
agruments展示方式是一个伪数组。(具有数组的length属性,按照索引号进行存储,他没有真正数组的一些方法,比如push,pop等)
只有函数才有arguments,每个函数都内置好了的
function test() {
console.log(arguments);
}
test(1, 2, 3); // { '0': 1, '1': 2, '2': 3 }//Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
\\使用agruments来获取最大值
function getMax(){
var max = 0;
for (var i = 0; i < arguments.length; i++){
if (arguments[i] > max){
max = arguments[i];
}
}
return max;
}
console.log(getMax(1, 2, 3)); // 5
console.log(getMax(5, 4, 3, 2, 1)); // 5
console.log(getMax(11, 22, 43, 25, 44)); // 5
利用函数封装的方法,来翻转数组
function reverse(arr) {
var newarr = [];
for (var i = arr.length - 1; i >= 0; i--) {
newarr.push(arr[i]);
}
return newarr;
}
var arr1 = reverse([1,2,3,45]);
console.log(arr1);
\\结果[45, 3, 2, 1]
js的预编译机制
就是相当于,在执行js语句的时候,会先编译再执行
然后具体的细节就是,先将遇到的var 变量和函数声明给放到作用域的前面再进行赋值。
//例子
var num = 10;
function fn1 (){
var num1 = 1;
console.log(num1);
}
//预编译的机制如下
var num;
function fn1 (){
var num1;
num1 = 1;
console.log(num1);
}
num = 10;
对象
创建对象的三种方式
方式1:
var test = new Object();
console.log(test); // true
方式2:
var test = {
age : 18,
name : 'zhangsan',
}
console.log(test.age);
方式3:利用构造函数创建对象
优点就是,能够批量的创建对象,类似python中间的类和实例化对象。构造函数创建类和函数的方法,就只有 在函数里面多了一个this来确保是在这个类,然后调用对象函数必须使用new。
//把相同的属性:相同的方法
//构造函数的语法格式
function 构造函数名(){
this.属性 = 值;
this.方法 = function() {
}
}
new 构造函数名
function Star(uname,age,sex){
this.uname = uname;
this.age = age;
this.sex = sex;
}
let zs = new Star('张三',18,'男');//构造函数不需要return,就能返回一个对象
console.log(zs);//Star {uname: '张三', age: 18, sex: '男'}
console.log(typeof zs);//得到object,说明就是一个对象
//创建网站英雄对象
function hero(age,type,blood,attack){
this.age = age;
this.type = type;
this.blood = blood;
this.attack = attack;
this.attack = function(){
console.log("attack");
}
this.defend = function(){
console.log("defend");
}
this.move = function(){
console.log("move");
}
};
var luna = new hero('露娜','打野','10000','法刺');
var houyi = new hero('后裔','发育路','5000','射手');
console.log(luna);
构造函数泛指某一大类,类似java里面的类class
对象指的是一个具体的实例,比如露娜,刘亦菲。
所以通过new创建对象的过程也被称为对象的实例化。
new关键字的执行过程
1.在内存中创建了一个空的对象。
2.让this指向这个新的对象。
3.执行构造函数里面的代码,让对象添加属性和方法。
4.返回这个对象(所以构造函数不需要return)
遍历对象
var obj = {
name:'xiaozhang',
age :'18',
sex:'famle'
fn1:function(){
}
}
//for in遍历对象
/* for (变量 in 对象){
} */
for(var k in obj){
console.log(k);//k变量输出的是属性名
console.log(obj[k]);//obj[k]输出的是属性值
}
使用for in 里面的变量,我们喜欢写k 或者 key
项目小作业-简易计算器
var a = prompt('1.加法运算\n2.减法运算\n3.乘法运算\n4.除法运算\n5.退出\n请输入你的选项');
function add() {
var a = parseFloat(prompt('请输入第一个数字'));
var b = parseFloat(prompt('请输入第二个数字'));
return a + b;
}
function sub() {
var a = parseFloat(prompt('请输入第一个数字'));
var b = parseFloat(prompt('请输入第二个数字'));
return a - b;
}
function mul() {
var a = parseFloat(prompt('请输入第一个数字'));
var b = parseFloat(prompt('请输入第二个数字'));
return a * b;
}
function div() {
var a = parseFloat(prompt('请输入第一个数字'));
var b = parseFloat(prompt('请输入第二个数字'));
return a / b;
}
if (a == 1) {
alert(add());
} else if (a == 2) {
alert(sub());
} else if (a == 3) {
alert(mul());
} else if (a == 4) {
alert(div());
} else if (a == 5) {
alert('退出');
}
效果:
内置对象
js里面的对象分为三类:自定义对象,内置对象,浏览器对象
前两种是js的基础内容,第三个是js独有
文档查询(MDN)忘记就去查
Math对象
math对象不是一个构造器,不需要new,属性和方法是静态的,直接使用就可以了
console.log(Math.PI); // 3.141592653589793
console.log(Math.max(1,4,2)); //4
封装自己的数学对象
var myMath = {
PI :3.14159265359,
MAX : function () {
var max = arguments[0];
for (var i = 1; i < arguments.length; i++) {
if (arguments[i] > max) {
max = arguments[i];
}
}
return max;
}
}
console.log(myMath.MAX(1, 2, 3, 4, 5)); // 5
Math.random()返回一个随机小数(0<=x<1)
方法里面不跟参数
代码验证
console.log(Math.random());//0.6026389167533179
//生成一定范围的整数随机数
function getrandNumber(min , max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
console.log(getrandNumber(1, 10)); // 1-10 arası rastgele sayı üretir
猜数字的案例
\\猜数字的案例
function getrandNumber(min , max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var random = getrandNumber(1, 10);
while (true) {//死循环
var num = prompt("请输入一个1-10的数字:");
if (num > random) {
alert("大了");}
else if (num < random) {
alert("小了");
} else {
alert("猜对了");
break;
}
}
日期对象
Date实例需要使用调用Date构造函数,必须使用new来调用
var date = new Date();
console.log(date);//Thu Feb 13 2025 21:27:07 GMT+0800 (中国标准时间)
如果Date没有参数,返回系统的当前时间
加参数
var date = new Date(2025,10,1);
var date = new Date('2025-10-1');
console.log(date);
返回当前的年,月
var date = new Date();
console.log(date.getFullYear());//2025
console.log(date.getMonth()+1);//2
获取时期的总毫秒的形式
Date获得总的毫秒数(时间戳),从1970年1月到现在
var date = new Date();
console.log(date.getTime());
console.log(date.valueOf());
var date1 = +new Date();
console.log(date1);
console.log(Date.now());
倒计时时间案例
function countDown(time){
var nowtime = +new Date();
var inputtime = +new Date(time);
var times = (inputtime - nowtime)/1000;
var d = parseInt(times/60/60/24);
d = d<10 ? '0'+d : d;
var h = parseInt(times/60/60%24);
h = h<10 ? '0'+h : h;
var m = parseInt(times/60%60);
m = m<10 ? '0'+m : m;
var s = parseInt(times%60);
s = s<10 ? '0'+s : s;
return d+'天'+h+'小时'+m+'分钟'+s+'秒';
}
console.log(countDown('2025-2-13 22:05:00'));
其他知识点,就查mdn吧
数组对象
Array();
添加删除数组方法
push方法
push方法可以给数组追加新的元素
push()参数直接写数组元素就可以。
push()完毕的返回值是新数组的长度
原数组也会发生变化,默认在原数组的末尾添加
unshift对象
在数组开头添加
arr = [1,2,3,4];
arr.unshift('5');
console.log(arr);
其他的属性和push对象差不多
pop对象
删除数组最后一个元素,一次只能删除一个。
也有返回值,你删除哪个元素,他就返回哪个元素。
pop里面不跟参数
shift对象
删除数组的第一个对象,一次只能删除一个,也没有参数
其他跟pop差不多
数组排序
1.翻转数组
reverse()直接就可以翻转了。
var arr = [1500,1200,2000,2100,1800];
arr.reverse();
console.log(arr);
2.数组排序(冒泡排序)
//当数组中的值都小于10的时候,冒泡排序直接用sort方法就可以实现
var arr = [3,1,2,5];
arr.sort();
console.log(arr);// [1, 2, 3, 5]
如果他的值是有两位数或者三位数的化就不能
var arr = [13,4,77,1,7];
arr.sort();
console.log(arr);
//[1, 13, 4, 7, 77]
这种情况的解决方法,有个很固定的方法,在sort()方法里面再写一个函数
var arr = [13,4,77,1,7];
arr.sort(function(a,b){
return a-b;//升序
//return b-a;//降序
});
console.log(arr);
//[1, 4, 7, 13, 77]
数组的索引方法
indexOf();//的使用方法
var arr = [13,4,77,1,7];
console.log(arr.indexOf(77)); // 2
假如数组里面有两个相同的值,返回第一个符合的索引,如果数组里面没有想要的值,就返回索引为-1
var arr = [13,4,77,1,7];
console.log(arr.indexOf(2)); // -1
lastIndexOf()从后面开始查找,但是索引号还是从左往右排序。
案例数组去重
核心算法,遍历旧数组,如果新数组里面没有这个元素,就存进去,有的化就不存了
function unique(arr){
var newarr = [];
for (var i = 0; i < arr.length;i++){
if (newarr.indexOf(arr[i]) == -1){
newarr.push(arr[i]);
}
}
return newarr;
}
var res = unique([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0]); // [1,2,3,4,5,6,7,8,9,0]
console.log(res);// [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
数组转换为字符串
1.toString()
var str = ['1', '2', '3', '4', '5'];
console.log(str.toString());//1,2,3,4,5
2,join()里面可以跟分隔符
里面如果没加参数,就默认以逗号分隔
var str = ['1', '2', '3', '4', '5'];
console.log(str.join());//1,2,3,4,5
console.log(str.join('-'));//1-2-3-4-5
其他数组对象
concat()连接两个数组
基本包装类型
根据前面的理论,属性和方法是在对象上才有的,而简单的数据类型不具有属性和方法才对,字符串属于简单数据类型,但是也有length属性,是因为有基本包装类型:把简单的数据类型包装成复杂的数据类型。
1.把简单的数据类型包装为复杂的数据类型
var temp = new String(‘andy’);
2.把临时遍历的值给str
str= temp
3.销毁这个临时变量
temp = null
字符串不变性
指的字符串不会随意改变,也不要随意拼接字符串
根据字符返回位置
和数组的方法差不多indexOf()
str.indexOf(‘要查找的字符’,[起始的位置])
var str = '改革春风吹满地,春天来了'//想找第二个春
console.log(str.indeOf('春',[3]))
查找字符串”abcdoefoxyozzopp”中o出现的位置以及次数
var str = 'abcdoefoxyozzopp';
var num = 0;
var index = str.indexOf('o');
while(index !== -1){
console.log(index);
num++;
index = str.indexOf('o',[index+1]);
}
console.log(num);
//查找数组
var arr = [
'pink',
'red',
'green',
'grew',
'pink'
];
var num=0;
var index = arr.indexOf('pink');
while(index !== -1){
console.log(index);
num++;
index = arr.indexOf('pink',index+1)
}
console.log(num);
webAPIs
前面学的js是基础语法,webapi是js的运用,可以做交互。
API
API就是一些预定的函数,提供应用程序与开发人员基于某种软件或硬件以访问一组例程的能力,相当于是一种工具,方便编程。
webapi太多了,学习主要的就行,然后以后需要用到的就查webapi的参考文档。
DOM
文档对象模型,是一个接口用来处理html,xml。
document文档
element元素
id
getElementById(‘time’);
因为文档页面是从上往下加载的,所以必须现有变迁,再用script写到标签的下面
参数id是大小写敏感的字符串
返回的是一个dom类型的对象
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>>
</head>
<body>
<div id="time">19.50</div>
<script>
var time = document.getElementById('time');
console.log(time);
console.log(typeof time);
console.dir(time); //打印我们返回的对象元素,更好的查看里面的属性和方法。
</script>
</body>
</html>
getElementsByTagName()
这个方法可以返回带有指定标签名的对象的集合。
<body>
<li>1</li>
<li>1</li>
<li>1</li>
<li>15</li>
<li>124</li>
<li>12/li>
<li>3</li>
<script>
var lis = document.getElementsByTagName('li');
console.dir(lis);
</script>
</body>
//返回的是获取对象的集合,以伪数组的形势存贮的
遍历伪数组里面的元素
<li>1</li>
<li>1</li>
<li>1</li>
<li>15</li>
<li>124</li>
<li>12/li>
<li>3</li>
<script>
var lis = document.getElementsByTagName('li');
console.dir(lis);
for (var i = 0; i < lis.length; i++) {
console.log(lis[i]);
}
</script>
如果页面只有一个元素,返回的还是伪数组。
如果页面一个都没有,就返回空的伪数组。
快捷键,alt+shift+框选,可以同时改多个
还可以获取某个元素内部所有指定标签的子元素
element.getElementsByTagName(‘标签名’);
父元素必须是单个对象,必须指明是哪个元素对象。获取的时候不包括父元素自己。
H5的获取元素的方法
1.getElementsByClassName()根据类名获取某些元素的集合
<li class="li">1</li>
<li>3</li>
<li>3</li>
<li>3</li>
<div id ='idtest'>无语</div>
<script>
var lis = document.getElementsByClassName('li');
console.log(lis);
var query = document.querySelector('.li');
var id1 = document.querySelector('#idtest');
console.log(query);
console.log(id1);
</script>
结果:
2.注意querySelector返回指定选择器的第一个元素对象,选择id要在idname前面加#,类选择的化要在classname前面加.(切记里面的选择器一定要加符号)
3.querySelectAall()可以得到所有的li,比querySelector更好点,更简单点。
<li class="li">1</li>
<li class="li">3</li>
<li class="li">3</li>
<li>3</li>
<div id ='idtest'>无语</div>
<script>
var query = document.querySelectorAll('.li');
console.log(query);
</script
<!-- NodeList(3) [li.li, li.li, li.li]
0
:
li.li
1
:
li.li
2
:
li.li
length
:
3
[[Prototype]]
:
NodeList -->
获取特殊元素
<script>
//1.获取body元素
var body = document.body;
//2.获取html元素
var html = document.documentElement;
console.log(body);
console.log(html);
</script
事件基础
事件由三部分组成 事件源 事件类型 事件处理程序 称为事件三要素
<button id = 'bind'>点我</button>
<script>
var things = document.getElementById('bind');
things.onclick = function(){
alert('hello');
}
//这是一个点击事件的例子
执行事件的过程
一个div元素,点我控制台就会显示我被点击
<div class = 'bind'>123</div>
<script>
var div = document.querySelector('.bind');
div.onclick = function(){
console.log('我被click');
}
</script>
操作元素
element.innerText
从起始位置到终止位置的内容,但是它去除html标签,同时空格和换行也会去掉
element.innerHTML
起始位置和终止位置的全部内容,包括html标签,同时保留空格和换行
案例,点击可以获取当前系统事件,放到div里面去。
<script>
var value1= document.getElementById('bind');
var value2= document.getElementById('bind1');
value1.onclick = function(){
value2.innerText = new Date().toLocaleString();
}
</script>
innertext不识别html标签,innerhtml识别标签
innerHTML用的比较多(w3标准)
<button id="tu1" title="tu1">图一</button>
<button id="tu2" title="tu2">图二</button>
<div>
<img src="images/1.jpg" >
</div>
<script >
document.getElementById('tu1').onclick = function(){
document.querySelector('img').src = 'images/1.jpg';
document.querySelector('img').title = 'tu1';
}
document.getElementById('tu2').onclick = function(){
document.querySelector('img').src = 'images/2.jpg';
document.querySelector('img').title = 'tu2';
}
</script>
案例 分时显示不同的图片,显示不同的问候语
<p>早上好</p>
<img src="images/1.jpg" alt="" title="tu1">
<script>
var p = document.querySelector('p');
var img = document.querySelector('img');
var time = new Date().getHours();
if (time < 12){
p.innerHTML = '早上好';
img.src = 'images/1.jpg';
img.title = 'tu1';
}
else{
p.innerHTML = '晚上好';
img.src = 'images/2.jpg';
img.title = 'tu2';
}
</script>
dom操作表单元素
<button>点击</button>
<input type="text" value="输入内容">、
<script>
let btn = document.querySelector('button');
let input = document.querySelector('input');
btn.onclick = function(){
input.value = '点击了按钮';
this.disable = true;
}
这里用的input.value而不是innerHTML
如果想要某个表单被禁用,那就让按钮不能点击,就要让这个按钮被禁用
btn.disabled = true;(button的disable属性)等于this.disable = true;这个this指向事件函数的调用者。
案例 模仿京东显示密码的案例
dom操作样式属性
element.style 行样式操作
element.className类名样式操作
js里面的样式采取驼峰命名法,比如fontSize,backgroundColor
js里面修改style样式操作,产生的是行内样式,css权重比较高
案例操作
显示和隐藏样式
<div id="div">
<button id="btn">点击</button>
<img src="images/1.jpg" style="width: 60px; height: 60px; display: block;" alt="" id="img">
</div>
<script>
document.getElementById('btn').onclick = function () {
if (document.getElementById('img').style.display == 'none') {
document.getElementById('img').style.display = 'block';
} else {
document.getElementById('img').style.display = 'none';
}
}
</script>
京东搜索框的聚焦和非聚焦输入框
两个事件一个获得焦点onfocus,一个是失去焦点,onblur
<input type="text" value="请输入">
<script>
var input = document.querySelector('input');
input.onfocus = function() {
if (input.value == '请输入') {
input.value = '';
this.style.color = 'black';
}
}
input.onblur = function() {
if (input.value == '') {
input.value = '请输入';
}
}
</script>
className的属性
element.style在该样式的时候过多就很复杂,如果很多的时候这里可以改元素的类更方便,element.className
<style>
.class{
color: red;
width: 100px;
height: 100px;
background-color: yellow;
}
</style>
<title>Document</title>
</head>
<body>
<div>点我</div>
<script>
var test = document.querySelector('div');
test.onclick = function(){
test.className = 'class';
}
</script>
但是这种方式会直接改类名,就会直接覆盖原来的类
如果想保留原来的类名
就在前面加个原来的类
var test = document.querySelector('div');
test.onclick = function(){
test.className = 'first class';
}//first是原来的类
排他思想
1.所有元素全部清除样式
2.留下自己的样式
3.顺序不能颠倒
但是我感觉这种的空间复杂度较大,我觉得有其他方法,这里就不多写。
百度换肤案例
<style>
.baidu img {
width: 100px;
}
</style>
<title>Document</title>
</head>
<body class="baidu" >
<li><img src="images/1.jpg" alt="" style="width:100px height=100px"></li>
<li><img src="images/2.jpg" alt="" style="width:100px height=100px"></li>
<script>
var imgs = document.querySelectorAll('img');
for(var i =0;i<imgs.length;i++){
imgs[i].onclick = function(){
document.body.style.backgroundImage = 'url(' +this.src+ ')';
}
}
</script>
鼠标滑过表格行变色案例
<style>
.tb {
border: solid 1px;
}
.bg {
background-color: blue;
}
</style>
</head>
<body>
<table class="tb">
<thead><td>1</td><td>1</td><td>1</td><td>1</td></thead>
<tbody>
<tr><td>1</td><td>1</td><td>1</td><td>1</td></tr>
<tr><td>1</td><td>1</td><td>1</td><td>1</td></tr>
</tbody>
</table>
<script>
var trs = document.querySelectorAll('tr');
for(var i =0;i<trs.length;i++){
trs[i].onmouseover=function(){
this.className = 'bg';
}
trs[i].onmouseout=function(){
this.className = '';
}
}
</script>
</body>
获取自定义属性
<input type="checkbox" checked="">
<script>
var int1 = document.querySelector('input');
console.log(int1.getAttribute('type'));
element.getAttribute能够获取自定义属性
element.属性 只能获取内置属性。
设置移除自定义属性值
div.setAttribute(‘index’,2);设置
div.removeAttribute(‘index’,2);移除
tab栏切换(重点案例,前端必须学会的)
<!DOCTYPE html>
<html lang="en">
<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>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
li {
list-style-type: none;
}
.tab {
width: 978px;
margin: 100px auto;
}
.tab_list {
height: 39px;
border: 1px solid #ccc;
background-color: #f1f1f1;
}
.tab_list li {
float: left;
height: 39px;
line-height: 39px;
padding: 0 20px;
text-align: center;
cursor: pointer;
}
.tab_list .current {
background-color: #c81623;
color: #fff;
}
.item_info {
padding: 20px 0 0 20px;
}
.item {
display: none;
}
</style>
</head>
<body>
<div class="tab">
<div class="tab_list">
<ul>
<li class="current">商品介绍</li>
<li>规格与包装</li>
<li>售后保障</li>
<li>商品评价(50000)</li>
<li>手机社区</li>
</ul>
</div>
<div class="tab_con">
<div class="item" style="display: block;">
商品介绍模块内容
</div>
<div class="item">
规格与包装模块内容
</div>
<div class="item">
售后保障模块内容
</div>
<div class="item">
商品评价(50000)模块内容
</div>
<div class="item">
手机社区模块内容
</div>
</div>
</div>
<script>
// 获取元素
var tab_list = document.querySelector('.tab_list');
var lis = tab_list.querySelectorAll('li');
var items = document.querySelectorAll('.item');
// for循环绑定点击事件
for (var i = 0; i < lis.length; i++) {
// 开始给5个小li 设置索引号
lis[i].setAttribute('index', i);
lis[i].onclick = function() {
// 1. 上的模块选项卡,点击某一个,当前这一个底色会是红色,其余不变(排他思想) 修改类名的方式
// 干掉所有人 其余的li清除 class 这个类
for (var i = 0; i < lis.length; i++) {
lis[i].className = '';
}
// 留下我自己
this.className = 'current';
// 2. 下面的显示内容模块
var index = this.getAttribute('index');
console.log(index);
// 干掉所有人 让其余的item 这些div 隐藏
for (var i = 0; i < items.length; i++) {
items[i].style.display = 'none';
}
// 留下我自己 让对应的item 显示出来
items[index].style.display = 'block';
}
}
</script>
</body>
</html>
判断是否是自定义属性
设置h5自定义属性,一定要在变量前面加data
比如data-index
div.setAttribute(‘data-time’,23);
拿到属性的值,就用getAttribute获取
H5新增,
div(div.dataset.index);(必须以data开头)
节点操作
父亲节点
在之前的操作获取一个元素,比较麻烦,获取两个元素,就必须声明两个变量,如果用节点操作,就比较简单
<div class="box">
<span class="test">1</span>
</div>
<script>
var box = document.querySelector('.box');
var test = document.querySelector('.test');
//这是之前的方法
//因为在这个html中,div是span的父亲节点,可以使用下面方法
var parent = document.querySelector('.test').parentNode//得到离元素最新的父亲节点,如果找不到父节点,就返回为空
console.log(parent);//验证,发现确实可以
儿子节点
使用方法,element.childNodes(返回的一个数组)返回所有的节点,包括文字节点,元素节点
这个时候为了区分,就得注意节点的type
文字节点的nodeType是3
元素节点的nodeType是1;
可以通过判断,但是这种麻烦
用简单的方法
chidren获取所有的子元素节点
var box = document.querySelector('.box');
var test = document.querySelector('.test');
var chird = document.querySelector('.box').children;
console.log(chird);//验证,发现确实可以
<div class="box">
<ul class="test">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
</div>
<script>
var list = document.querySelector('.test');
console.log(list.children[1]);
</script>
</body>
因为chidren是个伪数组,用上诉方法来,获取。
兄弟节点
<p>2</p>
<div>1</div>
<span>2</span>
<script>
var div = document.querySelector('div');
console.log(div.nextSibling);
console.log(div.previousSibling);
console.log(div.nextElementSibling);//下节点
console.log(div.previousElementSibling);//上节点,后面两个都是H5新增的有兼容性问题
</script>
创建节点
document.createElement('tagName')
添加节点
1.node.appendChild(child) //node是父亲,child是孩子
2.node.insertBefore(child,指定元素);//在元素之前插入
先创建元素,再添加元素
案例:实现留言板
<textarea name="" id=""></textarea>
<button>评论</button>
<span>请在下面评论</span>
<ul>
</ul>
<script>
var ul = document.querySelector('ul')
var textarea = document.querySelector('textarea');
var button = document.querySelector('button');
button.onclick=function(){
if(textarea.value==''){
alert('请输入内容');
}else{
var li = document.createElement('li');
ul.insertBefore(li,ul.children[0]);
li.innerHTML = textarea.value;
}
}
主要是当点击按钮后,就会创建新的li,然后从前面插入使用Inserbefore,符合留言板的逻辑。
删除节点
node.removeChild(child)
<ul>
<li>hello</li>
<li>hello1</li>
</ul>
<button>点击删除hello</button>
<script>
var ul=document.querySelector('ul');
var button =document.querySelector('button');
button.onclick=function(){
if(ul.children.length==0){
alert('没有内容');
}else{
ul.removeChild(ul.children[0]);
}
}
</script>
ul.removeChild(ul.children[0]);
一定要在ul.children这里指明父亲为ul。
留言板内容删除
有个小技巧阻止链接跳转在href添加’javascript:;’
"<a href='javascript:;'>删除</a>"
<body>
<textarea name="" id=""></textarea>
<button>发布</button>
<ul>
</ul>
<script>
// 1. 获取元素
var btn = document.querySelector('button');
var text = document.querySelector('textarea');
var ul = document.querySelector('ul');
// 2. 注册事件
btn.onclick = function() {
if (text.value == '') {
alert('您没有输入内容');
return false;
} else {
// console.log(text.value);
// (1) 创建元素
var li = document.createElement('li');
// 先有li 才能赋值
li.innerHTML = text.value + "<a href='javascript:;'>删除</a>";
// (2) 添加元素
// ul.appendChild(li);
ul.insertBefore(li, ul.children[0]);
// (3) 删除元素 删除的是当前链接的li 它的父亲
var as = document.querySelectorAll('a');
for (var i = 0; i < as.length; i++) {
as[i].onclick = function() {
// node.removeChild(child); 删除的是 li 当前a所在的li this.parentNode;
ul.removeChild(this.parentNode);
}
}
}
}
</script>
克隆节点(复制节点)
node.cloneNode(),括号里面为空或者里面是false浅拷贝 只复制标签不复制里面的内容
node.cloneNode(true),为true为深拷贝。
案例动态生成表格
<!DOCTYPE html>
<html lang="en">
<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>Document</title>
<style>
table {
width: 500px;
margin: 100px auto;
border-collapse: collapse;
text-align: center;
}
td,
th {
border: 1px solid #333;
}
thead tr {
height: 40px;
background-color: #ccc;
}
</style>
</head>
<body>
<table cellspacing="0">
<thead>
<tr>
<th>姓名</th>
<th>科目</th>
<th>成绩</th>
<th>操作</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<script>
// 1.先去准备好学生的数据
var datas = [{
name: '魏璎珞',
subject: 'JavaScript',
score: 100
}, {
name: '弘历',
subject: 'JavaScript',
score: 98
}, {
name: '傅恒',
subject: 'JavaScript',
score: 99
}, {
name: '明玉',
subject: 'JavaScript',
score: 88
}, {
name: '大猪蹄子',
subject: 'JavaScript',
score: 0
}];
// 2. 往tbody 里面创建行: 有几个人(通过数组的长度)我们就创建几行
var tbody = document.querySelector('tbody');
for(var i=0;i<datas.length;i++){
var tr=document.createElement('tr');
tbody.appendChild(tr);
for(var k in datas[i] ){
var td = document.createElement('td');
tr.appendChild(td);
td.innerHTML = datas[i][k];
}
var td = document.createElement('td');
td.innerHTML = '<a href="javascript:;">删除 </a>';
tr.appendChild(td);
}
var as = document.querySelectorAll('a');
for (var i=0;i<as.length;i++){
as[i].onclick = function(){
tbody.removeChild(this.parentNode.parentNode);
}
}
</script>
</body>
</html>
三种动态创建元素的区别(面试重点)
document.write()
直接将内容写进页面的内容流,但是文档执行完毕,将会导致页面全部重绘。
element.innerHTML
将内容直接写入某个dom节点,不会导致页面全部重绘
创建多个元素效率更高(不要拼接字符串,采取数组形式拼接),结构稍微复杂。
document.createElement()
创建多个元素效率稍低一点,但是结构更加清晰
注册事件
传统的注册方式
注册事件的唯一性
传统的事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数
方法监听注册方式
w3c标准推荐
addEventListener()他是一个方法
IE9以前不支持这个方法,可以用attatchEvent()代替
方式
evenTarget.addEventLisentener(type,listenr[, useCapture])
type:事件字符串类型,比如click,mouseover这里不带on lisener:事件处理函数,事件发生时,会调用监听函数
useCapture:可选参数,是一个布尔值,默认为false。学完DOM事件流后,进一步学习
<button>监听事件测试</button>
<script>
var btn = document.querySelector('button');
btn.addEventListener('click',function(){
alert('11');
})
</script>
可以绑定多个事件
<button>监听事件测试</button>
<script>
var btn = document.querySelector('button');
btn.addEventListener('click',function(){
alert('11');
})
btn.addEventListener('click',function(){
alert('22');
})
addEventLisentener是i9以上才支持的,低版本的化。用attachEvent事件监听方式,了解就好
删除事件(解绑事件)
删除事件的方法
1.传统注册方法
eventTarget.onclick = null;
2.监听注册方法
eventTarget.addEventListener('click',fn);
//在添加绑定的时候就不能用匿名函数的方式了,得写出来再调用才行,并且fn不加括号,比较特殊
eventTarget.removeEventListener('click',fn);
function fn(){
alert(22);
}
dom事件流
事件流描述得是页面中接收事件得顺序
分为三个阶段。
1.捕获阶段
2.当前目标阶段
3.冒泡阶段
意思就是假如一个div里面嵌套了一个div,如果两个都绑定了事件,那如果事件监听得的第三个参数决定是冒泡阶段还是捕获阶段,如果是true是事件捕获,如果不写和false是冒泡事件,捕获的化那就是先执行外面div的事件,再执行里面的div事件
事件对象
var div = document.queryselect('div');
div.onclick = function(event){}
//其中的event就是事件对象,写在侦听函数的小括号里面,当作形参来看
//事件对象只有有了事件才会存在。他是系统自动创建的,不需要我们传递参数
//事件对象是我们事件的一系列相关对象的集合,比如鼠标点击就包含了鼠标的相关信息。
//事件对象也可以自命名event写成也许
<div>1</div>
<script>
var div = document.querySelector('div');
div.onclick = function(){
console.log(event);
}
</script>
this和e.target的区别
this是绑定的事件对象,target是触发事件的对象
还有其他很多的事件对象,要看查文档吧。
阻止冒泡事件
标准写法:利用事件对象里面的stopPropagation()方法
<div class="father">
<div class="son">son儿子</div>
</div>
<script>
// 常见事件对象的属性和方法
// 阻止冒泡 dom 推荐的标准 stopPropagation()
var son = document.querySelector('.son');
son.addEventListener('click', function(e) {
alert('son');
e.stopPropagation(); // stop 停止 Propagation 传播
e.cancelBubble = true; // 非标准 cancel 取消 bubble 泡泡
}, false);
var father = document.querySelector('.father');
father.addEventListener('click', function() {
alert('father');
}, false);
document.addEventListener('click', function() {
alert('document');
})
</script>
事件委托,事件代理
不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点
案例:ul注册点击事件,然后利用事件对象的target来找到当前点击的li,因为点击li,事件会冒泡到ul。
提高了DOM的性能。
<ul>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
</ul>
<script>
// 事件委托的核心原理:给父节点添加侦听器, 利用事件冒泡影响每一个子节点
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
// alert('知否知否,点我应有弹框在手!');
// e.target 这个可以得到我们点击的对象
e.target.style.backgroundColor = 'pink';
})
</script>
常用的鼠标事件
1.禁止鼠标右键
contextmenu控制何时显示上下文
我是一段不愿意分享的文字
<script>
// 1. contextmenu 我们可以禁用右键菜单
document.addEventListener('contextmenu', function(e) {
e.preventDefault();
})
</script>
2.禁止鼠标选中
selectstart 开始选中
document.addEventListener('selectstart', function(e) {
e.preventDefault();
})
鼠标事件对象
e.clientX
e.clientY
这两个是鼠标在浏览器窗口的坐标
e.pageX
e.pageY
这两个是鼠标在文档页面的坐标。
e.screenX
e.screenY
距离电脑屏幕的坐标
跟随鼠标的小天使案例(这个还不错)
1.鼠标不断移动,注册mousemove
2.给document注册事件
3.图片移动距离,不占用位置,我们使用绝对位置即可
4.核心原理:每次移动鼠标,就可以获取最新的鼠标坐标,把这个xy的坐标作为图标的top和left值就可以移动图片
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
img{
position: absolute;
}
</style>
</head>
<body>
<img src="第三天/images/angel.gif" alt="">
<script>
var document = document.querySelector('document');
document.addEventListener('mousemove',function(e){
var X= e.clientX;
var Y= e.clientY;
var angel = document.querySelector('img');
angel.style.left = X + 'px';
angel.style.top = Y + 'px';
})
</script>
</body>
</html>
这里的img的css的postion要改为absolute才行。
angel.style.left = X + 'px';
angel.style.top = Y + 'px'; //千万要加上一个px单位
但是这样的化,图片在鼠标的右下角,可以改一下
angel.style.left = X-30 + ‘px’;
angel.style.top = Y -30+ ‘px’;
减一个30就差不多了。
常见的键盘事件
onkeyup
按键弹起的时候触发
onkeydown
按键按下的时候触发
onkeypress
按键按下时触发,但是不能识别功能键,shift,ctrl,箭头等都不可以
这三个事件的 执行顺序keydown>keypress>keyup
keycode可以获得键盘的ascii码
BOM
BOM是浏览器对象模型,他提供了独立内容而与浏览器窗口进行交互的对象,其核心是window。
主要学习BOM对象,但是他的兼容性比较差,没有标准。
BOM的顶级对象是window
在全局作用下的变量和函数其实都是window的属性和方法
<script>
var num = 10;
console.log(num);
console.log(window.num);
function test(){
console.log(11);
}
test();
window.test();
</script>
常见的window对象
窗口加载事件
在之前的学习中,我们想要让按钮绑定一个事件弹出对话框,但是script一直只能放在按钮的后面,有没有什么办法可以放到前面呢?
在window.onload页面加载完成后才会触发,我们把要执行的所有的内容都放到window.onload里面就可以了。
<!DOCTYPE html>
<html lang="en">
<head>
<script>
window.onaload = function(){
var bun = document.querySelector('button');
bun.addEventListener('click',function(){
alert('弹框');
})
}
</script>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button>点我弹框</button>
</body>
</html>
但是这里最好不要用onload这种是传统写法会有限制,最好用
window.addEventListener('click',function(){
var bun = document.querySelector('button');
bun.addEventListener('click',function(){
alert('弹框');
})
}
DomContentLoaded 仅当dom元素加载完成就可以了,不需要样式表和图片完全加载完后才弹出来。这个比较快
调整
resize 尺寸发生变化就会触发
<script>
window.addEventListener('load', function() {
var div = document.querySelector('div');
window.addEventListener('resize', function() {
console.log(window.innerWidth);
console.log('变化了');
if (window.innerWidth <= 800) {
div.style.display = 'none';
} else {
div.style.display = 'block';
}
})
})
</script>
<div></div>
</body>
这里需要注意一个参数,获窗口尺寸,window.innerWidth
定时器
setTimeout()定时器
window.setTimeout(调用函数,[延迟的毫秒数])
这个调用函数可以写函数,还可以直接写函数名
<script>
// 1. setTimeout
// 语法规范: window.setTimeout(调用函数, 延时时间);
// 1. 这个window在调用的时候可以省略
// 2. 这个延时时间单位是毫秒 但是可以省略,如果省略默认的是0
// 3. 这个调用函数可以直接写函数 还可以写 函数名 还有一个写法 '函数名()'
// 4. 页面中可能有很多的定时器,我们经常给定时器加标识符 (名字)
// setTimeout(function() {
// console.log('时间到了');
// }, 2000);
function callback() {
console.log('爆炸了');
}
var timer1 = setTimeout(callback, 3000);
var timer2 = setTimeout(callback, 5000);
// setTimeout('callback()', 3000); // 我们不提倡这个写法
</script>
</body>
setTimeout()也被称为回调函数
5s隐藏广告案例
5s后隐藏起来就可以了
<div>
<img src="第三天/images/wb.jpg" alt="">
</div>
<script>
var div = document.querySelector('div')
window.setTimeout(function(){
div.style.display = 'none';
},5000)
</script>
停止定时器
window.clearTimeout(timeout ID)
<button>点击停止定时器</button>
<script>
var btn = document.querySelector('button');
var timer = setTimeout(function() {
console.log('爆炸了');
}, 5000);//给定时器加了一个标识符timer
btn.addEventListener('click', function() {
clearTimeout(timer);//停止这个定时器里面写标识符
})
</script>
setInterval()定时器
window.setInterval(调用函数,[延迟的毫秒数])
这个跟上面的区别就是一旦开启,就一直执行,一直调用
<script>
// 1. setInterval
// 语法规范: window.setInterval(调用函数, 延时时间);
setInterval(function() {
console.log('继续输出');
}, 1000);
// 2. setTimeout 延时时间到了,就去调用这个回调函数,只调用一次 就结束了这个定时器
// 3. setInterval 每隔这个延时时间,就去调用这个回调函数,会调用很多次,重复调用这个函数
</script>
京东倒计时案例
<body>
<div>
<span class="hour">1</span>
<span class="minute">2</span>
<span class="second">3</span>
</div>
<script>
// 1. 获取元素
var hour = document.querySelector('.hour'); // 小时的黑色盒子
var minute = document.querySelector('.minute'); // 分钟的黑色盒子
var second = document.querySelector('.second'); // 秒数的黑色盒子
var inputTime = +new Date('2019-5-1 18:00:00'); // 返回的是用户输入时间总的毫秒数
countDown(); // 我们先调用一次这个函数,防止第一次刷新页面有空白
// 2. 开启定时器
setInterval(countDown, 1000);
function countDown() {
var nowTime = +new Date(); // 返回的是当前时间总的毫秒数
var times = (inputTime - nowTime) / 1000; // times是剩余时间总的秒数
var h = parseInt(times / 60 / 60 % 24); //时
h = h < 10 ? '0' + h : h;
hour.innerHTML = h; // 把剩余的小时给 小时黑色盒子
var m = parseInt(times / 60 % 60); // 分
m = m < 10 ? '0' + m : m;
minute.innerHTML = m;
var s = parseInt(times % 60); // 当前的秒
s = s < 10 ? '0' + s : s;
second.innerHTML = s;
}
</script>
再次发送短信需等60s再点击案例
<input type="text">
<button>
发送验证码
</button>
<script>
var btn = document.querySelector('button');
var time = 60;
btn.addEventListener('click',function(){
btn.disabled = true;
btn.innerHTML = time + 's后重新发送';
var timer = setInterval(function(){
time--;
btn.innerHTML = time + 's后重新发送';
if(time == 0){
clearInterval(timer);
btn.disabled = false;
btn.innerHTML = '发送验证码';
time = 60;//重置时间
}
},1000)
})
</script>
this指向问题
1.全局作用域或者普通函数中的this指向的全局对象window,定时器的this指向的也是Window
2.方法中的this,指向的也是调用者
3.构造函数中的this指向的实例对象
js执行机制
js是单线程的,这可能会造成一个任务执行太长,后面的还没完成,导致渲染不连贯。
同步和异步
为了解决线程问题,在html5中提出了webworker标准,允许js创建多个线程,就出现了同步和异步。
同步:
前一个任务结束后再执行后一个任务,程序的执行顺序和任务的顺序是一致的,同步的。、
比如:我们要烧水煮饭,烧水要10分钟,等水开了再去做饭,并不合理
异步:
在做一件事的时候,又可以去做另一件事。
js中是如何处理
js中有个执行栈,先看同步任务,如果没有回调函数,那都是同步任务,如果遇到回调函数,如定时器函数就放到异步任务中,那就先把同步任务完成,再完成异步任务。
console.log(1);
setTimeout(() => {
console.log(3);
}, 0);
console.log(2);
//结果是1,2,3
这里涉及多个名字,多了个 异步进程处理,和事件循环(有需要看ppt)
location对象
location对象属性
location.href 获取或者 设置整个url
location.host 返回主机 域名
location.port 返回端口号 没有返回就返回空字符串
location.path 返回路径
location.search 返回参数
location.hash 返回片段,返回锚点链接#后面部分
//案例获取提交的数据
index.html
<div></div>
<script>
console.log(location.search); // ?uname=andy
// 1.先去掉? substr('起始的位置',截取几个字符);
var params = location.search.substr(1); // uname=andy
console.log(params);
// 2. 利用=把字符串分割为数组 split('=');
var arr = params.split('=');
console.log(arr); // ["uname", "ANDY"]
var div = document.querySelector('div');
// 3.把数据写入div中
div.innerHTML = arr[1] + '欢迎您';
</script>
</body>
<form action="index.html">
用户名: <input type="text" name="uname">
<input type="submit" value="登录">
</form>//login.html
这个案例主要是分隔字符串,substr和split的方法使用。
location.assign()跟href一样,可以跳转页面,也称为重定向页面(可以记录浏览历史,可以后退)
location.replace虽然也可以跳转页面,但是不记录浏览页面,不能回退
location.reload重新刷新我们的页面。相当于刷新按钮,或者F5,如何参数为true就是强制刷新ctrl+F5
navigator对象
对象包含关于浏览器的信息,可以返回有客户端发送服务器的user-agent的头部信息
history对象
back()后退
forward()前进
go(参数)填1就是前进1,填-2就是后退
本地存储
localStorage
1.数据存储在用户的浏览器里面
2.设置和读取方便,页面刷新也不会丢失数据
作用:可以把数据永久的存储在用户的电脑上,除非手动删除,否则关闭页面也会存在
特征:多窗口共享
以键值对的形式存储
localStorage.setItem(key, value);
读取数据
localStorage.getItem(key);
删除本地存储 只删除名字
localStorage.removeItem(key);
查看,在浏览器的开发者工具里的应用里面本地存储里面找
改数据
localStorage.setItem('key', 'value');
localStorage.setItem('key','改');
本地存储只能存放字符串数据类型。键一定是要加引号
sessionStorage
特征:生命周期为关闭浏览器窗口
在同一窗口下数据可以共享
其他跟localStorage差不多
存储复杂的对象类型
存
假如要存储一个对象进去本地
<script>
const obj = {
name: '张三',
age: 18,
sex: '男'
}
localStorage.setItem('obj', obj);//这种方式存进去了是一个对象,虽然存进去了,但是取不出来,用不了
//这个时候就不能这么操作了,就必须通过一个转换为json格式才行
localStorage.setItem('obj', JSON.stringify(obj));//这样存进去的就是一个字符串了
//取出来的时候,需要将字符串转换为对象
const obj1 = JSON.parse(localStorage.getItem('obj'));
console.log(obj1);//这样就可以取出来了
</script>
JSON.stringify(obj)
转为JSON对象,都有引号,统一用双引号
json格式就是键值都是有两个引号引起来的字符串,长得和对象很像,但是有引号
取
将JSON字符串转换为对象。
JSON.parse()将字符串转为对象
console.log(localStorage.getItem('obj'));//这样取出来的是字符串
console.log(JSON.parse(localStorage.getItem('obj')));//这样取出来的是对象
数组的map方法 迭代数组
遍历数组处理数据并返回新的数组
map也被称为映射。map重点在于有返回值,foreach没有返回值
join方法
将数组中的元素拼接成一个字符串
arr.join(”);
如果用空字符串,则元素没有分隔,连在一起的
小括号为空,默认用逗号分隔。
正则表达式
正则表达式是一种模式,也是一种对象
const str = 'hello world'
const re = /前端/
console.log(re.test(str));
// false
re是规则
str是被检测得字符串
re.test(str)
这是写法
re.exec(str)这是返回数组
元字符
^ 以什么开始
$ 以什么结尾
字符类
[]匹配字符集合
{}前面的字符个数
. 匹配除换行符外的任意字符
预定义类
\d 相当于[0-9]
\w 相当于[A-Za-z0-9]
修饰符
/表达式/修饰符
修饰符,g是全局匹配,i是区分大小写
JS进阶
全局作用域和局部作用域(函数作用域,块级作用域)
let 和const都是块级作用域
var没有块级作用域。
少用全局变量,防止变量被污染。
script标签和js文件里的最顶层的就是全局作用域
作用域链
作用域链的本质是底层的变量查找机制
函数被执行的时候,会优先查找当前函数作用域中查找变量
如果当前作用域查不到则会依次逐级查找父级作用域直到全局作用域。
垃圾回收机制
js中的内存分配和回收都是自动完成的,内存在不适用的时候会被垃圾回收器自动回收
js环境中分配的内存,一般有如下的生命周期: 1.内存分配
2.内存使用
3.内存回收
全局变量一般不回收
一般情况下局部变量的值,会被自动回收掉。
内存泄漏:程序中分配的内存由于某种原因程序未释放叫做内存泄漏
引用计数:
只要数据类型没有没引用了,就回收
标记清除法:
现代浏览器已经不用引用计数了,都用标记计数。
核心算法:
1.标记清除算法将’不再使用的对象‘定义为’无法达到的对象‘
2.就是从根部出发定时扫描内存中的对象。凡是能够从根部到达的对象,都是需要使用的。
3.无法由根部触发触及到的对象被标记为不再使用,稍后进行回收。
闭包
概念:一个函数对周围状态的引用捆绑在一起,内层函数中访问到外层函数的作用域
简单理解:闭包=内层函数+外层函数的变量
function close_package(){
let a = 1;//const也可以
function func(){
console.log(a); // 1
}
func();
}
close_package();
里面的函数就用到了外面的常量a
闭包的基本格式
function close_package(){
let a = 1;//const也可以
function func(){
console.log(a); // 1
}
return func;
}
const fun = close_package();
fun();
闭包的作用,想让外部的函数访问内部的变量
可以保护变量私有。
闭包的应用 统计函数被调用的次数
//假如是原来这种写法,这个变量a是全局变量容易被修改
let a = 0;
function test() {
a++
console.log(a)
}
采用闭包的形式
function fn1(){
let i = 0;
function fn2(){
i++
console.log(i)
}
return fn2
}
const out = fn1()
现在就在外面访问不了了,太妙妙屋了
变量提升
变量提升是js的缺陷,它允许在变量声明之前被访问(仅存在var 声明变量)
这个跟我们前面的js预处理机制差不多。
所以出现了let 和const来解决这个问题
console.log("这是测试变量提升 "+a);
var a = 1;
//这是测试变量提升 undefined
其实就是先
var a;
console.log("这是测试变量提升 "+a);
a = 1;
//所以先声明,不赋值,所以是未定义
变量提升,只提升声明,不提示赋值,并且是提升到当前作用域
console.log("这是测试变量提升 "+a);
let a = 1;
//报错
函数提升
与变量提升比较类似,函数在声明之前就可以被调用
fun1()
function fun1(){
console.log('fun1');
}
//result = fun1()
其实就是
function fun1(){
console.log('fun1');
}
fun1()
函数提升会把函数声明提升到当前的作用域的最前面
在函数表达式写法的那里就会出问题
fn()
var fn = function(){
console.log('fn')
}
相当于
var fn
fn()
//fn是个变量的,不能被调用
函数进阶
动态参数
agruments的使用
前面有说
函数剩余参数
剩余参数允许我们将一个不定数量的参数表示成一个数组
function getsum(...arr){
console.log(arr);
}
getsum(1,2,3)
getsum(1,2)
// [1, 2, 3]
// [1, 2]
…就是剩余参数
两者区别
1.剩余参数,就是前面的参数可以允许自定义,所以更加灵活
假设,允许用户输入两个参数,其他任意
//例如
function test (a,b,...arr){
}//这里可以写两个形参a,b
2.剩余参数是一个真数组,可以用数组的方法,而agrument是伪数组,不能用数组的方法。
剩余参数的场景,用于获取多余的参数。
展开运算符
展开运算符(…)可以把数组给展开
const arr = [1,2,3,4,5,6,7,8,9,10];
console.log(...arr);
const arr = [1,2,3,4,5,6,7,8,9,10];
console.log(...arr);
console.log(arr);
//(1) 1,2,3,4,5,6,7,8,9,10
//(10) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
说明:
1.不会修改原数组
典型使用场景,求数组最大值
const arr = [1,2,3,4,5,6,7,8,9,10];
console.log(Math.max(...arr))
箭头函数(非常重要)
目的:引进箭头函数的目的是用更简短的函数写法并且不绑定this,箭头的函数的语法比函数更简洁
使用场景:箭头函数更适合用于需要匿名函数的地方。
//普通函数
function fn(){
}
//函数表达式
const = function (){
}
//箭头函数
const fn = () =>{
}
const jiantou = (x) => {
console.log(x)
}
jiantou(1)
只有一个形参的时候,可以省略小括号
const fn = x = >{
console.log(x)
}
fn(1)
//1
只有一行代码的时候可以省略大括号
const fn = x => console.log(x)
fn(1)
在return里面还能省
const fn = x = >{
return x+x
}
console.log(fn(1))
//可以简写成
const fn = x => x+x
console.log(fn(1))
在写一行的时候,不加return也能把结果给出来。
注意箭头函数可以直接返回一个对象
//原先是这样
const fn = (uname) => {
return {name:uname}
}
fn('张三')
可以改成这样
const fn = (uname) => ({uname:uname})
fn('张三')
这里因为对象的大括号和箭头函数的大括号冲突了,所以这里拿小括号包起来
箭头函数参数
箭头函数没有arguments但是有剩余参数…
箭头函数的this
箭头函数的this指向的是上一层函数的作用域
比如
const fn = ()=>{
console.log(this)
}
fn()
//打印出来就是window
箭头函数没有this,传统的函数写法有this
let obj = {
name : '张三',
age : 18,
sex : '男',
sayhi:function(){
console.log(this);
let i = 10
const count = () => {
console.log(this);
}
count()
}
}
obj.sayhi()
在这个 count函数里面,this因为箭头函数里面没有this他就去上面找,刚好上面是在传统的函数有this,传统的函数的this指向的是调用他的地方,所以this就是obj
所以在dom回调函数的时候,不建议用箭头函数,this指向的就是window了。
解构赋值
数组解构就是将数组中的元素快速的赋值给一系列变量的简洁语法
const arr = [100,60,80]
//数组解构 赋值
const [max,min,avg] = arr
console.log(max)//100
基本语法:交换两个变量
let a = 1
let b = 1;
[b,a] = [a,b]
console.log(a,b)
在let b =1的后面必须加分号,不然会报错
为什么必须加分号? 两种必须加分号的必须情况
立即执行函数要加
使用数组的时候解构
const arr = 'hello'
[1,2,3].map(function(item){
console.log(item)
})
//在这里就会报错
所以数组前面要加分号。
const arr = 'hello'
[1,2,3].map(function(item){
console.log(item)
})
//加了分号后就不会报错了
使用对象的时候解构
//解构的语法
const {uname,age} = {uname:'张三',age:18}
//等价于const uname = obj.uname
console.log(uname);
console.log(age);
有个要求,就是属性名和变量名必须相同。
如果对象和属性不一致的化就是undefined
对象解构的变量名,可以重新改名
用法 旧变量名:新变量名
const uname = '小王'
const {uname:name,age} = {uname:'张三',age:18}
数组对象的解构
const pig = [{uname : '张三', age: 18}]
//数组对象解构
const [{uname, age}] = pig
console.log(uname, age);
多级对象解构
//多级对象解构
const obj = {
name : '张三',
family:{
father:'张四',
mother:'张五',
}
}
const {name,family:{father}} = obj
console.log(name,father);
遍历数组foreach方法
被遍历的数组.forEach(funtion(当前元素,当前元素的索引号){
函数体})
当前元素 必须写,索引号可以不必要写。
遍历数组中的每个元素,只遍历,不返回数组
加强版的map循环,for循环
只能遍历数组,对象不可以
const arr = [1,2,3,4,5,6,7,8,9,10];
arr.map((item,index)=>{
console.log(item,index)
})
arr.forEach((item,index)=>{
console.log(item,index)
})
forEach适合遍历数组对象。
深入对象
数据的处理
构造函数
function people(name,age,sex){
this.name = name;
this.age = age
this.sex = sex
}
new people('xiaozhang','18','female')
console.log(people.name);
有两个约定
1.命名必须要大写字母开头
2.创建对象,必须要用new
3.使用new关键字调用构造函数叫做实例化
不加参数可以省略
构造函数没有return,返回的是一个对象。
实例成员,静态成员
实例成员包含实例属性和实例方法
静态成员的属性和方法被称为静态属性和静态方法。
面向对象的特性
1.封装性
2.继承性
3.多态性
构造函数的一些问题
function Goods(name,age,sex){
this.name = name;
this.age = age
this.sex = sex
this.study = function(){
console.log('学习');
}
}
const xiaozhang = new Goods('xiaozhang','18','female')
const xiaohong = new Goods('xiao红','13','male')
console.log(xiaozhang.study === xiaohong.study);
//result = false
表面上这两个sing都是相同的一模一样,但是不相同,这样地址是不同的,会出现浪费内存的情况,解决方法就是原型
原型
能够原型对象实现方法共享
js规定,构造函数里面有一个属性,叫做prototype属性,但是他其实是一个对象,就是原型
比如打印一下
function Goods(name,age,sex){
this.name = name;
this.age = age
this.sex = sex
this.study = function(){
console.log('学习');
}
}
console.log(Goods.prototype);
\\[[Prototype]]:Object
现在可以用这种写法
function Goods(name,age,sex){
this.name = name;
this.age = age
this.sex = sex
}
Goods.prototype.study = function(){
console.log('我要学习');
}//修改了这里,把this.study改成了this.prototype.study
const xiaozhang = new Goods('xiaozhang','18','female')
const xiaohong = new Goods('xiao红','13','male')
console.log(xiaozhang.study === xiaohong.study);
//res 是true
公共的方法写在原型对象里面
constructor属性
单词的意思就是构造器,构造函数
constructor是在原型对象里面的。指回了原来的对象。
function Goods(name,age,sex){
this.name = name;
this.age = age
this.sex = sex
}
Goods.prototype.study = function(){
console.log('我要学习');
}
const xiaozhang = new Goods('xiaozhang','18','female')
const xiaohong = new Goods('xiao红','13','male')
console.log(Goods.prototype.constructor === Goods);//true
但是假设我们要把多个自定义方法放进原型里面,会覆盖掉constructor的属性,必须创建后,还是要把constructor重新加上去。
Goods.prototype.study = function(){
console.log('我要学习');
}
Goods.prototype.read = function(){
console.log('我要读书');
}
这样单个写比较麻烦,因为原型本身也是对象,我把这里两个都放心去
Goods.prototype = {
constructor:Goods,//这里是关键,一定要重新指回去当前的构造函数
study:function(){
console.log('我要学习');
},
read:function(){
console.log('我要读书');
}
}
对象的 __ proto __
对象都会有这个属性__ proto __指向构造函数的prototype的原型对象。
__ proto __指向的prototype
所以这两个相等
__ proto __(对象原型)=== prototype(原型对象)
function Person(){
this.eys = 2
this.leg = 2
}
const ldh = new Person()
console.log(ldh.__proto__ === Person.prototype)//true
原型继承
通过原型去继承对象
function Person(){
this.eys = 2
this.leg = 2
}
function Man(){
this.name = 'man'
this.sex = 'male'
}
//因为man也是人,所以集成person
Man.prototype = new Person()
Man.prototype.constructor = Man
原型链
这个就有点套娃了,最大的就是Object,Object的prototype.__ proto __指向的就为null。
function Person(){
this.eys = 2
this.leg = 2
}
const ldh = new Person()
console.log(ldh.__proto__ === Person.prototype)
//Person.prototype这也是一个对象,也有__proto__属性,指向Object.prototype
console.log(Person.prototype.__proto__ === Object.prototype)//true
//Object.prototype.__proto__指向null
console.log(Object.prototype.__proto__ === null)//true
//Object.prototype.__proto__指向null,所以Person.prototype.__proto__指向Object.prototype
//ldh.__proto__指向Person.prototype,所以ldh.__proto__.__proto__指向Object.prototype
//ldh.__proto__.__proto__.__proto__指向null
原型链:基于原型对象的继承使得不同构造函数的原型对象关联在一起,并且这种关联的关系是一种链状的解构,我们将原型对象的链状结构关系称为原型链
原型链其实就是一个查找规则,先看当前的原型对象上查找看有没有,如果没有就去上一层的原型对象上查找看有没有,这就形成了一个链。
运算符instanceof
看一个对象是不是在原型链上
function Person(){
this.eys = 2
this.leg = 2
}
const ldh = new Person()
console.log(ldh instanceof Person);// true
console.log(ldh instanceof Object);//true
案例 模态框构造函数的写法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#delete{
width: 100px;
height: 50px;
background-color: pink;
color: white;
border: none;
border-radius: 5px;
}
#login{
width: 100px;
height: 50px;
background-color: pink;
color: white;
border: none;
border-radius: 5px;
}
.model {
width: 300px;
height: 100px;
background-color: white;
margin-top: 10px;
display: block;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border: 1px solid black;
}
.header {
width: 100%;
height: 30px;
background-color: pink;
text-align: center;
line-height: 30px;
}
.body {
width: 100%;
height: 70px;
text-align: center;
line-height: 70px;
}
.i {
position: absolute;
top: 0;
right: 0;
width: 30px;
height: 30px;
background-color: white;
text-align: center;
line-height: 30px;
}
</style>
</head>
<body>
<button id="delete">删除</button>
<button id="login">注册</button>
</body>
<script>
function model(title='',content=''){
this.modelBox = document.createElement('div');
this.modelBox.className = 'model';
this.modelBox.innerHTML = `
<div class="header">
${title}
<a class="i" href="javascript:;">×</a>
</div>
<div class="body">
${content}
</div>
`
console.log(this.modelBox);
}
model.prototype.open = function(){
//这个函数需要用this,所以不用箭头函数
document.body.append(this.modelBox);
this.modelBox.querySelector('.i').addEventListener('click',()=>{
this.close();
})}
model.prototype.close = function(){
this.modelBox.remove();
}
// new model('温馨提示','你没有删除权限');
// new model('友情提示','你没有登录');
document.querySelector('#delete').addEventListener('click',function(){
const del = new model('温馨提示','你没有删除权限')
del.open()
})
document.querySelector('#login').addEventListener('click',function(){
const login = new model('友情提示','你没有注册的')
login.open()
})
</script>
</html>
深入学习this & js异常处理
深浅拷贝的问题
开发的过程中经常需要复制一个对象。如果直接赋值会出现下面问题
const pink = {
name :'pink',
age : 18
}
const red = pink
red.name = 'red'
console.log(pink.name)//red
console.log(red.name)//red
这就出现了深拷贝的问题,把pink也改了
首先深浅拷贝针对引用类型
浅拷贝:拷的是地址
深拷贝:拷的是引用
浅拷贝
1.
PC端网页特效
元素偏移量offset
偏移量,可以相对应的动态的得到元素的位置金额偏移量
获取元素距离的定位父元素的位置
获取元素自身的大小
返回的数值都不带单位
<body>
<div class="father">
``` <div class="son"></div>
</div>
<div class="w"></div>
<script>
// offset 系列
var father = document.querySelector('.father');
var son = document.querySelector('.son');
// 1.可以得到元素的偏移 位置 返回的不带单位的数值
console.log(father.offsetTop);
console.log(father.offsetLeft);
// 它以带有定位的父亲为准 如果么有父亲或者父亲没有定位 则以 body 为准
console.log(son.offsetLeft);
var w = document.querySelector('.w');
// 2.可以得到元素的大小 宽度和高度 是包含padding + border + width
console.log(w.offsetWidth);
console.log(w.offsetHeight);
// 3. 返回带有定位的父亲 否则返回的是body
console.log(son.offsetParent); // 返回带有定位的父亲 否则返回的是body
console.log(son.parentNode); // 返回父亲 是最近一级的父亲 亲爸爸 不管父亲有没有定位
</script>
</body>
拖动模态框
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
.login-header {
width: 100%;
text-align: center;
height: 30px;
font-size: 24px;
line-height: 30px;
}
ul,
li,
ol,
dl,
dt,
dd,
div,
p,
span,
h1,
h2,
h3,
h4,
h5,
h6,
a {
padding: 0px;
margin: 0px;
}
.login {
display: none;
width: 512px;
height: 280px;
position: fixed;
border: #ebebeb solid 1px;
left: 50%;
top: 50%;
background: #ffffff;
box-shadow: 0px 0px 20px #ddd;
z-index: 9999;
transform: translate(-50%, -50%);
}
.login-title {
width: 100%;
margin: 10px 0px 0px 0px;
text-align: center;
line-height: 40px;
height: 40px;
font-size: 18px;
position: relative;
cursor: move;
}
.login-input-content {
margin-top: 20px;
}
.login-button {
width: 50%;
margin: 30px auto 0px auto;
line-height: 40px;
font-size: 14px;
border: #ebebeb 1px solid;
text-align: center;
}
.login-bg {
display: none;
width: 100%;
height: 100%;
position: fixed;
top: 0px;
left: 0px;
background: rgba(0, 0, 0, .3);
}
a {
text-decoration: none;
color: #000000;
}
.login-button a {
display: block;
}
.login-input input.list-input {
float: left;
line-height: 35px;
height: 35px;
width: 350px;
border: #ebebeb 1px solid;
text-indent: 5px;
}
.login-input {
overflow: hidden;
margin: 0px 0px 20px 0px;
}
.login-input label {
float: left;
width: 90px;
padding-right: 10px;
text-align: right;
line-height: 35px;
height: 35px;
font-size: 14px;
}
.login-title span {
position: absolute;
font-size: 12px;
right: -20px;
top: -30px;
background: #ffffff;
border: #ebebeb solid 1px;
width: 40px;
height: 40px;
border-radius: 20px;
}
</style>
</head>
<body>
<div class="login-header"><a id="link" href="javascript:;">点击,弹出登录框</a></div>
<div id="login" class="login">
<div id="title" class="login-title">登录会员
<span><a id="closeBtn" href="javascript:void(0);" class="close-login">关闭</a></span>
</div>
<div class="login-input-content">
<div class="login-input">
<label>用户名:</label>
<input type="text" placeholder="请输入用户名" name="info[username]" id="username" class="list-input">
</div>
<div class="login-input">
<label>登录密码:</label>
<input type="password" placeholder="请输入登录密码" name="info[password]" id="password" class="list-input">
</div>
</div>
<div id="loginBtn" class="login-button"><a href="javascript:void(0);" id="login-button-submit">登录会员</a></div>
</div>
<!-- 遮盖层 -->
<div id="bg" class="login-bg"></div>
<script>
// 1. 获取元素
var login = document.querySelector('.login');
var mask = document.querySelector('.login-bg');
var link = document.querySelector('#link');
var closeBtn = document.querySelector('#closeBtn');
var title = document.querySelector('#title');
// 2. 点击弹出层这个链接 link 让mask 和login 显示出来
link.addEventListener('click', function() {
mask.style.display = 'block';
login.style.display = 'block';
})
// 3. 点击 closeBtn 就隐藏 mask 和 login
closeBtn.addEventListener('click', function() {
mask.style.display = 'none';
login.style.display = 'none';
})
// 4. 开始拖拽
// (1) 当我们鼠标按下, 就获得鼠标在盒子内的坐标
title.addEventListener('mousedown', function(e) {
var x = e.pageX - login.offsetLeft;
var y = e.pageY - login.offsetTop;
// (2) 鼠标移动的时候,把鼠标在页面中的坐标,减去 鼠标在盒子内的坐标就是模态框的left和top值
document.addEventListener('mousemove', move)
function move(e) {
login.style.left = e.pageX - x + 'px';
login.style.top = e.pageY - y + 'px';
}
// (3) 鼠标弹起,就让鼠标移动事件移除
document.addEventListener('mouseup', function() {
document.removeEventListener('mousemove', move);
})
})
</script>
</body>
</html>
模仿京东放大镜
(打瞌睡去了)这里有点复杂,就没写了,看ppt
元素可视区client系列
和offset的差不多,但是返回的是不包含边框的。
但是会包含padding的位置。
立即执行函数
不需要调用,立马就能执行。
写法,这两种
(function(){})()
(function(){}())
<script>
(function(){
console.log(1);
})();
//第二种
(function(){
console.log(2);
}());
(function(这里 写形参){}(这里写传递的实参))
立即执行函数的好处,独立创建了个作用域,所有的变量都是局部变量,不会有名字冲突。
给数组新建一个原型,来求数组的和。
const arr = [1,2,6]
Array.prototype.sum = function(){
return this.reduce((pre,cur)=>pre+cur,0)
}
console.log(arr.sum());
###