JS学习day11 -- 事件

事件是可以被 javaScript 侦测到的行为。网页中的每个元素都可以产生某些可以触发javaScript函数的事件。

1、事件基础

1、事件函数

事件函数:被事件调用的函数

var box = document.getElementById('box');
function fn() { }

box.onclick = fn; // fn就是事件函数
fn(); // fn不是事件函数

box.onclick = function () { // 事件函数
    fn(); // fn不是事件函数
}
2、事件对象

事件对象:当一个事件发生的时候,跟这个事件有关的一些信息,保存在一个对象中,这个对象,就是事件对象

  • 标准浏览器(IE9及以上):是事件函数的第一个参数
  • IE和谷歌:是全局的event对象
var box = document.getElementById('box');
box.onclick = function (ev) {
    // console.log(ev); // 标准浏览器(IE9及以上)
    // console.log(event); // IE和谷歌(IE8及以下)
    var ev = ev || event; // 兼容处理
    console.log(ev);

    console.log(ev.type); // 事件类型

    // console.log(ev.target); // 事件源 IE9及以上支持
    // console.log(ev.srcElement); // 事件源 IE8及以下支持
    var target = ev.target || ev.srcElement; // 事件源的兼容
    console.log(target);

    console.log(ev.clientX, ev.clientY); // 鼠标距可视区的距离
    console.log(ev.pageX, ev.pageY); // 鼠标到文档的距离  IE8及以下没有

    console.log(ev.ctrlKey); // 事件发生的时候,是否按下了ctrl键
    console.log(ev.altKey); // 事件发生的时候,是否按下了alt键
    console.log(ev.shiftKey); // 事件发生的时候,是否按下了shift键

}

2、事件绑定与取消

1、事件的绑定

需求:给同一个元素同一个事件绑定两个不同的处理函数

var box = document.getElementById('box');
function fn1() {
    console.log(1);
    console.log(this === window);
}
function fn2() {
    console.log(2);
}
// 赋值的写法,后面的把前面的覆盖了
box.onclick = fn1;
box.onclick = fn2;
// IE8及以下不支持
// 元素.addEventListener(不要on的事件类型, 触发的函数, 是否捕获);
// 是否捕获: 默认false,即不捕获,就是冒泡
box.addEventListener('click', fn1, false);
box.addEventListener('click', fn2, false);
// IE8及以下支持
// 元素.attachEvent(要on的事件类型, 触发的函数);
// 没有第三个参数,默认为冒泡
box.attachEvent('onclick', fn1);
box.attachEvent('onclick', fn2);
// 区别:
1、标准的没有on,IE8及以下有on
2、标准的可以捕获,也可以冒泡,而IE8及以下,只有冒泡
3、标准的是正序,IE8及以下倒序
4、标准浏览器触发的函数中的this是这个元素,而IE8及以下触发函数的this是window
// 兼容的原理: 检查浏览器是否持这个方法,标准浏览器返回函数,IE8及以下返回undefined
console.log(box.addEventListener);
if (box.addEventListener) {
    // 标准浏览器
    box.addEventListener('click', fn1, false);
    box.addEventListener('click', fn2, false);
} else {
    // IE8及以下
    box.attachEvent('onclick', fn1);
    box.attachEvent('onclick', fn2);
}
// 封装: 
function bind(ele, event, callback) {
    if (ele.addEventListener) {
        // 标准浏览器
        ele.addEventListener(event, callback, false);
    } else {
        // IE8及以下
        ele.attachEvent('on' + event, callback);
    }
}
bind(box, 'click', fn1);
bind(box, 'click', fn2);
2、事件绑定取消
// 赋值的写法,后面的把前面的覆盖了
box.onclick = fn1;
box.onclick = null; // 取消
// IE8及以下不支持
// 元素.addEventListener(不要on的事件类型, 触发的函数, 是否捕获);
// 元素.removeEventListener(不要on的事件类型, 触发的函数, 是否捕获);

