Realization of modal box component with vue

Keywords: Javascript Vue Mobile

Basically, every project needs to use modal box components. In recent projects, alert components and confirm are two completely different designs, so they are divided into two components. This paper mainly discusses the implementation of confirm components.

Component structure

<template>
    <div class="modal" v-show="show" transition="fade">
        <div class="modal-dialog">
            <div class="modal-content">
                <!--head-->
                <div class="modal-header">
                    <slot name="header">
                        <p class="title">{{modal.title}}</p>
                    </slot>
                    <a v-touch:tap="close(0)" class="close" href="javascript:void(0)"></a>
                </div>
                <!--Content area-->
                <div class="modal-body">
                    <slot name="body">
                        <p class="notice">{{modal.text}}</p>
                    </slot>
                </div>
                <!--tail,Operating button-->
                <div class="modal-footer">
                    <slot name="button">
                        <a v-if="modal.showCancelButton" href="javascript:void(0)" class="button {{modal.cancelButtonClass}}" v-touch:tap="close(1)">{{modal.cancelButtonText}}</a>
                        <a v-if="modal.showConfirmButton" href="javascript:void(0)" class="button {{modal.confirmButtonClass}}" v-touch:tap="submit">{{modal.confirmButtonText}}</a>
                    </slot>
                </div>
            </div>
        </div>
    </div>
    <div v-show="show" class="modal-backup" transition="fade"></div></template>

Modal frame structure is divided into three parts, namely, head, internal area and operation area, all provide slot s, which can be customized according to needs.

style

.modal {    position: fixed;    left: 0;    top: 0;    right: 0;    bottom: 0;    z-index: 1001;    -webkit-overflow-scrolling: touch;    outline: 0;    overflow: scroll;    margin: 30/@rate auto;
}.modal-dialog {    position: absolute;    left: 50%;    top: 0;    transform: translate(-50%,0);    width: 690/@rate;    padding: 50/@rate 40/@rate;    background: #fff;
}.modal-backup {    position: fixed;    top: 0;    right: 0;    bottom: 0;    left: 0;    z-index: 1000;    background: rgba(0, 0, 0, 0.5);
}

Here are just some basic styles, there is nothing to say. This project is on the mobile side, using Taobao's adaptive layout scheme, @rate is the conversion rate when cutting manuscripts.

Interface definition

/**
 * modal Modal interface parameters
 * @param {string} modal.title Modal box title
 * @param {string} modal.text Modal box content
 * @param {boolean} modal.showCancelButton Whether to display Cancel Button
 * @param {string} modal.cancelButtonClass Cancel button style
 * @param {string} modal.cancelButtonText Cancel button text
 * @param {string} modal.showConfirmButton Whether to display the confirmation button
 * @param {string} modal.confirmButtonClass Determine Button Style
 * @param {string} modal.confirmButtonText Determine the button label text
 */props: ['modalOptions'],computed: {    /**
     * Format the parameters entered by props and assign default values to the parameters
     */    modal: {
        get() {
            let modal = this.modalOptions;
            modal = {                title: modal.title || 'Tips',                text: modal.text,                showCancelButton: typeof modal.showCancelButton === 'undefined' ? true : modal.showCancelButton,                cancelButtonClass: modal.cancelButtonClass ? modal.showCancelButton : 'btn-default',                cancelButtonText: modal.cancelButtonText ? modal.cancelButtonText : 'cancel',                showConfirmButton: typeof modal.showConfirmButton === 'undefined' ? true : modal.cancelButtonClass,                confirmButtonClass: modal.confirmButtonClass ? modal.confirmButtonClass : 'btn-active',                confirmButtonText: modal.confirmButtonText ? modal.confirmButtonText : 'Determine',
            };            return modal;
        },
    },
},

The parameters of the interface are defined here. You can customize the title, content, whether to display buttons and buttons, and use a computer to control the default values of parameters.

Internal Method of Modal Frame

