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

Add non-passive event modifier #10778

Open
tobyzerner opened this issue Oct 30, 2019 · 9 comments
Open

Add non-passive event modifier #10778

tobyzerner opened this issue Oct 30, 2019 · 9 comments

Comments

@tobyzerner
Copy link

tobyzerner commented Oct 30, 2019

What problem does this feature solve?

An event modifier to support passive events was added in #5132.

In the last couple of years, browsers have adopted the passive behavior by default for touchstart and touchmove events (reference). Thus, to be able to cancel one of these events by calling e.preventDefault(), you need to explicitly pass { passive: false } when adding the event listener.

With the current API this is impossible to achieve in a Vue template (as far as I can tell). You must manually add and remove the event listener in a component hook like so:

this.$refs.someElement.addEventListener('touchstart', this.start, { passive: false });
this.$refs.someElement.addEventListener('touchmove', this.move, { passive: false });

// later
this.$refs.someElement.removeEventListener('touchstart', this.start);
this.$refs.someElement.removeEventListener('touchmove', this.move);

What does the proposed API look like?

An event modifier that does the opposite of the passive event modifier, specifying the option as false instead of true.

Unsure of the naming - perhaps nonPassive, active, assertive, intentional.

<div
  @touchstart.active="start"
  @touchmove.active="move"
></div>
@kleinfreund
Copy link

In vue/src/core/vdom/helpers/update-listeners.js:22, normalizeEvent always returns an object with a set passive property.

I’m not familiar with Vue’s source code, but does that mean that when the .passive modifier is not present, each event handler is always declared as active? This seems wrong in the light of browser’s changing the default for certain event types to be passive by default (see Improving scrolling performance with passive listeners). If .passive is not present, I don’t expect event handlers to be marked as not passive.

With regards to the feature request itself, I think “active” would be a natural choice here.

@WORMSS
Copy link
Contributor

WORMSS commented Nov 20, 2019

nonPassive seems like the more logical opposite of passive.
Just wondering what wins if you do

@scroll.passive.nonPassive="..."

vs

@scroll.nonPassive.passive="..."

Any difference at all? which one wins?
If neither is passed, I believe passive should be left as undefined.

@inspire22
Copy link

Any1 figure out a workaround to this? touchstart & conditionally setting preventDefault in the running code doesn't seem to work to cancel the event.

@Kvothe1997
Copy link

In Vue 3, the following code generates a "passive : false" event listener attached to that div.

<div
  @touchstart="function"
></div>

@wangf1978
Copy link

wangf1978 commented Nov 24, 2022

I think vue need this feature, otherwise modern browser will report tons of warnings, now edge/chrome need set the passive to true or false explictly in the addEventListener for some events, for example, touchstart, wheel and so on, otherwise it will report warnings, it is already disaster for me, I don't have easy way to solve it.

image

Here is my code clip:

    ...
    <div v-if="img.focused == true && img.selected == false" class="photo_selection" 
            v-on:click="on_toggle_photo_checkbox(img, true, $event, imgTypePos + start_list_idx_in_vw)"
            v-on:touchstart.prevent="on_toggle_photo_checkbox(img, true, $event, imgTypePos + start_list_idx_in_vw)">
    ...

If I didn't use the v-on:touchstart/wheel, and handle these events with raw javascript DOM API addEventListener, there is so much effort for me, because the elements binding "touchstart" event in my project are dynamically created or destroyed by v-if.

Can vue team consider adding a new modifier to pass event option with passive: false?

@WORMSS
Copy link
Contributor

WORMSS commented Nov 24, 2022

@wangf1978 short term solution, you could add a ref and use vueuse's useEventListener(divRef, 'touchstart', eventCallback, { passive: true })

But I am unsure if that solution would work for you as I am unsure where some of your variables are coming from.

@wangf1978
Copy link

wangf1978 commented Nov 24, 2022

@wangf1978 short term solution, you could add a ref and use vueuse's useEventListener(divRef, 'touchstart', eventCallback, { passive: true })

But I am unsure if that solution would work for you as I am unsure where some of your variables are coming from.

@WORMSS Thanks for your wonderful solution, but it seems not to be so fit for my scenario:
The div element is generated and destroyed dynamically and frequently by v-if directive in virtual DOM, actually I don't have chance to insert my javascript code for them, and all the related events are controlled v-on: directive, so event modifier seems to be the more direct, elegant and natural way.

@WORMSS
Copy link
Contributor

WORMSS commented Nov 24, 2022

the divRef would be what links the elements, the events would be added/removed as soon as the elements are added/removed from the dom. (it will internally add a watcher on divRef and when it changes, does what it needs to to add the event.

<template>
  <div
    ref="divRef"
    v-if="condition"
    @click="yourevent"
 />
<script setup>
  import { unref } from 'vue';
  import { useEventListener } from '@vueuse/core';
  const divRef = ref(null);
  const eventCallback = (evt) => {
      on_toggle_photo_checkbox(unref(img), true, evt, unref(imgTypePos) + unref(start_list_idx_in_vw));
  };
  useEventListener(divRef, 'touchstart', eventCallback, { passive: true });
</script>

again, I've had to guesstimate some of this, so just assumed most of it are refs/computed, but unref doesn't care if it's a value/ref/computed, it will get the value regardless.

@VladiStep
Copy link

VladiStep commented Mar 19, 2024

In Vue 3, the following code generates a "passive : false" event listener attached to that div.

<div
  @touchstart="function"
></div>

Even if it's true, then it doesn't do that in this case: <div v-on="{ wheel: wheelHandler }" ... - it still produces the "Added non-passive event listener to a scroll-blocking 'wheel' event." warning.

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

No branches or pull requests

8 participants