【千锋】H5大前端-学习打卡05(JavaScript)
【JS的BOM】操作浏览器
操作浏览器的一些内容。
获取窗口尺寸
- 宽度:
window.innerWidth
- 高度:
window.innerHeight
弹出层
- 提示框:
window.alert()
- 询问框:
window.confirm()
- 输入框:
window.prompt()
标签页的开启和关闭
- 开启:
window.open()
- 关闭:
window.close()
历史操作记录
- 回退:
window.history.back()
- 前进:
window.history.forward()
浏览器常见事件
- 资源加载完毕:
window.onload = function () {}
- 页面尺寸改变:
window.onresize = function () {}
- 滚动条位置改变:
window.onscroll = function () {}
滚动条卷去的尺寸
当 HTML 页面有
<!DOCTYPE html>
时用第一种代码,没有时用第二种代码。
书写代码时可以都写上:var height = document.documentElement.scrollTop || document.body.scrollTop
- 高度:
document.documentElement.scrollTop
document.body.scrollTop
- 宽度:
document.documentElement.scrollLeft
document.body.scrollLeft
浏览器滚动到
window.scrollTo()
- 例子1
1
window.scrollTO( left, top)
- 例子2
1
2
3
4
5window.scrollTo( {
left: xx,
top: yy,
behavior: 'smooth'
} )
- 例子1
【JS定时器】
间隔定时器
按照指定周期(毫秒)去执行指定的代码
像定时闹钟,可重复执行
- 语法:
setInterval(函数, 时间)
- 函数:要执行的内容
- 时间:单位毫秒
1 | setInterval(function () { |
延时定时器
在固定的时间(毫秒)后指定一次代码
像延时炸弹,只执行一次
- 语法:
setTimeout(函数, 时间)
- 函数:时间到达时要执行的内容
- 时间:单位毫秒
1 | setTimeout(function () { |
定时器的返回值
不区分定时器的种类,是个从1开始的正整数,
返回值表示:是当前页面的第几个定时器
关闭定时器
语法一:clearInterval(要关闭的定时器返回值)
语法二:clearTimeout(要关闭的定时器返回值)
注意:不区分定时器种类
1 | <button id="close">关闭定时器</button> |
【JS的DOM操作】(上)
操作文档流相关的内容和方法
一、获取元素的方式
1. 根据id名称
语法:document.getElementById( 'id名称' )
作用:获取文档流中 id 名对应的一个元素
返回值:
- 如果有 id 对应的元素,就是这个元素
- 如果没有 id 对应的元素,返回null
2. 根据类名
语法:document.getElementsByClassName( '元素类名' )
作用:获取文档流中所有类名对应的元素(上面Element后有s)
返回值:必然是一个伪数组
- 如果有类名对应的元素,有多少取多少
- 如果没有类名对应的元素,返回空的伪数组
3. 根据标签名
语法:document.getElementsByTagName( '标签名' )
作用:获取文档流中所有标签名对应的元素(上面Element后有s)
返回值:必然是一个伪数组
- 如果有标签名对应的元素,有多少取多少
- 如果没有标签名对应的元素,返回空的伪数组
4. 根据选择器获取一个
语法:document.querySelector( '选择器' )
作用:获取文档流中满足选择器的第一个元素
返回值:
- 如果有选择器对应的元素,获取到第一个
- 如果没有标签名对应的元素,返回null
5. 根据选择器获取一组
语法:document.querySelectorAll( '选择器' )
作用:获取文档流中所有满足选择器的元素
返回值:必然是一个伪数组
- 如果有选择器对应的元素,有多少取多少
- 如果没有选择器对应的元素,返回空的伪数组
二、操作元素的内容
文本内容
- 获取:
元素.innerText
- 设置:
元素.innerText = '新内容'
超文本内容
- 获取:
元素.innerHTML
- 设置:
元素.innerHTML = '新内容'
三、操作元素属性
原生属性
- 获取:
元素.属性名
- 设置:
元素.属性名 = '属性值'
自定义属性
- 获取:
元素.getAttribute( '属性名' )
- 设置:
元素.getAttribute( '属性名', '属性值' )'
- 删除:
元素.removeAttribute( '属性名' )
四、操作元素类名
- 获取:
元素.className
- 设置:
元素.className = '新类名'
注意:在获取
background-color
这种带有中划线的属性时,要改成backroundColor
这种驼峰命名法
比如console.log( box.style.backroundColor )
又如box.style.backroundColor = 'green'
五、操作元素行内样式
- 获取:
元素.style.样式名
- 设置:
元素.style.样式名 = '样式值'
注意:只能获取和设置元素的行内样式
六、获取元素非行内样式
获取:window.getComputedStyle(元素).样式名
注意:可以获取行内样式,也可以获取非行内样式
【案例】通栏收起/全选/Tab切换
- 顶部通栏的收起与隐藏,以及回到顶部的按钮:教程视频
- 全选:教程视频(注意视频中for循环内应该用let来声明变量,详情请见→讲解博文)
- 选项卡(Tab切换):教程视频(用到了遍历数组的
forEach()
方法)
【JS的DOM操作】(下)
一、节点操作
创建
语法:document.createElement( '标签名称' )
作用:创建一个指定标签元素
返回值:一个创建好的标签元素节点
1 | var div = document.createElement( 'div' ) |
插入
需要先执行上面代码创建一个节点,然后执行下面代码插入到一个已经存在的结构内。
语法一:
父节点.appendChild( 子节点 )
作用:把子节点
放在父节点
的内部,并且放在最后的位置语法二:
父节点.insertBefore( 要插入的子节点, 哪一个子节点的前面 )
作用:把子节点
放在父节点
的内部,并且放在指定某一个子节点的前面
删除
语法一:
父节点.removeChild( 子节点 )
作用:从父节点
内删除某一个子节点
语法二:
节点.remove()
(无参数)
作用:把自己
删除
替换
语法:父节点.replaceChild( 换上节点, 换下节点 )
作用:在父节点内,使用换上节点
替换掉换下节点
克隆
语法:节点.cloneNode( 是否克隆后代节点 )
作用:把该节点复制
一份一模一样的内容
二、获取元素的尺寸
语法一:
元素.offsetHeight
和元素.offsetWidth
获取:元素“内容 + padding + border”区域的尺寸语法二:
元素.clientHeight
和元素.clientWidth
获取:元素“内容 + padding”区域的尺寸
两个语法的区别是:是否加上边框
【案例】动态渲染数据
如拿到数据后渲染成表格到前端页面
【JS的事件】(上)
通俗地讲,就是通过代码的方式和页面中的某些内容做好一个约定(事件绑定)
当用户触发指定行为的时候,就会执行代码
事件绑定
三要素:
- 事件源:和谁做约定
- 事件类型:约定什么行为
- 事件处理函数:当用户触发该行为的时候,执行什么代码
语法:事件源.on = 事件处理函数
要提前获取该元素哦!
事件类型
事件对象
就是当事件触发的时候,一个描述该事件信息的对象数据类型.
方法很简单,直接在上面说的那些事件处理函数内接受形参就可以了:
1 | // 直接在事件处理函数内接受形参 |
获取到的有很多信息,常见的如下:
1. 鼠标事件
坐标信息:
offsetX
和offsetY
clientX
和clientY
pageX
和pageY
2. 键盘按键
键盘编码:事件对象.keyCode
【案例】鼠标跟随
【JS的事件】(下)
事件传播
就是浏览器响应事件的总机制
浏览器的事件响应机制:
- 浏览器最先知道事件的发生
捕获阶段
:从Window按照结构子级的顺序传递到目标目标阶段
:准确触发事件的那个元素接收到行为冒泡阶段
:从目标按照结构子级的顺序传递到Window
浏览器的传播机制默认都是在冒泡阶段触发事件的,点击子级时,子级触发事件并往外传播给父级,如果父级也绑定了事件,也会触发父级的,比如下面的例子,点击最里层的inner,这三个嵌套在一起的元素都会被触发。
1 | <div class="outer"> |
阻止事件传播
语法:事件对象.stopPropagation()
比如在上面那个案例中innner的onclick事件添加个参数e(作为事件对象),在代码里添加上方语句后只触发inner自己的事件:
1 | <div class="outer"> |
事件委托
利用事件冒泡的机制,把自己的事件委托给结构父级中的某一层。
比如下方代码,无论点击的是哪个 li 元素,绑定点击事件的 ul 元素都会触发事件。
1 | <ul> |
那如何确定点击的是哪一个 li 元素?或者点击的是不是 ul 呢?我们把上面中的JS里,加入形参e作为事件对象,运用target属性,target拿到的就是你点击的那个元素:
1 | // 事件委托 |
上面的写法中,根据你点击的元素,控制台打印出的可能是<ul></ul>
、<li>3</li>
等
我们换一种写法,利用 target 的 tagName 属性(就是target获取的标签元素的大写标签名):
1 | // 事件委托 |
这样写之后,点击 ul 不会触发了。点击任何的 li 都会触发,这就是事件委托。
【案例】轮播图
【面向对象】
一、了解面向对象
了解面向对象:面向对象是我们的一种开发方式。视频讲解
面向过程:一种关注过程的开发方式
=> 在开发过程中,我们要关注每一个细节、步骤,顺序面向对象:一种面向对象的开发方式
=> 在开发过程中,我们看看有没有一个对象能帮我们完成任务
面向对象的核心:高内聚低耦合(就是对面向过程的高度封装)
二、创建对象的方式
1. 字面量方式创建对象
1 | var obj = { ... } |
1 | var obj = { |
2. 内置构造函数方式创建对象
1 | var obj = new Object() |
1 | var obj = new Object() |
3. 工厂函数创建对象
1 | // 1.制造一个工厂函数 |
工厂模式有返回值,因为通过调用函数会把把函数返回值(这里就是函数封装的对象obj)给返回,然后我们通过声明一个变量obj1去接收,此时变量obj1里面存的就是对象,然后通过对象调用属性与方法,如果没有返回值就会报错。
4. 自定义构造函数创建对象
1 | // 1.制造一个自定义构造函数 |
构造函数的首字母习惯上大写(这里的构造函数是CreateObj),用来区分于普通函数,内部使用的this对象,来指向即将要生成的实例对象,使用New关键字来联用生成实例对象。
通过上面代码比较,我们会发现工厂模式创建了一个空对象obj,并且返回了这个对象,但是构造函数没有这一步,那是因为用new关键字实例化对象已经帮我们做了以下操作:
- 创建一个空对象 obj;
- 将新创建的空对象的隐式原型指向其构造函数的显示原型。
- 使用 call 改变 this 的指向
- 如果无返回值或者返回一个非对象值,则将 obj 返回作为新对象;如果返回值是一个……
后两种方法的异同
关于工厂函数创建对象和自定义构造函数创建对象
共同点:
都是函数,都可以创建对象,都可以传入参数
不同点:
工厂模式:
- 函数名是小写
- 有new
- 有返回值
- new之后的对象是当前的对象
- 直接调用函数就可以创建对象
自定义构造函数:
- 函数名是大写(首字母)
- 没有new
- 没有返回值
- this是当前的对象
- 通过new的方式来创建对象
三、构造函数的使用
四、构造函数的不合理
五、原型prototype
每个函数都有函数原型prototype,只要向要构造的函数的原型上写一些方法,那么每一个该构造函数实例化后的对象都会使用原型上的方法,每一个实例都可以使用,并且用的都是同一个函数,不会出现浪费空间的行为。
1 | function Person() {} |
六、简单版面向对象选项卡HTML
- 抽象内容
- 书写构造函数
【原型和原型链】
1. 原型
- 构造函数的不好
- 用原型来解决问题
每一个构造函数天生自带一个 prototype 属性,是一个对象数据类型
每一个实例对象天生自带一个属性 __proto__
,指向所构造函数的 prototype
当访问对象的成员的时候,首先在自己身上查找,如果没有,自动去到 __proto__
上查找
我们把需要设置给实例的方法,放在构造函数(prototype)上,所有用此构造函数创建出的实例都可以访问使用
2. 原型链
问题1:实例对象身上的
__proto__
指向谁?
=> 指向所属构造函数的 prototype
=> p1所属的构造函数是 Person
=> 所以p1.__proto__指向 Person.prototype问题2:
Person.prototype
的__proto__
指向谁?
=> Person.prototype 所属构造函数是谁
=> 因为 Person.prototype 是一个对象数据类型(Object)
=> 在 JS内所有的 Object 数据类型都是属于 Object 这个内置的构造函数
=> Person.prototype 是属于 Object 这个内置构造函数的
=> Person.prototype 的 proto 指向 Object.prototype问题3:
Person
的__proto__
指向谁?
=>
=>
=>
不想写了,看视频吧……【两手一摊】
原型链:
1. 用__proro__
串联起来的对象链状结构
2. 注意:是使用 __proro__
串联的那条才算
3. 每一个对象数据类型,都有一个属于自己的原型链
4. 作用:为了访问对象成员(先找自己有没有,再顺着链往上找__proro__
)
5. 一直往上找,直到 Object.protype 都没有要找的成员,那么返回 undefined
【ES6语法规则】
定义变量
除了之前的var
关键字,又新增了两个。
let
:定义变量const
:定义常量(特殊的变量)
var
、let
和const
区别如下:
var
会进行预解析let
和const
不会进行预解析
在定义声明之前使用变量会报错
var
可以声明两个重名的变量let
和const
不能定义重名变量
定义重名变量会报错
var
没有块级作用域(是指一个可以执行代码段的{}
都会限制该变量的适用范围)let
和const
有块级作用域
也就是说用它们定义的变量,出了花括号就不能用了
let
和const
区别如下:
let
定义变量的时候可以不赋值const
在定义变量的时候必须赋值
let
可以定义的变量可以被修改const
定义的变量一经赋值无法修改
总而言之:
var
的作用域更大;let
的作用域小,除了出了花括号不能用之外,和var其实差不多;const
的作用域小,除了出了花括号不能用之外,还是一次性的,不能改变其值;
箭头函数
是ES6在语法中对函数表达式
的简写
对于声明式函数不能使用
在某些规则上又和以前的函数有些不一样
什么是函数表达式?
函数表达式,又叫做“匿名函数”
也就是我们不需要单独定义函数,就能直接进行赋值使用的那句代码
1 | // 这些都叫函数表达式 |
箭头函数就是指,在我们书写函数表达式的时候,省略掉function
关键字不写,在小括号
和后面花括号
之间加一个箭头=>
,这就是箭头函数的语法
1 | // 这些都叫函数表达式 |
箭头函数的特殊之处:
某些情况下可以省略小括号
()
=> 当你的形参只有一个的时候1
2
3
4
5
6
7//没有形参时,不能省
var fn1 = () => { console.log('我没有形参') }
//有形参时,能省小括号
var fn2 = (a) => { console.log('我有一个形参',a) }
//可以写成
var fn2 = a => { console.log('我有一个形参,并省去了小括号',a) }某些情况下可以省略花括号
{}
=> 当你的代码只有一句话的时候可以省略
=> 并且自动将这一句话的结果当做返回值1
2
3
4
5//代码只有一句话
var fn1 = (a, b) => {
return a + b
}
console.log(fn1(10, 20))箭头函数没有
arguments
1
2
3
4
5
6
7
8
9
10
11//普通函数里有`arguments
var fn1 = function () {
console.log(arguments)
}
fn1(100, 200, 300)
//箭头函数里没有`arguments
var fn1 = () => {
console.log(arguments)
}
fn1(100, 200, 300)箭头函数内没有
this
=> 箭头函数的 this 就是外部作用域的 this1
2
3
4
5
6
7var obj = {
fn1: function () { console.log(this) },
fn2: () => { console.log(this) }
}
obj.fn1() //因为 fn1 函数被 obj 调用,所以 this 是 obj
obj.fn2() //因为是箭头函数,内部没有 this ,就是外部作用域的 this
函数参数默认值
- 函数在定义的时候,可以直接给形参设置一个默认值
- 当没有使用实参的时候,就使用默认值
- 当传递了实参,就使用传递的实参
- 普通函数可以使用,箭头函数也可以使用
1 | // 设置参数 a 的默认值为100 |
解构赋值
快速从
对象
或者数组
中获取成员1: 数组的解构赋值:快速从数组中获取数据
1 | //以前 |
1 | // 数组的解构赋值(用中括号[]) |
- 2: 对象的解构赋值:快速从对象中获取数据
1 | //以前 |
1 | // 对象的解构赋值(用花括号{}) |
1 | // 表示定义一个变量a,获取的是 obj 内叫做 a 的成员的值 |
模板字符串
就是 ES6 内新增的定义字符串的方式
1 | // 以前 |
区别:
- 反引号中内容可以换行
- 可以直接在字符串内解析变量
1
2
3
4
5
6
7//当需要解析变量的时候,直接
${ 变量 }
//比如
var age = 3
var s1 = `我是百里飞洋,今年 ${age} 岁了`
console.log(s1)
展开运算符
符号:...
作用:展开数组的中括号[]
,或者展开对象的大括号{}
1 | // 1. 打印四个数 |
有哪些应用?
作用1:合并数组
1
2
3
4
5
6var arr1 = [10, 20]
var arr2 = [30, 40]
var arr3 = [50, 60, 70]
var arr4 = [80, 90]
// 合并数组
var arr5 = [...arr1, ...arr2, ...arr3, ...arr4]作用2:给函数传递参数
1
2
3
4
5
6
7var arr1 = [ 10, 20, 17, 7, 31, 22, 12 ]
//传统方式
var max = Math.max(10, 20, 17, 7, 31, 22, 12)
console.log(max)
//使用展开运算符的方式
var max = Math.max(...arr)
console.log(max)作用3:复制对象
1
2
3
4
5
6
7
8var obj = { name: 'Jack', age: 18 }
var obj2 = {
gender: '男',
...obj
//相当于在这里插入了 name: 'Jack', age: 18 这两个成员
//注意:当有相同成员的时候,后面的会覆盖前面的,注意顺序问题
}
console.log(obj2)
类语法
就是用 ES6 的语法书写构造函数,语法格式如下:
1 | class 类名 { |
原来构造函数的写法:
1
2
3
4
5
6
7
8
9
10
11
12// 1.构造函数
function Person(name, age) {
this.name = name
this.age = age
}
// 2.原型上添加方法(给实例使用)
Person.prototype.sayHi = function () { console.log('hello world') }
// 3.用法:新建一个对象
var p1 = new Person('Jack', 18)
console.log(p1) //打印对象
p1.sayHi() //执行原型上的方法可以不和
new
关键字连用,不报错但不规范。用类语法构造函数的写法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 1.类的书写
class Person {
constructor (name, age) {
// 这里按照ES5的构造函数体书写
this.name = name
this.age = age
}
// 2.直接书写原型上的方法即可
sayHi () { console.log('你好 世界') }
}
// 3.用法:新建一个对象(还是一样的)
var p1 = new Person('张三', 18)
console.log(p1) //打印对象
p1.sayHi() //执行原型上的方法类语法新建对象时必须和
new
关键字连用,否则会报错。原来书写 静态属性 和 静态方法 的方法
1
2
3
4
5
6
7//静态属性
Person.a = 100
//静态方法
Person.go = function() {console.log('跑起来')}
console.log(Person.a)
Person.go()
- 用类语法书写 静态属性 和 静态方法 的方法(需要加上一个
static
关键字)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16class Person {
constructor (name, age) {
this.name = name
this.age = age
}
sayHi () { console.log('你好 世界') }
//静态属性
static a = 100
//静态方法
static go () { console.log('running') }
}
var p1 = new Person('张三', 18)
console.log(p1) //打印对象
p1.sayHi() //执行原型上的方法
特别感谢: