Vue: Enlace de eventos condicional

Creado en 31 dic. 2017  ·  34Comentarios  ·  Fuente: vuejs/vue

¿Qué problema resuelve esta función?

En este momento, si queremos que un controlador de eventos se ejecute de forma condicional, debemos colocar la condición en el controlador de eventos, lo que significa que el evento todavía está suscrito y pagamos la tarifa de asignación de memoria por la suscripción del evento (el addEventListener subyacente y el controlador correspondiente).

En algunos escenarios, esto es un fastidio. Por ejemplo: digamos que tengo eventos de mouse (mouseover, mouseout) que solo son significativos en dispositivos que realmente tienen un puntero / mouse y, por lo tanto, no tienen sentido en dispositivos móviles y táctiles.

En este momento, tendría que crear las suscripciones de eventos y agregar la condición en el controlador (o en este caso, ni siquiera es necesario, ya que los eventos nunca se activarían) PERO todavía he adjuntado estos controladores y he asignado memoria para ellos. lo que, especialmente en plataformas con limitaciones de memoria, como los navegadores móviles, es un desperdicio.

Al hacer que la suscripción al evento en sí sea condicional, podemos evitar esto.

¿Cómo se ve la API propuesta?

En su forma más simple, podríamos simplemente examinar el controlador proporcionado y, si es falso (o simplemente nulo), cortocircuitar la suscripción al evento y NO aplicar la operación addEventListener subyacente.

De esta forma, la condición puede aparecer en la propia declaración vinculante del evento:

<div @mouseover="condition ? handler : null" /> 
feature request has PR

Comentario más útil

@Kingwl que todavía agrega el oyente, que es lo que OP quiere evitar.

La sugerencia de @sqal es en realidad una solución alternativa válida y se puede simplificar a:

<div v-on="{ mouseover: condition ? handler : null }">

Todos 34 comentarios

@asiFarran

En este momento, tendría que crear las suscripciones de eventos y agregar la condición en el controlador (o en este caso, ni siquiera es necesario, ya que los eventos nunca se activarían)

En realidad, hay otra forma sencilla de manejar este caso. Puede pasar la propiedad calculada con su objeto de escucha (o nulo si no se cumple la condición) a v-on , ejemplo: https://jsfiddle.net/c0Le92xe/

tal vez necesites
<div @mouseover="e => condition && handler(e)" />

@Kingwl que todavía agrega el oyente, que es lo que OP quiere evitar.

La sugerencia de @sqal es en realidad una solución alternativa válida y se puede simplificar a:

<div v-on="{ mouseover: condition ? handler : null }">

Sí, la solución de @sqal es buena y con la inclusión de programas como @ yyx990803 se acerca lo suficiente a lo que tenía en mente. ¡Gracias!

Sin embargo, esto me lleva a un problema más profundo: si ocurre una revinculación (cambio de datos) y luego de la evaluación, la condición cambia (o más generalmente si el objeto de especificación de evento pasado a v-on es diferente), las suscripciones de eventos existentes no se limpian. Todavía (con suerte) se eliminarán al final del ciclo de vida del componente, pero no cuando 'deberían', que es cuando v-on se vuelve a enlazar.

Este puede ser un caso límite que no tiene un gran impacto en la mayoría de los escenarios, pero solo como referencia:

En mi escenario, tengo un SVG complejo y necesito (opcionalmente) adjuntar controladores de mouse over / out a elementos específicos basados ​​en cierta lógica.
El componente es de larga duración y los datos subyacentes cambian lo que lleva a un reenlace donde necesito adjuntar los controladores de eventos a diferentes elementos en cada reenlace; de ​​ahí mi necesidad de deshacerme de las suscripciones anteriores para que no se queden huérfanos, tristes y bebiendo. memoria.

Una solución típica, y lo que voy a terminar haciendo, es configurar un oyente de eventos de 'nivel superior' (por tipo de evento) y dejar que los eventos lleguen a él, pero para explicar mi motivación para probarlo de la manera Vue primero. , hay bastante procesamiento que tiene que suceder en mis controladores que tenía la intención de precalcular y hornear directamente en las suscripciones de eventos en sí para que los controladores tengan menos que hacer (respuesta más rápida y fluida) y no se invoquen en todo para los elementos que no lo requieren (en lugar de filtrar esto confiando en las consultas DOM en el controlador).

@VsevolodTrofimov, el objetivo era evitar que la suscripción al evento ocurriera. La aplicación de la condición en el controlador no satisface este requisito. Tenga en cuenta los comentarios anteriores, ya que proporcionan una resolución satisfactoria.

Estoy cerrando este tema para reflejar eso.

<div v-on="{ mouseover: condition ? handler : null }">

¿Es posible pasar $event y otros argumentos al controlador?

@pmayer
<div v-on="{ mouseover: condition ? $event => handler($event, arg) : null }">

O curry al manejador y usa

<div v-on="{ mouseover: condition ? handler(arg) : null }">