// 是否捕获: 默认false,即不捕获,就是冒泡
box.addEventListener('click', fn1, false);
box.addEventListener('click', fn2, false);
box.removeEventListener('click', fn2, false);
// IE8及以下支持
// 元素.attachEvent(要on的事件类型, 触发的函数);
// 元素.detachEvent(要on的事件类型, 触发的函数);

// 没有第三个参数,默认为冒泡
box.attachEvent('onclick', fn1);
box.attachEvent('onclick', fn2);
box.detachEvent('onclick', fn2);
// 封装: 参数:元素 事件 函数
function bind(ele, event, callback) {
    if (ele.addEventListener) {
        // 标准浏览器
        ele.addEventListener(event, callback, false);
    } else {
        // IE8及以下
        ele.attachEvent('on' + event, callback);
    }
}
// 封装: 参数:元素 事件 函数
function unbind(ele, event, callback) {
    if (ele.removeEventListener) {
        // 标准浏览器
        ele.removeEventListener(event, callback, false);
    } else {
        // IE8及以下
        ele.detachEvent('on' + event, callback);
    }
}

bind(box, 'click', fn1);
bind(box, 'click', fn2);
unbind(box, 'click', fn2);

3、DOM事件流

1、事件流

分为三个阶段

1、捕获阶段(进来的过程):从docuemt-html-body-box1-box2-box3,从不太具体的元素,到具体的元素

2、处于目标阶段

3、冒泡阶段(出去的过程):从box3-box2-box1-body-html-document,从具体的元素到不太具体的元素

  • 事件经过某个元素,如果这个元素上面绑定着事件,就会触发这个事件
  • 如果要捕获,就必须addEventListener绑定,而冒泡是默认存在的,即"元素.事件"和"attacheEvent"这种绑定都只有冒泡
<div id="box1">
    <div id="box2">
        <div id="box3"></div>
    </div>
</div>
var box1 = document.getElementById('box1');
var box2 = document.getElementById('box2');
var box3 = document.getElementById('box3');
function fn() {
    console.log(this.id);
}

// 这种形式的绑定,默认冒泡触发
box1.onclick = fn;
box2.onclick = fn;
box3.onclick = fn;

// 事件流:三个阶段
// 1、捕获阶段(进来的过程):从docuemt-html-body-box1-box2-box3,从不太具体的元素,到具体的元素
// 2、处于目标阶段
// 3、冒泡阶段(出去的过程):从box3-box2-box1-body-html-document,从具体的元素到不太具体的元素

// 事件经过某个元素,如果这个元素上面绑定着事件,就会触发这个事件

// ----------------------------
// 元素.addEventListener(事件, 函数, 是否捕获);
box1.addEventListener('click', fn, true);
box2.addEventListener('click', fn, true);
box3.addEventListener('click', fn, true);

box1.addEventListener('click', fn, false);
box2.addEventListener('click', fn, false);
box3.addEventListener('click', fn, false);
2、阻止事件冒泡
  • 标准浏览器:ev.stopPropagation();
  • IE浏览器:ev.cancelBubble = true;
// 阻止冒泡的兼容
function stopPropagation(ev) {
    if (ev.stopPropagation) {
        ev.stopPropagation();
    } else {
        ev.cancelBubble = true;
    }
}

二级菜单

// 需求:1、点击按钮,box显示; 2、点击页面的任何地方,box隐藏
var btn = document.querySelector('button');
var box = document.getElementById('box');

// 阻止冒泡
// 标准浏览器:ev.stopPropagation();
// IE浏览器:ev.cancelBubble = true;

// 1、点击显示
btn.onclick = function (ev) {
    var ev = ev || event;
    // ev.stopPropagation(); // 标准浏览器
    // ev.cancelBubble = true; // IE8及以下
    stopPropagation(ev); // 阻止冒泡兼容处理

    box.style.display = 'block';
}

// 2、点击隐藏
document.onclick = function () {
    // setTimeout(function () {
    box.style.display = 'none';
    // }, 2000);
}

// 阻止冒泡的兼容
function stopPropagation(ev) {
    if (ev.stopPropagation) {
        // 标准浏览器
        ev.stopPropagation();
    } else {
        // IE8及以下
        ev.cancelBubble = true;
    }
}

