Detailed use cases of vue3 teleport

Detailed use cases of vue3 teleport

Official Website

https://cli.vuejs.org/en/guide/

Sometimes there's a part of a component's template that logically belongs in that component, but from a technical perspective it's better to move that part of the template to another location in the DOM outside of the Vue app.

Case

insert image description here

insert image description here

Both components are in the parent element and are children of the parent component, but from a technical point of view, they should be mounted under the body

Unmodified version

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Vue3</title>
  <script src="./vue.js"></script>
</head>
<body>
<div id="hello-vue" class="box">
  <div>I am the parent component</div>
  <div>I am the parent component</div>
  <div>I am the parent component</div>
  <div>I am the parent component</div>
  <div>I am the parent component</div>
  <div>I am the parent component</div>
  <button @click="handleClick">Click me to show subcomponents</button>
  <cpn ref="compRef" @show-confirm="showConfirm"></cpn>
  <confirm ref="confirmRef" @confirm="handleConfirm" @cancel="handleCancel" text="Are you sure you want to exit?"></confirm>
</div>
<!--The component displayed after clicking the button-->
<template id="mycpn">
  <transition name="list-fade">
    <div class="cpnContainer" v-show="isshow" @click.stop="handleClose()">
      <div class="inner-wrapper" @click.stop>
        Using transition
        <div class="text">
          <div>I am inner-text</div>
          <div>I am inner-text</div>
          <div>I am inner-text</div>
          <div>I am inner-text</div>
          <div>I am inner-text</div>
        </div>
        <div class="close" @click="handleClose()">close</div>
      </div>
    </div>
  </transition>

</template>

<!--Confirm to close the confirm component-->
<template id="confirm">
  <transition name="confirm-fade">
    <div v-show="isshow" class="confirm">
      <div class="confirm-wrapper">
        <div class="confirm-content">
          <p>{{text}}</p>
          <div class="btnContainer">
            <button style="background-color: darkseagreen;margin-right: 40px" @click="confirm">{{confirmBtnText}}</button>
            <button @click="cancel">{{cancelBtnText}}</button>
          </div>
        </div>
      </div>
    </div>
  </transition>
</template>
<script>
  const cpn = {
    template: "#mycpn",
    props: {},
    data() {
      return {
        // bbb: 145612
        isshow: false
      }
    },
    methods: {
      show() {
        this.isshow = true
      },
      hide() {
        // console.log("hide")
        this.isshow = false
      },
      handleClose() {
        // console.log("hide")
        this.$emit("show-confirm")
      },

    }
  }

  const confirm = {
    template: "#confirm",
    props: {
      text: {
        type: String,
        default: 'fdsafdasfdas'
      },
      confirmBtnText: {
        type: String,
        default: 'OK'
      },
      cancelBtnText: {
        type: String,
        default: 'Cancel'
      }
    },
    data() {
      return {
        // bbb: 145612
        isshow: false
      }
    },
    methods: {
      show() {
        this.isshow = true
      },
      hide() {
        this.isshow = false
        //Control the display of subcomponents},
      // After clicking the button, dispatch the event confirm() to the parent component {
        this.hide();
        this.$emit("confirm")
      },
      cancel() {
        this.hide()
        this.$emit('cancel')
      }
    }
  }
  const HelloVueApp = Vue.createApp({
    data() {
      return {
        message: 'Hello Vue!!'
      }
    },
    components:
      cpn,
      confirm
    },
    methods: {
      handleClick() {
        // The parent component calls the child component's method // this.$refs.compRef.show()
        this.$refs.compRef.show()
      },
      showConfirm() {
        console.log("fdsa")
        this.$refs.confirmRef.show()
      },
      // Click Cancel or Confirm to execute the following logic handleConfirm() {
        this.$refs.compRef.hide()
      },
      handleCancel() {

      }
    }
  }).mount("#hello-vue")

