Vue implements Modal component based on Teleport

Vue implements Modal component based on Teleport

1. Get to know Teleport

For example, if we write global components such as Modal components, Message components, and Loading components without Teleport, and introduce them into a .vue file, their HTML structure will be added to the component template, which is not perfect.

  • No Teleport

  • Teleport

The following is a practical introduction on how to develop Modal components using Teleport

2. Basic usage of Teleport

The writing of Teleport is very simple. You just need to wrap the content with <Teleport></Teleport> and use to specify which parent node to hang the HTML under.

<teleport to="#modal">
Contents</teleport>

3. First step optimization

If we hard-code the DOM that Teleport is to mount in the code, then every time a global component is created, a DOM node will be required, and there will be more and more of them, and they will always exist. This writing method is not very elegant. A better solution is:

  • When creating a component, dynamically create a DOM node document.createElement().
  • And add it to the body, document.body.appendChild(),
  • Destroy this dom document.body.removeChild() when the component is uninstalled.
setup(){
  const node = document.createElement('div')
  node.id = 'modal'
  document.body.appendChild(node)
  onUnmounted(() => {
    document.body.removeChild(node)
  })
}

4. Second step optimization

If we want to add Message components, Loading components and other functions in the future, we will also need to use Teleport. It is a bit redundant to write such a piece of code in each component. Vue3 enables us to easily extract the logical functions, thereby achieving the purpose of logic reuse.

We create the useDOMCreate.ts file in the src-hooks folder to encapsulate this logic

// hooks/useDOMCreate.ts
import { onUnmounted } from 'vue'

function useDOMCreate(nodeId:string):void {
  const node = document.createElement('div')
  node.id = nodeId
  document.body.appendChild(node)
  onUnmounted(() => {
    document.body.removeChild(node)
  })
}
export default useDOMCreate

use:

import useDOMCreate from '../hooks/useDOMCreate'
setup(props, ctx) {
    useDOMCreate('modal')
}

5. Implement Modal component

The details of encapsulating the Modal component will not be discussed here, and there is no complicated logic. Directly on the code.

//Modal.vue
<template>
  <teleport to="#modal">
    <div class="modal d-block" tabindex="-1" v-if="isVisible">
      <div class="modal-dialog">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title">{{title}}</h5>
            <button type="button" class="close" data-dismiss="modal" aria-label="Close">
              <span aria-hidden="true" @click="onClose">&times;</span>
            </button>
          </div>
          <div class="modal-body">
            <slot></slot>
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-secondary" data-dismiss="modal" @click="onClose">Cancel</button>
            <button type="button" class="btn btn-primary" @click="onConfirm">Confirm</button>
          </div>
        </div>
      </div>
    </div>
  </teleport>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import useDOMCreate from '../hooks/useDOMCreate'
export default defineComponent({
  name: 'Modal',
  emits: ['model-close', 'model-confirm'],
  props: {
    title:
      type: String,
      default: ''
    },
    isVisible: {
      type: Boolean,
      default: false
    }
  },
  setup(props, ctx) {
    useDOMCreate('modal')
    const onClose = () => {
      ctx.emit('model-close')
    }
    const onConfirm = () => {
      ctx.emit('model-confirm')
    }
    return {
      onClose,
      onConfirm
    }
  }
})
</script>

Usage Examples

<template>
  <div class="post-detail-page">
    <button type="button" class="btn btn-danger" @click="handleDelete">Delete</button>
    <modal title='Are you sure to delete? ' :isVisible="modalVisible" @model-close="handleModalClose" @model-confirm="handleModalConfim">
      <p>Are you sure you want to delete this article? </p>
    </modal>
  </div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
import Modal from '../components/Modal.vue'

export default defineComponent({
  name: 'post-detail',
  components: { Modal },
  setup() {
    const modalVisible = ref(false)
    const handleDelete = () => {
      modalVisible.value = true
    }
    const hanldeModalClose = () => {
      modalVisible.value = false
    }
    const handleModalConfim = () => {
      modalVisible.value = false
      ...
     //Subsequent logical processing}
    return {
      hanldeModalClose,
      handleModalConfim,
      handleDelete,
      modalVisible
    }
  }
})
</script>

The above is the details of how vue implements Modal components based on Teleport. For more information about vue Teleport implementing Modal components, please pay attention to other related articles on 123WORDPRESS.COM!

You may also be interested in:
  • Detailed explanation of the use of Teleport in Vue3
  • Detailed explanation of how to use the vue3 Teleport instant movement function
  • Detailed explanation of the practice and principle of Vue3 Teleport
  • How to customize dialog and modal components in Vue3
  • Handwritten Vue pop-up window Modal implementation code
  • The modal component of iview in vue component has a problem: whether the modal is displayed or not should use v-show

<<:  How to reset the root password in mysql8.0.12

>>:  Implementation of the Pycharm installation tutorial on Ubuntu 18.04

Recommend

Prometheus monitors MySQL using grafana display

Table of contents Prometheus monitors MySQL throu...

MySQL 5.7.17 installation and configuration tutorial under CentOS6.9

CentOS6.9 installs Mysql5.7 for your reference, t...

Setting up shared folders in Ubuntu virtual machine of VMWare14.0.0

This is my first blog post. Due to time constrain...

How to create a responsive column chart using CSS Grid layout

I have been playing around with charts for a whil...

Detailed process of zabbix monitoring process and port through agent

Environment Introduction Operating system: centos...

JavaScript offsetParent case study

1. Definition of offsetParent: offsetParent is th...

How to restore docker container data

The project test environment database data is los...

Detailed explanation of CocosCreator project structure mechanism

Table of contents 1. Project folder structure 1. ...

Summary of Linux commands commonly used in work

Use more open source tools such as docker and kub...

In-depth understanding of the seven communication methods of Vue components

Table of contents 1. props/$emit Introduction Cod...

How to configure static network connection in Linux

Configuring network connectivity for Linux system...

How to change the encoding of MySQL database to utf8mb4

The utf8mb4 encoding is a superset of the utf8 en...