4、事件默认行为

事件的默认行为: 即赋予了元素特殊的操作,如点击链接会跳转到其他的网页,在浏览器中右击鼠标会弹出菜单。

当我们不需要这些默认行为的时候,可以手动阻止

  • 标准:ev.preventDefault();
  • IE8及以下:ev.returnValue = false;
var a = document.querySelector('a');
a.onclick = function (ev) {
    var ev = ev || event;
    // ev.preventDefault();
    // ev.returnValue = false;

    preventDefault(ev); // 兼容,传入事件对象即可
}

function preventDefault(ev) {
    if (ev.preventDefault) {
        // 标准浏览器
        ev.preventDefault();
    } else {
        // IE8及以下
        ev.returnValue = false;
    }
}

右键菜单

var box = document.getElementById('box');

// 右键菜单
document.oncontextmenu = function (ev) {
    var ev = ev || event;

    var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;

    // 1、阻止默认的右键菜单
    preventDefault(ev); // 事件默认行为兼容

    // 2、让自定义的显示
    box.style.display = 'block';
    box.style.left = ev.clientX + 'px';
    box.style.top = ev.clientY + scrollTop + 'px';
}

// 点击页面的任何地方,隐藏
document.onclick = function () {
    box.style.display = 'none';
}

function preventDefault(ev) {
    if (ev.preventDefault) {
        // 标准浏览器
        ev.preventDefault();
    } else {
        // IE8及以下
        ev.returnValue = false;
    }
}

5、键盘事件

  • keydown:按下键盘键
  • keypress:紧接着keydown事件触发(只有按下字符键时触发,字符键即可打印)
  • keyup:释放键盘键

顺序为:keydown -> keypress ->keyup

详解

  • 1、用户按下键盘上的字符键时:首先会触发keydown事件,然后紧接着触发keypress事件,最后触发keyup事件,如果用户按下了一个字符键不放,就会重复触发keydown和keypress事件,直到用户松开该键为止。
  • 2、当用户按下非字符键时:首先会触发keydown事件,然后就触发keyup事件,如果用户按下了一个非字符键不放,就会重复触发keydown事件,直到用户松开该键为止。
  • 3、在keyup 事件中无法阻止浏览器默认事件,因为在keypress时,浏览器默认行为已经完成,即将文字输入文本框(尽管这时还没显示),这个时候不管是preventDefault还是returnValue = false,都不能阻止在文本框中输入文字的行为,如要阻止默认行为,必须在keydown或keypress时阻止
  • 4、发生keypress事件意味着按下的键会影响到屏幕中文本的显示,即在所有浏览器中,按下能够插入或删除字符的键都会触发keypress事件

注意:英文输入法,所有浏览器都支持这三个事件。中文输入法(浏览器之间表现得不太一致),所以建议不用keypress

// 键盘事件只能在能响应用户输入的标签上触发。(input、document)
var input = document.querySelector('input');

// 按下
input.onkeydown = function () {
    console.log('onkeydown', this.value);
}

// keypress
input.onkeypress = function () {
    console.log('onkeypress', this.value);
}

// 抬起
input.onkeyup = function () {
    console.log('onkeyup', this.value);
}

键盘事件的事件对象

var input = document.querySelector('input');

input.onkeyup = function (ev) {
    var ev = ev || event; // {} 它里面就有很多的属性和方法

    console.log(ev.keyCode); // 按键对应的编码
    console.log(ev.key); // 对应按键 IE8及以下不支持

    // 其它属性同之前的事件对象
    console.log(ev.shiftKey);
    console.log(ev.altKey);
    console.log(ev.ctrlKey);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gc5SXsKQ-1607956957185)(图片1.png)]

案例:控制div的移动

6、滚轮事件

1、滚轮事件
var box = document.getElementById('box');

// 在box上滚动,向上滚,盒子高度减少,向下滚,盒子高度增加

// 标准和IE
// 事件:onmousewheel
box.onmousewheel = function () {
    console.log('走了');
}

