點燈坊

失くすものさえない今が強くなるチャンスよ

Vue 之 Capture Event Modifier

Sam Xiao's Avatar 2020-10-06

DOM Event 天生具有 Event Propagation 特性,且是由內向外觸發 Event,若想由外向內觸發,則稱為 Event Capturing,Vue 提供了 capture Event Modifier,讓我們在 HTML Template 就能以 Declarative 形式使 Event 往內層傳遞。

Version

Vue 2.6.11
Tailwind CSS 1.8.10

Event Propagation

capture000

按下 Click Me,會發現 3 個 click event 都會被觸發,這正是其 Event Propagation 特性。

capture001

當按下綠色部分,會發現只有 2 個 click event 都會被觸發, 則不觸發,因為 Event Propagation 只會向外,而不會向內。

<template>
  <div @click="onOuterClick" class="p-3 bg-blue-500">
    <div @click="onMiddleClick" class="p-3 bg-green-500">
      <div @click="onInnerClick" class="bg-red-500">Click Me</div>
    </div>
  </div>
</template>

<script>
let onOuterClick = function() {
  console.log('Outer click')
}

let onMiddleClick = function() {
  console.log('Middle click')
}

let onInnerClick = function() {
  console.log('Inner click')
}

export default {
  methods: {
    onOuterClick,
    onMiddleClick,
    onInnerClick
  }
}
</script>

第 2 行

<div @click="onOuterClick" class="p-3 bg-blue-500">
  <div @click="onMiddleClick" class="p-3 bg-green-500">
    <div @click="onInnerClick" class="bg-red-500">Click Me</div>
  </div>
</div>

三層 <div>click event 都有其 event handler,因此能觀察 Event Propagation,且每個 <div>都增加其 padding 方便 click。

element.addEventListener()

capture002

按下 Click Me,會發現 3 個 click event 都會被觸發,但順序與 Event Propagation 相反,而是由外向內觸發,此稱為 Event Capturing。

capture003

當按下綠色部分,會發現只有 2 個 click event 都會被觸發, 則不觸發,但順序與 Event Propagation 相反,而是由外向內觸發。

<template>
  <div ref="outer" class="p-3 bg-blue-500">
    <div ref="middle" class="p-3 bg-green-500">
      <div ref="inner" class="bg-red-500">Click Me</div>
    </div>
  </div>
</template>

<script>
let onOuterClick = function() {
  console.log('Outer click')
}

let onMiddleClick = function() {
  console.log('Middle click')
}

let onInnerClick = function() {
  console.log('Inner click')
}

let mounted = function() {
  this.$refs.outer.addEventListener('click', onOuterClick, true)
  this.$refs.middle.addEventListener('click', onMiddleClick, true)
  this.$refs.inner.addEventListener('click', onInnerClick, true)
}

export default {
  mounted
}
</script>

22 行

let mounted = function() {
  this.$refs.outer.addEventListener('click', onOuterClick, true)
  this.$refs.middle.addEventListener('click', onMiddleClick, true)
  this.$refs.inner.addEventListener('click', onInnerClick, true)
}

若要實現 Event Capturing,標準做法是使用 addEventListener() 註冊 event handler,且在第 3 個 argument 傳 true

Capture Modifier

<template>
  <div @click.capture="onOuterClick" class="p-3 bg-blue-500">
    <div @click.capture="onMiddleClick" class="p-3 bg-green-500">
      <div @click.capture="onInnerClick" class="bg-red-500">Click Me</div>
    </div>
  </div>
</template>

<script>
let onOuterClick = function() {
  console.log('Outer click')
}

let onMiddleClick = function() {
  console.log('Middle click')
}

let onInnerClick = function() {
  console.log('Inner click')
}

export default {
  methods: {
    onOuterClick,
    onMiddleClick,
    onInnerClick
  }
}
</script>

第 2 行

<div @click.capture="onOuterClick" class="p-3 bg-blue-500">
  <div @click.capture="onMiddleClick" class="p-3 bg-green-500">
    <div @click.capture="onInnerClick" class="bg-red-500">Click Me</div>
  </div>
</div>

Vue 提供了 capture event modifier,讓我們在 HTML template 就能實現 Event Capturing,不必寫 JavaScript。

Conclusion

  • capture event modifier 讓我們以 declarative 方式實現 Event Capturing,不必特別寫 JavaScript

Reference

Summer。桑莫。夏天, Vue.js Methods 與事件處理 (Event Handling)