Heim  >  Artikel  >  Web-Frontend  >  So übergeben Sie Ereignisse in Vue-Komponenten

So übergeben Sie Ereignisse in Vue-Komponenten

亚连
亚连Original
2018-06-14 15:44:382912Durchsuche

Meine jüngste Arbeit erfordert die Verwendung von Vue, daher bin ich zuletzt mit Vue in Kontakt gekommen. Jetzt stelle ich Ihnen die Ereignisübertragung zwischen Vue-Komponenten vor

Da die neue Arbeit die Verwendung von Vue erfordert, bin ich in letzter Zeit mit Vue in Kontakt gekommen. Da ich React bereits verwendet habe, habe ich sehr schnell mit Vue angefangen.

Ich habe auch versucht, einige Ähnlichkeiten und Unterschiede zwischen den beiden zu finden. Neben einigen weiteren Hilfsmethoden sollte der größte Unterschied darin bestehen, dass es für die Kommunikation zwischen Komponenten nicht nur Requisiten, sondern auch ein Ereignis gibt Listener, der zwischen Komponenten übergeben werden kann.

In vue2.+ führte Vue jedoch den Diff-Algorithmus und den virtuellen Dom ein, um die Effizienz zu verbessern. Um mit häufigen Aktualisierungen von Dom-Elementen umzugehen, wird eine Optimierungslösung vorgeschlagen. Gibt es einen Konflikt zwischen häufigen Änderungen und Aktualisierungen und der Initialisierung von Ereignis-Listenern? ? Schreiben wir einen einfachen Code, um dies zu überprüfen.

Wir schreiben zwei von p erstellte Schaltflächen, eine ist in HTML-Code geschrieben und die andere wird in Form einer Komponente eingefügt. Die beiden Schaltflächen sind genau gleich, aber wir fügen der äußeren Schaltfläche ein deaktiviertes Attribut hinzu Layer und übergeben if-else, um deaktivierte Schaltflächen zu bestimmen und unterschiedliche Schaltflächen anzuzeigen (natürlich würden wir in normalen Szenarien keinen solchen Code schreiben, hier simulieren wir nur ein spezielles Szenario auf diese Weise und prüfen, ob dieses Szenario in unserem Unternehmen existiert) .

<template>
 <p class="test">
 <p class="btn" v-if="disabled" @click="handleClick">可点击</p>
 <p class="btn" v-else >不可点击</p>
 <Button v-if="disabled" @clickTest="handleClick">可点击</Button>
 <Button v-else>不可点击</Button>
 </p>
</template>

<script>
import Button from &#39;./Button&#39;
export default {
 data () {
 return {
  disabled: true
 }
 },
 methods: {
 handleClick() {
  alert(&#39;可点击&#39;)
 }
 },
 components: {
 Button,
 },
 mounted() {
 setTimeout(() => {
  this.disabled = false
 }, 1000)
 }
}
</script>
<style>
.btn{
 margin: 100px auto;
 width: 200px;
 line-height: 50px;
 border: 1px solid #42b983;
 border-radius: 5px;
 color: #42b983;
}
</style>

Fügen wir einen kleinen Stil hinzu, damit es so gut wie möglich aussieht. Es sieht sehr einfach aus. Zwei Schaltflächen sind an ein Klickereignis gebunden, wenn sie anklickbar sind. Der Unterschied besteht darin, dass es sich bei dem einen um direkt geschriebenen HTML-Code und bei dem anderen um eine Komponente handelt. Der Code der Komponente lautet wie folgt:

<template>
 <p class="btn" @click="handleClick"><slot></slot></p>
</template>
<script>
 export default {
  methods: {
   handleClick() {
    this.$emit(&#39;clickTest&#39;)
   }
  }
 }
</script>

Fügen Sie dann einen 1-sekündigen settimeout zum gemounteten Zeitraum hinzu, um „disabled“ in „false“ zu ändern, und dann testen wir ihn

Wenn „Deaktiviert“ immer noch wahr ist, wird beim Klicken auf beide Schaltflächen eine anklickbare Warnung angezeigt. Wenn sich „disabled“ jedoch in „false“ ändert, wird die in HTML geschriebene nicht mehr angezeigt, die in den folgenden Komponenten geschriebene jedoch weiterhin.

Es ist sehr schwierig, ein solches Problem zu lokalisieren, wenn es auftritt, da der Code dieses Clicktest-Ereignis offensichtlich nicht aufruft und wir auf der Seite auch feststellen können Die Schaltfläche ist nicht mehr anklickbar. Warum wird diese Veranstaltung immer noch ausgerufen?

Beginnen wir mit dem Diff-Algorithmus. Die Algorithmuskomplexität des herkömmlichen Diff-Baum-Algorithmus beträgt O(n^3). Als React den Diff-Algorithmus einführte, wurde die stufenübergreifende Bewegung eliminiert Die Ähnlichkeiten und Unterschiede von Knoten auf derselben Ebene reduzieren die Komplexität des Algorithmus auf O(n), sodass wir die gesamte Seite häufig und ohne Einschränkungen aktualisieren können (natürlich in Maßen).

(haha, kein Bild)

Diff hat eine Strategie, bei der zwei Komponenten mit derselben Klasse eine ähnliche Baumstruktur erzeugen und zwei Komponenten mit unterschiedlichen Klassen unterschiedliche Baumstrukturen erzeugen. Die Vergleichsreihenfolge ist also

1) Baumdiff

2) Komponentendiff