</script>
</body>
<style>
    * {
        font-size: 50px;
    }

    /*vue built-in transition*/
    .list-fade-enter-active, .list-fade-leave-active {
        transition: opacity .3s;
    }

    .list-fade-enter-active .inner-wrapper, .list-fade-leave-active .inner-wrapper {
        transition: all .3s;
    }

    .list-fade-enter-from, .list-fade-leave-to {
        opacity: 0;
    }

    .list-fade-enter-from .inner-wrapper, .list-fade-leave-to .inner-wrapper {
        transform: translate3d(0, 100%, 0);
    }


    /*Subcomponent style*/
    .cpnContainer {
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        background: rgba(0, 0, 0, .3);
    }

    .inner-wrapper {
        padding: 70px;
        background-color: darkcyan;
        position: fixed;
        bottom: 0;
        width: 100%;
        box-sizing: border-box;
    }

    .close {
        position: absolute;
        top: 50px;
        right: 50px;
    }

    /*confirm component style*/
    .confirm {
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        background-color: rgba(0, 0, 0, 0.14);
    }

    .btnContainer {
        padding: 0 70px;
    }
    .confirm-wrapper{
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        z-index: 999;
        box-shadow: 0px 0px 80px 3px rgba(0, 0, 0, 0.2);
    }
    .confirm-content{
        overflow: hidden;
        width: 600px;
        border-radius: 13px;
        background: white
    }
    .confirm-content p {
        display: block;
        padding-left: 40px;
    }

    /*.confirm-content {*/
    /* border-radius: 8px;*/
    /* box-shadow: 0px 0px 80px 3px rgba(0, 0, 0, 0.2);*/
    /* position: absolute;*/
    /* top: 50%;*/
    /* left: 50%;*/
    /* transform: translate(-50%, -50%);*/
    /* !*The margin top of the p tag affects the parent element bfc*!*/
    /* !*overflow: hidden;*!*/
    /* background-color: white;*/
    /*}*/

    .confirm-content button {
        border: 1px solid cornflowerblue;
        background-color: transparent;
        padding: 25px 50px;
        margin-bottom: 30px;
        border-radius: 5px;
    }
    .confirm-fade-enter-active ,.confirm-fade-leave-active {
        transition: all .3s;
    }
    .confirm-fade-enter-from ,.confirm-fade-leave-to{
        opacity: 0;
    }
    .confirm-fade-enter-active .confirm-content {
        animation: confirm-zoom-in .3s;
        transform-origin: center;
    }
    .confirm-fade-leave-active .confirm-content {
        animation: confirm-zoom-out .3s;
        transform-origin: center;
    }

    @keyframes confirm-zoom-in {
        0% {

            transform: scale(0);
        }
        60% {
            transform: scale(1.1);
        }
        100% {
            transform: scale(1);
        }
    }
    @keyframes confirm-zoom-out {
        0% {
            transform: scale(1);
        }
        30% {
            transform: scale(0.4);
        }
        100% {
            transform: scale(0);
        }
    }

</style>
</html>

layout

Modified version

layout
insert image description here

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Vue3</title>
  <script src="./vue.js"></script>
</head>
<body>
<div id="hello-vue" class="box">
  <div>I am the parent component</div>
  <div>I am the parent component</div>
  <div>I am the parent component</div>
  <div>I am the parent component</div>
  <div>I am the parent component</div>
  <div>I am the parent component</div>
  <button @click="handleClick">Click me to show subcomponents</button>
  <cpn ref="compRef" @show-confirm="showConfirm"></cpn>
  <confirm ref="confirmRef" @confirm="handleConfirm" @cancel="handleCancel" text="Are you sure you want to exit?"></confirm>
