在 Composition API 中使用 props 與 emit 操控 modal
在前端工程師的日常中,modal/ 彈出視窗 是常常會遇到的工作情境。畫面大概就是外部元件有一個按鈕,按下去會有一個對話框(內部元件)彈出來,對話框上有個按鈕,點擊後對話框就會關閉。
如果前端框架是 Vue 的話,一般我們會在外部元件定義一個布林值,預設為 false
,按下外部的按鈕後,布林值會變為 true
。
開啟:在內部元件 modal 用 props 接收外部元件的布林值,綁上
v-if= props 接收到的布林值
。這樣就可以由外部元件控制內部元件的開啟。關閉:內元件 modal 可以由元件內部的按鈕關閉,按下按鈕後以 emit 傳送一個事件去觸發外部元件反轉布林值,達成元件的關閉。
App.vue(外部元件)
<template>
<button @click="isOpen = true">showModal</button>
<!-- 外部元件中插入內部元件 modal -->
<!-- props 口訣:先內後外 :open="isOpen"-->
<!-- emit 口訣:先內後外 @close="isOpen = !isOpen"-->
<Modal :open="isOpen" @close="isOpen = !isOpen">
<p>
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quo molestiae
consectetur blanditiis aspernatur velit autem labore amet
</p>
</Modal>
</template>
<script>
import { ref } from "vue";
import Modal from "./components/ModalView.vue";
// import HelloWorldVue from "./components/HelloWorld.vue";
export default {
components: { Modal },
setup() {
// 由 isOpen 的 true 或 false 控制 modal 的開關
const isOpen = ref(false);
return {
isOpen,
};
},
};
</script>
<style>
</style>
/components/ModalView.vue(內部元件)
<template>
<transition name="fade">
<!-- 控制背景 -->
<div class="vue-modal" v-if="open">
<transition name="drop-in">
<!-- 彈跳視窗本體 props 為 open,所以 v-if="open" -->
<div class="vue-modal-inner" v-if="open">
<div class="vue-modal-content">
<slot />
<!-- @click="close" 觸發 emit 事件,傳送至外層切換 isOpen -->
<button type="button" @click="close">close</button>
</div>
</div>
</transition>
</div>
</transition>
</template>
<script>
import { onMounted, onUnmounted } from "vue";
export default {
props: {
open: {
type: Boolean,
requires: true,
},
},
// peops 這個參數一定要帶到,才能使用 {emit}
setup(props, { emit }) {
const close = () => {
emit("close");
};
const handleKeyup = (event) => {
close();
};
onMounted(() => document.addEventListener("keyup", handleKeyup));
onUnmounted(() => document.removeEventListener("keyup", handleKeyup));
return { close };
},
};
</script>
<style scoped>
*,
::before,
::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.vue-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow-x: hidden;
overflow-y: auto;
background-color: rgba(0, 0, 0, 0.04);
z-index: 1;
}
.vue-modal-inner {
max-width: 500px;
margin: 2rem auto;
}
.vue-modal-content {
position: relative;
background-color: #fff;
border: 1px solid rgba(0, 0, 0, 0.3);
background-clip: padding-box;
border-radius: 0.3rem;
padding: 1rem;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
.drop-in-enter-active,
.drop-in-leave-active {
transition: all 0.3s easeout;
}
.drop-in-enter-from,
.drop-in-leave-to {
opacity: 0;
transform: translateY(-50px);
}
</style>
在 Composition API 中使用 props 與 emit 操控 modal
https://popeye-ux.github.io/2023/01/27/modal-props-emit/