data() {    return {
        show: false,   // Whether to display modal box
        resolve: '',
        reject: '',
        promise: '',  // Save the promise object
    };
},
methods: {    /**
     * Determine that promise is a perfect state
     */
    submit() {        this.resolve('submit');
    },    /**
     * Close and determine promise as reject status
     * @param type {number} Close mode 0 means close button, 1 means cancel button close
     */
    close(type) {        this.show = false;        this.reject(type);
    },    /**
     * Show confirm pop-up and create promise object
     * @returns {Promise}
     */
    confirm() {        this.show = true;        this.promise = new Promise((resolve, reject) => {            this.resolve = resolve;            this.reject = reject;
        });        return this.promise;   //Return promise object and call parent component
    },
},

There are three methods defined in the modal box, the core part is confirm method, which is defined in the modal box, but it is called to the parent component using the modal box. This method returns a promise object and stores the resolve and reject in the data of the modal component. When clicking the cancel button, the reject state is determined and the modal box is closed. When the button is determined, the resolve state is determined, and the modal box is not closed. After the callback processing of the parent component of the modal component is completed, the modal box is manually controlled to close.

call

<!-- template --><confirm v-ref:dialog :modal-options.sync="modal"></confirm><!-- methods -->this.$refs.dialog.confirm().then(() => {
    // Callback processing by clicking the confirm button
    callback();
    this.$refs.dialog.show = false; 
}).catch(() => {
    // Callback Processing by Clicking Cancel Button
    callback();
});

Using v-ref to create an index makes it easy to get the method inside the modal box component. Such a modal box component is complete.

Other implementations

In the modal box component, it is more difficult to achieve when clicking on the confirm and cancel buttons, the parent callback processing, I do this component, but also refer to some of the actual implementation.

Using Event Forwarding

This method was implemented by my colleagues on the previous project, using $dispatch and $broadcast to distribute or broadcast events.

First receive the send event from dispatch in the root component, and then broadcast the event Name from the send event

events: {    /**
     * Forwarding events
     * @param  {string} eventName Event name
     * @param  {object} arg       Event parameters
     * @return {null}
     */
    'transmit': function (eventName, arg) {
        this.$broadcast(eventName, arg);
    }
},

Secondly, the modal box component receives the event name triggered by the confirm and Cancel buttons passed from the parent component, and triggers when the cancel and confirm buttons are clicked.

// Receive the event, get the event name events that need to cancel and confirm the button: {tip': function (obj) {this event.={
            cancel: obj.events.cancel,
            confirm: obj.events.confirm
        }
    }
}// Cancel button cancel: function () {this. $dispatch ('transmit', this. events. cancel);
}// Determine the button submit: function () {this. $dispatch ('transmit', this. events. submit);
}

The modal box is called in the parent component as follows:

this.$dispatch('transmit','tip',{
    events: {
        confirm: 'confirmEvent'
    }
});this.$once('confirmEvent',function() {
    callback();
}

The first step is to pass the tip event, pass the name of the event to the modal box, then use $once to listen for events triggered by the confirmation or cancellation button, and then call back after the event is triggered.

Does this method look dizzy? So vue 2.0 cancels $dispatch and $broadcast. We are still using $1.0 in recent projects, but we are no longer using $dispatch and $broadcast to facilitate future upgrades.

Use emit to trigger

This method comes from vue-bootstrap-modal, emit s an event when clicking the cancel and confirm buttons, and listens for the event directly on the component. The advantage of this method is that the event is easier to track.

// Determine the button OK () {this. $emit ('ok'); if (this. close WhenOK) {this. show = false;
    }
},// Cancel button cancel () {this. $emit ('cancel'); this. show = false;
},

Call:

<modal title="Modal Title" :show.sync="show" @ok="ok" @cancel="cancel">
    Modal Text
</modal>

But when we use it, we often encounter such a scenario. Within a component, we often use multiple dialog boxes. The dialog boxes may be just a little different in text and different callbacks. At this time, we need to write once for each dialog box in template, which is a bit troublesome.


Posted by donnierivera on Wed, 12 Jun 2019 11:09:03 -0700