欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

vue3 teleport的使用案例详解

程序员文章站 2022-03-16 21:02:01
官网https://cli.vuejs.org/zh/guide/有时组件模板的一部分逻辑上属于该组件,而从技术角度来看,最好将模板的这一部分移动到 dom 中 vue app 之外的其他位置。案例这...

官网

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

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

案例

vue3 teleport的使用案例详解

vue3 teleport的使用案例详解

这两个组件都是在父元素里的,是父组件的子级,但是从技术角度来看,他们是应该是挂载在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>

布局

修改版

布局
vue3 teleport的使用案例详解

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