The introduction
It is a common requirement for pages to refer to popup components. If popup components are forced into the page, although it works functionally, there is no decoupling between the components and the page, which is not conducive to later maintenance and function expansion. Here’s an example to illustrate the downside.
< template > < div > < button @ click = "openModal ()" > click < / button > < Modal: is_open = "is_open @ close" = "close ()" / > < / div > </template> <script> import Modal from ".. /components/Modal/Modal"; Export default {components: {Modal,}, data(){return {is_open:false}}, methods: {openModal() {// display pop-up this.is_open = true; }, close(){this.is_open = false; this.is_open = false; }}}; </script>Copy the code
Modal is an externally introduced popup component, and the parent controls the popup hiding and showing through IS_open. A careful analysis of the above structure presents the following problems.
- Modal components are hardcoded to force on the parent component
components
Which is registered and rendered in the parent component’s template<Modal />
Imagine that a popup component needs to be written once in the parent component, and each of the five popups needs to be written five times in the parent template. The popup component should be decoupled from the parent component. It should not be written in the parent’s template. - The parent component needs to set a separate state
is_open
To control the pop-up display and hide, if the parent component needs to introduce more than one pop-up, it is bound to define more than one state to control the pop-up.
In order to decouple the popup from the parent, the ideal way is to use the idea of functional programming, where you only need to call a function within the parent to make the popup appear. Let’s see how to do that.
Pop-up component processing
Let’s implement a very simple but powerful utility function that encapsulates the popup component. If the parent component needs to use which popup component to call the function directly can be easily shown or hidden.
implementation
import Vue from 'vue';
export const createModal = (Component, props) => {
const vm = new Vue({
render: (h) =>
h(Component, {
props,
}),
}).$mount();
document.body.appendChild(vm.$el);
const ele = vm.$children[0];
ele.destroy = function() {
vm.$el.remove();
ele.$destroy();
vm.$destroy();
};
return ele;
};
Copy the code
Component
Is the popup component called by the parent component and passed in here as an argument.props
Is ultimately passed to the inside of the popup componentprops
new
aVue
Instance,render
In the function corresponding to the property,h
Is used to turn popup components into virtual DOM$mount
Be sure to call, which converts the virtual DOM into real DOM elementsvm.$el
Is the component that corresponds to the popup that comes inComponent
To render the real DOM, mount it under the body, and the page will display a pop-up box- It is not enough to show the popup, we also need to create a destroy method for the popup component
destroy
, includingvm.$children[0]
The corresponding is the popup componentvue
Instance, which can be calleddestroy
Finally, the instance is returned for an external call through which the properties and methods inside the popup component can be called.
application
As a test Demo, the component structure of the pop-up box is as follows. The content of the template is very simple. Render a header title and content. Define two methods show() and hide() to manipulate the is_open state to control the display and hide of the popup.
<template> <div class="modal" v-if="is_open"> <div class="content"> <p class="close" @click="hide()">close</p> <p class="title">{{ title }}</p> <div>{{ content }}</div> </div> </div> </template> <script> export default { props: ["title", "content"], data() { return { is_open: false, }; }, methods: { show() { this.is_open = true; }, hide() { this.is_open = false; ,}}}; <style lang="scss" scoped> .modal { position: fixed; top: 0; left: 0; right: 0; bottom: 0; Background-color: rgba(0, 0, 0, 0.6); .content { width: 200px; height: 200px; background-color: #fff; margin: 0px auto; margin-top: 200px; text-align: center; font-size: 14px; color: #333; padding: 5px; .title { margin-bottom: 20px; font-size: 16px; } .close { text-align: right; } } } </style>Copy the code
Page components
<template> <div class="test-v2"> < button@click ="openModal()"> Click </button> </div> </template> <script> import Modal from ".. /.. /components/Modal/Modal"; import { createModal } from ".. /.. /util/Modal"; Export default {methods: {openModal() {this.ele = createModal(Modal, {title: "popup ", content:" content ",}); this.ele.show(); }}};Copy the code
The page parent component can obtain the Modal instance this.ele of the popup component by calling the createModal method. This.ele gives you access to all the properties and methods inside the popup component, including show() and hide().
- After the above modification, the decoupling between the popup component and the parent component is realized. Pop-up components do not need to be registered in the parent component and rendered within the template.
- If the parent component needs to pass data to the popup component, you can use
createModal
The second argument object, which ends up withprops
Is injected into the interior of the pop-up component. show()
andhide()
Methods are defined inside the popup box and can be called directly by the parent component to control their display and hiding. In addition to the page destruction to call oncethis.ele.destroy()
To prevent memory leaks.
It is clear from the final DOM structure diagram that the popup is mounted below the body, not inside the page component. This makes it easier and more convenient to define some styles related to CSS positioning in the pop-up box, without being affected and interfered with by the page components.
extension
There are many other things that can be done on top of this, such as the message prompt.
The message prompt box is also a pop-up box. As a best practice, simply write a line of code Alert(“Hello World “) and the page will immediately pop up with a Hello World message. The effect is as follows.
implementation
The parent page structure looks like this. Call the Alert() function and the page displays a prompt box.
<template> <div class="test-v2"> <button @click="alert()">Alert</button> </div> </template> <script> import { Alert } from ".. /.. /util/Modal"; export default { methods: { alert() { Alert("Hello world"); ,}}}; </script>Copy the code
The Alert function is implemented as follows.
const alert_array = []; Export const Alert = (MSG, duration = 3000) => {let top = 100; If (alert_array. Length > 0) {const index = alert_array. Length; top = top + index * 50; } const ele = createModal(AlertComponent, { title: msg, top, }); alert_array.push(ele); const timer = setTimeout(() => { clearTimeout(timer); const index = alert_array.indexOf(ele); index ! == -1 && alert_array.splice(index, 1); ele.destroy(); }, duration); };Copy the code
AlertComponent
Is a custom disappear prompt component (to be introduced), calledcreateModal()
Get an instance of each prompt box stored in an arrayalert_array
In the.- Click the button once to bring up a message box, click the button a second time, the second message box should appear below the first box, so according to the array
alert_array
Dynamically calculates the absolute positioning top value, which is passed as an argument when creating the popup instance. - Timer control Removes the pop-up box after 3 seconds by default.
AlertComponent The contents of the AlertComponent are as follows: Top_value = “this.top-30” > < p style = “padding-top: 0px; padding-top: 0px; padding-top: 0px;
<template> <div class="alert-component" :style="{ top: `${top_value}px`, opacity: opacity }" > {{ title }} </div> </template> <script> export default { props: ["title", "top"], data() { return { top_value: this.top - 30, opacity: 0, }; }, mounted() { const timer = setTimeout(() => { clearTimeout(timer); this.top_value = this.top; this.opacity = 1; }); }}; </script> <style> .alert-component { height: 20px; border-radius: 4px; position: absolute; min-width: 300px; left: 50%; transform: translateX(-50%); background-color: #f0f9eb; color: #67c23a; align-items: center; padding: 10px 16px; The transition: all 0.25 s linear; opacity: 0; } </style>Copy the code
At the end
With the createModal tool function, not only the message prompt box, but also the message confirmation box, dynamic form mode box can be further encapsulated to simplify processing. When the pop-up box is decoupled from the page, the overall code logic becomes clearer, which is a huge benefit for later maintenance and extension.