事件对象
- 概念:当时事件发生的时候,所以跟事件相关的信息(事件类型,事件目标,鼠标位置等)都会存储在事件对象event中。
- 获取方式:
console.log(event); //ie chrome 火狐会报错
console.log(window.event); //ie chrome 火狐不报错,没有值
console.log(ev); //火狐专用(一定要在形参中传入ev) - 兼容处理
var oEvent = window.event || ev
事件对象属性
oDiv.onclick = function (ev) {
//事件对象兼容
var oEvent = window.event || ev
console.log(oEvent);
//事件类型
console.log(oEvent.type);
//事件目标
console.log(oEvent.target || oEvent.srcElement);
//鼠标位置,相对于屏幕
console.log(oEvent.clientX, oEvent.clientY);
//鼠标位置,相对于页面
console.log(oEvent.pageX, oEvent.pageY);
//是某按住了某些键,返回一个布尔值
//alt
console.log(oEvent.altKey);
//ctrl
console.log(oEvent.ctrlKey);
//shift
console.log(oEvent.shiftKey);
}
- 事件绑定
- 标准浏览器: 元素.addEventListener(‘事件类型(不加on)’,事件处理函数,是否捕获)
默认false冒泡 true捕获 - IE浏览器:
元素.attachEvent(‘事件类型(加on)’,事件处理函数) - 区别:
标准 addEventListener
①不加on
②是否捕获
③this——触发事件的对象
IE attachEvent
①加on
②没有捕获
③this——window
④IE低版本浏览器,会倒序执行
- 标准浏览器: 元素.addEventListener(‘事件类型(不加on)’,事件处理函数,是否捕获)
function fn1() {
console.log(111);
}
function fn2() {
console.log(222);
}
function fn3() {
console.log(333);
}
//封装
function on(ele, type, fun) {
if (ele.addEventListener) { //有值,说明支持这个方法
ele.addEventListener(type, fun)
} else {
ele.attachEvent('on' + type, fun)
}
}
on(oDiv,'mouseover',fn1)
on(oDiv,'mouseover',fn2)
on(oDiv,'mouseover',fn3)
- DOM事件流
- 事件捕获阶段:当事件发生的时候,事件从window开始依次往子元素传递
- 确定目标阶段:找到目标
- 事件冒泡阶段:从事件目标开始处理事件,处理完以后依次往父元素传递,一直传到 window
注意IE只有冒泡,没有捕获
<div id="box1">
<div id="box2">
<div id="box3">
</div>
</div>
</div>
//冒泡 先触发自己,再依次触发父级
oDiv[0].addEventListener('click', fn1) //111
oDiv[1].addEventListener('click', fn2) //222 111
oDiv[2].addEventListener('click', fn3) //333 222 111
//捕获 从最顶层父级开始,依次往下传递,最后触发自己的
oDiv[0].addEventListener('click', fn1, true) //111
oDiv[1].addEventListener('click', fn2, true) //111 222
oDiv[2].addEventListener('click', fn3, true) //111 222 333
- stopPropagation
- 概念:该方法将停止事件的传播,阻止它被分派到其他document节点
- 兼容:oEvent.stopPropagation ? oEvent.stopPropagation() : oEvent.cancelBubble = true
//点击显示
btn.onclick = function (ev) {
oDiv.style.display = 'block'
//事件对象兼容
var oEvent = window.event || ev
//该方法将阻止事件的传播,阻止它被分配到其他document节点
//标准浏览器oEvent.stopPropagation() ie低版本:oEvent.cancelBubble = true
oEvent.stopPropagation ? oEvent.stopPropagation() : oEvent.cancelBubble = true
}
document.onclick = function () {
oDiv.style.display = 'none'
}
- 事件取消
- 元素.事件—————————–元素.事件=null
- 元素.addEventListener()————元素.removeEventListener(事件类型,事件处理函数)
- 元素.attachEvent()——————元素.detachEvent(事件类型,事件处理函数)
oDiv[0].onclick = function(){
console.log(111)
}
oDiv[0].onclick = null
oDiv[0].addEventListener('click',fn1)
oDiv[0].removeEventListener('click',fn1)
oDiv[0].attachEvent('onclick',fn1)
oDiv[0].detachEvent('onclick',fn1)
- 取消默认行为 :浏览器给的行为
- 元素.事件———————–return false
- 元素.addEventListener()———————oEvent.preventDefault()
- 元素.attachEvent()—————————oEvent.returnValue = false
// 元素.事件
oA.onclick = function () {
return false
}
oA.addEventListener('click', function (ev) {
//事件对象兼容
var oEvent = window.event || ev
oEvent.preventDefault()
})
oA.attachEvent('onclick',function(ev){
//事件对象兼容
var oEvent = window.event || ev
oEvent.returnValue = false
})
- 鼠标右击事件
- 元素.oncontextmenu
/*
分析:
1、获取元素
2、给元素添加右击事件
3、获取鼠标点击的位置 在这之前做事件对象兼容
4、把这个位置赋值给div
5、取消右击的默认事件
*/
var oDiv = document.getElementsByTagName('div')[0]
document.oncontextmenu = function (ev) {
//事件对象兼容
var oEvent = window.event || ev
console.log(oEvent);
//获取鼠标X轴位置
var clientX = oEvent.clientX
//获取鼠标Y轴位置
var clientY = oEvent.clientY
//赋值给div
oDiv.style.left = clientX + 'px'
oDiv.style.top = clientY + 'px'
//取消默认事件(右键)
return false
}
- 键盘事件
- onkeydown 键盘按下
- onkeypress 在键盘被按下并释放一个键时发生
- onkeyup 键盘抬起
document.onkeydown = function (ev) {
//事件对象兼容
var oEvent = window.event || ev
console.log(oEvent);
console.log('我的按键是:' + oEvent.key);
console.log('我的编码是:' + oEvent.keyCode);
//是否按了alt
console.log(oEvent.altKey);
//是否按了ctrl
console.log(oEvent.ctrlKey);
//是否按了shift
console.log(oEvent.shiftKey);
//判断是否按了ctrl+shift
if (oEvent.ctrlKey == true && oEvent.shiftKey == true) {
console.log('我按了ctrl+shift');
}
//判断是否按了ctrl+c
if (oEvent.ctrlKey == true && oEvent.keyCode == 67) {
console.log('我按了ctrl+c');
}
}
案例:控制div的移动(左上右下:37-38-39-40)
<div></div>
<script src="./ujiuye.js"></script>
<script>
var oDiv = document.getElementsByTagName('div')[0]
document.onkeydown = function (ev) {
// console.log(111);
//事件对象兼容
var oEvent = window.event || ev
//获取可视区宽度
var clientX = document.documentElement.clientWidth
if (parseInt(getStyle(oDiv, 'left')) <= -100) {
oDiv.style.left = clientX + 'px'
}
switch (oEvent.keyCode) {
case 37:
oDiv.style.left = parseInt(getStyle(oDiv, 'left')) - 10 + 'px';
break;
case 38:
oDiv.style.top = parseInt(getStyle(oDiv, 'top')) - 10 + 'px';
break;
case 39:
oDiv.style.left = parseInt(getStyle(oDiv, 'left')) + 10 + 'px';
break;
case 40:
oDiv.style.top = parseInt(getStyle(oDiv, 'top')) + 10 + 'px';
break;
}
}
</script>
- 滚轮事件
- ie/chrome:元素.onmousewheel
- 滚动方向:oEvent.wheelDelta 下:-120 上:120
- 火狐:元素.addEventListener(‘DOMMouseScroll’,处理函数)
- 滚动方向:oEvent.detail 下:3 上:-3
- ie/chrome:元素.onmousewheel
封装滚轮方向:
function scroll(ev) {
//事件对象兼容
var oEvent = window.event || ev
if (oEvent.wheelDelta) {
//如果能走到这里,说明是谷歌浏览器
if (oEvent.wheelDelta > 0) {
console.log('向上滚动');
} else {
console.log('向下滚动');
}
} else {
//如果能走到这里,说明是火狐浏览器
if (oEvent.detail > 0) {
console.log('向下滚动');
} else {
console.log('向上滚动');
}
}
}
//谷歌浏览器
document.onmousewheel = function(){
scroll()
}
//火狐浏览器
document.addEventListener('DOMMouseScroll',scroll)
案例:滚轮改变div的高度
function scroll(ev) {
//事件对象兼容
var oEvent = window.event || ev
//定义一个变量用来保存当前是向上滚动还是向下滚动
var tag = true
if (oEvent.wheelDelta) {
//如果能走到这里,说明是谷歌浏览器
tag = oEvent.wheelDelta > 0 ? true : false
} else {
//如果能走到这里,说明是火狐浏览器
tag = oEvent.detail > 0 ? false : true
}
//向下滚动false,向上滚动是true
//获取当前的高度
var h = parseInt(getStyle(oDiv, 'height'))
console.log(h);
if (tag) {
//向上滚动
oDiv.style.height = h - 10 + 'px'
} else {
//向下滚动
oDiv.style.height = h + 10 + 'px'
}
}
oDiv.onmousewheel = function () {
scroll()
}
oDiv.addEventListener('DOMMouseScroll', scroll)
- 事件代理
- 概念:事件代理(事件委托):找一个元素**(父元素)代理**,当事件发生时,由这个元素通知具体的元素去处理事件
- 原理:将事件绑定在父元素身上,当事件发生的时候,通过事件目标获取到具体的子元素,去处理事件 (接收事件目标 oEvent.tagret || oEvent.srcElement)
- 优点:提高性能,让后面所有子元素都同样拥有效果
oUl.onclick = function (ev) {
//事件对象兼容
var oEvent = window.event || ev
//用来接收事件目标 oEvent.tagret||oEvent.srcElement
var tagret = oEvent.tagret || oEvent.srcElement
tagret.style.background = 'pink'
}
oUl.innerHTML += '<li>999</li>'
//多个输入框各自通过滚轮增减数字
function scroll(ev) {
//事件处理兼容
var oEvent = window.event || ev
//事件代理
var target = oEvent.tagret || oEvent.srcElement
var tag = true
//向上滑动,tag=true;向下滑动,tag=false
if (oEvent.detail) {
tag = oEvent.detail > 0 ? false : true
} else {
tag = oEvent.wheelDelta > 0 ? true : false
}
//向上滑动,值++;向下滑动,值--
if(tag){
target.value++
}
else{
target.value--
}
}
document.body.onmousewheel = function(){
scroll()
}
document.body.addEventListener('DOMMouseScroll',scroll)
拖拽
<div></div>
<img src="../拖拽/img/123.jpg" alt="">
<script>
var oDiv = document.getElementsByTagName('div')[0]
var oImg = document.getElementsByTagName('img')[0]
drag(oDiv)
drag(oImg)
function drag(ele) {
ele.onmousedown = function (ev) {
// 事件处理兼容
var oEvent = window.event || ev
//当鼠标点下,获取鼠标到盒子的x,y(鼠标到屏幕的距离-盒子到屏幕的距离)
var mouseToBoxL = oEvent.clientX - ele.offsetLeft
var mouseToBoxT = oEvent.clientY - ele.offsetTop
//获取屏幕可视宽高
var clientW = document.documentElement.clientWidth
var clientH = document.documentElement.clientHeight
//盒子实际宽高
var boxW = ele.offsetWidth
var boxH = ele.offsetHeight
//ie低版本浏览器取消图片文字拖拽默认事件:设置捕获(一次性的,鼠标抬起后需要释放捕获才能重新设置捕获)
if (ele.setCapture) {
ele.setCapture()
}
document.onmousemove = function (ev) {
//事件处理兼容
var oEvent = window.event || ev
//控制范围(当盒子到左屏幕的距离<0时,设置盒子到左屏幕的距离=0;当盒子到左屏幕的距离>(屏幕宽-盒子实际宽度)时,设置盒子到左屏幕的距离=屏幕宽-盒子实际宽度)
// 控制范围(当盒子到上屏幕的距离<0时,设置盒子到上屏幕的距离=0;当盒子到上屏幕的距离>(屏幕高-盒子实际高度)时,设置盒子到上屏幕的距离=屏幕宽-盒子实际高度)
//时刻获取鼠标位置来确定盒子位置
var L = oEvent.clientX - mouseToBoxL
var T = oEvent.clientY - mouseToBoxT
if (L < 0) {
L = 0
} else if (L > clientW - boxW) {
L = clientW - boxW
}
if (T < 0) {
T = 0
} else if (T > clientH - boxH) {
T = clientH - boxH
}
//当鼠标移动,盒子的位置随之改变(设置定位样式为:鼠标到屏幕的距离-鼠标到盒子的距离)
ele.style.left = L + 'px'
ele.style.top = T + 'px'
}
document.onmouseup = function () {
document.onmousemove = null
document.onmouseup = null
//释放捕获
if (ele.releaseCapture) {
ele.releaseCapture()
}
}
//标准浏览器取消图片拖拽默认事件
return false
}
}
碰撞检测
<div></div>
<p></p>
<script>
var oDiv = document.getElementsByTagName('div')[0]
var oP = document.getElementsByTagName('p')[0]
//获取大盒子各边的位置
var bigL = oP.offsetLeft
var bigT = oP.offsetTop
var bigR = bigL + oP.offsetWidth
var bigB = bigT + oP.offsetHeight
oDiv.onmousedown = function (ev) {
// 事件处理兼容
var oEvent = window.event || ev
//当鼠标点下,获取鼠标到盒子的x,y(鼠标到屏幕的距离-盒子到屏幕的距离)
var mouseToBoxL = oEvent.clientX - oDiv.offsetLeft
var mouseToBoxT = oEvent.clientY - oDiv.offsetTop
//获取屏幕可视宽高
var clientW = document.documentElement.clientWidth
var clientH = document.documentElement.clientHeight
//盒子实际宽高
var boxW = oDiv.offsetWidth
var boxH = oDiv.offsetHeight
//ie低版本浏览器取消图片文字拖拽默认事件:设置捕获(一次性的,鼠标抬起后需要释放捕获才能重新设置捕获)
if (oDiv.setCapture) {
oDiv.setCapture()
}
document.onmousemove = function (ev) {
//事件处理兼容
var oEvent = window.event || ev
//控制范围(当盒子到左屏幕的距离<0时,设置盒子到左屏幕的距离=0;当盒子到左屏幕的距离>(屏幕宽-盒子实际宽度)时,设置盒子到左屏幕的距离=屏幕宽-盒子实际宽度)
//控制范围(当盒子到上屏幕的距离<0时,设置盒子到上屏幕的距离=0;当盒子到上屏幕的距离>(屏幕高-盒子实际高度)时,设置盒子到上屏幕的距离=屏幕宽-盒子实际高度)
//时刻获取鼠标位置来确定盒子位置
var L = oEvent.clientX - mouseToBoxL
var T = oEvent.clientY - mouseToBoxT
if (L < 0) {
L = 0
} else if (L > clientW - boxW) {
L = clientW - boxW
}
if (T < 0) {
T = 0
} else if (T > clientH - boxH) {
T = clientH - boxH
}
//当鼠标移动,盒子的位置随之改变(设置定位样式为:鼠标到屏幕的距离-鼠标到盒子的距离)
oDiv.style.left = L + 'px'
oDiv.style.top = T + 'px'
//在移动的时候,时刻获取小盒子各边的位置
var divL = oDiv.offsetLeft
var divT = oDiv.offsetTop
var divR = divL + oDiv.offsetWidth
var divB = divT + oDiv.offsetHeight
//判断安全区,小盒子右边<大盒子左边;小盒子下边<大盒子上边;小盒子左边>大盒子右边;小盒子上边>大盒子下边
if (divR < bigL || divB < bigT || divL > bigR || divT > bigB){
oP.style.background = 'green'
}else
oP.style.background = 'yellow'
}
document.onmouseup = function () {
document.onmousemove = null
document.onmouseup = null
//释放捕获
if (oDiv.releaseCapture) {
oDiv.releaseCapture()
}
}
//标准浏览器取消图片拖拽默认事件
return false
}
</script>
缓冲运动
// 封装调用测试缓冲运动
var timer
function bufferMove(ele,attr,target){
clearInterval(timer)
timer = setInterval(function () {
//获取当前位置
var localNow = parseInt(getStyle(ele, attr))
//速度步长:(目标位置-当前位置)/固定系数
var step = (target - localNow) / 10
//判断运动的方向:正向运动向上取整,负向运动向下取整
step = step > 0 ? Math.ceil(step) : Math.floor(step)
if (localNow == target) {
localNow = target
clearInterval(timer)
}
//设置div新的位置
ele.style[attr] = localNow + step + 'px'
}, 16)
}
oDiv.onclick = function(){
bufferMove(oDiv,'top',300)
}
多属性运动
<div></div>
<div></div>
<script src="../运动函数封装/ujiuye.js"></script>
<script>
//多属性运动,多个属性对应相对应的目标值,可以用对象
var oDiv = document.getElementsByTagName('div')
var oP = document.getElementsByTagName('p')[0]
// 封装调用测试缓冲运动
var timer
function bufferMove(ele, json, fn) {
//区分不同元素的定时器id(元素.timer)
clearInterval(ele.timer)
ele.timer = setInterval(function () {
//假设所有的样式都已经执行完
var tag = true
for (var attr in json) {
//获取当前位置(如果样式为透明度,则其获取到的透明浮点值*100;如果获取到的为其他样式,则当前位置为样式取整)
var localNow = attr == 'opacity' ? getStyle(ele, attr) * 100 : parseInt(getStyle(ele, attr))
//速度步长:(目标位置-当前位置)/固定系数
var step = (json[attr] - localNow) / 10
//判断运动的方向:正向运动向上取整,负向运动向下取整
step = step > 0 ? Math.ceil(step) : Math.floor(step)
//如果当前位置还没到目标值,则状态为false
if (localNow != json[attr]) {
tag = false
}
//设置div新的样式(如果样式为透明度,则设置透明值为(当前位置+步长)/100;如果为其他样式,则设置新样式为(当前位置+步长+'px')
ele.style[attr] = attr == 'opacity' ? (localNow + step) / 100 : localNow + step + 'px'
if (tag == true) {
//当全部键值对完成后清除定时器
clearInterval(ele.timer)
//回调函数
fn && fn(ele,
{
'height': 100,
'width': 100,
'opacity': 20
})
}
}
}, 30)
}
oDiv[0].onmouseover = function () {
bufferMove(this,
{
'height': 300,
'width': 300,
'opacity': 100
}, bufferMove)
}
oDiv[1].onmouseover = function () {
bufferMove(this,
{
'height': 300,
'width': 300,
'opacity': 100
}, bufferMove)
}
//此时两个盒子的定时器共用一个,相互影响,需要给当前元素设置独立的定时器,万物皆对象,元素.键名(ele.timer)
</script>
回调函数
- 某个动作或某个事件完成以后调用的函数
一般在封装函数中,都可以设置回调函数,但这个回调函数不是必传的参数,即使传了也可以选择不用(fn && fn())
轮播图
<script>
var oUl = document.getElementsByTagName('ul')[0]
var oP = document.getElementsByTagName('p')[0]
var oSpan = document.getElementsByTagName('span')
var wrap = document.getElementById('wrap')
//1、 91-102 设置静态页面并设置初始样式
var imgArr = ['./img/1.jpg', './img/2.jpg', './img/3.jpg', './img/4.jpg']
//定义接收图片的字符串
var str1 = ''
//定义接收span的字符串
var str2 = ''
for (var i = 0; i < imgArr.length; i++) {
str1 += '<li><img src="' + imgArr[i] + '"></li>'
str2 += '<span>' + (i + 1) + '</span>'
}
oUl.innerHTML = str1 + '<li><img src="' + imgArr[0] + '"></li>'
oP.innerHTML = str2
oSpan[0].className = 'active'
//定义一个n来表示当前是第几张图片
var n = 0
//2、设置自动轮播
var timer1 = setInterval(autoNext, 3000)
function autoNext() {
/*
第一次移动 -960*1
第二次移动 -960*2
第三次移动 -960*3
*/
//3、执行n++
n++
//5、判断是否为最后一张
if (n >= imgArr.length + 1) {
oUl.style.left = '0px'
n = 1
}
//4、每次移动ul -960*n的位置
move(oUl, 'left', 30, -960 * n)
//7、干掉小方块所有样式
for (var i = 0; i < oSpan.length; i++) {
oSpan[i].className = ''
}
//6、设置小方块的样式
if (n == imgArr.length) {
// 说明当前是那张假图
oSpan[0].className = 'active'
} else {
// 说明当前是正常轮播
oSpan[n].className = 'active'
}
}
wrap.onmouseover = function () {
clearInterval(timer1)
}
wrap.onmouseleave = function () {
timer1 = setInterval(autoNext, 3000)
}
//点击小方块
//1)循环遍历每一个小方块
for (var i = 0; i < oSpan.length; i++) {
//3)设置自定义索引
oSpan[i].index = i
//2)给每一个小方块添加点击事件
oSpan[i].onclick = function () {
//4)移动ul,每次移动-960*this.index的距离
move(oUl, 'left', 30, -960 * this.index)
//6)干掉所有
for (var j = 0; j < oSpan.length; j++) {
oSpan[j].className = ''
}
//5)给当前这个小方块添加样式
this.className = 'active'
//7)改变n的值
n = this.index
}
}
</script>
面向对象的概念
- 面向过程:我们之前按照步骤写代码就是面向过程的编程思维
- 面向对象:使用对象时,只关注对象提供的功能,不关注其内部细节
- 遇到问题就找对象,有对象就用对象,没有对象就造对象,使用对象来解决问题
- 面向对象的特点
- 封装:将大量的全局变量和函数封装成对象的属性和方法,从而减少全局变量,防止全局作用域的污染
- 继承:面向对象思想实现了js中的对象的继承
- 多态:在同一种操作中,不同环境下有不同的效果(譬如js中的+:运算/字符串拼接)
- 对象的组成
- 属性(静态)————对象中的属性
- 方法(动态)————对象中值为函数的属性
对象的创建
- 字面量创建
- var obj = {属性名:属性值,……….}
- 优点:写法方便
- 缺点:不利于创建大量对象
- 实例化创建
- var obj = new Object()
- 优点:创建出来的对象类型明确
- 缺点:不利于创建大量对象
- 工厂模式(工厂函数)创建
- 创建方式:
①封装一个函数
②在函数内部创建一个对象
③将属性和方法添加到封装的函数中
④返回创建出来的对象 - 优点:可以创建大量对象
- 缺点:this指向不明确,this值是window,而不是创建出来的对象
- 创建方式:
- 构造函数创建
- 创建方式:function Fn(name){ this.name=name }
- 实例化方式:var obj = new Fn()
- 在new的时候执行了四个步骤
①js隐式创建空对象
②js隐式将构造函数的this赋值给隐式创建的对象
③通过this给空对象绑定属性
④js隐式返回绑定好属性的对象 - 注意:
①构造函数首字母必须大写
②不需要在构造函数内部new Object()
③属性和方法直接加在this上
④不需要return
⑤调用的时候必须加new(如果不加new就和普通调用函数一样) - 缺点:如果创建的对象有相同的属性,会浪费资源
- 原型
- 原型的获取方式
①构造函数.prototype
②子对象._ _ proto _ _ - 作用
①可以给子对象继承自身的属性
②子对象可以使用原型的属性但不拥有
- 原型的获取方式
- 原型创建
- 创建方式:Fn.prototype.money = ‘5000W’
- 实例化方式:var obj = new Fn()
- 构造函数内不写任何属性(空构造函数),而是将所有属性写入原型中,继承给每一个子对象,最大程度节省内存空间
- 缺点:不能传参
- 混合创建(构造函数创建+原型创建)
- 构造函数中定义可变的属性和方法(可以传参)
- 原型中定义共享的属性和方法(节约内存)
- 动态混合创建
//字面量创建
var stu = {'sno':1,'name':'张三','age':18}
console.log(stu)
console.log(stu.sno)
//实例化创建
var stu = new Object()
stu.sno = 1
stu.name = '张三'
stu.age = 18
console.log(stu)
console.log(stu.sno)
//工厂模式(工厂函数)创建
function stu(sno,name,age){
var person = new Object()
person.sno = sno
person.name = name
person.age = age
return person
}
console.log(stu(1,'张三',18))
console.log(stu(1,'张三',18).sno)
//构造函数创建
function Fn(sno,name,age){
this.sno = sno
this.name = name
this.age = age
}
var stu = new Fn(1,'张三',18)
console.log(stu)
console.log(stu.sno)
//原型创建
function Fn(){}
Fn.prototype.sno = 1
Fn.prototype.name = '张三'
Fn.prototype.age = 18
console.log(Fn.prototype) //通过创建函数找原型
var stu = new Fn() //通过创建函数创建子对象
console.log(stu.__proto__) //通过子对象找原型
console.log(stu.sno) //子对象继承原型的属性和方法
//混合创建(构造函数+原型)
function Fn(sno,name,age){
this.sno = sno
this.name = name
this.age = age
}
Fn.prototype.course = '信息安全'
Fn.prototype.class = '03'
var stu = new Fn(1,'张三',18)
console.log(stu)
console.log(stu.course)
console.log(stu.__proto__.constructor)//子对象的原型对应的创建函数
案例:飞机大战:
/*
静态: 图片路径、X、Y
动态: 把路径转换成图片,设置X和Y
*/
var wrap = document.getElementsByTagName('div')[0]
function Plane(src, x, y) {
this.imgNode = null
this.planeSrc = src
this.planeX = x
this.planeY = y
this.init()
}
Plane.prototype.init = function () {
this.imgNode = document.createElement('img')
this.imgNode.src = this.planeSrc
this.imgNode.style.left = this.planeX + 'px'
this.imgNode.style.top = this.planeY + 'px'
wrap.appendChild(this.imgNode)
}
var obj1 = new Plane('./image/大飞机挨打.png', 100, 100)
var obj2 = new Plane('./image/飞机爆炸.gif', 200, 400)
new Plane('./image/我的飞机.gif', 200, 200)
案例:选项卡
<button>按钮一</button>
<button>按钮二</button>
<button>按钮三</button>
<div class="active">11111</div>
<div>22222</div>
<div>33333</div>
<script>
function ChooseCard() {
this.btn = document.getElementsByTagName('button')
this.oDiv = document.getElementsByTagName('div')
var that = this
for (var i = 0; i < this.btn.length; i++){
this.btn[i].index = i
//点击按钮后改变div的样式为公共的动态方法,放在原型里面
this.btn[i].onclick = function(){
//构造函数中的方法
that.init(this.index)
}
}
}
ChooseCard.prototype.init = function(index){
//原型里面的this指向构造函数,目前需要获取到构造函数中的div的个数,干掉所有
for(var j=0;j<this.oDiv.length;j++){
this.oDiv[j].className = ''
}
//此时索引因为此时点击的按钮的索引,可以传入一个参数
this.oDiv[index].className = 'active'
}
new ChooseCard()
</script>
命名空间
概念:当项目足够大,或者用了很多第三方框架,可能会出现命名不够用的情况,使用命名空间来解决这个问题
var obj1 = {}
var obj2 = {}
obj1.name = 'zhangSan'
obj2.name = 'liSi'
console.log(obj1.name);
console.log(obj2.name);
面向对象继承
- 原型链继承
- 原型链:从子对象开始到Object.prototype为止中间由_ _proto _ _属性链接起来的一个链式结构就是原型链
- 在原型链中每一个原型的属性最后都会继承给子对象
- 原型链查找规则:当一个对象调用属性时,会先在当前对象中查找,有就用,没有 就向原型中查找,如果还没有就继续向上一级原型中查找,直到Object.prototype,如果有就用,没有就返回undefined
- 缺点:由于继承的是原型链中的属性,因此属性的值无法修改
//构造奶奶函数
function GrandMother(name,age){
this.name = name
this.age = age
}
//奶奶函数prototype找到爷爷原型
GrandMother.prototype.money = '500w'
//奶奶函数new了一个爸爸
var father = new GrandMother('张三',24)
//构造一个空的妈妈函数
var mother = function(){}
//妈妈函数prototype找到了爸爸原型
mother.prototype = father
//妈妈函数new了一个我
var me = new mother()
console.log(me)
console.log(me.__proto__)
console.log(me.__proto__.__proto__)
//不能拥有属于我自己的名字和年龄
- 对象冒充继承
- call和apply:用来改变this指向
- 用法:
①函数.call(要改变的this值,实参1,实参2,实参3………)
②函数.apply(要改变的this值,[实参1,实参2,实参3………]) - 优势:可以随意改变属性的值
- 缺点:不能继承原型链中的属性
//一代构造函数
function First(name, age) {
this.name = name
this.age = age
}
//BadWoman
function BadWoman() {
console.log(this); //指向badwoman
// First.call(this, '如花', 45)
First.apply(this,['如花', 45])
}
var obj = new BadWoman()
console.log(obj);
- 组合(混合)式继承
- 对象冒充+原型链继承
- 小瑕疵:构造函数中的属性原型中也有,会有一个资源浪费的问题
/*
混合(组合)继承
对象冒充+原型链
*/
//大构造函数First
function First(name, age) {
this.name = name
this.age = age
}
//大构造函数的原型
First.prototype.money = '500W'
//大构造函数的子对象
var Second = new First('zhangSan', 18)
//小构造函数
function BadWoman() {
First.apply(this, ['liSi', 6])
}
BadWoman.prototype = Second
//实例化小构造函数的子对象
var obj = new BadWoman()
console.log(obj);
console.log(obj.name);
console.log(obj.age);
console.log(obj.money);
- 寄生混合式继承
- 我们一般会创建一个空函数,然后这个空函数的原型指向父类的原型,再实例化这个空函数,赋给子的原型,再修改子对象constructor。将这个过程用一个函数包起来,这个函数接收两个参数,子类构造函数和父类构造函数。
- 我们一般会创建一个空函数,然后这个空函数的原型指向父类的原型,再实例化这个空函数,赋给子的原型,再修改子对象constructor。将这个过程用一个函数包起来,这个函数接收两个参数,子类构造函数和父类构造函数。
function fn(child, parent) {
//child是badwoman子构造函数 parent是First父构造函数
//1、创建空函数
var F = function () {}
//2、空函数的原型指向父类的原型
F.prototype = parent.prototype
//3、实例化这个空函数
var obj = new F()
//4、把实例化的空函数赋值给子原型
child.prototype = obj
//5、
obj.constructor = child
}
//大构造函数First
function First(name, age) {
this.name = name
this.age = age
}
//大构造函数的原型
First.prototype.money = '500W'
//大构造函数的子对象
var Second = new First('zhangSan', 18)
//小构造函数
function BadWoman() {
First.apply(this, ['liSi', 6])
}
fn(BadWoman, First)
//实例化小构造函数的子对象
var obj = new BadWoman()
console.log(obj);
console.log(obj.name);
console.log(obj.age);
console.log(obj.money);
- 原型中的this指向构造函数
- 事件中的this指向触发事件的元素
- 一般函数this指向window
- 构造函数this指向构造函数
- 轮播图插件:link
- momentjs官方文档:link
- animate.css动画:link
- cubic-bezier速度曲线:link
- 阿里巴巴图标库:link
- Font-awesome图标库:link
正则表达式
- 正则对象:RegExp
- 概念:是对字符串操作的一种逻辑公式,就是用事先定义好的一些特殊字符,及这些特定字符的组合,组成一个‘规则字符串’,这个规则字符串用来表达对字符串的一种过滤逻辑。规定文本检索的内容,通常被用来检索、替换文本
- 创建方式:
- 构造函数创建 :new RegExp(‘检索字符’,’修饰符’)
- 字面量创建: /’检索字符’/’修饰符’
//1、构造函数创建 new RegExp('检索字符','修饰符')
var pat1 = new RegExp('hello')
console.log(pat1); // /hello/
//2、字面量创建 /检索字符/修饰符
var pat2 = /hello/
console.log(pat2); // /hello/
- 修饰符
- g:global 执行一个全局匹配
- i:ignore Case 执行一个不区分大小写的匹配
//1、g 全局
var str = 'hello java,hello web,hello ui'
var reg1 = /hello/
var reg2 = /hello/g
console.log(str.replace(reg1, '你好')); //你好 java,hello web,hello ui
console.log(str.replace(reg2, '你好')); //你好 java,你好 web,你好 ui
//2、i 不区分大小写
var str = 'abcdefg'
var reg1 = /C/
var reg2 = /C/i
console.log(str.search(reg1)); //-1
console.log(str.search(reg2)); //2
- 检索方法
- 正则方法
- test:检索字符串中是否包含在正则要检索的内容 (返回布尔值) reg.test(str)
- exec:进行具体检索,检索到正则规定的内容返回一个数组 reg.exec(str)
- 正则方法
//test:检索字符串中是否包含正则要检索的内容(返回布尔值)
console.log(reg1.test(str)); //true
console.log(reg2.test(str)); //false
//exec:进行具体检索,检索到正则规定的内容返回一个数组
var reg3 = /e/
console.log(reg3.exec(str)); //["e", index: 1, input: "hello world", groups: undefined]
var reg4 = /m/
console.log(reg4.exec(str)); //null
- 字符串方法
- replace:替换正则匹配的字符串str.replace(reg)
- split:按正则规定的内容拆成数组str.split(reg)
- match:返回正则匹配的内容,和exec一样str.match(reg)
- search:返回正则匹配的第一个字符串的位置,如果没有就返回 -1 str.search(reg)
var s = 'ujiuye java'
//replace
var reg5 = /java/
console.log(s.replace(reg5, 'web')); //ujiuye web
//split
//\s匹配空白字符、空格、制表符和换行符
var reg6 = /\s/
console.log(s.split(reg6)); //["ujiuye", "java"]
//match
var reg7 = /e/
console.log(s.match(reg7)); //["e", index: 5, input: "ujiuye java", groups: undefined]
//search
var reg8 = /j/
console.log(s.search(reg8)); //1
- 元字符
//1、. 除换行符以为的任意字符
var str = '\nweb'
var reg = /./
console.log(reg.exec(str)); //["w", index: 1, input: "↵web", groups: undefined]
var str = 'abcde1234'
var reg = /ab.....34/ig
console.log(reg.exec(str)); //["abcde1234", index: 0, input: "abcde1234", groups: undefined]
//2、 [ ] 匹配字符集中任意一个字符
var str = 'm23'
var reg = /[0-9]/ig
console.log(reg.exec(str)); //["2", index: 1, input: "m23", groups: undefined]
//6位银行卡密码
var str = '369h56'
var reg = /[0-9][0-9][0-9][a-z][0-9][0-9]/ig
console.log(reg.exec(str)); //["369h56", index: 0, input: "369h56", groups: undefined]
//3、 [^]匹配除字符集中的任意一个字符
var str = "123"
//匹配除0-9以外的任意字符
var reg = /[^0-9]/ig
console.log(reg.exec(str)); //null 因为123都是数字,都是0-9之内的数字
//4、 \d 匹配数字
var str = 'ab5'
var reg = /\d/ig
console.log(reg.exec(str)); //["5", index: 2, input: "ab5", groups: undefined]
//5、 \D 匹配非数字
var str = 'abc'
var reg = /\D/ig
console.log(reg.exec(str)); //["a", index: 0, input: "abc", groups: undefined]
//6、 \w 匹配数字字母下划线
var str = '%%%_'
var reg = /\w/ig
console.log(reg.exec(str)); //["_", index: 3, input: "%%%_", groups: undefined]
//7、 \W 匹配非数字非字母非下划线
var str = '%%%_'
var reg = /\W/ig
console.log(reg.exec(str)); //["%", index: 0, input: "%%%_", groups: undefined]
//8、 \s 匹配空格
var str = 'hello world'
var reg = /\s/ig
console.log(reg.exec(str)); //[" ", index: 5, input: "hello world", groups: undefined]
//9、 \S 匹配非空格
var str = 'hello world'
var reg = /\S/ig
console.log(reg.exec(str)); //["h", index: 0, input: "hello world", groups: undefined]
//10、 \b单词边界
var str = 'he is boy heisboy'
var reg = /\bis\b/
console.log(reg.exec(str)); //["is", index: 3, input: "he is boy heisboy", groups: undefined]
//11、 \B非单词边界
var str = 'he is boy heisboy'
var reg = /\Bis\B/
console.log(reg.exec(str)); //["is", index: 12, input: "he is boy heisboy", groups: undefined]
console.log(str.replace(reg, 'mm')); //he is boy hemmboy
var reg = /\bis\B/
console.log(reg.exec(str)); //null
//12、^以开头 ^a 以a开头
var str = '123456'
var reg = /^1\d\d\d\d\d/ig
console.log(reg.exec(str)); //["123456", index: 0, input: "123456", groups: undefined]
//13、$以结尾 a$ 以a结尾
var str = '123456'
var reg = /\d\d\d\d\d6$/ig
console.log(reg.exec(str)); //["123456", index: 0, input: "123456", groups: undefined]
//以1开头,以6结尾
var reg = /^1\d\d\d\d6$/ig
console.log(reg.exec(str)); //["123456", index: 0, input: "123456", groups: undefined]
- 量词
//1、 ?匹配0个或者1个 f?匹配0个f或者1个f
var str = 'abc'
var reg = /a?/ig
console.log(reg.exec(str)); //["a", index: 0, input: "abc", groups: undefined]
//2、 *匹配0个或者多个 f* 匹配0个f或者多个f 尽可能多匹配
var str = 'aaaaaaaaaabcaaaaa'
var reg = /a*/
console.log(reg.exec(str)); //["aaaaaaaaaa", index: 0, input: "aaaaaaaaaabcaaaaa", groups: undefined]
//3、 +匹配至少一个 f+匹配至少一个f
var str = 'abbbbbc'
var reg = /b+/ig
console.log(reg.exec(str)); //["bbbbb", index: 1, input: "abbbbbc", groups: undefined]
//以a开头,中间放数字(至少一个数字),以数字结尾
var str = "a1234"
var reg = /^a\d+$/ig
console.log(reg.exec(str)); //["a1234", index: 0, input: "a1234", groups: undefined]
//4、 m{x,y} 匹配m,至少x次,最多y次 m{x} 匹配m,x次
var str = '12345679'
var reg = /^[0-9]\d{6,8}/ig
console.log(reg.exec(str)); //["1234569", index: 0, input: "1234569", groups: undefined]
//密码 6位数字
var str = "123456"
var reg = /^\d{6}$/ig
console.log(reg.exec(str)); //["123456", index: 0, input: "123456", groups: undefined]
- 其他
//1、 | 或者
var str = 'logo'
var reg = /this|that|where|logo/ig
console.log(reg.exec(str)); //["logo", index: 0, input: "logo", groups: undefined]
//2、 () 分组
var str = "hello world hahaha hehehe"
var reg = /(\w+) (\w+) (\w+) (\w+)/ig
var arr = reg.exec(str)
console.log(arr); //["hello world", "hello", "world", index: 0, input: "hello world", groups: undefined]
console.log(RegExp.$1); //hello
console.log(RegExp.$2); //world
console.log(RegExp.$3); //hahaha
console.log(RegExp.$4); //hehehe
//需求:交换hello和world位置
console.log(str.replace(reg, '$2 $1 $3 $4')); //world hello hahaha hehehe
//3、 (?!^......) 预测不到后面不能是什么
var str = '2222222'
var reg = /(?!^\d+)/ig
console.log(str.search(reg)); //1 //0表示符合条件 1表示不符合条件
var str = '******'
console.log(str.search(reg)); //0
/*
****** 0 符合条件
222222 1 不符合条件
*/
匿名函数
- 概念:定义时未直接指定名称的函数,如果函数只需要调用一次,就可以声明匿名函数
- 优点:节省内存空间。匿名函数可以有效的保证在页面上写入JavaScript,而不会造成全局变量的污染
//1、普通函数
function fn(){}
//2、表达式函数
var fn1 = function(){}
//3、构造函数
function Fn2(name){
this.name = name
}
var Fn3 = function(name){
this.name = name
}
//4、事件函数
document.onclick = function(){}
//5、回调函数
function fn4(f){
f&&f()
}
//匿名函数自执行 (函数)()
(function(){
console.log(111);
})()
//匿名函数有参数
(function (a) {
console.log(a); //6
})(6)
//匿名函数有返回值
var f = (function (a) {
return a * a
})(6)
console.log(f); //36
闭包
- 概念:闭包就是能够读取其他函数内部变量的函数(函数里面套函数,内部函数可以访问外部函数变量),在本质上,闭包是将函数内部和外部链接起来的桥梁
- 特点:在闭包中的变量,会一直存储在内存中,类似于全局变量,避免了全局污染
- 非必要情况下不要使用闭包,因为会一直存储在内存中,容易造成内存泄漏
function fn1() {
var i = 10
function fn2() {
console.log(i++);
}
return fn2
}
var f = fn1()
console.log(f); //fn2这个函数
f() //10
f() //11
f() //12
案例:
var oLi = document.getElementsByTagName('li')
//点击li打印对应的索引值
for(var i=0;i<oLi.length;i++){
/* oLi[i].index = i
oLi[i].onclick = function(){
console.log(this.index)
} */
/* //匿名函数
(function(x){
oLi[x].onclick = function(){
console.log(x)
}
})(i) */
//闭包
function f(x){
oLi[x].onclick = function(){
console.log(x)
}
}
f(i)
}
ajax
- Async Javascript and XML 异步js和XML代码
- 异步:浏览器在请求数据的时候可以同时进行,不用排队等候,不会造成代码阻塞
- 同步:浏览器在请求数据的时候不可以同时进行,需要排队等候
- 概念:指一种创建交互式网页的网页开发技术
- 传统的网页(不是用Ajax)如果需要更新内容,必须重载整个网页页面。通过在后台与服务器进行少量数据交互,Ajax可以使网页实现异步更新。这意味着可以在不重新加载整个网页 的情况下,对网页的某部分进行更新
- ajax创建步骤
- ①实例化ajax对象:var xhr = new XMLHttpRequest()
- ②建立连接:xhr.open(请求方式,url地址(必传),是否异步)
请求方式:get/post。url地址:后台服务器地址。第三个参数:默认为true(异步)false(同 步),一般不传 - ③发送请求:xhr.send()
- ④接收响应数据:xhr.onreadystatechange = function(){}
- 通信状态码(ajax生命周期) xhr.readyState
- 0:ajax对象还没创建出来
- 1:建立起了和后台数据库的连接 open
- 2:请求已经发送出去 send
- 3:后台数据库接收到请求,并开始处理
- 4:后台数据库处理完毕,并将请求的数据响应给前端页面
在本地请求数据,因为0和1持续时间过短,因此时间还没来得及触发状态码就直接变成2了
- 网络状态码 xhr.status
- 网络状态码整理:link
- 200:请求响应成功,数据源是后台数据库
- 304:请求响应成功,数据源是本地缓存
- 403:没有权限访问
- 404:服务器找不到请求的网页。
- 500及以上:后台代码逻辑有误
- 503:服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。
- 获取响应的数据:xhr.responseText
- get请求
- 四部曲
- ①创建ajax对象
- ②建立连接
- ③发送请求
- ④通过事件监听响应状态来获取数据
- 优点:在网络传输上速度相对较快
- 缺点:
- ①在提交数据时会直接显示在url地址的后面,不安全
- get请求提交的数据量比较小,大小只有4kb左右
- 四部曲
- Wamp
- windows Apache MySQL PHP
- 这是一个服务器集成软件,安装完之后,计算机就会成为一台本地服务器
- wamp文件夹中的www文件夹是用来存放项目的目录,我们需要使用服务器环境打开html文件,所以项目都需要存放在www文件夹中
- 启动方式:在浏览器地址栏中输入 127.0.0.1(本地服务器)
- post
- 五部曲
- ①创建ajax对象
- ②建立连接
- ③设置请求头
- ④发送请求
- ⑤通过事件监听响应状态来获取数据
- 请求头
- ajax对象.setRequestHeader(“Content-type”,“application/x-www-form-url encoded”)
- 优点:
- ①提交的数据不会显示在地址栏后面,相对较安全
- ②传输数据要比get大很多
- 五部曲
- json文件创建
- ①Json文件不能添加注释
- ②Json多余逗号要删除
- ③数据一定要键值对形式
- ④不能使用单引号,一定要是用双引号
- ⑤数据由逗号分隔
- ⑥最外层只能有一个
- ⑦花括号表示保存对象
- ⑧方括号表示保存数组
- 类型转换
- ①eval(str) 传入一个字符串,转化为具体js的数据类型
- ②JSON.parse(str) 将json类型字符串转换为json类型
- ③JSON.stringify(obj) 将json类型转换为json类型字符串
封装ajax:
<div></div>
<script>
var oDiv = document.getElementsByTagName('div')[0]
function ajax(url, method, data, success) {
//1、创建ajax对象
var xhr = new XMLHttpRequest()
//2、判断是get还是post
if (method == 'get') {
//判断data是否有值
if (data) {
url += '?' + data
}
xhr.open(method, url)
xhr.send()
} else {
//建立连接
xhr.open(method, url)
//设置请求头
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
//判断data是否有值
if (data) {
xhr.send(data)
} else {
xhr.send()
}
}
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200 || xhr.status === 304) {
success(xhr.responseText)
}
}
}
}
ajax('get.txt', 'post', 'username=admin', function (res) {
console.log(res);
oDiv.innerHTML = res
})
</script>
弹入弹出轮播图
<div class="wrap">
<div class="center">
<ul></ul>
<p></p>
</div>
</div>
<script src="./ujiuye.js"></script>
<script>
var oUl = document.getElementsByTagName('ul')[0]
var oP = document.getElementsByTagName('p')[0]
var oLi = document.getElementsByTagName('li')
var oSpan = document.getElementsByTagName('span')
var wrap = document.getElementsByClassName('wrap')[0]
ajax('banner.txt', 'get', '', function (res) {
var arr = eval(res)
console.log(arr);
//定义一个字符串用来接收
var str1 = ''
var str2 = ''
for (var i = 0; i < arr.length; i++) {
str1 += '<li><img src="' + arr[i].bannerSrc + '"></li>'
str2 += '<span></span>'
}
oUl.innerHTML = str1
oP.innerHTML = str2
//设置默认样式
oLi[0].style.opacity = 1
oSpan[0].className = 'active'
wrap.style.background = arr[0].bannerBG
//用来表示当前是第几张图片
var bannerIndex = 0
var timer1 = setInterval(bannerAuto, 3000)
function bannerAuto() {
bannerIndex++
if (bannerIndex >= arr.length) {
bannerIndex = 0
}
//上一张隐藏
//1显示 0隐藏 2显示 1隐藏 3显示 2隐藏 4显示 3隐藏 5显示 4隐藏 0显示 0-1=-1 -1隐藏
//bannerIndex - 1 > 0 ? bannerIndex-1 : arr.length-1
bufferMove(oLi[bannerIndex - 1 > 0 ? bannerIndex - 1 : arr.length - 1], {
'opacity': 0
})
//下一张显示
bufferMove(oLi[bannerIndex], {
'opacity': 100
})
//改变背景
wrap.style.background = arr[bannerIndex].bannerBG
//改变span
for (var i = 0; i < oSpan.length; i++) {
oSpan[i].className = ''
}
oSpan[bannerIndex].className = 'active'
}
wrap.onmouseenter = function () {
clearInterval(timer1)
}
wrap.onmouseleave = function () {
timer1 = setInterval(bannerAuto, 3000)
}
//移入小span
for (var i = 0; i < oSpan.length; i++) {
oSpan[i].index = i
oSpan[i].onmouseover = function () {
//让之前的那一张隐藏
bufferMove(oLi[bannerIndex], {
'opacity': 0
})
//让对应的li显示
bufferMove(oLi[this.index], {
'opacity': 100
})
//改变小span
for (var j = 0; j < oSpan.length; j++) {
oSpan[j].className = ''
}
this.className = 'active'
wrap.style.background = arr[this.index].bannerBG
bannerIndex = this.index
}
}
})
</script>