Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

第 94 题:vue 在 v-for 时给每项元素绑定事件需要用事件代理吗?为什么? #145

Open
yygmind opened this issue Jun 23, 2019 · 19 comments
Labels

Comments

@yygmind
Copy link
Contributor

yygmind commented Jun 23, 2019

No description provided.

@Loading-m
Copy link

不需要,因为vue源码里已经做了处理

@1006223320
Copy link

在vue 中 vue 做了处理
如果我们自己在非vue 中需要对很多元素添加事件的时候,可以通过将事件添加到它们的父节点而将事件委托给父节点来触发处理函数

@zrainice
Copy link

之前好像看过 react / vue 这些框架都自己实现了一套事件,把事件都代理到document上面了,所以不需要自己手动再去代理了,如果不用框架需要代理到父级元素

@LaylaCao
Copy link

哪位大佬能给段代码 0.0

@yeyan1996
Copy link

说一下我个人理解,先说结论,可以使用

事件代理作用主要是 2 个

  1. 将事件处理程序代理到父节点,减少内存占用率
  2. 动态生成子节点时能自动绑定事件处理程序到父节点

这里我生成了十万个 span 节点,通过 performance monitor 来监控内存占用率和事件监听器的数量,对比以下 3 种情况

  1. 不使用事件代理,每个 span 节点绑定一个 click 事件,并指向同一个事件处理程序
  <div>
      <span 
        v-for="(item,index) of 100000" 
        :key="index" 
        @click="handleClick">
        {{item}}
      </span>
    </div>
  1. 不使用事件代理,每个 span 节点绑定一个 click 事件,并指向不同的事件处理程序
  <div>
      <span 
        v-for="(item,index) of 100000" 
        :key="index" 
        @click="function () {}">
        {{item}}
      </span>
    </div>
  1. 使用事件代理
<div  @click="handleClick">
      <span 
        v-for="(item,index) of 100000"  
        :key="index">
        {{item}}
      </span>
    </div>

image

image

image

可以看到使用事件代理无论是监听器数量和内存占用率都比前两者要少

同时对比 3 个图中监听器的数量以及我以往阅读 vue 源码的过程中,并没有发现 vue 会自动做事件代理,但是一般给 v-for 绑定事件时,都会让节点指向同一个事件处理程序(第二种情况可以运行,但是 eslint 会警告),一定程度上比每生成一个节点都绑定一个不同的事件处理程序性能好,但是监听器的数量仍不会变,所以使用事件代理会更好一点

@GitHdu
Copy link

GitHdu commented Jun 24, 2019

源码没有做事件代理

https://forum.vuejs.org/t/is-event-delegation-necessary/3701/2

@yeyan1996
Copy link

嗯,看了楼上的那篇文章,和我的结论大致相同,只有在非常非常多的节点中,使用事件代理会提高一点性能,否则绑定在每个节点中几乎没有差别

@PerfectYan
Copy link

源码没有做事件代理

https://forum.vuejs.org/t/is-event-delegation-necessary/3701/2

快三年了,真的没有做优化吗?

@shenxiang11
Copy link

shenxiang11 commented Jul 9, 2019

<ul>
      <li
        v-for="i in 10"
        :key="i"
        @click="c"
      >{{i}}</li>
    </ul>

屏幕快照 2019-07-09 下午2 48 57

一本正经胡说八道的,事件并没有被代理

@xinlanlan
Copy link

react好像跟vue不一样,react好像所有事件都委托到document上了吧,然后进行派发

@chenzesam
Copy link

react 是委托到 document 上, 然后自己生成了合成事件, 冒泡到 document 的时候进入合成事件, 然后他通过 getParent() 获取该事件源的所有合成事件, 触发完毕之后继续冒泡
vue 是怎么做的我就不清楚了, 但是尤大应该会意识到合成事件带来的好处, 跨端跨浏览器

@CHristopherkeith
Copy link

CHristopherkeith commented Jul 19, 2019

vue本身不做事件代理

  1. 普通html元素和在组件上挂了.native修饰符的事件。最终EventTarget.addEventListener()挂载事件
  2. 组件上的,vue组件实例上的自定义事件(不包括.native)会调用原型上的$on,$emit(包括一些其他api $off,$once等等)

参考:
https://segmentfault.com/a/1190000009750348

@eEmpty
Copy link

eEmpty commented Jul 23, 2019

react好像跟vue不一样,react好像所有事件都委托到document上了吧,然后进行派发

对的,react 代理到了 document 上

@yaodongyi
Copy link

yaodongyi commented Sep 19, 2019