3) Elementdiff

Zurück zu unserem Code, wenn wir Komponente ausführen diff, wir denken, dass es sich um dieselben Komponenten handelt, und führen dann einen Element-Diff aus, d Im DOM in der Komponente hat Vue den Ereignis-Listener, der der Komponente hinzugefügt wurde, nicht gelöscht.

Werfen wir einen Blick auf den Vue-Code

Vue.prototype.$emit = function (event: string): Component {
 const vm: Component = this
 if (process.env.NODE_ENV !== &#39;production&#39;) {
  const lowerCaseEvent = event.toLowerCase()
  if (lowerCaseEvent !== event && vm._events[lowerCaseEvent]) {
  tip(
   `Event "${lowerCaseEvent}" is emitted in component ` +
   `${formatComponentName(vm)} but the handler is registered for "${event}". ` +
   `Note that HTML attributes are case-insensitive and you cannot use ` +
   `v-on to listen to camelCase events when using in-DOM templates. ` +
   `You should probably use "${hyphenate(event)}" instead of "${event}".`
  )
  }
 }
 let cbs = vm._events[event]
 if (cbs) {
  cbs = cbs.length > 1 ? toArray(cbs) : cbs
  const args = toArray(arguments, 1)
  for (let i = 0, l = cbs.length; i < l; i++) {
  try {
   cbs[i].apply(vm, args)
  } catch (e) {
   handleError(e, vm, `event handler for "${event}"`)
  }
  }
 }
 return vm
 }

Vue ermittelt über das _events-Attribut in vdom, ob gebundene Ereignisse vorhanden sind. Wir schauen uns die _events

:
clickTest
:
Array(1)
0
:
ƒ invoker()
length
:

der nicht anklickbaren Schaltfläche an und stellen fest, dass der Clicktest immer noch vorhanden ist. Das ist das Problem.

Wie können wir also ein solches Problem vermeiden? Sollen wir das Problem durch Diff-Vergleich lösen oder uns den Code ansehen?

function sameVnode (a, b) {
 return (
 a.key === b.key && (
  (
  a.tag === b.tag &&
  a.isComment === b.isComment &&
  isDef(a.data) === isDef(b.data) &&
  sameInputType(a, b)
  ) || (
  isTrue(a.isAsyncPlaceholder) &&
  a.asyncFactory === b.asyncFactory &&
  isUndef(b.asyncFactory.error)
  )
 )
 )
}

Das heißt, für Diff ist das sogenannte Same-First-Determination-Prinzip der Schlüssel.

key ist auch ein Attribut, das bei der Einführung von diff hinzugefügt wird. Es wird verwendet, um zu bestimmen, ob die vorderen und hinteren VDOM-Bäume einheitliche Elemente sind (beachten Sie, dass es sich um eine Geschwisterbeziehung handelt), sodass wir nur den Schlüssel hinzufügen müssen Der Code zur Vermeidung dieses Problems

<Button key="1" v-if="disabled" @clickTest="handleClick">可点击</Button>
<Button key="2" v-else>不可点击</Button>

Auf diese Weise wird das Popup-Fenster nicht mehr angezeigt, wenn wir auf die Schaltfläche klicken.

key hat eine breite Palette von Funktionen, wenn wir das Array durchlaufen, um Dom zu generieren. Das Hinzufügen einer bestimmbaren eindeutigen ID (beachten Sie, dass der Array-Index nicht verwendet werden sollte) optimiert unsere Vergleichseffizienz und erfordert weniger Dom-Operationen. Wir werden einem p auch einen Schlüssel hinzufügen, um sicherzustellen, dass es aufgrund von Änderungen in Geschwisterelementen nicht erneut gerendert wird (dieser Typ von p ist normalerweise an andere Ereignisse oder Aktionen als React oder Vue gebunden, z. B. das Generieren einer Leinwand usw.). ).

Gibt es außer dem Hinzufügen dieses unnötigen Schlüsselwerts zur Komponente noch eine andere Möglichkeit, das Problem zu lösen?

Ja, es gibt eine sehr Vue-feindliche, aber reaktionsähnliche Möglichkeit, das Rückrufereignis durch Requisiten weiterzuleiten, wie diese,

<Button v-if="disabled" :clickTest="handleClick">可点击</Button>
<Button v-else>不可点击</Button>
  props: {
   &#39;clickTest&#39;: {
    type: Function
   }
  },
  methods: {
   handleClick() {
    //this.$emit(&#39;clickTest&#39;)
    this.clickTest && this.clickTest()
   }
  }

虽然vue给了我们更方便的事件传递的方式,但props里是允许我们去传递任何类型的,我的期望是在真实的dom上或者在公共组件的入口处以外的地方,都是通过props的方式来传递结果的。虽然这种方式很不vue,而且也享受不到v-on给我们带来的遍历,但是这样确实可以减少不必要的麻烦。

当然既然用了vue,更好的利用vue给我们带来的便利也很重要,所以对于这种很少会出现的麻烦,我们有一个预期,并可以快速定位并修复问题,就可以了。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

在vue中如何通过v-for处理数组

使用vue如何实现收藏夹

在node.js中有关npm和webpack配置方法

如何通过js将当前时间格式化?

使用vue引入css,less相关问题

Das obige ist der detaillierte Inhalt vonSo übergeben Sie Ereignisse in Vue-Komponenten. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn