踩坑:preventDefault

preventDefault

这个用来阻止默认行为。什么是默认行为呢?在初学的时候,最常举得例子就是<a>标签,它的点击事件出发后,默认行为就是进行跳转。

现在如果想要阻止点击<a>标签后的跳转行为,就可以使用preventDefault

<div>
    <a id='a' href="http://www.baidu.com">《《传送门》》</a>
</div>

<script>
    const aElement = document.querySelector('#a');
    aElement.addEventListener('click', e => e.preventDefault());
</script>

兼容性鼠标事件

<div id='outer'>
    <div id='inner'>

    </div>
</div>

<script>
    const outer = document.querySelector('#outer');
    const inner = document.querySelector('#inner');

    outer.addEventListener('mousedown', ()  => {
        console.log('outer-mousedown');
    });
    outer.addEventListener('mouseup', ()  => {
        console.log('outer-mouseup');
    });

    inner.addEventListener('mousedown', ()  => {
        console.log('inner-mousedown');
    });
    inner.addEventListener('mouseup', ()  => {
        console.log('inner-mouseup');
    });
</script>

看上面的例子,如果点击#inner会发生什么?首先会触发mousedown事件,由于都是在冒泡阶段进行处理,所以输出inner-mousedownouter-mousedown;然后触发mouseup同样在冒泡阶段处理,输出inner-mouseupouter-mouseup

最终会输出:

inner-mousedown
outer-mousedown
inner-mouseup
outer-mouseup

上面的结果不难看懂,接下来做一些修改:

<div id='outer'>
    <div id='inner'>

    </div>
</div>

<script>
    const outer = document.querySelector('#outer');
    const inner = document.querySelector('#inner');

    outer.addEventListener('mousedown', ()  => {
        console.log('outer-mousedown');
    });
    outer.addEventListener('mouseup', ()  => {
        console.log('outer-mouseup');
    });

    inner.addEventListener('mousedown', ()  => {
        console.log('inner-mousedown');
    });
    inner.addEventListener('mouseup', ()  => {
        console.log('inner-mouseup');
    });
    inner.addEventListener('pointerdown', e  => {
        console.log('inner-pointerdown');
        e.preventDefault();
    });

</script>

这次,在inner上绑定了一个pointerdown事件,点击之后发现,只输出了inner-pointerdown,也就是说,mouse相关的事件一个都没有触发。

这就是题目说的,mousedownpointerdown的默认行为,可能会有疑问:如果将outermousedown放在捕获阶段处理呢?其实这里产生了一个误区,捕获和冒泡仅仅会影响相同事件的处理顺序,也就是说,如果将outermousedown在捕获阶段处理,也仅仅只是让outermousedown先于innermousedown,和其他事件没有关系。

回到上面的问题,由于mousedownpointerdown的默认行为,所以pointerdown先于mousedown触发,因此,先触发innerpointerdown,之后,本来要触发默认行为,inner触发一个mousedown事件,但是被通过e.preventDefault()阻止了,所以,并没有触发mousedown事件。

现在,已经弄清楚两个mousedown为什么没有触发了,还有一个问题两个mouseup为什么没有触发?举一反三,是因为mousedown没有触发,也就是说,mouseupmousedown的默认行为,因此,必须先触发mousedown才能触发mouseup。也可以做个实验,在最初的例子中,阻止innermousedown的默认行为。

关于这一段的问题,MDN有详细的解释:

The browser may map generic pointer input to mouse events for compatibility with mouse-based content. This mapping of events is called compatibility mouse events. Authors can prevent the production of certain compatibility mouse events by canceling the pointerdown event but note that:

  • Mouse events can only be prevented when the pointer is down.
  • Hovering pointers (e.g. a mouse with no buttons pressed) cannot have their mouse events prevented.
  • The mouseover, mouseout, mouseenter, and mouseleave events are never prevented (even if the pointer is down).

阻止mousedown的默认行为,会阻止blur

假设有一个输入框,在blur事件触发时,会执行一些操作;有另一个按钮,在按钮电击时,执行某些操作,但是,不希望触发输入框的blur事件。

这就和上面所说的默认行为一样,如果输入框要触发blur事件,一定会在其他元素上触发mousedown,反过来说,一个非输入框的元素触发mousedown,它的默认行为就是输入框触发blur

<input type="text" id='input'>
<div id='dom'>
</div>

<script>
    const dom = document.querySelector('#dom');
    const input = document.querySelector('#input');

    dom.addEventListener('mousedown', e => e.preventDefault());
    input.addEventListener('blur', () => console.log('input-blur'));
</script>

这时,点击#dom时,默认情况下#input失去焦点,触发blur,但这里阻止了这种默认行为。

注意,如果将上面的dom结构改成:

<div id='dom'>
    <input type="text" id='input'>
</div>

<script>
    const dom = document.querySelector('#dom');
    const input = document.querySelector('#input');

    dom.addEventListener('mousedown', e => e.preventDefault());
    input.addEventListener('blur', () => console.log('input-blur'));
    input.addEventListener('focus', ()=>console.log('input-focus'));
</script>

这次再点击,就会发现#input连焦点都没办法获取,这和上面的原因也一样,mousedown的默认行为也有获取焦点focus,如果阻止默认行为,获取焦点的事件也会被阻止。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值