vue自身没有做事件代理,如果需要,则直接代理到父节点。对于mpvue写小程序来说,还是很有必要的,毕竟安卓机小程序性能太差。

    <ul @click="meths">
      <li v-for="(item,key) in 10" :key="key" :data-index="key">{{item}}</li>
    </ul>

    // vue
    meths(e) {
      if (e.target.nodeName.toLowerCase() === 'li') {
        console.log(e.target.dataset.index)
      }
    }

    // mpvue
    meths(e) {
        console.log(e.target.dataset.index)
    }  

@JohnieXu
Copy link

JohnieXu commented Oct 9, 2019

说一下我个人理解,先说结论,可以使用

事件代理作用主要是 2 个

  1. 将事件处理程序代理到父节点,减少内存占用率
  2. 动态生成子节点时能自动绑定事件处理程序到父节点

这里我生成了十万个 span 节点,通过 performance monitor 来监控内存占用率和事件监听器的数量,对比以下 3 种情况

  1. 不使用事件代理,每个 span 节点绑定一个 click 事件,并指向同一个事件处理程序
  <div>
      <span 
        v-for="(item,index) of 100000" 
        :key="index" 
        @click="handleClick">
        {{item}}
      </span>
    </div>
  1. 不使用事件代理,每个 span 节点绑定一个 click 事件,并指向不同的事件处理程序
  <div>
      <span 
        v-for="(item,index) of 100000" 
        :key="index" 
        @click="function () {}">
        {{item}}
      </span>
    </div>
  1. 使用事件代理
<div  @click="handleClick">
      <span 
        v-for="(item,index) of 100000"  
        :key="index">
        {{item}}
      </span>
    </div>

image

image

image

可以看到使用事件代理无论是监听器数量和内存占用率都比前两者要少

同时对比 3 个图中监听器的数量以及我以往阅读 vue 源码的过程中,并没有发现 vue 会自动做事件代理,但是一般给 v-for 绑定事件时,都会让节点指向同一个事件处理程序(第二种情况可以运行,但是 eslint 会警告),一定程度上比每生成一个节点都绑定一个不同的事件处理程序性能好,但是监听器的数量仍不会变,所以使用事件代理会更好一点

上面有回答说react/vue框架已经帮我们实现了统一的事件代理,为何说这里的第1,2种写法属于非事件代理(vue中)?

@habc0807
Copy link

react好像跟vue不一样,react好像所有事件都委托到 document 上了吧,然后进行派发

React 中的事件是合成事件,所有事件都委托到 document 了,最后通过addEventListener来监听事件,react-dom 中 合成事件的处理源码:

// react-dom/src/events/EventListener.js 
export function addEventBubbleListener(
  element: Document | Element,
  eventType: string,
  listener: Function,
): void {
  element.addEventListener(eventType, listener, false);
}

// 调用处
addEventBubbleListener(element, getRawEventName(topLevelType)

@chaijinsong
Copy link

首先我们需要知道事件代理主要有什么作用?

  • 事件代理能够避免我们逐个的去给元素新增和删除事件
  • 事件代理比每一个元素都绑定一个事件性能要更好

从vue的角度上来看上面两点

  • 在v-for中,我们直接用一个for循环就能在模板中将每个元素都绑定上事件,并且当组件销毁时,vue也会自动给我们将所有的事件处理器都移除掉。所以事件代理能做到的第一点vue已经给我们做到了
  • 在v-for中,给元素绑定的都是相同的事件,所以除非上千行的元素需要加上事件,其实和使用事件代理的性能差别不大,所以也没必要用事件代理

@yygmind yygmind added the Vue label Dec 16, 2019
@BUPTlhuanyu
Copy link

react 是委托到 document 上, 然后自己生成了合成事件, 冒泡到 document 的时候进入合成事件, 然后他通过 getParent() 获取该事件源的所有合成事件, 触发完毕之后继续冒泡
vue 是怎么做的我就不清楚了, 但是尤大应该会意识到合成事件带来的好处, 跨端跨浏览器

每个dom都有的事件都代理到document上,但是一些特殊的比如focus这种必须放在input这些dom上。

@BUPTlhuanyu
Copy link

react 是委托到 document 上, 然后自己生成了合成事件, 冒泡到 document 的时候进入合成事件, 然后他通过 getParent() 获取该事件源的所有合成事件, 触发完毕之后继续冒泡
vue 是怎么做的我就不清楚了, 但是尤大应该会意识到合成事件带来的好处, 跨端跨浏览器

每个dom都有的事件都代理到document上,但是一些特殊的比如focus这种必须放在input这些dom上。

https://juejin.im/post/5d0af976e51d454fbf540a0f

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests