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