上一篇:
15.0 vue3 provide&inject跨组件通信方式_十一月的萧邦-CSDN博客上一篇:14.0 vue3 customRef的使用_十一月的萧邦-CSDN博客上一篇:vue3 toRaw&markRawhttps://blog.csdn.net/qq_42543244/article/details/122793302本篇记录vue3的customRef,customRef是vue3的一大亮点,custom的意思大家都懂,自定义的意思,一旦出现自定义,那么就代表我们可以做很多基于自己的需求的操作,vue3的官方文档的关于这块的示例其实已经蛮不错了,看代码需求是这样,我们需https://blog.csdn.net/qq_42543244/article/details/122869521本篇记录vue3中新标签 Teleport标签,并且来封装一个dialog组件,最后呈现效果:
dialog组件内将会有之前记录学习的知识内容,props传值,slot的使用,refs的调用方式以及Teleport标签等等
文件目录:
App.vue
<template>
<div class="grand">
<h1>我是app</h1>
<child></child>
</div>
</template>
<script>
import Child from "@/components/Child.vue";
export default {
name: "App",
components: {
Child,
},
/*
Fragment:
·在vue2中我们必须要有一个根标签,
·vue3中我们可以没有根标签,内部会将多个标签包含在一个Fragment虚拟元素中
好处:减少标签层级,减小内存占用(多少能较少点吧...)
Teleport:
是一种能够将我们的模板移动到 DOM 中 Vue app 之外的其他位置的技术
场景:像 modals,toast 等这样的元素,很多情况下,我们将它完全的和我们的 Vue 应用的 DOM 完全剥离,管理起来反而会方便容易很多
原因在于如果我们嵌套在 Vue 的某个组件内部,那么处理嵌套组件的定位、z-index 和样式就会变得很困难
另外,像 modals,toast 等这样的元素需要使用到 Vue 组件的状态(data 或者 props)的值
这就是 Teleport 派上用场的地方
传送,瞬间移动,玩过lol,王者荣耀的朋友可以稍微联想一哈
*/
};
</script>
<style scoped>
.grand {
background-color: rgb(150, 156, 154);
padding: 50px;
}
</style>
Child.vue
<template>
<div class="child">
<h2>我是child</h2>
<button @click="showDialog">显示弹出框木兰辞</button>
<my-dialog ref="refDialog" :id="123" @confirm="confirm" title="木兰辞">
<template v-slot:content>
<div class="msg">
唧唧复唧唧,木兰当户织。不闻机杼声,唯闻女叹息。
问女何所思,问女何所忆。女亦无所思,女亦无所忆。昨夜见军帖,可汗大点兵,军书十二卷,卷卷有爷名。阿爷无大儿,木兰无长兄,愿为市鞍马,从此替爷征。
东市买骏马,西市买鞍鞯,南市买辔头,北市买长鞭。旦辞爷娘去,暮宿黄河边,不闻爷娘唤女声,但闻黄河流水鸣溅溅。旦辞黄河去,暮至黑山头,不闻爷娘唤女声,但闻燕山胡骑鸣啾啾。
万里赴戎机,关山度若飞。朔气传金柝,寒光照铁衣。将军百战死,壮士十年归。
归来见天子,天子坐明堂。策勋十二转,赏赐百千强。可汗问所欲,木兰不用尚书郎,愿驰千里足,送儿还故乡。
爷娘闻女来,出郭相扶将;阿姊闻妹来,当户理红妆;小弟闻姊来,磨刀霍霍向猪羊。开我东阁门,坐我西阁床,脱我战时袍,著我旧时裳。当窗理云鬓,对镜帖花黄。出门看火伴,火伴皆惊忙:同行十二年,不知木兰是女郎。
雄兔脚扑朔,雌兔眼迷离;双兔傍地走,安能辨我是雄雌?
</div>
</template>
</my-dialog>
<son></son>
</div>
</template>
<script>
import Son from "./Son.vue";
import MyDialog from "./MyDialog.vue";
import {ref} from "vue";
export default {
components: {Son, MyDialog},
setup() {
let refDialog = ref(null);
function showDialog() {
refDialog.value.open();
}
function confirm() {
console.log("点击了确定按钮");
refDialog.value.close();
}
return {refDialog, showDialog, confirm};
},
};
</script>
<style scoped>
.child {
background-color: rgb(22, 129, 201);
padding: 50px;
}
</style>
Son.vue
<template>
<h3 class="son">我是son</h3>
<button @click="showDialog">显示弹出框出师表</button>
<my-dialog ref="refDialog" :id="123" @confirm="confirm" title="出师表">
<template v-slot:content>
<div class="msg">
先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气,不宜妄自菲薄,引喻失义,以塞忠谏之路也。
宫中府中,俱为一体,陟罚臧否,不宜异同。若有作奸犯科及为忠善者,宜付有司论其刑赏,以昭陛下平明之理,不宜偏私,使内外异法也。
侍中、侍郎郭攸之、费祎、董允等,此皆良实,志虑忠纯,是以先帝简拔以遗陛下。愚以为宫中之事,事无大小,悉以咨之,然后施行,必能裨补阙漏,有所广益。
将军向宠,性行淑均,晓畅军事,试用于昔日,先帝称之曰能,是以众议举宠为督。愚以为营中之事,悉以咨之,必能使行阵和睦,优劣得所。
亲贤臣,远小人,此先汉所以兴隆也;亲小人,远贤臣,此后汉所以倾颓也。先帝在时,每与臣论此事,未尝不叹息痛恨于桓、灵也。侍中、尚书、长史、参军,此悉贞良死节之臣,愿陛下亲之信之,则汉室之隆,可计日而待也。
臣本布衣,躬耕于南阳,苟全性命于乱世,不求闻达于诸侯。先帝不以臣卑鄙,猥自枉屈,三顾臣于草庐之中,咨臣以当世之事,由是感激,遂许先帝以驱驰。后值倾覆,受任于败军之际,奉命于危难之间,尔来二十有一年矣。
先帝知臣谨慎,故临崩寄臣以大事也。受命以来,夙夜忧叹,恐托付不效,以伤先帝之明,故五月渡泸,深入不毛。今南方已定,兵甲已足,当奖率三军,北定中原,庶竭驽钝,攘除奸凶,兴复汉室,还于旧都。此臣所以报先帝而忠陛下之职分也。至于斟酌损益,进尽忠言,则攸之、祎、允之任也。
愿陛下托臣以讨贼兴复之效,不效,则治臣之罪,以告先帝之灵。若无兴德之言,则责攸之、祎、允等之慢,以彰其咎;陛下亦宜自谋,以咨诹善道,察纳雅言。深追先帝遗诏,臣不胜受恩感激。
今当远离,临表涕零,不知所言。
</div>
</template>
</my-dialog>
</template>
<script>
import MyDialog from "./MyDialog.vue";
import {ref} from "vue";
export default {
components: {MyDialog},
setup() {
let refDialog = ref(null);
function showDialog() {
refDialog.value.open();
}
function confirm() {
console.log("点击了确定按钮");
refDialog.value.close();
}
return {refDialog, showDialog, confirm};
},
};
</script>
<style scoped>
.son {
background-color: rgb(218, 199, 29);
padding: 20px 0;
}
.msg {
color: brown;
line-height: 30px;
}
</style>
MyDialog.vue
<template>
<teleport to="body">
<div class="mask" v-if="isShow">
<div class="dialog">
<div class="header">{{ title }}</div>
<div class="content">
<slot name="content"></slot>
</div>
<div class="footer">
<button @click="close">取消</button>
<button @click="confirm">确定</button>
</div>
</div>
</div>
</teleport>
</template>
<script>
/*
使用teleport移动至设置元素所在位置
*/
import { ref } from "vue";
export default {
props: {
id: {
type: Number,
default: null,
},
title: {
type: String,
default: "提示",
},
},
emits: ["confirm"],
setup(props, { emit }) {
let isShow = ref(false);
getData();
function getData() {
console.log("拿到的id===>", props.id);
}
function open() {
isShow.value = true;
}
function close() {
isShow.value = false;
}
function confirm() {
emit("confirm");
}
return { isShow, open, close, confirm };
},
};
</script>
<style scoped>
.mask {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 99;
}
.dialog {
width: 500px;
background-color: #fff;
border-radius: 10px;
padding: 20px;
}
.header {
text-align: center;
font-size: 23px;
font-weight: bold;
}
.content {
max-height: 300px;
overflow: auto;
margin: 20px 0;
}
.footer {
display: flex;
align-items: center;
justify-content: flex-end;
height: 50px;
}
.footer > button {
margin-left: 10px;
width: 80px;
height: 30px;
}
</style>
可能还会有人疑惑,Teleport标签到底有什么用?请看下图
去掉teleport标签对,审查元素,看看弹出框的位置
可以看出来dialog元素在引用的父组件下,但是这样带来的效果并不是很好,比如会被父组件中的某些css样式影响到,在elementui的dialog组件中我们会见到这两个属性
在vue3中我们利用teleport可以轻易的达到此目的,请看加上teleport后,dialog组件已经和app处于同级关系
结束!!!