什么是Teleport?——
是一个内置组件,它是一种能够将我们的模板渲染至指定DOM节点,不受父级style、v-show等属性影响,但data、prop数据依旧能够共用的技术;类似于 React 的 Portal。
主要解决的问题 因为Teleport节点挂载在其他指定的DOM节点下,完全不受父级style样式影响
有时我们可能会遇到这样的场景:一个组件模板的一部分在逻辑上从属于该组件,但从整个应用视图的角度来看,它在 DOM 中应该被渲染在整个 Vue 应用外部的其他地方。
这类场景最常见的例子就是全屏的模态框。理想情况下,我们希望触发模态框的按钮和模态框本身是在同一个组件中,因为它们都与组件的开关状态有关。但这意味着该模态框将与按钮一起渲染在应用 DOM 结构里很深的地方。这会导致该模态框的 CSS 布局代码很难写。
父组件App.vue
我是App组件
子组件Child.vue
我是Child组件
这是一个提示
现在来看没有问题
可是如果父元素加一个定位:
position: relative;
遮罩层就会变成这样
以后嵌套组件变多了,遮罩组件的父级组件存在定位语句是很正常的。如果能把这个组件渲染到body
标签的子标签就好了。这时就可以使用Teleport
组件。
to - string :必传
挂载的目标,只能是父级标签。兄弟、子级都会报错。
挂载目标必须是有效的查询选择器或 HTMLElement
disabled - boolean :非必传
是否禁用。true则挂载到目标节点下,false为当前位置。
动态变化 disabled 值时,只是位置会变动,内容并不会销毁重新渲染!
接收一个 to
prop 来指定传送的目标。to
的值可以是一个 CSS 选择器字符串,也可以是一个 DOM 元素对象。这段代码的作用就是告诉 Vue “把以下模板片段传送到 body
标签下”。
父组件App.vue
中使用组件的位置改成这样。
可以发现这个组件确实被渲染到body
标签下面了。
提示
挂载时,传送的
to
目标必须已经存在于 DOM 中。理想情况下,这应该是整个 Vue 应用 DOM 树外部的一个元素。如果目标元素也是由 Vue 渲染的,你需要确保在挂载之前先挂载该元素。
以下teleport例子将会报错!
teleport目标元素demo
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
以下官方代码列举写法。但是前面说过 “ 挂载目标必须是有效的查询选择器或 HTMLElement ”
实际填h1 h2等原生标签、以及自定义的标签都是没问题的。以下应该是官方文档的一个纰漏。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
关于样式: teleport
teleport挂载的目标即使不在当前组件,scoped 内的样式在 teleport 中是生效的。
原因:scoped 生成的唯一属性会作用于 teleport 内的各元素
试想下面这样的 HTML 结构:
<div class="outer">
<h3>Tooltips with Vue 3 Teleporth3>
<div>
<MyModal />
div>
div>
接下来我们来看看 modal-button
的实现。
<script setup>
import { ref } from 'vue'
const open = ref(false)
</script>
<template>
<button @click="open = true">Open Modal</button>
<div v-if="open" class="modal">
<p>Hello from the modal!</p>
<button @click="open = false">Close</button>
</div>
</template>
<style scoped>
.modal {
position: fixed;
z-index: 999;
top: 20%;
left: 50%;
width: 300px;
margin-left: -150px;
}
</style>
这个组件中有一个 当在初始 HTML 结构中使用这个组件时,会有一些潜在的问题: Hello from the modal! 我们也可以将 在某些场景下可能需要视情况禁用 这里的 一个可重用的模态框组件可能同时存在多个实例。对于此类场景,多个 比如下面这样的用例: 渲染的结果为: 参考 一个 This should be red 得出的 class 将被哈希化以避免冲突,实现了同样的将 CSS 仅作用于当前组件的效果。 参考 CSS Modules spec 以查看更多详情,例如 global exceptions 和 composition。 你可以通过给 自定义注入名称(多个可以用数组) 可以通过 单文件组件的 这个语法同样也适用于 ``,且支持 JavaScript 表达式 (需要用引号包裹起来): hello 实际的值会被编译成哈希化的 CSS 自定义属性,因此 CSS 本身仍然是静态的。自定义属性会通过内联样式的方式应用到组件的根元素上,并且在源值变更的时候响应式地更新。 当 转换为: 子组件的根元素# 使用 处于 scoped 样式中的选择器如果想要做更“深度”的选择,也即:影响到子组件,可以使用 :deep() 这个伪类 默认情况下,作用域样式不会影响到 在A组件修改class a 的颜色 默认情况下,作用域样式不会影响到 解决方案 slotted 在之前我们想加入全局 样式 通常都是新建一个style 标签 不加scoped 现在有更优雅的解决方案 如果想让其中一个样式规则应用到全局,比起另外创建一个 效果等同于上面 你也可以在同一个组件中同时包含作用域样式和非作用域样式: Scoped 样式不能代替 class。由于浏览器渲染各种各样 CSS 选择器的方式, 在递归组件中小心使用后代选择器! 对于一个使用了 首先抛出一个最暴力的方案,但这存在影响其他同名样式的风险。当你意识不到哪出问题的时候,就会让人抓狂。(不推荐的方案!) 涉及到异步组件加载了对应全局样式,又访问了其他页面,选择器相同时则会出现样式不以你预想的情况出现! vue2方案: 在 有些像 Sass 之类的预处理器无法正确解析 vue3 推荐方案: vue2的写法在vue3 仍然可以使用,但vue3 文档只写了 无论 代码案例解释: 按钮来触发打开模态框,和一个 class 名为
.modal
的 position: fixed
能够相对于浏览器窗口放置有一个条件,那就是不能有任何祖先元素设置了 transform
、perspective
或者 filter
样式属性。也就是说如果我们想要用 CSS transform
为祖先节点 z-index
受限于它的容器元素。如果有其他元素与 z-index
,则它会覆盖住我们的模态框。
提供了一个更简单的方式来解决此类问题,让我们不需要再顾虑 DOM 结构的问题。让我们用
改写一下
:
接收一个 to
prop 来指定传送的目标。to
的值可以是一个 CSS 选择器字符串,也可以是一个 DOM 元素对象。这段代码的作用就是告诉 Vue “把以下模板片段传送到 body
标签下”。
和 `` 结合使用来创建一个带动画的模态框。你可以看看这个示例。21.3 禁用 Teleport
。举例来说,我们想要在桌面端将一个组件当做浮层来渲染,但在移动端则当作行内组件。我们可以通过对
动态地传入一个 disabled
prop 来处理这两种不同情况。isMobile
状态可以根据 CSS media query 的不同结果动态地更新。21.4 多个 Teleport 共享目标
组件可以将其内容挂载在同一个目标元素上,而顺序就是简单的顺次追加,后挂载的将排在目标元素下更后面的位置上。
22.CSS功能
22.1 CSS Modules#
标签会被编译为 CSS Modules 并且将生成的 CSS class 作为
$style
对象暴露给组件:
22.1.1 自定义注入名称#
module
attribute 一个值来自定义注入 class 对象的属性名:
与组合式 API 一同使用#
useCssModule
API 在 setup()
和 中访问注入的 class。对于使用了自定义注入名称的
块,
useCssModule
接收一个匹配的 module
attribute 值作为第一个参数:
22.2 CSS 中的
v-bind()
# 标签支持使用
v-bind
CSS 函数将 CSS 的值链接到动态的组件状态:
22.3 组件作用域 CSS
22.3.1
标签带有
scoped
attribute 的时候,它的 CSS 只会影响当前组件的元素,和 Shadow DOM 中的样式封装类似。使用时有一些注意事项,不过好处是不需要任何的 polyfill。它的实现方式是通过 PostCSS 将以下内容:
scoped
后,父组件的样式将不会渗透到子组件中。不过,子组件的根节点会同时被父组件的作用域样式和子组件的作用域样式影响。这样设计是为了让父组件可以从布局的角度出发,调整其子组件根元素的样式。22.3.1 深度选择器
// 编译后
.a[data-v-f3f3eg9] .b {
/* ... */
}
22.3.3 插槽选择器
渲染出来的内容,因为它们被认为是父组件所持有并传递进来的。使用 :slotted
伪类以明确地将插槽内容作为选择器的目标:A.vue
App.vue
渲染出来的内容,因为它们被认为是父组件所持有并传递进来的。
22.3.4 全局选择器
,可以使用
:global
伪类来实现 (看下面的代码):
一定要写在scoped里面
22.3.5 混合使用局部与全局样式
22.3.6 注意
p { color: red }
结合作用域样式使用时 (即当与 attribute 选择器组合的时候) 会慢很多倍。如果你使用 class 或者 id 来替代,例如 .example { color: red }
,那你几乎就可以避免性能的损失。.a .b
选择器的样式规则来说,如果匹配到 .a
的元素包含了一个递归的子组件,那么所有的在那个子组件中的 .b
都会匹配到这条样式规则。22.4 组件修改子组件样式
// 全局样式
<style>
.customClassName{
color:red;
}
style>
内使用
>>>
或/deep/
,vue2时期我一直统一用的是/deep/
,避免>>>
无法解析的问题。>>>
。这种情况下你可以使用 /deep/
或 ::v-deep
操作符取而代之——两者都是>>>
的别名,同样可以正常工作。
// 或者
:deep()
这一个API案例,为了统一风格和提高规范,建议按照v3文档 使用·:deep()
。
>>> /deep/
还是 :deep()
都是写在 .el-dialog .el-dialog__body
前。此处进行原因分析、解释:data-v-7d766012
),并且编译后CSS选择器也会有这段唯一标识。注意!是组件自身的元素。不包括子组件、父组件!
// 编译结果如下
.a[data-v-f3f3eg9] .b .c{
/* ... */
}
.a是当前组件的类名,data-v-f3f3eg9 是当前组件的唯一标识, .b .c是你想影响的子组件的对应类名的样式!
这时候当前组件的.a自然匹配的上, .b .c 由于不存在父组件的唯一标识,自然也就匹配的上子组件对应的.b .c
!!如果是 .a[data-v-f3f3eg9] .b[data-v-f3f3eg9] .c
由于是唯一标识, .b自然不可能是 data-v-f3f3eg9
此时这就匹配不到子元素对应的class='b',自然也无法将样式作用于 class='c' !!
LabVIEW中编程更改进程的优先级
【软件设计师21天-考点整理】7)计算机系统构成及硬件基础知识
蓝桥杯---列名
火爆全网,22个web自动化测试疑难解答总结,一路狂飙...
Google Play 索引表
Llama3 中文通用 Agent 微调模型来啦!(附手把手微调实战教程)
【Unity入门计划】Collision2D类&Collider2D类
ES6 Map数据结构
Spring MVC 框架学习(八)---- SSM 框架整合