• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

vue3 teleport的使用案例详解

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

官网

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使用内容请搜索极客世界以前的文章或继续浏览下面的相关文章希望大家以后多多支持极客世界!


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
node连接mysql查询事务处理的实现发布时间:2022-02-05
下一篇:
JavaScript面试之如何实现数组拍平(扁平化)方法发布时间:2022-02-05
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap