「シャドウモーダル」div上にあるESCボタンをクリックすると、「close」イベントが発生することを期待していますが、発生していません
vue 2.5.13、理由は何ですか?
<template>
<div class="shadow-modal"
@keyup.esc="$emit('close')">
<transition name="modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">
default header
</slot>
</div>
<div class="modal-body">
<slot name="body">
default body
</slot>
</div>
<div class="modal-footer">
<slot name="footer">
<a href="#"
class="btn btn--diagonal btn--blue"
@click="$emit('close')">Cancel</a>
</slot>
</div>
</div>
</div>
</div>
</transition>
</div>
</template>
Keyboradイベントをバインドしようとしているのはinput要素ではありませんが、tabindexを定義しない限り機能しません。
<div class="shadow-modal" @keyup.esc="$emit('close')" tabindex="0">
リファレンスは次のとおりです。 https://www.w3.org/WAI/GL/WCAG20/WD-WCAG20-TECHS/SCR29.html
(以前の2つの回答とは別に。)
Vueですべてのイベントを処理する必要はありません。
ここで別の方法
export default {
created() {
document.onkeydown = evt => {
evt = evt || window.event;
if (evt.keyCode == 27) {
this.$emit("close");
}
};
}
};
DmitrySemenovソリューションは私には有効ですが、ページに複数のモーダルがある場合、それは最良のソリューションではありません。私はそれを試してみましたが、すべてのモーダルに対してcloseイベントが発生することを発見しました。
それを行う最善の方法は、モーダルが表示されたときに「キーアップ」イベントを登録し、非表示にしてから登録を解除することだと思います。イベントは必要なときにのみ登録されるため、利点があります。それを行うには、「show」プロパティのウォッチャーを追加する必要があります。
props: {
show: {
type: Boolean,
default: false
}
},
watch: {
show() {
if (this.show === false) {
window.removeEventListener("keyup", this.onEscapeKeyUp);
} else {
window.addEventListener("keyup", this.onEscapeKeyUp);
}
}
},
methods: {
onEscapeKeyUp(event) {
if (event.which === 27) {
this.$emit("close");
}
}
}
モーダルにはv-if="show"
モーダルの可視性を制御します。
<div class="modal-mask" v-if="show" @click="$emit('close');">
<template>
<transition name="modal">
<div class="modal-mask" v-if="show" @click="$emit('close');">
<div class="modal-wrapper" @click.stop>
<div class="modal-container">
<div class="modal-header"><slot name="header"></slot></div>
<div class="modal-body"><slot name="body"></slot></div>
<div class="modal-footer">
<slot name="footer">
<div class="buttons">
<a class="button" href="#" @click.prevent="$emit('close');">
OK
</a>
</div>
</slot>
</div>
</div>
</div>
</div>
</transition>
</template>
<script>
export default {
name: "Modal",
props: {
show: {
type: Boolean,
default: false
}
},
watch: {
show() {
const body = document.querySelector("body");
if (this.show === false && body.style.overflow === "hidden") {
body.style.overflow = "";
window.removeEventListener("keyup", this.onEscapeKeyUp);
} else {
body.style.overflow = "hidden";
window.addEventListener("keyup", this.onEscapeKeyUp);
}
}
},
methods: {
onEscapeKeyUp(event) {
if (event.which === 27) {
console.log("close event");
this.$emit("close");
}
}
}
};
</script>
<style lang="scss" scoped>
.modal-mask {
position: fixed;
z-index: 1100;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
overflow: auto;
transition: opacity 0.3s ease;
display: flex;
justify-content: center;
align-items: center;
}
.modal-wrapper {
max-width: 980px;
width: 100%;
}
.modal-container {
padding: 1.5em 2em;
background-color: white;
border-radius: 2px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
transition: all 0.3s ease;
}
.wrapper {
max-width: 980px;
}
.modal-body {
margin: 1em 0;
}
.modal-enter {
opacity: 0;
}
.modal-leave-active {
opacity: 0;
}
.modal-enter .modal-container,
.modal-leave-active .modal-container {
-webkit-transform: scale(1.1);
transform: scale(1.1);
}
</style>
<template>
<div id="app">
<button @click="show1 = true;">Show first modal</button>
<button @click="show2 = true;">Show second modal</button>
<Modal :show="show1" @close="show1 = false;">
<div slot="header"><h1>First Modal</h1></div>
<div slot="body">
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Rem beatae
repellat dolores deleniti illum voluptatem facilis neque ut placeat,
eius iusto tempore! Totam omnis non tempore perferendis expedita numquam
neque!
</div>
</Modal>
<Modal :show="show2" @close="show2 = false;">
<div slot="header"><h1>Second Modal</h1></div>
<div slot="body">
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Rem beatae
repellat dolores deleniti illum voluptatem facilis neque ut placeat,
eius iusto tempore! Totam omnis non tempore perferendis expedita numquam
neque!
</div>
</Modal>
</div>
</template>
<script>
import Modal from "./components/Modal";
export default {
name: "App",
components: {
Modal
},
data() {
return {
show1: false,
show2: false
};
}
};
</script>
私の代替実装
<template>
<div class="shadow-modal"
@keyup.esc="$emit('close')">
<transition name="modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">
default header
</slot>
</div>
<div class="modal-body">
<slot name="body">
default body
</slot>
</div>
<div class="modal-footer">
<slot name="footer">
<a href="#"
class="btn btn--diagonal btn--blue"
@click="$emit('close')">Cancel</a>
</slot>
</div>
</div>
</div>
</div>
</transition>
</div>
</template>
<script>
export default {
beforeMount() {
window.addEventListener('keyup', this.onEscapeKeyUp);
},
beforeDestroy () {
window.removeEventListener('keyup', this.onEscapeKeyUp)
},
methods: {
onEscapeKeyUp (event) {
if (event.which === 27) {
this.$emit('close');
}
},
},
};
</script>