</div>
<!--The component displayed after clicking the button-->
<template id="mycpn">
  <teleport to="body">
    <transition name="list-fade">
      <div class="cpnContainer" v-show="isshow" @click.stop="handleClose()">
        <div class="inner-wrapper" @click.stop>
          Using transition
          <div class="text">
            <div>I am inner-text</div>
            <div>I am inner-text</div>
            <div>I am inner-text</div>
            <div>I am inner-text</div>
            <div>I am inner-text</div>
          </div>
          <div class="close" @click="handleClose()">close</div>
        </div>
      </div>
    </transition>
  </teleport>


</template>

<!--Confirm to close the confirm component-->
<template id="confirm">
  <teleport to="body">
    <transition name="confirm-fade">
      <div v-show="isshow" class="confirm">
        <div class="confirm-wrapper">
          <div class="confirm-content">
            <p>{{text}}</p>
            <div class="btnContainer">
              <button style="background-color: darkseagreen;margin-right: 40px" @click="confirm">{{confirmBtnText}}</button>
              <button @click="cancel">{{cancelBtnText}}</button>
            </div>
          </div>
        </div>
      </div>
    </transition>
  </teleport>

</template>
<script>
  const cpn = {
    template: "#mycpn",
    props: {},
    data() {
      return {
        // bbb: 145612
        isshow: false
      }
    },
    methods: {
      show() {
        this.isshow = true
      },
      hide() {
        // console.log("hide")
        this.isshow = false
      },
      handleClose() {
        // console.log("hide")
        this.$emit("show-confirm")
      },

    }
  }

  const confirm = {
    template: "#confirm",
    props: {
      text: {
        type: String,
        default: 'fdsafdasfdas'
      },
      confirmBtnText: {
        type: String,
        default: 'OK'
      },
      cancelBtnText: {
        type: String,
        default: 'Cancel'
      }
    },
    data() {
      return {
        // bbb: 145612
        isshow: false
      }
    },
    methods: {
      show() {
        this.isshow = true
      },
      hide() {
        this.isshow = false
        //Control the display of subcomponents},
      // After clicking the button, dispatch the event confirm() to the parent component {
        this.hide();
        this.$emit("confirm")
      },
      cancel() {
        this.hide()
        this.$emit('cancel')
      }
    }
  }
  const HelloVueApp = Vue.createApp({
    data() {
      return {
        message: 'Hello Vue!!'
      }
    },
    components:
      cpn,
      confirm
    },
    methods: {
      handleClick() {
        // The parent component calls the child component's method // this.$refs.compRef.show()
        this.$refs.compRef.show()
      },
      showConfirm() {
        console.log("fdsa")
        this.$refs.confirmRef.show()
      },
      // Click Cancel or Confirm to execute the following logic handleConfirm() {
        this.$refs.compRef.hide()
      },
      handleCancel() {

      }
    }
  }).mount("#hello-vue")

