vue怎么触发元素的原生事件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue怎么触发元素的原生事件相关的知识,希望对你有一定的参考价值。

参考技术A   DOM事件
  在Vue中为DOM元素绑定事件的具体方法在文章中的 方法与事件处理器 章节,通过v-on指令或事件语法糖 @ 为DOM元素绑定事件。Vue解析组件模板后,在绑定更新 v-on 指令时会为DOM元素绑定事件(当然如果元素为 iframe ,会等到 iframe 加载完成后再为其绑定事件)。
  Vue中为DOM元素绑定事件是采用DOM2级事件的处理方式,因为Vue服务的是IE9以上的现代浏览器,他们也都是支持DOM2级事件。因此下例中
  
  实际上相当于
  el.addEventListener('click', func)
  所以 addEventListener 支持绑定的事件, v-on 指令也都支持。同样的理论上也可以解绑事件,虽然也有相应的 api ,但是Vue文档中并没有显示地告诉我们怎么做。
  在代码中可以看到,每个 v-on 指令都有一个reset 方法, reset 方法是当指令所绑定方法发生改变时,重新绑定事件之前的解绑操作,我们可以利用这个 api 来解绑事件。因此如果需要解绑事件,我们可以遍历 vm._directives 找到相应该指令,进行解绑。
  当然既然是采用DOM2级事件处理,也可以使用 removeEventListener 直接进行解绑,看这个 demo 。 执行解绑操作后 btn1 的确解绑成功了,但 btn2 没有解绑成功,这要说到 v-on 指令的 修饰符 ,见源码中对带有修饰符的 handler 的处理。顾名思义,修饰符修饰过的 handler 做了更多的事情,Vue的处理是包装原 handler 新的 handler 用于向DOM元素绑定,而解绑时仍然解绑原方法当然会失败。
  当然这只是分析Vue的事件绑定原理,大多数情况下我们并不需要去解绑事件。合理的利用事件委托可以解决大部分由事件绑定引起的性能问题。
  自定义事件
  Vue自定义事件是为组件间通信设计,自定义事件提供了 $on、$off、$once、$emit、$broadcast、$dispatch 几个 api,非常简洁。
  首先提两个vm的私有变量,vm._events 和 vm._eventCount。每个vm实例所有的自定义事件都将存储在 vm._events,而 vm._eventsCount 存储的是执行事件广播后子组件触发自定义事件处理程序的数量,这是为了事件广播优化而来的,如果 vm._eventsCount[event] 数量为零,当事件广播时则可断定子组件没有该事件的监听器,就没必要向子组件层层捕获该事件监听器了。
  $on
  注册一个自定义事件,注册事件很简单,首先将其挂载到该实例下
  vm._events[event] = fn
  然后是向上传播,更新各个组件的 _eventsCount。这里需要注意,我们可以通过 $on 为生命周期注册钩子, 点击 查看demo,但是生命周期不可冒泡和广播,所以需要更新 eventsCount 前需要过滤。 查看modifyListenerCount
  $once
  因为 $once 注册的事件是一次性的,执行完后卸载,所以其实 $once 调用 $on 来注册事件的函数是包装过的。
  $off
  理解了注册事件的流程(其实就是更改 _events 和 _eventsCount)那么卸载事件也就很清晰了。
  但是$off支持三种卸载方式
  1、 如果没有参数,则删除所有的事件监听器
  遍历 _events,冒泡更新每个事件的 _eventsCount,清空 vm._events
  2、 如果只提供了事件,则删除这个事件所有的监听器
  冒泡更新每个事件的 _eventsCount,vm._events 中剔除该事件
  3、 如果同时提供了事件与回调,则只删除这个回调
  遍历 vm._events[event] 的事件处理方法,如果该事件处理方法和回调相同,则从 vm._events[event] 剔除该事件处理方法,并冒泡更新该事件的 _eventsCount
  $emit
  触发事件,直接遍历 vm._events[event] 的每个事件处理程序并执行。
  $emit 返回 shouldPropagate,shouldPropagate 是一个布尔值,取决于父链上的是否存在该事件的监听器以及,事件处理程序返回的值。他决定 $dispatch 是否停止冒泡。
  dispatch
  派发事件。首先在实例上触发该事件,默认情况下将会停止冒泡传播,但如果 $emit 返回的 shouldPropagate 为 true,则该事件会继续沿父链向上传播,即在父组件继续向上派发事件。
  broadcast
  事件广播。深度优先遍历子组件,并执行各个子组件的监听器事件处理程序,在绑定和卸载自定义事件时会会每个组件维护一个 vm._eventsCount,而它的作用正是在深度遍历的时候给予提示,避免不必要的深度遍历。
  通过自定义事件在组件之间的传播,我们可以利用它进行组件通信。组件通信在应用开发过程中是一个棘手的问题,因为它直接关系到整个应用的健壮和可维护程度,在开发大型项目中建议引入vuex,从应用架构的角度来考虑组件通信相比这种事件形式更容易维护,比如多个子组件都有派发事件与父组件进行通信,如果子组件派发事件不注意命名规范,出现命名重复情况,那么父组件监听器根本不知道这个事件是从哪里派发过来的以技如何处理,这是隐患之一。如果采用这种方式进行组件通信,那么必将导致子组件大量派发事件,那么父组件将要维护大量的事件监听器,如果时间久了,很容易忘记监听器和派发事件子组件的对应关系,这又增加了开发与维护成本。充斥着事件派发的组件维护成本也是一个容易留坑的地方。此外通过事件可以进行父子组件的通信,但兄弟组件的通信有需要增加不少开发成本。
  组件的自定义事件
  在上文分析DOM元素绑定事件中,我们用到这个例子
  
  但是有时候会出现 v-on 为组件绑定事件的情况,如
  
  上文中没有分析到,留在这里说,这里有两个明显区别
  是组件而不是DOM元素
  自定义事件而不是DOM事件
  因此显然 addEventLisntener 不适用,而且Vue执行的也是和第一个例子完全不同的处理方式, 对其的处理在 registerComponentEvents 。它其实是为组件注册自定义事件。这里 v-on 指令绑定的结果是 demoVm._a href="" title="成都app制作开发公司events[myfunc] = [func] 以及更新 _eventsCount。
  查看这个 demo 。
  可见 v-on 指令既可为DOM元素绑定事件也可为组件绑定自定义事件。明白了这个,这个issuse 的原因也就很明了了。本回答被提问者采纳

