Vue样式篇
📦 Vue3
style
- 全称
v-bind:style
,简写:style
😃 如果样式需要浏览器前缀,Vue 会自动加上
也可以自己传递
1 | <div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div> |
- 如果浏览器不需要前缀,结果就只有
display: flex
传递对象
- 可用 camelCase 或者 kebab-cased
使用:style="{}"
或者是:style="[]"
绑定的样式
记得值也需要用
""
包住,React 中就不用。如果需要使用模板字符串,双引号换成**`**
常见使用:
1 | const activeColor = ref("red"); |
1 | <div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div> |
传递数组
在 JS 中写好的样式对象传递到行内的数组中
1 | <div :style="[baseStyles, overridingStyles]"></div> |
在组件上使用style
,组件内的根元素会继承组件上的样式。👉class 透传
class
- 全称
v-bind:class
,简写:class
记得值也需要用
""
包住
class
和:class
可同时存在,渲染后合并
1 | <div class="main-pane" :class="{ active: isActive }"></div> |
- 样式类
active
是否存在,取决于isActive
是否为 true - 和
style
一样,支持绑定对象或者计算属性,也支持数组
绑定数组的时候,还可以在数组里面嵌套对象
1 | <div :class="[{ active: isActive }, errorClass]"></div> |
组件上的 class
对于单根组件,组件上的class
会和组件内根元素的合并
1 | <!-- 子组件模板 --> |
1 | <!-- 在使用组件时 --> |
渲染结果
1 | <p class="foo bar baz boo">Hi!</p> |
对于多根组件,在组件内部需要使用$attr.class
来指定哪个根元素来接收
1 | <!-- MyComponent 模板使用 $attrs 时 --> |
1 | <MyComponent class="baz" /> |
要在 JS 中获取到,可以通过useAttrs()
在setup
中
1 | <script setup> |
不用setup
的话
1 | export default { |
不能用监听器来监听 attrs 的变化
<style>
标签
css 预处理器
<style lang='xx'></style>
:xx
一般会有 less, sass(使用的时候传scss)。
1 | <style lang="scss"> |
样式作用域
<style scoped></style>
:使得里面的样式仅在当前组件可用
- 在同一组件中,可和代表全局的
<style></style>
同时存在 - 谨慎使用后代选择器
1 | <style scoped> |
转换为:
1 | <style> |
- data-v-f3f3eg9 后面的哈希值根据文件的路径生成
使用了作用域之后,父组件样式不会影响子组件。不过为了布局考虑,子组件的根节点会受到影响
深度选择器::deep()
在scoped作用域里面,要选择子组件里面的内容,使用伪类:deep()
1 | <style scoped> |
括号里面的内容不需要用引号包起来
插槽选择器::slotted
默认情况下,scoped
不会影响到<slot/>
渲染出来的内容,因为它们被认为是父组件所持有并传递进来的。
要指定插槽的额内容
1 | <style scoped> |
全局选择器::global
就是让当前指定的选择器配置的样式全局范围内生效
1 | <style scoped> |
CSS Modules
<style module="xxx">
被编译成 CSS Module
- 在 CSS Module 里的内容会变成对象
- 直接
module
,使用默认名称$style
- 自定义名称
module="classes"
- 直接
- 可在
<template>
和<script setup>
中使用
在模板中使用
1 | <template> |
- 绑定的 class会进行哈希化
在 setup 中使用
1 | import { useCssModule } from "vue"; |
CSS 中的 v-bind
在<style>
中用来绑定<script>
中的值
1 | <script setup> |
动画
Vue 提供组件 <Transition>
和 <TransitionGroup>
来处理元素的
- 进入
- 离开
- 列表顺序变化
的过渡效果
<Transition>
,组件或元素进入或离开DOM 时应用动画<TransitionGroup>
,在一个v-for
列表的元素或组件被插入,移动,删除时应用动画
<Transition>
组件
仅支持单个元素或者一个单根组件
动画通过默认插槽传递给它包裹的元素或者组件上。触发条件:
v-if
v-show
<component>
切换的时候- 改变特殊的
key
属性
整个动画过程:
- Vue 会自动检测目标元素是否应用了 CSS 过渡或动画。则一些
CSS过渡class
(v-enter
那些)会在适当的时机被添加和移除。 - 如果有作为监听器的
JavaScript钩子
,这些钩子函数会在适当时机被调用。 - 上面两点都没,那么 DOM 的插入、删除操作将在浏览器的下一个动画帧后执行。
🚗 可用的属性和事件
属性
1 | interface TransitionProps { |
事件
- @before-enter
- @before-leave
- @enter
- @leave
- @appear
- @after-enter
- @after-leave
- @after-appear
- @enter-cancelled
- @leave-cancelled (v-show only)
- @appear-cancelled
基于 CSS 的过渡效果
CSS 过渡 class
v-enter-from
:进入动画的起始状态。在元素插入之前添加,在元素插入完成后的下一帧移除。v-enter-active
:进入动画的生效状态。应用于整个进入动画阶段。在元素被插入之前添加,在过渡或动画完成之后移除。这个 class 可以被用来定义进入动画的持续时间、延迟与速度曲线类型。v-enter-to
:进入动画的结束状态。在元素插入完成后的下一帧被添加 (也就是v-enter-from
被移除的同时),在过渡或动画完成之后移除。v-leave-from
:离开动画的起始状态。在离开过渡效果被触发时立即添加,在一帧后被移除。v-leave-active
:离开动画的生效状态。应用于整个离开动画阶段。在离开过渡效果被触发时立即添加,在过渡或动画完成之后移除。这个 class 可以被用来定义离开动画的持续时间、延迟与速度曲线类型。v-leave-to
:离开动画的结束状态。在一个离开动画被触发后的下一帧被添加 (也就是v-leave-from
被移除的同时),在过渡或动画完成之后移除。
使用name
属性声明一个过渡效果名来代替前缀v
:
1 | <Transition name="fade"> |
name
可动态绑定
搭配 css 自己的 tansition
属性;也可以使用 css 的animation
,一般都在*-enter-active
和*-leave
中使用
同时使用
transition
和animation
,需要在标签中使用type
属性传入两者之一,以告诉 Vue 需要关注哪种动画类型
1 | /* |
🎇 动画效果会直接应用在子元素上,此外还可以选择指定更深层次的子元素来触发动画效果
1 | <Transition name="nested"> |
1 | /* 应用于嵌套元素的规则 */ |
还可以单独拿出来,添加一个过渡延迟,以获得交错效果
1 | /* 延迟嵌套元素的进入以获得交错效果 */ |
通过向标签传递duration
来指定过渡的持续时间,以确保这个延迟会在这个动画周期中生效(如果在transitionend
和animationend
时间结束了,延迟都没到来)
1 | <Transition :duration="550">...</Transition> |
自定义过渡 class
向 <Transition>
传递以下的 props 来指定自定义的过渡 class:
- enter-from-class
- enter-active-class
- enter-to-class
- leave-from-class
- leave-active-class
- leave-to-class
在使用第三方 CSS 动画库的时候非常有用
1 | <!-- 假设你已经在页面中引入了 Animate.css --> |
JavaScript 钩子
也可与听过监听<Transition>
组件上的事件来实现动画
1 | <Transition |
1 | // 在元素被插入到 DOM 之前被调用 |
使用仅由 JavaScript 执行的动画时,可添加一个 :css="false"
,告诉 Vue 可跳过对 CSS 过渡的自动检测。使用之后:
@enter
和@leave
回调函数done
是必须的,否则钩子会被同步调用,过渡将立即完成
可复用
😃 可以向标签里面传递<slot>
来封装成可复用的过渡组件
1 | <!-- MyTransition.vue --> |
1 | <MyTransition> |
其他过渡效果
出现时过渡
初次渲染时应用一个过渡效果
1 | <Transition appear> |
元素间过渡
使用 v-if
/ v-else
/ v-else-if
在几个组件之间切换
1 | <Transition> |
过渡模式
想先执行离开动画,等它完成之后在执行元素的进入动画
1 | <Transition mode="out-in"> |
- 也支持
in-out
,但是不常用
组件之间过渡
1 | <Transition name="fade" mode="out-in"> |
性能考虑
多数使用transform
和opacity
- 因为不会影响到 DOM 结构
- 多数现代浏览器的
transform
动画会使用 GPU 进行硬件加速
相比之下height
、margin
这些会触发 CSS 布局变动,计算消耗就高了。🌏 查看更多
<TransitionGroup>
组件
和<Transition>
基本相同的属性、CSS 过渡 class、JavaScript 钩子
区别:
- 默认情况下不会生成容器元素;通过
tag
指定一个元素作为容器元素来渲染(外层自动生成的包裹层) - _过渡模式_(
mode
)不可用 - 列表中每个元素需要有唯一
key
- CSS 过渡 class 会被应用在列表上而不是容器元素上
在DOM 模板(html 文件或者 JS 片段)中使用时,需要使用
<transition-group>
1 | <TransitionGroup name="list" tag="ul"> |
1 | .list-move, /* 对移动中的元素应用的过渡 */ |
事件和<Transition>
一样
属性对比<Transition>
少了mode
,其他一样,并且多了两个:
1 | interface TransitionGroupProps extends Omit<TransitionProps, "mode"> { |
渐进延迟列表动画
- 通过读取元素的 data attribute
把每一个元素的索引渲染为该元素上的一个 data attribute
1 | <TransitionGroup |
在 JavaScript 钩子中,基于当前元素的 data attribute 对元素的进场动画添加一个延迟
1 | function onEnter(el, done) { |