</script>
</body>
<style>
    * {
        font-size: 50px;
    }

    /*vue built-in transition*/
    .list-fade-enter-active, .list-fade-leave-active {
        transition: opacity .3s;
    }

    .list-fade-enter-active .inner-wrapper, .list-fade-leave-active .inner-wrapper {
        transition: all .3s;
    }

    .list-fade-enter-from, .list-fade-leave-to {
        opacity: 0;
    }

    .list-fade-enter-from .inner-wrapper, .list-fade-leave-to .inner-wrapper {
        transform: translate3d(0, 100%, 0);
    }


    /*Subcomponent style*/
    .cpnContainer {
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        background: rgba(0, 0, 0, .3);
    }

    .inner-wrapper {
        padding: 70px;
        background-color: darkcyan;
        position: fixed;
        bottom: 0;
        width: 100%;
        box-sizing: border-box;
    }

    .close {
        position: absolute;
        top: 50px;
        right: 50px;
    }

    /*confirm component style*/
    .confirm {
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        background-color: rgba(0, 0, 0, 0.14);
    }

    .btnContainer {
        padding: 0 70px;
    }
    .confirm-wrapper{
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        z-index: 999;
        box-shadow: 0px 0px 80px 3px rgba(0, 0, 0, 0.2);
    }
    .confirm-content{
        overflow: hidden;
        width: 600px;
        border-radius: 13px;
        background: white
    }
    .confirm-content p {
        display: block;
        padding-left: 40px;
    }

    /*.confirm-content {*/
    /* border-radius: 8px;*/
    /* box-shadow: 0px 0px 80px 3px rgba(0, 0, 0, 0.2);*/
    /* position: absolute;*/
    /* top: 50%;*/
    /* left: 50%;*/
    /* transform: translate(-50%, -50%);*/
    /* !*The margin top of the p tag affects the parent element bfc*!*/
    /* !*overflow: hidden;*!*/
    /* background-color: white;*/
    /*}*/

    .confirm-content button {
        border: 1px solid cornflowerblue;
        background-color: transparent;
        padding: 25px 50px;
        margin-bottom: 30px;
        border-radius: 5px;
    }
    .confirm-fade-enter-active ,.confirm-fade-leave-active {
        transition: all .3s;
    }
    .confirm-fade-enter-from ,.confirm-fade-leave-to{
        opacity: 0;
    }
    .confirm-fade-enter-active .confirm-content {
        animation: confirm-zoom-in .3s;
        transform-origin: center;
    }
    .confirm-fade-leave-active .confirm-content {
        animation: confirm-zoom-out .3s;
        transform-origin: center;
    }

    @keyframes confirm-zoom-in {
        0% {

            transform: scale(0);
        }
        60% {
            transform: scale(1.1);
        }
        100% {
            transform: scale(1);
        }
    }
    @keyframes confirm-zoom-out {
        0% {
            transform: scale(1);
        }
        30% {
            transform: scale(0.4);
        }
        100% {
            transform: scale(0);
        }
    }

</style>
</html>

Knowledge used in the case

How does the parent component call the child component method? Use ref to get the component and call the method in the component.
About events to prevent bubbling child components from sending events to parent components (emit)
boxshadow
Vue transition animation question: Why can't the confirm-zoom animation be placed on the container but only on the content?

This is the end of this article about the demo of using vue3 teleport. For more relevant content about using vue3 teleport, please search the previous articles of 123WORDPRESS.COM or continue to browse the related articles below. I hope you will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Detailed explanation of how to use Teleport, a built-in component of Vue3
  • Detailed explanation of the use of Teleport in Vue3
  • Detailed explanation of how to use the vue3 Teleport instant movement function

<<:  MySQL EXPLAIN statement usage examples

>>:  Basic HTML directory problem (difference between relative path and absolute path)

Recommend

The process of deploying a project to another host using Jenkins

environment Hostname ip address Serve Jenkins 192...

Improving the effect of hyperlinks in web design and production

Hyperlinks enable people to jump instantly from pa...

Detailed explanation of the solution to font blur when using transform in CSS3

This question is very strange, so I will go strai...

CSS3 achieves conic-gradient effect

grammar: background-image: conic-gradient(from an...

Three solutions for sub-functions accessing external variables in JavaScript

Preface When we write web pages, we will definite...

Detailed explanation of Vue filters

<body> <div id="root"> <...

Use HTML and CSS to create your own warm man "Dabai"

The final result is like this, isn’t it cute… PS:...

How to use echarts to visualize components in Vue

echarts component official website address: https...

How to set a dotted border in html

Use CSS styles and HTML tag elements In order to ...

9 Practical CSS Properties Web Front-end Developers Must Know

1. Rounded Corners Today's web designs are con...

Two ways to build a private GitLab using Docker

The first method: docker installation 1. Pull the...

About 3 common packages of rem adaptation

Preface I wrote an article about rem adaptation b...

Play mp3 or flash player code on the web page

Copy code The code is as follows: <object id=&...

MySQL view introduction and basic operation tutorial

Preface View is a very useful database object in ...