一、JavaScript基础
JavaScript是运行在客户端的脚本语言。浏览器有渲染引擎和JS引擎。浏览器本身并不会执行JS代码,而是通过JS引擎来执行JS代码。JS引擎执行代码时逐行解释每一句代码,然后由计算机去执行。
JavaScript由三部分组成:ECMAScript(JS基础)、DOM页面文档对象模型(对页面中各种元素进行操作)、BOM浏览器对象模型(对浏览器窗口进行操作)
JS三种写法:内嵌式、行内式、外部 (script中src引入)
多行注释:shift+alt+a
1.输入输出语句
- alert(msg):浏览器弹出警示框
- console.log(msg):浏览器控制台打印输出信息
- prompt(msg):浏览器弹出输入框,用户可以输入
2.变量
变量就是存放数据的容器,可以通过变量名获取数据或者修改数据。本质上是程序在内存中申请的一块用来存放数据的空间
变量声明:
var age;//声明一个叫做age的变量
注:尽量不使用name作为变量名
3.数据类型
-
数据类型简介:在计算机中,不同的数据占用的存储空间是不同的,为了便于把数据分成所需内存大小不同的数据,充分利用存储空间,于是定义了不同的数据类型。JS是一种弱类型或者说动态语言。这说明变量的类型是在程序运行过程中被确定的。JS引擎根据等号右边的值的数据类型来判断。JS拥有动态类型,所以意味着相同的变量可以用作不同的类型
-
数据类型分类:简单数据类型(Number、String、Boolean、Undefined、Null)和复杂数据类型(object)
简单数据类型 | 说明 |
---|---|
Number | 数字型,包含整形值和浮点型值,默认为0 |
Boolean | 布尔值类型,如true、false,默认为false |
String | 字符串类型,默认值“” |
Undefined | 声明了变量但是没有赋值 |
Null | 声明了变量赋值为null |
1.数字型
数字前加0表示八进制,数字前加0x表示十六进制
JS中数值的最大值Number.MAX_VALUE,最小值Number.MIN_VALUE,Infinity表示无穷大,-Infinity表示无穷小,NaN(Not a Number)表示非数值
isNaN()方法用来判断非数字,如果是数字返回false,如果不是数字返回true
2.字符串型
转义符 | 解释说明 |
---|---|
\n | 换行符 |
\ | 斜杠 |
’ | 单引号 |
" | 双引号 |
\t | tab缩进 |
\b | 空格 |
通过字符串的length可以获取整个字符串的长度
字符串拼接:字符串+任何类型 = 拼接后的新字符串
3.undifined和null
//声明变量未赋值就是undifined
var str1;
console.log(str1+'pink');//undefinedpink
console.log(str1+1);//NaN
var str2=null;
console.log(str2+'pink');//nullpink
console.log(str2+1);//1
4.typeof检测数据类型
console.log(typeof str);//string
5.数据类型转换
- 转换为字符串
方式 | 说明 |
---|---|
toString() | 转换成字符串 |
String() 强制转换 | 转换成字符串 |
加号拼接字符串 隐式转换 | 和字符串拼接的结果都是字符串 |
- 转换成数字型
方式 | 说明 |
---|---|
parseInt(string)函数 | 将string类型转换成整数数值型 并且直接把小数部分切掉,不会四舍五入 |
parseFloat(string)函数 | 将string类型转换成浮点数数值型 |
Number() 强制转换函数 | 将string类型转换成数值型 |
js隐式转换(. * /) | 利用算术运算隐式转换为数值型 |
- 转换成布尔型
Boolean()函数:代表空、否定的值会转换为false,如:’’、0、NaN、null、undefined,其余的全部转换为true
4.运算符
浮点数在算术运算中会有精度问题,尽量避免用浮点数直接运算
==:会进行数据类型转换,就是判断值想不想等
===:要求值和数据类型都要完全一致
逻辑与:
- 语法:表达式1 && 表达式2
- 如果第一个表达式的值为真,则返回表达式2
- 如果第一个表达式的值为假,则返回表达式1(第一个表达式为假,就不再进行后面的运算,而是直接返回)
逻辑或:
- 语法:表达式1 || 表达式2
- 如果第一个表达式的值为真,则返回表达式1
- 如果第一个表达式的值为假,则返回表达式2
运算符优先级:
从高到低 | 顺序 |
---|---|
小括号 | () |
一元运算符 | ++ – ! |
算术运算符 | 先* / % 后 + - |
关系运算符 | > >= < <= |
相等运算符 | == != 三等 |
逻辑运算符 | 先&&后或 |
赋值运算符 | = |
逗号运算符 | , |
5.分支
1.if分支结构:
if(条件表达式){
//执行语句
}
2.if...else分支结构
if(条件表达式){
//执行语句1
}else {
//执行语句2
}
3.if else if语句
可以利用多个条件选择语句执行
4.三元表达式: 条件表达式? 表达式1 : 表达式2
如果条件表达式为真则返回表达式1,如果条件表达式为假则返回表达式2
//数字补0案例
var time=prompt('请输入一个0-59的数字');
var result=time<10 ? '0'+time : time;
alert(result);
5.switch语句
如果表达式的是值类型,那么和value匹配的时候一定是三等于匹配,值和数据类型都要一样
switch(表达式){
case value1:
执行语句1;
break;
case value2:
执行语句2;
break;
.....
default:
执行最后的语句;
}
6.循环
- for循环
- 双重for循环
- while循环
- do while循环
- continue break
for循环:
乘法表:
var str='';
for(var i=1;i<=9;i++){
for(var j=1;j<=i;j++){
str=str+j+'*'+i+'='+i*j+' ';
}
str+='\n';
}
alert(str);
while循环:
var k=1;
var sum=0;
while(k<=100){
sum+=k;
k++;
}
alert(sum);
do…while循环:是先执行一次循环体再判断条件
continue:跳出本次循环,继续下一个循环
break:退出整个循环
7.数组
数组中可以放任意的数据类型
- 创建数组:
//第一种
var arr = new Array();
//第二种
var arr=[];
- 数组元素:数组名.length
- 新增数组元素:修改length
8.函数
函数形参和实参个数匹配:
- 如果实参个数和形参的个数一致,则正常输出结果
- 如果实参大数大于形参的个数,那么有几个形参就取几个形参
- 如果实参个数小于形参的个数,那么多余的形参没有值送过来就是undefined
return函数返回只能返回一个值,如果返回写了多了值,就返回最后一个值。如果没有return,就返回undefined
当我们不确定有多少个函数传递的时候,可以用arguments来获取。在JS中,arguments实际上是当前函数的一个内置对象,所有函数都内置了一个arguments对象,arguments对象中存储了传递的所有实参。arguements是伪数组:具有数组的length属性、按照索引的方式进行存储、它没有真正数组的一些方法。只有函数才有arguments对象
9.作用域
作用域:就是代码名字在某个范围内起作用和效果,作用域是为了提高程序的可靠性和减少命名冲突
全局作用域:整个script标签,或者是一个单独的js文件
局部(函数)作用域:在函数内部就是局部作用域,这个代码的名字只在函数内部起作用
根据作用域的不同,变量分为全局变量和局部变量。但是如果在函数内部没有声明而是直接赋值的变量也是全局变量,并且函数的形参也可以看做局部变量。全局变量只有浏览器关闭的时候才会销毁比较内存资源,而局部变量是当我们程序执行完毕就会销毁,比较节省内存资源。
内部函数可以访问外部函数的变量,而外部函数是不能够访问内部函数中声明的变量的。内部函数访问外部函数的变量采用的是链式查找的方式来决定取哪个值,这就是作用域链(就近原则)
10.预解析
JS解析器在运行JS分为两步:预解析、代码执行
预解析:JS引擎会把JS里面所有的var 和function提升到当前作用域的最前面
代码执行:按照代码书写的顺序执行
预解析分为变量预解析(变量提升)、函数预解析(函数提升):
变量提升就是把所有的变量声明提升到当前作用域的最前面,不提升赋值操作
函数提升就是把所有的函数声明提升到当前作用域的最前面,不调用函数
<script>
var num=10;
fun();
function fun() { //预解析会把声明提到前面,所以是可以正常调用的
console.log(num);
var num=20;
}
//相当于执行以下操作:输出undefined
var num;
function fun() { //预解析会把声明提到前面,所以是可以正常调用的
var num;
console.log(num);
num=20;
}
num=10;
fun();
</script>
f1();
console.log(c);
console.log(b);
console.log(a);
function f1() {
var a=b=c=9; //相当于 var a=9 ; b=9 ; c=9; b,c是直接赋值
// var a=9,b=9,c=9;这才是都声明了
console.log(a);
console.log(b);
console.log(c);
}
//相当于:输出9 9 9 9 9 报错
function f1() {
var a;
a=9;
b=9;//全局变量
c=9;//全局变量
console.log(c);
console.log(b);
console.log(a);
}
f1();
console.log(a);
console.log(b);
console.log(c);
11.对象
对象:自定义对象、内置对象、浏览器对象
创建对象:
- 对象字面量创建
var obj={
uname:'张三丰',
age:18,
sex:'男',
sayHi:function(){
console.log('hi');
}
}
console.log(obj.uname);//调用属性第一种方法
console.log(obj['age']);//调用属性的第二个方法
obj.sayHi();//调用函数
- 利用new Object创建对象
var obj=new Object();
obj.uname='张三丰';
obj.age=18;
obj.sex='男';
obj.sayHi=function() {
console.log('Hi');
}
- 利用构造函数创建对象:前面两种每次只能创建一个对象,有很多属性和方法是大量相同的,可以利用函数的方法去重复这些相同的代码,这个函数叫构造函数,里面封装的是对象
//利用构造函数创建对象
//构造函数的首字母要大写
function Star(uname,age,sex) {
this.uname=name;
this.age=age;
this.sex=sex;
this.sing=function(music) {
console.log(music);
}
}
var ldh = new Star('刘德华',18,'男');
for-in遍历对象
var obj= {
name='pink',
age:18,
sex:'男'
}
for(var k in obj) {
console.log(k);//得到的是属性名
console.log(obj[k]);//得到的是属性值
}
数学对象Math
- Math.PI 圆周率
- Math.floor() 向下取整
- Math.ceil() 向上取整
- Math.round() 四舍五入,就近取整 -3.5取整是-3
- Math.abs() 绝对值
- Math.max() 最大值
- Math.min() 最小值
//返回两个数之间的随机整数
function getRandom(min,max) {
return Math.floor(Math.random()*(max-min+1))+min;
}
//随机点名
var arr=['张三','李四','王五','张三丰','李思思'];
console.log(arr[getRandom(0,4)]);
Date日期对象
Date日期对象是一个构造函数,必须使用new 来调用创建我们的对象
//不跟参数,返回系统当前时间
var date=new Date();
console.log(date);
//参数常用的方法,数字型 2019,10,01 或者是字符串型'2019-10-1 8:8:8'
var date1=new Date(2019,11,1);//返回的是10月不是11月
console.log(date1);
var date2=new Date('2019-10-1 8:8:8');
console.log(date2);
日期格式化:
- getFullYear() 获取当年
- getMonth() 获取当月(0-11)
- getDate() 获取当天日期
- getDay() 获取星期几 0-6 周日返回的是0
- getHour() 获取当前小时
- getMinutes() 获取当前分钟
- getSeconds() 获取当前秒钟
//格式化日期
var date=new Date();
var year=date.getFullYear();
var month=date.getMonth()+1;
var dates=date.getDate();
var day=date.getDay()
var arr=['星期日','星期一','星期二','星期三','星期四','星期五','星期六'];
console.log('今天是'+year+'年',+month+'月'+dates+'日'+arr[day]);
function getTime() {
var time=new Date();
var h=time.getHours();
h=h < 10 ? '0'+h : h ;
var m=time.getMinutes();
m=m < 10 ? '0'+m : m;
var s=time.getSeconds();
s=s < 10 ? '0'+s :s;
return h+':'+m+':'+s;
}
console.log(getTime());
获取日期的总的毫秒形式:是基于1970年1月1日起的毫秒数(时间戳),因为毫秒数永远都不会有重复的数字
//获得Date总的毫秒数 不是当前时间的毫秒数,而是举例1970年1月1日过了多少毫秒
//1.通过valueOf() getTime()得到
var date = new Date();
console.log(date.valueOf());
console.log(date.getTime());
//2.简单的写法(最常用的写法)
var date1= +new Date();//返回的也是毫秒数
console.log(date1);
//3.H5新增的方法
console.log(Date.now());
计时器:
//用时间戳来做,用户输入事件总的毫秒数减去现在时间的毫秒数,得到的就是剩余时间的毫秒数
//然后把剩余时间的毫秒数转换为天、时、分、秒
function countDown(time) {
//用户输入的就是time
var inputTime= +new Date(time);
var nowTime= +new Date();//当前时间总的毫秒数
var times = (inputTime-nowTime)/1000;//就是剩余时间总的秒数
var d = parseInt(times/60/60/24);//天
d < 10 ? '0'+ d : d ;
var h = parseInt(times/60/60%24);//时
h < 10 ? '0'+ h : h ;
var m = parseInt(times/60%60);//分
m < 10 ? '0'+ m : m ;
var s = parseInt(times%60);//秒
s < 10 ? '0'+ s : s ;
return d + '天' + h + '时' + m +'分' + s + '秒';
}
console.log(countDown('2022-5-1 18:00:00'));
数组对象
判断是不是数组:
//检测是否为数组
//1.instanceof 运算符 可以检测是否为数组
var arr = [];
console.log(arr instanceof Array);
//2.Array.isArray()方法
console.log(Array.isArray(arr));
添加删除元素:
- push(参数…):末尾添加一个或者多个元素 返回新的长度
- pop():删除数组最后一个元素,返回它删除的元素
- unshift(参数…):向数组的开头添加一个或者更多元素 并返回新的长度
- shift():删除数组的第一个元素并返回第一个元素
//push()在数组末尾添加一个或者多个元素 并返回新的长度
var arr=[1,2,3];
arr.push(4,6,7);
console.log(arr);
//pop() 删除数组最后一个元素 并返回删除的元素
arr.pop();
console.log(arr);
//unshift() 在数组前面添加一个或者多个元素 并返回数组的长度
arr.unshift(0,2);
console.log(arr);
//shift() 在数组的前面删除一个元素 返回第一个元素
arr.shift();
console.log(arr);
数组排序:
- reverse():颠倒数组中的元素顺序
- sort():对数组的元素进行排序
//翻转数组
arr.reverse();
console.log(arr);
//排序:按照升序
arr.sort(function(a,b){
return a-b;
});
console.log(arr);
//降序排列
arr.sort(function(a,b){
return b-a;
})
console.log(arr);
数组索引:
- indexOf():在数组中查找给定元素的第一个索引,如果不存在就返回-1
- lastIndexOf():在数组中的最后一个索引,如果不存在就返回-1
重点案例:数组去重
//遍历旧数组,然后拿着旧数组的元素去新数组里面查,如果没有就存到新数组里面
var arr=['c','a','z','a','x','a','x','c','b'];
var newArr= [];
for(var k in arr) {
if(newArr.indexOf(arr[k]) === -1){
newArr.push(arr[k]);
}
}
console.log(newArr);
数组转换为字符串:
- toString():把数组转换成字符串,逗号分隔每一项
- join(‘分隔符’):把数组中的所有元素转换为一个字符串
//数组转换为字符串
//1.toString()
var arr=[1,2,3];
console.log(arr.toString());//1,2,3
//2.join('分隔符') 默认是逗号分隔
var arr1=['green','blue','pink'];
console.log(arr1.join('|'));
**基本包装类型:**把简单的数据类型不包装成为了复杂的数据类型,有String、Number、Boolean
var str = 'andy';
console.log(str.length);
//实际上:
var temp = new String('andy');//生成临时变量
str = temp;
temp = null;//销毁临时变量
字符串的不可变:指的是里面的值不可变,虽然看上去可变,但是那是地址变了,内存中新开辟了一个内存空间。字符串的所有方法都不会修改字符串本身,而是操作完成返回一个新的字符串
根据字符返回位置:
- indexOf():返回第一个字符的位置,找不到返回-1 第一个参数是要查找的字符,第二个是开始查找的位置(可省)
- lastIndexOf():返回最后一个
//查找'abcoefoxyozzopp'中所有o出现的位置以及次数
var str = 'abcoefoxyozzopp';
var num=0;//出现的次数
var index = str.indexOf('o');
while(index !== -1) {
console.log(index);
num++;
str.indexOf('o',index+1);
}
console.log(num);
根据位置返回字符:
- charAt(index):返回指定位置的字符
- charCodeAt(index):返回指定位置处字符的ASCII码 判断用户按了哪个键
- str(index):获取指定位置处的字符
统计出现次数最多的字符:
//统计出现次数最多的字符
//利用charAt()遍历这个字符串
//把每个字符都存储给对象,如果对象没有这个属性就位1,如果存在了就+1
//遍历对象,得到最大值的该字符
var str = 'abcoefoxyozzopp';
var o = {};//创建一个对象
for(var i=0;i<str.length;i++) {
var chars=str.charAt(i);
if(o[chars]){
o[chars]++;
}else {
o[chars]=1;//属性值赋值为1
}
}
//遍历对象
var max=0;
var ch='';
for(var k in o){
//k是属性名
//o[k]是属性值
if(o[k]>max){
max=o[k];
ch=k;
}
}
console.log('最多的字符是'+ch+',出现的次数是'+max);
- concat(str1,str2…):用于连接多个字符串
- substr(start,length):从start位置开始,length是个数
- slice(start,end):从start开始,到end结束,取不到end
- substring(start,end):从start开始,截取到end,取不到endd,基本和slice相同,但是不接受负值
- replace(‘被替换的字符’,‘替换为的字符’):只会替换第一个字符
- split(‘分隔符’):把字符转换为数组,根据分隔符来分割
//字符串转换为数组
var str2='red,pink,blue';
console.log(str2.split(','));
12.简单数据类型和复杂数据类型
简单数据类型(值类型):在存储时存储的是值本身,有string、number、boolean、undefined、null,但是null返回的是一个空对象,所以如果有一个变量以后打算存储为对象,但是暂时没想好放啥,就可以设置为null。是存放到栈里面,直接开辟一个存储空间存放值
复杂数据类型(引用类型):在存储变量是存储的是地址,通过new关键字创建对象,如Object、Array、Date等。首先在栈里面存放地址,然后这个地址指向堆里面的数据
堆:存放复杂数据类型
栈:存放简单数据类型
DOM
DOM是文档对象模型,通过这些DOM接口可以改变网页的内容、结构和样式
- 文档:一个页面就是一个文档,document
- 元素:页面中所有的标签就是元素,element
- 节点:网页中的所有内容都是节点(标签、属性、文本、注释等),node
1.获取元素
- 根据ID名获取:getElementById() ,返回的是一个元素对象
<div id="time">2019-9-9</div>
<script>
//因为文档页面从上往下加载,所以script要写在标签下面
var timer = document.getElementById('time');//返回的是element对象
console.log(timer);
console.log(typeof timer);
//打印返回的元素对象更好查看里面的属性和方法
console.dir(timer);
</script>
- 根据标签名获取:getElementsByTagName():返回指定标签名的对象集合,以伪数组的形式存储
<ul>
<li>知否知否</li>
<li>知否知否</li>
<li>知否知否</li>
<li>知否知否</li>
<li>知否知否</li>
</ul>
<script>
var lis = document.getElementsByTagName('li');
console.log(lis);
//遍历打印元素对象
//得到的元素对象是动态的
for(var i=0 ; i<lis.length ;i++) {
console.log(lis[i]);
}
//如果页面中只有一个li,返回的也是伪数组形式
//如果页面中没有这个元素返回的是空的伪数组形式
</script>
- 获取某个元素内部所有指定标签名的子元素:element.getElementsByTagName 必须指明父元素,获取的时候不包括父元素
<ul>
<li>知否知否</li>
<li>知否知否</li>
<li>知否知否</li>
<li>知否知否</li>
<li>知否知否</li>
</ul>
<ol id="ol">
<li>颜色</li>
<li>颜色</li>
<li>颜色</li>
<li>颜色</li>
<li>颜色</li>
</ol>
<script>
//element.getElementsByTagName
//获取ol里面的li
var ol = document.getElementById('ol');
console.log(ol.getElementsByTagName('li'));
</script>
- HTML5新增的根据类名获取元素:document.getElementsByClassName(‘类名’)
- HTML5新增的根据选择器返回第一个元素对象:document.querySelector(‘选择器’)
- 根据指定选择器返回:document.querySlectorAll(‘选择器’)
<div class="box"></div>
<div class="box"></div>
<script>
var firstBox = document.querySelector('.box');
console.log(firstBox);
console.log(document.querySelectorAll('.box'));
</script>
- 获取body元素:document.body
- 获取html元素:document.documentElement
2.事件基础
事件是可以被JS检测到的行为,事件就是触发响应的一个机制
鼠标事件 | 触发条件 |
---|---|
onclick | 鼠标点击左键触发 |
onmouseover | 鼠标经过触发 |
onmouseout | 鼠标离开触发 |
onfocus | 获得鼠标焦点触发 |
onblur | 失去鼠标焦点触发 |
onmousemove | 鼠标移动触发 |
onmouseup | 鼠标弹起触发 |
onmousedown | 鼠标按下触发 |
<button id="btn">唐伯虎</button>
<script>
//点击一个按钮弹出对话框
//事件由三部分组成:事件源、事件类型、事件处理程序
//事件源:事件被触发的对象 谁 按钮
var btn = document.getElementById('btn');
//事件类型:如何触发 什么事件 比如鼠标点击onclick 鼠标经过等等
//事件处理程序 通过一个函数赋值的方式完成
btn.onclick = function() {
alert('点秋香');
}
</script>
3.操作元素
3.1 改变元素的内容
- element.innerText:从起始位置到终止位置,但它去除html标签,同时空格和换行也会去掉
- element.innerHTML:起始位置到终止位置的全部内容,包括html标签,同时保留空格和换行
<button>显示当前系统的时间</button>
<div>某个时间</div>
<p>123</p>
<script>
//当我们点击了按钮 div里面的文字会发生变化
//获取元素
var btn = document.querySelector('button');
var div = document.querySelector('div');
//注册时间
btn.onclick=function() {
//让div里面的文字变化
div.innerText=getDate();
}
function getDate() {
var date=new Date();
var year=date.getFullYear();
var month=date.getMonth()+1;
var dates=date.getDate();
var day=date.getDay()
var arr=['星期日','星期一','星期二','星期三','星期四','星期五','星期六'];
return '今天是'+year+'年'+month+'月'+dates+'日'+arr[day];
}
//我们元素可以不添加事件
var p = document.querySelector('p');
p.innerText = getDate();
</script>
区别:
<div></div>
<p>
我是文字
<span>123</span>
</p>
<script>
//innerText
var div = document.querySelector('div');
div.innerText = '<strong>今天是</strong>';//不识别html标签
div.innerHTML = '<strong>今天是</strong>';//识别html标签
//可以获取内容
var p = document.querySelector('p');
console.log(p.innerText);//不识别标签,去除空格和换行
console.log(p.innerHTML);//识别标签 保留空格和换行
</script>
3.2 修改元素属性
<button id="liu">刘德华</button>
<button id="zhang">张学友</button>
<img src="./imgs/liu.jpg" alt="" title="刘德华">
<script>
//修改元素属性
//获取元素
var ldh = document.getElementById('liu');
var zxy = document.getElementById('zhang');
var img = document.querySelector('img');
//注册事件
zxy.onclick = function() {
img.src = './imgs/zhang.jpg';
img.title = '张学友';
}
ldh.onclick = function() {
img.src = './imgs/liu.jpg';
img.title = '刘德华';
}
</script>
3.3 表单元素的属性操作
利用DOM可以操作以下表单元素的属性:type、value、checked、selected、disabled
样例:仿京东显示密码
3.4 样式属性的操作
可以通过JS修改元素的大小、颜色、位置等样式。JS修改style样式操作产生的是行内样式,css权重比较高
- element.style 行内样式操作
- element.className 类名样式操作
仿淘宝关闭二维码:
<div class="box">
淘宝二维码
<img src="./imgs/liu.jpg" alt="">
<i class="close-btn">x</i>
</div>
<script>
//核心思路:利用样式的显示和隐藏完成,display:none隐藏元素 display:block显示元素
//点击按钮,就让二维码盒子隐藏起来即可
var btn = document.querySelector('.close-btn');
var box = document.querySelector('.box');
btn.onclick = function() {
box.style.display = 'none';
}
</script>
使用className修改元素样式:适合于样式较多或者功能复杂的情况,会覆盖掉以前的类名
<style>
div {
width: 100px;
height: 100px;
background-color: pink;
}
.change {
background-color: blue;
color: #fff;
font-size: 25px;
margin-top: 100px;
}
</style>
</head>
<body>
<div>文本</div>
<script>
var test = document.querySelector('div');
test.onclick = function() {
//让当前元素的类名改为了change
this.className = 'change';
}
</script>
3.5排他事件
点击一个按钮,当前点击的按钮变颜色:
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>
<script>
//获取所有按钮元素
var btns = document.getElementsByTagName('button');
for(var i=0;i<btns.length;i++) {
//用循环给按钮绑定点击事件
btns[i].onclick = function() {
//先把所有按钮颜色去掉,然后再改变当前元素的把背景颜色
for(var i=0;i<btns.length;i++) {
btns[i].style.backgroundColor = '';
}
this.style.backgroundColor='pink';
}
}
</script>
表单全选取消:
<div class="wrap">
<table>
<thead>
<tr>
<th>
<input type="checkbox" id="j_cbAll">
</th>
<th>商品</th>
<th>价钱</th>
</tr>
</thead>
<tbody id="j_tb">
<tr>
<td>
<input type="checkbox">
</td>
<td>iphone8</td>
<td>8888</td>
</tr>
<tr>
<td>
<input type="checkbox">
</td>
<td>iphone9</td>
<td>8888</td>
</tr>
<tr>
<td>
<input type="checkbox">
</td>
<td>iphone10</td>
<td>8888</td>
</tr>
<tr>
<td>
<input type="checkbox">
</td>
<td>iphon11</td>
<td>8888</td>
</tr>
</tbody>
</table>
</div>
<script>
//全选和取消全选:让下面所有复选框的checked属性跟随全选按钮即可
var j_cbAll = document.getElementById('j_cbAll');
var j_tbs = document.getElementById('j_tb').getElementsByTagName('input');
j_cbAll.onclick = function() {
for(var i=0 ; i<j_tbs.length ; i++) {
j_tbs[i].checked = this.checked;
}
}
//下面的复选框需要全部选中,上面全选才能选中:给下面所有的复选框绑定点击事件
//每次点击都要循环查看下面的复选框有没有没选中的,如果有一个没选中,上面的全选就不选中
for(var i=0 ; i<j_tbs.length ; i++){
j_tbs[i].onclick = function() {
var flag=true;//控制全选按钮是否选中
for(var i=0 ; i<j_tbs.length ; i++) {
//如果有一个按钮没有选中,那么就改为false
if(!j_tbs[i].checked){
flag=false;
break;
}
}
j_cbAll.checked=flag;
}
}
</script>
3.6自定义属性的操作
获取元素自定义属性:element.getAttribute(‘属性’)
<div id="demo" index="1"></div>
<script>
var div = document.querySelector('div');
//1.获取元素的属性值
//(1)element.属性:获取元素本身自带的属性
console.log(div.id);
//(2).element.getAttribute('属性'):主要获得程序员自定义的属性
console.log(div.getAttribute('id'));
console.log(div.getAttribute('index'));
</script>
设置属性值:
- element.属性=‘值’:设置内置属性值
- element.setAttribute(‘属性’,‘值’):主要针对自定义属性
//2.设置元素的属性值
//(1)element.属性=''
div.id='test';
console.log(div.id);
//(2)element.setAttribute('属性','值'):
div.setAttribute('id','test1');
console.log(div.id);
移除属性:element.removeAttribute(‘属性’)
3.7 重要案例:tab栏切换
<div class="tab">
<div class="tab_list">
<ul>
<li class="current">商品介绍</li>
<li>规格与包装</li>
<li>售后保障</li>
<li>商品评价</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">商品评价模块内容</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');
console.log(items);
//for循环绑定点击事件
for(var i=0 ; i<lis.length ; i++) {
lis[i].setAttribute('index',i);
//选项卡模块
lis[i].onclick = function() {
for(var i=0 ; i<lis.length; i++){
lis[i].className='';
}
this.className='current';
//显示模块内容
//给tab_list里面的所有li添加自定义属性,属性值从0开始
var index = this.getAttribute('index');
//让其余item的div隐藏
for(var i=0;i<items.length;i++){
items[i].style.display = 'none';
}
//显示响应的div
items[index].style.display = 'block';
}
}
</script>
4.节点操作
一般地,节点至少有nodeType(节点类型)、nodeName(节点名称)、nodeValue(节点值)这三个基本属性
- 元素节点 nodeType为1(标签)
- 属性节点 nodeType为2(类名等)
- 文本节点 nodeType为3(文本节点包括文字、空格、换行等)
4.1节点层级
父级节点:node.parentNode 得到的是最近的父节点,如果找不到就返回空
子节点:parentNode.childNodes(标准) 返回的是包含指定节点的子节点的集合,该集合为及时更新的集合。得到的所有子节点包含元素节点和文本节点
//子节点:获取ul里面的li
var ul = document.querySelector('ul');
console.log(ul.childNodes);//得到9个节点 4个li和5个换行
//得到元素节点
for(var i=0 ; i<ul.childNodes.length; i++){
//如果nodeType是1表示是元素节点
if(ul.childNodes[i].nodeType == 1){
console.log(ul.childNodes[i]);
}
}
子节点:parentNode.children(非标准) 获取子元素
console.log(ul.children);
获取第一个子节点:parentNode.firstChild 不管是文本节点还是元素节点都可以获得
获取第一个子节点:parent.firstElementChild 获取第一个元素节点(IE9以上)
获取最后一个子节点:parentNode.lastChild 不管是文本节点还是元素节点都可以获得
获取最后一个子节点:parent.lastElementChild 获取第一个元素节点(IE9以上)
<ol>
<li>我是li1</li>
<li>我是li2</li>
<li>我是li3</li>
<li>我是li4</li>
</ol>
<script>
var ol = document.querySelector('ol');
//获取第一个和最后一个li
console.log(ol.firstElementChild);
console.log(ol.lastElementChild);
//实际开发的写法
console.log(ol.children[0]);//第一个子元素
console.log(ol.children[ol.children.length-1]);//最后一个子元素
</script>
新浪下拉菜单:
<script>
//导航栏里面的li都要有鼠标经过的效果
//当鼠标经过li的时候,里面的ul显示,鼠标离开 ul就隐藏
//获取nav里面的li
var nav = document.querySelector('.nav');
var lis = nav.children;
for(var i=0 ; i<lis.length ; i++){
//鼠标经过的时候显示这个下拉菜单
lis[i].onmouseover = function() {
this.children[1].style.display = 'block';
}
lis[i].onmouseout = function() {
this.children[1].style.display = 'none';
}
}
</script>
下一个兄弟节点:node.nextSibling 包含元素节点和文本节点等等
下一个兄弟节点:node.nextElementSibling 得到元素节点 IE9+
上一个兄弟节点:node.previousSibling 包含元素节点和文本节点等等
上一个兄弟节点:node.previousElementSibling 得到元素节点 IE9+
4.2创建额添加节点
创建节点:document.createElement(‘tagName’)
添加节点:node.appendChild(child) 在子元素的最后添加
添加节点:node.insertBefore(child,指定元素) 在指定元素的前面插入
<ul>
<li>123</li>
</ul>
<script>
//创建节点元素节点
var li = document.createElement('li');
//添加到ul中
var ul = document.querySelector('ul');
ul.appendChild(li);//在ul的子节点的最后插入
//在指定元素的前面插入
var lili = document.createElement('li');
//查到123前面
ul.insertBefore(lili,ul.children[0]);
</script>
4.3 删除节点
删除节点:node.removeChild(child)
4.4 复制节点
node.cloneNode():把node这个节点复制
如果括号里面为空或者false,则是浅拷贝,只克隆复制节点本身,不克隆里面的内容
如果括号里面为true,那么就是深拷贝,复制标签并且复制里面的内容
4.5动态生成表格
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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>
//准备好学生的数据 用对象来存储
var dates =[ {
name:'魏璎珞',
subject:'JavaScript',
score:100
},
{
name:'弘历',
subject:'JavaScript',
score:98
},
{
name:'傅恒',
subject:'JavaScript',
score:99
},
{
name:'明玉',
subject:'JavaScript',
score:88
}
];
//先生成行
var tbody = document.querySelector('tbody');
for(var i=0 ; i<dates.length ; i++) {
var tr = document.createElement('tr');
tbody.appendChild(tr);
//行里面创建单元格 单元格数量取决于每个对象的个数
for(var k in dates[i]) {
//创建单元格
var td = document.createElement('td');
td.innerHTML = dates[i][k];
tr.appendChild(td);
}
//创建有删除两个字的单元格
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>
5.三种动态创建元素的区别
- document.write():是直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘
- innerHTML:创建多个元素效率更高(不要拼接字符串,采用数组形式拼接),结构稍微复杂
- createElement():创建多个元素效率稍微低一点点,但结构更加清晰
6.DOM高级事件
- 能够写出元素注册事件的两种方式
- 能够说出删除事件的两种方式
- 能够说出DOM事件流的三个阶段
- 能够利用事件对象完成跟随鼠标案例
- 能够封装组织冒泡的兼容性函数
- 能够说出事件委托的原理
- 能够说出常用的鼠标和键盘事件
6.1 注册事件
给元素添加事件,成为注册事件或者绑定事件
注册事件有两种方式:传统方式和方法监听注册方式
传统方式:利用on开头的事件,特点是注册事件的唯一性,同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数
方法监听注册方式:addEventListener()方法,在IE9之前可以用attachEvent()代替。特点是同一个元素同一个事件可以注册多个监听器,会按照注册的顺序依次执行
eventTarget.addEventListener(type,listener(,useCapture)):
- type:事件类型字符串,比如click、mouseover,不需要带on
- listener:事件处理函数,事件发生时,会调用该监听函数
- useCapture:可选参数,是一个布尔值,默认是false,学完DOM事件流后,再进一步学习
<button>方法监听注册事件</button>
<script>
var btn = document.querySelector('button');
//事件类型一定要加引号
btn.addEventListener('click',function() {
alert('22');
})
</script>
eventTarget.attchEvent(eventNameWithOn,callback):
- eventNameWithOn:事件类型字符串,比如onclick、onmouseover,要带on
- callback:事件处理函数,当目标触发事件时回调函数被调用
注册事件兼容性解决方案:
function addEventListener(element,eventName,fn){
if(element.addEventListener) {
element.addEventListener(eventName,fn);
}else if(element.attachEvent) {
element.attachEvent('on'+eventName,fn);
}else {
//相当于element.on事件=fn
element['on'+eventName] = fn;
}
}
6.2 删除事件
- 传统注册方式:element.οnclick=null
- 方法监听注册方式:eventTarget.removeEventListener(type,listener[,useCapture])
<div>1</div>
<div>2</div>
<div>3</div>
<script>
var divs = document.querySelectorAll('div');
function fn() {
alert('11');
divs[1].removeEventListener('click',fn);
}
divs[1].addEventListener('click',fn);
</script>
- eventTarget.detachEvent(eventNameWithOn,callback)
divs[2].attachEvent('onclick',fn1);
function fn1() {
alert('33');
divs[2].detachEvent('onclick',fn1);
6.3DOM事件流
事件流描述的是从页面中接收事件的顺序。事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即DOM事件流
事件冒泡:事件开始时由最具体的元素接收,然后逐级向上传播到DOM最顶层节点的过程
事件捕获:由DOM最顶层节点开始,然后逐级向下传播到最具体的元素接受过程
注意:
- JS代码中只能执行捕获或者冒泡中的一个阶段
- onclick和attchEvent只能得到冒泡阶段
- onblur、onfocus、onmouseenter、onmouseleave是没有冒泡事件的
- addEventListener第三个参数如果是true,表示事件捕获阶段调用时间处理程序,如果是false表示事件冒泡阶段调用事件处理程序
<div class="father">
<div class="son">son盒子</div>
</div>
<script>
var son = document.querySelector('.son');
//捕获阶段:body-father-son
//body father都没有监听器,所以只有一个son会弹出,如果father绑定了那么就会弹出
son.addEventListener('click',function(){
alert('son');
},true)
var father = document.querySelector('.father');
father.addEventListener('click',function(){
alert('father');
},true)
//冒泡阶段,false或者是不写 son-father-html-document
son.addEventListener('click',function(){
alert('son');
})
var father = document.querySelector('.father');
father.addEventListener('click',function(){
alert('father');
})
</script>
6.4 事件对象
- 在函数的小括号里面,当形参来看
- 事件对象只有有了事件才会存在,它是系统给我们自动创建的,不需要我们传递参数
- 事件对象是我们事件的一系列相关数据的集合 跟事件相关的 比如鼠标点击就包含了鼠标的相关信息,比如鼠标坐标
- 这个事件对象我们可以自己命名
- IE9一下通过window.event来获取事件对象
事件对象常见的属性和方法:
事件对象属性方法 | 说明 |
---|---|
e.target | 返回触发事件的对象 标准 |
e.srcElement | 返回触发事件的对象 非标准 IE6-8使用 |
e.type | 返回事件的类型 不带on |
e.cancelBubble | 阻止冒泡 IE6-8使用 |
e.returnValue | 阻止默认操作 非标准 IE6-8使用 比如不让链接跳转 |
e.preventDefault() | 阻止默认事件 标准 |
e.stopPropagation() | 阻止冒泡 标准 |
e.target返回的是触发事件的对象,而this返回的是绑定事件的对象
阻止默认行为:
//阻止默认事件
//阻止链接跳转或者让提交按钮不提交
var a = document.querySelector('a');
a.addEventListener('click',function(e){
e.preventDefault();
})
阻止冒泡事件:
//阻止事件冒泡
if(e && e.stopPropagation) {
e.stopPropagation();
}else {
window.event.cancelBubble = true;
}
事件委托:
不是给每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。如:ul中有很多的li,我们可以给ul注册点击事件,然后利用事件对象的target来找到当前点击的li,因为点击li,事件会冒泡到ul上,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>
6.5 常用的鼠标事件
鼠标事件 | 触发条件 |
---|---|
onclick | 鼠标点击左键触发 |
onmouseover | 鼠标经过触发 |
onmouseout | 鼠标离开触发 |
onfocus | 获得鼠标焦点触发 |
onblur | 失去鼠标焦点触发 |
onmousemove | 鼠标移动触发 |
onmouseup | 鼠标弹起触发 |
onmousedown | 鼠标按下触发 |
禁止鼠标右键菜单:contextmenu主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单
document.addEventListener('contextmenu',function(e){
e.preventDefault();
})
禁止鼠标选中文字:
document.addEventListener('selectstart',function(e){
e.preventDefault();
})
鼠标事件对象MouseEvent:
鼠标事件对象 | 说明 |
---|---|
e.clientX | 返回鼠标相对于浏览器窗口可视区的X坐标 |
e.clientY | 返回鼠标相对于浏览器窗口可视区的Y坐标 |
e.pageX | 返回鼠标相对于文档页面的X坐标 IE9+支持 |
e.pageY | 返回鼠标相对于文档页面的Y坐标 IE9+支持 |
e.screenX | 返回鼠标相对于电脑屏幕的X坐标 |
e.screenY | 返回鼠标相对于电脑屏幕的Y坐标 |
6.6 常用键盘事件
键盘事件 | 触发条件 |
---|---|
onkeyup | 某个键盘按键被松开时触发 不区分字母大小写 |
onkeydown | 某个键盘按键被按下时触发 不区分字母大小写 |
onkeypress | 某个键盘按键被按下时触发 但是不识别功能键如ctrl |
执行顺序:keydown-keypress-keyup
<script>
//keyup按键弹起的时候触发
document.addEventListener('keyup',function(){
console.log('弹起了')
})
//keydown按键按下的时候触发
document.addEventListener('keydown',function(){
console.log('弹下了')
})
//keypress按键按下的时候触发 不能识别功能键
document.addEventListener('keypress',function(){
console.log('press弹下了')
})
</script>
键盘事件对象keyboardEvent:keyCod属性可以返回相应键的ASCII码值
BOM浏览器对象模型
- BOM概述
- window对象的常见事件
- 定时器
- JS执行机制
- location对象
- navigator对象
- history对象
1.概述
BOM是浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是window。BOM由一系列相关的对象构成,并且每个对象都提供了很多的方法和属性。学习的是与浏览器窗口交互的一些对象,比如说刷新页面、跳转页面等等
window对象是浏览器的顶级对象:它不仅是JS访问浏览器窗口的一个接口,还是一个全局对象定义在全局作用于中的变量、函数都会变成window对象的属性和方法,在调用的时候可以省略window
2.window对象的常见事件
- 窗口加载事件:window.onload = function(){} 当文档内容全部加载完成时会触发该事件 包含样式表、图片、flash等等
- document.addEventListener(‘DOMContentLoaded’,function(){}):仅当DOM加载完成,不包括样式表、图片、flash等等 IE9+支持
- 调整窗口大小事件:window.οnresize=function(){} 只要窗口大小发生像素变化就会触发
3.定时器
3.1两种定时器
- setTimeout():window.setTimeout(调用函数,[延迟的毫秒数]) 该定时器在定时器到期后执行回调函数 window可以省略。这个回调函数需要等待时间,时间到了再去执行这个函数,并且只执行一次
<script>
//2s后调用这个函数,如果省略时间,那么默认是0
var time1 = setTimeout(function(){
console.log('123')
},2000);
function callback(){
console.log('爆炸了');
}
var time2 = setTimeout(callback,3000);
</script>
-
停止定时器:window.clearTimeout(timeoutID)
-
window.setInterval(回调函数,[间隔的毫秒数]):没隔这个时间就去调用这个函数
-
window.clearInteval(intervalID)
3.2倒计时
<span class="hour">1</span>
<span class="minute">2</span>
<span class="second">3</span>
<script>
//倒计时是不断变化的,需要用定时器setInterval来实现
//用三个盒子分别存放时分秒
//三个盒子利用innerHTML存入时间
var hour = document.querySelector('.hour');
var minute = document.querySelector('.minute');
var second = document.querySelector('.second');
var inputTime = +new Date('2021-5-25 18:00:00');//用户输入时间总的毫秒数
//防止第一次调用有空白
countDown();
//开启定时器
setInterval(countDown,1000);
//获取剩余时间的时分秒
function countDown() {
var nowTime = +new Date();//当前时间总的毫秒数
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;
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>
4.同步和异步
JS虽然是单线程的语言,但是可以进行异步,JS的异步是通过回调函数实现的,通常有以下三种类型:
- 普通事件:如click、resize等
- 资源加载,如load、error等
- 定时器,包括setInterval、setTimeout等
异步任务相关的糊掉函数添加到任务(消息)队列中
先执行主线程执行栈中的同步任务,然后在执行消息队列中找异步任务,再把义务人无放到主线程执行栈中执行
5.location对象
location是用于获取或者设置URL并且可以解析URL的属性
location对象属性 | 返回值 |
---|---|
location.href | 获取或者设置整个URL |
location.host | 返回主机域名 |
location.port | 返回端口号,如果没写则返回空字符串 |
location.pathname | 返回路径 |
location.search | 返回参数 |
location.hash | 返回片段 #后面内容 常见于链接 锚点 |
location常见方法:
location对象方法 | 返回值 |
---|---|
location.assign() | 可以跳转页面,也为重定向页面 可以后退 |
location.replace() | 替换当前的页面,因为不记录历史,所以不能后退页面 |
location.reload() | 重新加载页面,相当于刷新按钮或者F5 如果参数为true强制刷新crtl+F5 |
6.navigator对象
包含有关浏览器的信息,它有很多属性,最常用的是userAgent,该属性可以返回由客户端发送给服务器的user-agent头部的值
7.history对象
与浏览器历史记录进行交互,该对象包含用户访问过的URL
方法 | 作用 |
---|---|
back() | 可以后退功能 |
forward() | 前进功能 |
go(参数) | 前进后退功能 如果参数是1表示前进一个页面,如果参数是-1表示后退1个页面 |
PC端网页特效
- 能够说出常见offset系列属性的作用
- 能够说出常见client系列属性的作用
- 能够说出常见scroll系列属性的作用
- 能够封装简单动画函数
- 能够写出网页轮播图案例
1.元素偏移量offset系列
该系列的相关属性可以动态的得到元素的位置、大小等
offset系列属性 | 作用 |
---|---|
element.offsetParent | 返回作为该元素带有定位的父级元素,如果父级元素都没有定位就返回body |
element.offsetTop | 返回元素相对带有定位父元素上方的偏移 |
element.offsetLeft | 返回元素带有定位父元素左边框的偏移 |
element.offsetWidth | 返回自身包括padding、边框、内容区的宽度,返回的数值不带单位 |
element.offsetHeight | 返回自身包括padding、边框、内容区的高度,返回的数值不带单位 |
offset与style的区别
offset:
- 可以得到任意样式表中的样式值
- 获取的数值是没有单位的
- 包含padding+border+width
- 只能获取不能赋值
- 想要获取元素大小位置,用offset更加合适
style:
- 只能得到行内样式表中的样式值
- 获取的是带有单位的字符串
- 获得不包含padding和border的值
- 可以获取也可以赋值
- 如果给元素更改值,那么就要用style改变
2.拖动模态框案例
<!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>
//获取元素
var login = document.querySelector('.login');
var mask = document.querySelector('.login-bg');
var link = document.querySelector('#link');//弹出登录框
var closeBtn = document.querySelector('#closeBtn');//关闭按钮
link.addEventListener('click' ,function(){
mask.style.display = 'block';
login.style.display = 'block';
})
closeBtn.addEventListener('click' ,function(){
mask.style.display = 'none';
login.style.display = 'none';
})
//拖拽:鼠标按下、鼠标移动、鼠标松开
//拖拽过程:鼠标移动的过程中,获得最新的值赋值给模态框的left和top,这样模态框就可以跟着鼠标移动
//鼠标按下触发的事件源是最上面一行,就是id为title
//鼠标的坐标减去鼠标在盒子内的坐标,才是模态框真正的位置,因为鼠标拖拽的时候再盒子内的位置并不会变
//按下鼠标就可以知道鼠标在盒子内的位置
var title = document.querySelector('#title');
title.addEventListener('mousedown',function(e){
//鼠标在盒子内的坐标
var x = e.pageX - login.offsetLeft;
var y = e.pageY - login.offsetTop;
//移动事件要写在按下事件的内部,因为只有按下了才能够去移动
document.addEventListener('mousemove',move)
function move(e){
//鼠标移动的时候,是鼠标在页面中的坐标减去在盒子内的坐标得到模态框的坐标
login.style.left = e.pageX - x +'px';
login.style.top = e.pageY - y +'px';
}
//鼠标弹起,溢出鼠标移动时间
document.addEventListener('mouseup',function(){
document.removeEventListener('mousemove',move)
})
})
</script>
</body>
</html
3.client系列
我们利用client系列的相关属性来获取元素可视区的相关信息
client系列属性 | 作用 |
---|---|
element.clientTop | 返回元素上边框的大小 |
element.clientLeft | 返回元素左边框的大小 |
element.clientWidth | 返回自身包括padding、内容区,不含边框,返回数值不带单位 |
element.clientHeight | 返回自身包括padding、内容区,不含边框,返回数值不带单位 |
立即执行函数:不需要调用,立马能够自己执行,作用是创建了一个独立的作用域避免了命名冲突的问题
- (function() {})();
- (function(){}());
4.scroll系列
利用这个系列可以动态的到元素的大小、滚动距离等
scroll系列属性 | 作用 |
---|---|
element.scrollTop | 返回被卷去的上侧距离,返回数值不带单位 |
window.pageYOffset | 返回页面被卷去的上侧距离,返回数值不带单位 |
element.scrollLeft | 返回被卷去的左侧距离,返回数值不带单位 |
window.pageXOffset | 返回页面被卷去的左侧距离,返回数值不带单位 |
element.scrollWidth | 返回自身实际的宽度,不含边框,返回的数值不带单位 |
element.scrollHeight | 返回自身实际的高度,不含边框,返回的数值不带单位 |
scroll是真正的内容大小,因为内容有可能超出盒子范围
4.mouseover和mouseenter的区别
- mouseover:鼠标经过自身盒子会触发,经过子盒子还是会触发
- mouseenter:鼠标只经过自身盒子的时候触发,因为mouseenter不会冒泡
5.动画函数封装
核心原理:通过定时器setInteval()不断移动盒子的位置
实现步骤:
- 获取盒子当前的位置
- 让盒子在当前位置加上1个移动距离
- 利用定时器不断重复这个操作
- 加一个结束定时器的条件
- 注意此元素需要添加定位,才能使用element.style.left
动画函数的封装:需要传递2个参数,动画对象和移动到的距离
注意:动画对象一定要加定位
function animate(obj,target){
var timer = setInterval(function(){
if(obj.offsetLeft >= target){
//停止
clearInterval(timer);
}
obj.style.left = obj.offsetLeft + 1 +'px';
},30);
}
动画函数给不同元素记录不同定时器:
如果多个元素都使用这个动画函数,每次都要var声明定时器,我们可以给不同的元素使用不同的定时器
function animate(obj,target){
//让元素只有一个定时器可以执行,因为如果有些触发事件绑定这个动画,那么可能导致定时器越来越多,然后元素越来越快
//先清除以前的定时器,只保留当前一个定时器
clearInterval(obj.timer);
obj.timer = setInterval(function(){
if(obj.offsetLeft >= target){
//停止
clearInterval(obj.timer);
}
obj.style.left = obj.offsetLeft + 1 +'px';
},30);
}
**缓动动画:**让元素运动速度有变化,最常见的是让速度慢慢停下来
思路:
- 让盒子每次移动的距离慢慢变小,速度就会慢慢落下来
- 核心算法:(目标值-现在的位置)/10 作为每次移动的距离
- 停止的条件是盒子当前的位置等于目标位置
- 步长值需要取整
function animate(obj,target){
//让元素只有一个定时器可以执行,因为如果有些触发事件绑定这个动画,那么可能导致定时器越来越多,然后元素越来越快
//先清除以前的定时器,只保留当前一个定时器
clearInterval(obj.timer);
obj.timer = setInterval(function(){
//每一次都要计算步长
//避免小数,正数往上取整,负数往下取整
var step = (target - obj.offsetLeft)/10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if(obj.offsetLeft >= target){
//停止
clearInterval(obj.timer);
}
//把步长慢慢变小
obj.style.left = obj.offsetLeft + step +'px';
},30);
}
动画函数添加回调函数:
回调函数的原理是函数可以作为一个参数,则这个函数作为参数传到另一个函数里面,当那个函数执行完之后,再执行传进去的这个函数,这个过程叫做回调
<script>
var div = document.querySelector('div');
//得到盒子当前的位置
//动画函数的封装
//给不同的元素指定了不同的定时器
function animate(obj,target,callback){
//让元素只有一个定时器可以执行,因为如果有些触发事件绑定这个动画,那么可能导致定时器越来越多,然后元素越来越快
//先清除以前的定时器,只保留当前一个定时器
clearInterval(obj.timer);
obj.timer = setInterval(function(){
//每一次都要计算步长
//避免小数,正数往上取整,负数往下取整
var step = (target - obj.offsetLeft)/10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if(obj.offsetLeft >= target){
//停止
clearInterval(obj.timer);
//回调函数写到定时器结束里面
if(callback){
//执行
callback();
}
}
//把步长慢慢变小
obj.style.left = obj.offsetLeft + step +'px';
},30);
}
animate(div,500,function(){});
</script>