// 火狐
// 事件:DOMMouseScroll,必须addEventListener绑定
box.addEventListener('DOMMouseScroll', function () {
    console.log('我也走了');
}, false);
2、滚轮方向
var box = document.getElementById('box');

// 在box上滚动,向上滚,盒子高度减少,向下滚,盒子高度增加

// 标准和IE
// 事件:onmousewheel
// 方向:ev.wheelDelta  向上120   向下-120
box.onmousewheel = function (ev) {
    var ev = ev || event;
    console.log(ev.wheelDelta);
}

// 火狐
// 事件:DOMMouseScroll,必须addEventListener绑定
// 方向:ev.detail  向上-3  向下3
box.addEventListener('DOMMouseScroll', function (ev) {
    console.log(ev.detail);
}, false);
3、方向兼容
var box = document.getElementById('box');

// 在box上滚动,向上滚,盒子高度减少,向下滚,盒子高度增加

// 标准和IE
// 事件:onmousewheel
// 方向:ev.wheelDelta  向上120   向下-120
box.onmousewheel = function (ev) {
    var ev = ev || event;
    console.log(wheelDelta(ev));
}

// 火狐
// 事件:DOMMouseScroll,必须addEventListener绑定
// 方向:ev.detail  向上-3  向下3
box.addEventListener('DOMMouseScroll', function (ev) {
    console.log(wheelDelta(ev));
}, false);

// 滚轮方向的兼容  向上120  向下-120
function wheelDelta(ev) {
    if (ev.wheelDelta) {
        // 标准和IE
        return ev.wheelDelta;
    } else {
        // 火狐
        return -40 * ev.detail;
    }
}
4、最终实现
var box = document.getElementById('box');

// 在box上滚动,向上滚,盒子高度减少,向下滚,盒子高度增加

bind(box, 'mousewheel', fn); // 标准和IE
bind(box, 'DOMMouseScroll', fn); // 火狐

function fn(ev) {
    var h = box.clientHeight; // 盒子的高度
    var ev = ev || event;
    if (wheelDelta(ev) > 0) {
        // 向上
        h--;
    } else {
        // 向下
        h++;
    }
    box.style.height = h + 'px';
}


// 滚轮方向的兼容  向上120  向下-120
function wheelDelta(ev) {
    if (ev.wheelDelta) {
        // 标准和IE
        return ev.wheelDelta;
    } else {
        // 火狐
        return -40 * ev.detail;
    }
}

// 封装: 
function bind(ele, event, callback) {
    if (ele.addEventListener) {
        // 标准浏览器
        ele.addEventListener(event, callback, false);
    } else {
        // IE8及以下
        ele.attachEvent('on' + event, callback);
    }
}

7、事件委托

  • 事件委托:也叫事件代理,从JavaScript高级程序设计上讲:事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。
  • 事件委托,将事件绑定给父级,触发事件的是子级,利用冒泡的原理,找事件源,判断事件源决定做相应的事
<ul>
    <li>吃饭</li>
    <li>睡觉</li>
    <li>打豆豆</li>
</ul>
var ul = document.querySelector('ul');

// 给所有的li添加一个点击事件,改变它的背景颜色(新添加的元素,没有这个事件)
var li = document.getElementsByTagName('li');
for (var i = 0; i < li.length; i++) {
    li[i].onclick = function () {
        this.style.backgroundColor = 'red';
    }
}

// 事件委托
// 和普通方式的区别
// 1、新添加的元素有之前的事件
// 2、如果元素过多,普通方式增加开销,耗性能,而事件委托提高性能
ul.onclick = function (ev) {
    var ev = ev || event;
    var target = ev.target || ev.srcElement; // 事件源,即点击的哪个元素
    // console.log(target.nodeName); // 被点击的这个元素的大写的标签名
    // console.log(target.tagName); // 被点击的这个元素的大写的标签名
    if (target.nodeName === 'LI') {
        target.style.background = 'yellow';
    }
}


// 给ul添加一条li
var item = document.createElement('li');
item.innerHTML = '我是洋洋';
ul.appendChild(item);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值