C贸mo crear un di谩logo de confirmaci贸n en Vue.js

    Introducci贸n

    Un di谩logo de confirmaci贸n es un patr贸n de interfaz de usuario en el que se le dar谩 al usuario la opci贸n de continuar con su acci贸n o cancelarla. Se usa com煤nmente con acciones destructivas o irreversibles, para asegurarse de que el usuario realmente quiera continuar.

    En este art铆culo, implementaremos un di谩logo de confirmaci贸n modular y reutilizable en Vue.js.

    Creaci贸n de un componente emergente reutilizable

    Comencemos por crear un componente base reutilizable para cualquier tipo de componente emergente. De esa manera, no tenemos que volver a implementar la mec谩nica emergente varias veces. Esto se puede reutilizar m谩s tarde para crear cualquier cosa, desde un cuadro de alerta hasta una ventana emergente de bolet铆n.

    Comencemos con la plantilla:

    <!-- components/PopupModal.vue -->
    
    <template>
        <transition name="fade">
            <div class="popup-modal" v-if="isVisible">
                <div class="window">
                    <slot></slot>
                </div>
            </div>
        </transition>
    </template>
    

    Observe que agregamos un vac铆o <slot></slot> etiqueta a la plantilla. Esta etiqueta nos permite insertar cualquier contenido en el PopupModal elemento en el <slot></slot> etiqueta. Para leer m谩s sobre c贸mo funcionan las tragamonedas, consulte la Gu铆a de Vue en las tragamonedas.

    Tambi茅n hemos agregado el <transition name="fade"> etiqueta a la plantilla. Usaremos esto en la siguiente secci贸n para animar un efecto de aparici贸n / desaparici贸n gradual en el di谩logo.

    Luego, agregaremos el data(), open() y close() funciones de eventos:

    <!-- components/PopupModal.vue -->
    
    <script>
    export default {
        name: 'PopupModal',
    
        data: () => ({
            isVisible: false,
        }),
    
        methods: {
            open() {
                this.isVisible = true
            },
    
            close() {
                this.isVisible = false
            },
        },
    }
    </script>
    

    Y finalmente, agreguemos un poco de estilo:

    <!-- components/PopupModal.vue -->
    
    <style scoped>
    /* css class for the transition */
    .fade-enter-active,
    .fade-leave-active {
        transition: opacity 0.3s;
    }
    .fade-enter,
    .fade-leave-to {
        opacity: 0;
    }
    
    .popup-modal {
        background-color: rgba(0, 0, 0, 0.5);
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        padding: 0.5rem;
        display: flex;
        align-items: center;
        z-index: 1;
    }
    
    .window {
        background: #fff;
        border-radius: 5px;
        box-shadow: 2px 4px 8px rgba(0, 0, 0, 0.2);
        max-width: 480px;
        margin-left: auto;
        margin-right: auto;
        padding: 1rem;
    }
    </style>
    

    Animaci贸n de di谩logo de confirmaci贸n

    En la etiqueta de la plantilla ver谩 una etiqueta de transici贸n <transition name="fade">. Se utiliza para animar estados simples de entrada / salida. Todo lo que est茅 dentro de esta etiqueta se animar谩 si se agreg贸 o se quit贸 de la etiqueta.

    Estamos usando un condicional v-if="isVisible" para ocultar y mostrar la ventana emergente. Puede leer m谩s sobre esto en el Gu铆a de Vue sobre transiciones.

    Para especificar c贸mo cambia el contenido, hemos llamado a nuestra animaci贸n fade. Para implementar esta transici贸n en CSS, agregaremos clases con el prefijo del nombre fade, coincidiendo con nuestro name atributo del <transition> etiqueta.

    Todo lo que hace es animar la opacidad cuando la ventana emergente se cierra y se abre:

    .fade-enter-active,
    .fade-leave-active {
        transition: opacity 0.3s;
    }
    .fade-enter,
    .fade-leave-to {
        opacity: 0;
    }
    

    Heredar el componente emergente

    Para crear nuestro di谩logo de confirmaci贸n, heredaremos el PopupModal por composici贸n y personalice la ventana modal reutilizable para que se convierta en un di谩logo de confirmaci贸n.

    Creemos un nuevo archivo, components/ConfirmDialogue.vue y define una plantilla dentro de ella:

    <!-- components/ConfirmDialogue.vue -->
    
    <template>
        <popup-modal ref="popup">
            <h2 style="margin-top: 0">{{ title }}</h2>
            <p>{{ message }}</p>
            <div class="btns">
                <button class="cancel-btn" @click="_cancel">{{ cancelButton }}</button>
                <span class="ok-btn" @click="_confirm">{{ okButton }}</span>
            </div>
        </popup-modal>
    </template>
    

    Porque definimos el <slot></slot> etiqueta en el popup-modal componente, todo lo que ponemos entre sus etiquetas de componente (<popup-modal></popup-modal>) se representar谩 entre sus <slot> etiquetas en su lugar.

    Tambi茅n agregamos un ref="popup" al popup-modal etiqueta. Al establecer ese atributo, ahora podemos acceder al popup-modal instancia con this.$refs.popup. Usaremos esa referencia para llamar open() y close() en el modal emergente.

    Luego, implementemos los m茅todos del componente padre:

    <!-- components/ConfirmDialogue.vue -->
    
    <script>
    import PopupModal from './PopupModal.vue'
    
    export default {
        name: 'ConfirmDialogue',
    
        components: { PopupModal },
    
        data: () => ({
            // Parameters that change depending on the type of dialogue
            title: undefined,
            message: undefined, // Main text content
            okButton: undefined, // Text for confirm button; leave it empty because we don't know what we're using it for
            cancelButton: 'Go Back', // text for cancel button
            
            // Private variables
            resolvePromise: undefined,
            rejectPromise: undefined,
        }),
    
        methods: {
            show(opts = {}) {
                this.title = opts.title
                this.message = opts.message
                this.okButton = opts.okButton
                if (opts.cancelButton) {
                    this.cancelButton = opts.cancelButton
                }
                // Once we set our config, we tell the popup modal to open
                this.$refs.popup.open()
                // Return promise so the caller can get results
                return new Promise((resolve, reject) => {
                    this.resolvePromise = resolve
                    this.rejectPromise = reject
                })
            },
    
            _confirm() {
                this.$refs.popup.close()
                this.resolvePromise(true)
            },
    
            _cancel() {
                this.$refs.popup.close()
                this.resolvePromise(false)
                // Or you can throw an error
                // this.rejectPromise(new Error('User cancelled the dialogue'))
            },
        },
    }
    </script>
    

    Finalmente, agreguemos un poco de estilo para que se vea un poco mejor:

    <!-- components/ConfirmDialogue.vue -->
    
    <style scoped>
    .btns {
        display: flex;
        flex-direction: row;
        justify-content: space-between;
    }
    
    .ok-btn {
        color: red;
        text-decoration: underline;
        line-height: 2.5rem;
        cursor: pointer;
    }
    
    .cancel-btn {
        padding: 0.5em 1em;
        background-color: #d5eae7;
        color: #35907f;
        border: 2px solid #0ec5a4;
        border-radius: 5px;
        font-weight: bold;
        font-size: 16px;
        text-transform: uppercase;
        cursor: pointer;
    }
    </style>
    

    Uso del di谩logo de confirmaci贸n

    Para utilizar el di谩logo de confirmaci贸n, debe incluir solo el components/ConfirmDialogue.vue componente. Por ejemplo, creemos una p谩gina con un bot贸n ‘Eliminar’ que se asegure de si realmente desea eliminar otra p谩gina:

    <template>
        <div>
            <h1>Delete Page</h1>
            <button class="delete-btn" @click="doDelete">Delete Page</button>
            <confirm-dialogue ref="confirmDialogue"></confirm-dialogue>
        </div>
    </template>
    
    <script>
    import ConfirmDialogue from '../components/ConfirmDialogue.vue'
    
    export default {
        components: { ConfirmDialogue },
        methods: {
            async doDelete() {
                const ok = await this.$refs.confirmDialogue.show({
                    title: 'Delete Page',
                    message: 'Are you sure you want to delete this page? It cannot be undone.',
                    okButton: 'Delete Forever',
                })
                // If you throw an error, the method will terminate here unless you surround it wil try/catch
                if (ok) {
                    alert('You have successfully delete this page.')
                } else {
                    alert('You chose not to delete this page. Doing nothing now.')
                }
            },
        },
    }
    </script>
    
    <style scoped>
    .delete-btn {
        padding: 0.5em 1em;
        background-color: #eccfc9;
        color: #c5391a;
        border: 2px solid #ea3f1b;
        border-radius: 5px;
        font-weight: bold;
        font-size: 16px;
        text-transform: uppercase;
        cursor: pointer;
    }
    </style>
    

    Ya que estamos usando await en nuestro m茅todo para obtener el resultado del di谩logo de confirmaci贸n, necesitamos agregar async a nuestra definici贸n de m茅todo.

    Alternativamente, puede preferir el enfoque de estilo de promesa:

    this.$refs.confirmDialogue.show({
        title: 'Delete Page',
        message: 'Are you sure you want to delete this page? It cannot be undone.',
        okButton: 'Delete Forever',
    }).then((result) => {
        if (ok) {
            alert('You have successfully delete this page.')
        } else {
            alert('You chose not to delete this page. Doing nothing now.')
        }
    })
    

    Para ver por qu茅 hemos sugerido lanzar un error si el usuario cancela el di谩logo de confirmaci贸n, vea qu茅 tan fluido es el siguiente c贸digo:

    await this.$refs.confirmDialogue.show({
        title: 'Delete Page',
        message: 'Are you sure you want to delete this page? It cannot be undone.',
        okButton: 'Delete Forever',
    })
    alert('Deleting this page.')
    

    Dado que la cancelaci贸n no requiere ninguna acci贸n, simplemente no hay necesidad de manejar ese estado en absoluto. Y si decide manejar una solicitud de cancelaci贸n, simplemente envuelva ese c贸digo con un try/catch.

    Conclusi贸n

    En este art铆culo, definimos un componente emergente modal reutilizable en Vue.js y lo heredamos para implementar un di谩logo de confirmaci贸n. Luego, le agregamos animaciones con fines est茅ticos y ejecutamos un par de ejemplos de c贸mo usar el componente para solicitar informaci贸n a los usuarios.

     

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *