vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > vue3 teleport使用

vue3 teleport的使用案例详解

作者:伤心小王子

这篇文章主要介绍了vue3 teleport的使用demo,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

官网

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

有时组件模板的一部分逻辑上属于该组件,而从技术角度来看,最好将模板的这一部分移动到 DOM 中 Vue app 之外的其他位置。

案例

在这里插入图片描述

在这里插入图片描述

这两个组件都是在父元素里的,是父组件的子级,但是从技术角度来看,他们是应该是挂载在body下面的

未修改版

<!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>我是父组件</div>
  <div>我是父组件</div>
  <div>我是父组件</div>
  <div>我是父组件</div>
  <div>我是父组件</div>
  <div>我是父组件</div>
  <button @click="handleClick">点我显示子组件</button>
  <cpn ref="compRef" @show-confirm="showConfirm"></cpn>
  <confirm ref="confirmRef" @confirm="handleConfirm" @cancel="handleCancel" text="确定退出吗"></confirm>
</div>
<!--点击按钮后显示的那个组件-->
<template id="mycpn">
  <transition name="list-fade">
    <div class="cpnContainer" v-show="isshow" @click.stop="handleClose()">
      <div class="inner-wrapper" @click.stop>
        用到了transition
        <div class="text">
          <div>我是inner-text</div>
          <div>我是inner-text</div>
          <div>我是inner-text</div>
          <div>我是inner-text</div>
          <div>我是inner-text</div>
        </div>
        <div class="close" @click="handleClose()">close</div>
      </div>
    </div>
  </transition>

</template>

<!--确认关闭confirm组件-->
<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: '确定'
      },
      cancelBtnText: {
        type: String,
        default: '取消'
      }
    },
    data() {
      return {
        // bbb: 145612
        isshow: false
      }
    },
    methods: {
      show() {
        this.isshow = true
      },
      hide() {
        this.isshow = false
        // 控制子组件的显示
      },
      // 点击按钮后向父组件派发事件
      confirm() {
        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() {
        // 父组件调用子组件的方法
        // this.$refs.compRef.show()
        this.$refs.compRef.show()
      },
      showConfirm() {
        console.log("fdsa")
        this.$refs.confirmRef.show()
      },
      // 点击取消或确定以后的逻辑
      handleConfirm() {
        this.$refs.compRef.hide()
      },
      handleCancel() {

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

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

    /*vue内置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);
    }


    /*子组件样式*/
    .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组件样式*/
    .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%);*/
    /*    !*p标签的margin top影响到了父元素 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>

布局

修改版

布局
在这里插入图片描述

<!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>我是父组件</div>
  <div>我是父组件</div>
  <div>我是父组件</div>
  <div>我是父组件</div>
  <div>我是父组件</div>
  <div>我是父组件</div>
  <button @click="handleClick">点我显示子组件</button>
  <cpn ref="compRef" @show-confirm="showConfirm"></cpn>
  <confirm ref="confirmRef" @confirm="handleConfirm" @cancel="handleCancel" text="确定退出吗"></confirm>
</div>
<!--点击按钮后显示的那个组件-->
<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>
          用到了transition
          <div class="text">
            <div>我是inner-text</div>
            <div>我是inner-text</div>
            <div>我是inner-text</div>
            <div>我是inner-text</div>
            <div>我是inner-text</div>
          </div>
          <div class="close" @click="handleClose()">close</div>
        </div>
      </div>
    </transition>
  </teleport>


</template>

<!--确认关闭confirm组件-->
<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: '确定'
      },
      cancelBtnText: {
        type: String,
        default: '取消'
      }
    },
    data() {
      return {
        // bbb: 145612
        isshow: false
      }
    },
    methods: {
      show() {
        this.isshow = true
      },
      hide() {
        this.isshow = false
        // 控制子组件的显示
      },
      // 点击按钮后向父组件派发事件
      confirm() {
        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() {
        // 父组件调用子组件的方法
        // this.$refs.compRef.show()
        this.$refs.compRef.show()
      },
      showConfirm() {
        console.log("fdsa")
        this.$refs.confirmRef.show()
      },
      // 点击取消或确定以后的逻辑
      handleConfirm() {
        this.$refs.compRef.hide()
      },
      handleCancel() {

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

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

    /*vue内置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);
    }


    /*子组件样式*/
    .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组件样式*/
    .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%);*/
    /*    !*p标签的margin top影响到了父元素 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>

案例用到的知识

父组件如何调用子组件方法 用ref拿到组件 调用组件里的方法就ok
关于事件阻止冒泡
子组件向父组件通信 派发事件(emit)
boxshadow
vue transition动画
疑问 confirm-zoom动画为什么不能放在container上 只能放在content上

到此这篇关于vue3 teleport的使用demo的文章就介绍到这了,更多相关vue3 teleport使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文