Con la solución sugerida

<div v-on="{ mouseover: condition ? handler : null }">

¿Hay alguna forma de aplicar modificadores como ".stop.prevent"?

Hola @ yyx990803 @VsevolodTrofimov

La solución sugerida aquí (usando v-on="{ mouseover: condition ? handler : null }" ) no funciona realmente con la última versión de Vue.

Recibo este error:
Invalid handler for event "mouseover": got null

Entonces, parece que Vue en realidad está tratando de despedir al controlador en lugar de desvincular el evento 🤔.

@DawidMyslak
Simplemente cámbielo a lo siguiente y funcionará

v-on="condition ? { mouseover: handler } : {}"

o, si su controlador se llama mouseover

v-on="condition ? { mouseover } : {}"

¡Bonito @pbastowski !

¡Gracias chicos!

Es posible que desee ajustar con la función en línea si está llamando a un controlador con datos personalizados. Algo como esto

v-on="condition ? { mouseover: () => handler(somedata) } : {}"

Esto debería estar en los documentos de Vue

@DawidMyslak
Simplemente cámbielo a lo siguiente y funcionará

v-on="condition ? { mouseover: handler } : {}"

o, si su controlador se llama mouseover

v-on="condition ? { mouseover } : {}"

¿Hay alguna forma de combinar esto con .once ?

Puede utilizar https://vuejs.org/v2/guide/render-function.html#Event -amp-Key-Modifiers

<button v-on="{ '~click': () => foo = new Date() }">Trigger only once</button>

Una pregunta sobre esto, ¿habrá pérdidas de memoria o los detectores de eventos no se eliminarán cuando haga lo siguiente y la condición cambie regularmente?

<template>
<div  v-on="myListeners">
some content
</div>
</template>
<script>
...
computed: {
  myListeners() {
    return this.canExecute ? { click: () => this.$emit(...) } : {};
  },
},
...
</script>

Entonces, en resumen, ¿ v-on maneja el cambio o no?

@dietergeerts lo hace.

¿Funciona esto con eventos nativos? No pude hacerlo funcionar con keydown.native .

FYI. Desde 2.6 (aún no publicado), podrá aplicar un enlace de evento condicional de la siguiente manera:

<div @[event]="handler" /> 

Mientras que event resuelve en null , la vinculación se eliminará.

@Justineo Eso es genial, pero acabo de probar la versión beta y tampoco parece funcionar con modificadores (de ningún tipo). ¿Eso no se ha implementado todavía? ¿Está planeado?

@AlansCodeLog debería funcionar con todos los modificadores. Si no funciona, debería abrir un nuevo número con una reproducción.

@ yyx990803 Está bien, veré si puedo reproducirlo.

Abrí un problema aquí: # 9417

tal vez necesites
<div @mouseover="e => condition && handler(e)" />

Versión de JavaScript del navegador

<div @mouseover="condition && handler(arguments[0])" />

@ kieryk123 ¿Puede proporcionar un enlace de CodeSandbox para verlo?

En mi caso, estaba tratando de hacer esto en un elemento de botón deshabilitado (a través de Vuetify), pero aparentemente Chrome no activa los eventos necesarios, y el elemento debería estar envuelto en un div o similar para capturar el evento.

Hola.
Traté de hacerlo así, pero no funciona.

// not working
v-on="{ [condition ? 'click.stop' : 'click'] : eventfunc }"
// or
// error
v-on="{ condition ? 'click.stop' : 'click' : eventfunc }"

hay alguna otra solucion?
¡Gracias por adelantado!

Aquí está el truco para eventos nativos (usando Vue v2.6.11):

@mouseenter.native="condition && handler($event)"

<div @[event]="handler" />

@Justineo ¿ Se agregó esta sintaxis a Vue?
No puedo conseguir que funcione. ¿Quizás podría enviar un enlace a los documentos donde pueda leer más al respecto?

@proArtex gracias, ¡también funciona para mí!
@keyup.delete="title.length === 0 && cancelTopicCreation()"

La pregunta es ... ¿por qué?

@AndrewBogdanovTSS echa un vistazo a este violín https://jsfiddle.net/pbastowski/v0wt5qpo/27/

La sintaxis funciona bien para clics normales y nativos. Tenga en cuenta que los eventos .native solo están disponibles en componentes de Vue y no en elementos HTML simples.

@pbastowski, la cadena simple está funcionando, sí, pero lo que necesito es poder resolver el valor del evento en función de algunos datos reactivos, así que necesito algo como

<h2 @[() => someProp ? 'mouseup' : null]="alert('Normal click on an HTML element')">H2 Element - click it</h2>

y esa sintaxis no me funciona

@AndrewBogdanovTSS Simplemente mueva su lógica a una calculada, vea el ejemplo actualizado aquí https://jsfiddle.net/pbastowski/v0wt5qpo/63/

¿Fue útil esta página
0 / 5 - 0 calificaciones