20170613-原生拖放

重点知识

拖放事件

拖动某元素时,会在被拖动元素上以此触发下列事件:

  • dragstart:当拖拽元素开始被拖拽的时候触发的事件

  • drag:当拖拽元素的过程中一直触发的事件

  • dragend:当拖拽完成后触发的事件

当某个元素被拖放到一个有效的放置目标上时,放置目标上回依次触发下列事件:

  • dragenter:当拖曳元素进入目标元素的时候触发的事件

  • dragover:拖拽元素在目标元素上移动的时候触发的事件

  • dragleave:当拖曳元素离开目标元素的时候触发的事件

  • drop:被拖拽的元素在目标元素上同时鼠标放开触发的事件

自定义放置目标:

在拖放元素经过某些无效放置目标时,可以看到一种特殊的光标(圆环中有一条反斜线),表示不能放置。虽然所有元素都支持放置目标事件,但这些元素默认是不允许放置的。如果拖动元素经过不允许放置的元素,无论用户如何操作,都不会触发drop事件。不过,你可以把任何元素变成有效的放置目标,方法是:重写dragenter和dragover事件的默认行为

例如,假如一个ID为“droptarget”的div元素,可以用如下代码将它变成一个放置目标

var droptarget = document.getElementById(‘droptarget‘)
droptarget.addEventListener(‘dragover‘, function(event){
    event.preventDefault()
}
droptarget.addEventListener(‘dragenter‘, function(event){
    event.preventDefault()
}

dataTransfer对象

dataTransfer对象,它是事件对象的一个属性,用于从被拖放元素向放置目标传递字符串格式的数据

detaTransfer对象有两个主要方法:getData()和setData()。setData()方法的第一个参数,也是getData()方法的唯一的一个参数,是一个字符串,表示保存的数据类型,取值为“text”和“URL”

event.dataTransfer.setData("text", "some text");
var text = event.dataTransfer.getData("text");
  • 注意:保存在dataTransfer对象中的数据只能在drop事件处理程序中读取。

可拖动

默认情况下,只有图像、链接、文本是可以拖动的。让其他元素可以拖放也是可能的。HTML5为所有HTML元素规定了一个draggable属性,表示元素是否可以拖动。图像和链接的draggable属性自动设置成了true,而其他元素这个属性的默认值都是false。通过设置这个属性可以使其他元素可拖动

<div draggable="true">...</div>

相关实例

<div class="dustbin">
  <br/>垃<br/>圾<br/>桶
</div>
<div class="dragbox">
  <div class="drag-item" draggable="true">item 1</div>
  <div class="drag-item" draggable="true">item 2</div>
  <div class="drag-item" draggable="true">item 3</div>
  <div class="drag-item" draggable="true">item 4</div>
  <div class="drag-item" draggable="true">item 5</div>
</div>
<div class="dragremind"></div>
var dustbin = document.querySelector(‘.dustbin‘);
var draglist = document.getElementsByClassName(‘drag-item‘);
var remind = document.querySelector(‘.dragremind‘);
var dragElem = null;

for(var i=0;i<draglist.length;i++){
  draglist[i].addEventListener("drag", function(event){
    event.dataTransfer.effectAllowed = "move";
    dragElem = event.target;
  });
  
}

dustbin.addEventListener("dragover", function(event){
  event.preventDefault();
});

dustbin.addEventListener("dragenter", function(event){
  event.preventDefault();
  this.style.color = "#fff";
});
dustbin.addEventListener("dragleave", function(event){
  this.style.color = "#000";
});

dustbin.addEventListener("drop", function(event){
  if(dragElem){
    remind.innerText = dragElem.innerText;
    dragElem.parentElement.removeChild(dragElem);
    this.style.color = "#000";
  }
});

参考资料

《JavaScript高级程序设计》

HTML5 drag & drop 拖拽与拖放简介

以上是关于vue怎么触发元素的原生事件的主要内容,如果未能解决你的问题,请参考以下文章

vue.bind啥时候触发

20170613-原生拖放

20170613-原生拖放

vue常用修饰符

vue-learning:27 - component - 组件三大API之二:event

vue中的点击事件