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

Example code for realizing charging effect of B station with css+svg

difficulty Two mask creation of svg graphics Firs...

Detailed description of the function of new in JS

Table of contents 1. Example 2. Create 100 soldie...

MySQL compression usage scenarios and solutions

Introduction Describes the use cases and solution...

How to use fdisk to partition disk in Linux

Commonly used commands for Linux partitions: fdis...

Linux parted disk partition implementation steps analysis

Compared with fdisk, parted is less used and is m...

How to use CURRENT_TIMESTAMP in MySQL

Table of contents Use of CURRENT_TIMESTAMP timest...

Install Docker on Centos7 (2020 latest version available, just copy and paste)

Refer to the official documentation here for oper...

MySQL database table and database partitioning strategy

First, let's talk about why we need to divide...

Summary of the use of html meta tags (recommended)

Meta tag function The META tag is a key tag in th...

Summary of 7 types of logs in MySQL

There are the following log files in MySQL: 1: re...

SVN installation and basic operation (graphic tutorial)

Table of contents 1. What is SVN 2. Svn server an...

Sample code for using CSS to write a textured gradient background image

The page length in the project is about 2000px or...

Detailed explanation of where the image pulled by docker is stored

20200804Addendum: The article may be incorrect. Y...

Create a custom system tray indicator for your tasks on Linux

System tray icons are still a magical feature tod...