css作用域选择器标准化-:deep,:slotted,:global
:deep-穿透子组件内部,:slotted-影响插槽内容,:global-定义全局样式
javascript
<template>
<div class="parent-container">
<h2>Parent Component</h2>
<!-- 普通子组件 -->
<ChildComponent />
<!-- 带有插槽的子组件 -->
<ChildWithSlot>
<p class="slotted-content">This is slotted content!</p>
</ChildWithSlot>
<!-- 全局样式按钮 -->
<button class="global-button">A Global Styled Button</button>
</div>
</template>
<script setup>
import ChildComponent from './ChildComponent.vue';
import ChildWithSlot from './ChildWithSlot.vue';
</script>
<style scoped>
.parent-container {
padding: 20px;
background-color: #f9f9f9;
}
/* 1. :deep() - 穿透到子组件内部 */
.parent-container :deep(.child-text) {
color: red;
font-weight: bold;
}
/* 2. :slotted() - 影响插槽内容 */
:slotted(.slotted-content) {
background-color: lightblue;
padding: 5px;
border-radius: 3px;
}
/* 3. :global() - 定义全局样式 (即使在 scoped 内) */
:global(.global-button) {
background-color: #42b883; /* Vue Green */
color: white;
border: none;
padding: 10px 15px;
cursor: pointer;
border-radius: 5px;
}
</style>
ChildComponent.vue
javascript
<template>
<div class="child-wrapper">
<p class="child-text">This text should be red and bold.</p>
</div>
</template>
<style scoped>
.child-wrapper {
padding: 10px;
border: 1px solid #ccc;
}
.child-text {
color: initial; /* This will be overridden by parent's :deep() */
}
</style>
ChildWithSlot.vue
javascript
<template>
<div class="slot-wrapper">
<h4>Child With Slot:</h4>
<slot></slot>
</div>
</template>
<style scoped>
.slot-wrapper {
margin-top: 20px;
padding: 10px;
background-color: #eaeaea;
border-radius: 4px;
}
</style>
Composition API 集成 (useCssModule)
通过 useCssModule API 在 setup() 和 <script setup> 中访问注入的 class。使用了自定义注入名称的 <style module> 块,useCssModule 接收一个匹配的 module attribute 值作为第一个参数
javascript
import { useCssModule } from 'vue'
// 在 setup() 作用域中...
// 默认情况下,返回 <style module> 的 class
useCssModule()
// 具名情况下,返回 <style module="classes"> 的 class
useCssModule('classes')
javascript
<script setup lang="ts">
import { useCssModule } from 'vue'
const classes = useCssModule()
</script>
<template>
<p :class="classes.red">red</p>
</template>
<style module>
.red {
color: red;
}
</style>
Module默认情况-动态切换类
useCssModule结合computed,动态地根据状态(如 theme 是 light 还是 dark)来应用不同的CSS Modules类
javascript
<template>
<div :class="dynamicContainerClass">
<h1 :class="styles.title">{{ title }}</h1>
<p :class="styles.content">{{ content }}</p>
<button @click="toggleTheme">Switch to {{ currentTheme === 'light' ? 'Dark' : 'Light' }} Theme</button>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
import { useCssModule } from 'vue';
const title = ref('Themed Component');
const content = ref('This content changes its appearance based on the theme.');
const currentTheme = ref('light'); // 'light' or 'dark'
const styles = useCssModule(); // 获取 CSS Modules 对象
const toggleTheme = () => {
currentTheme.value = currentTheme.value === 'light' ? 'dark' : 'light';
};
// 计算属性,根据当前主题返回相应的类名数组
const dynamicContainerClass = computed(() => [
styles.container,
currentTheme.value === 'light' ? styles.lightTheme : styles.darkTheme
]);
</script>
<style module>
.container {
padding: 2rem;
border-radius: 8px;
transition: background-color 0.3s ease, color 0.3s ease; /* 平滑过渡 */
}
.lightTheme {
background-color: #ffffff;
color: #333333;
}
.darkTheme {
background-color: #2d2d2d;
color: #eeeeee;
}
.title {
font-size: 1.8rem;
margin-bottom: 1rem;
}
.content {
font-size: 1rem;
line-height: 1.6;
margin-bottom: 1.5rem;
}
</style>
Module具名情况-分离样式
在复杂的组件中,将基础样式,布局样式,主题样式等多种独立的样式分离到不同的css modules中便于管理
javascript
<template>
<div :class="[base.container, layout.grid, theme.cardTheme]">
<h2 :class="typography.heading">Card Title</h2>
<p :class="typography.bodyText">Card Content</p>
</div>
</template>
<script setup>
import { useCssModule } from 'vue';
// 分别获取不同功能的样式对象
const base = useCssModule('base');
const layout = useCssModule('layout');
const typography = useCssModule('typography');
const theme = useCssModule('theme');
</script>
<style module="base">
.container {
box-sizing: border-box;
/* Reset or base styles */
}
</style>
<style module="layout">
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
}
</style>
<style module="typography">
.heading {
font-size: 1.5rem;
font-weight: bold;
margin-bottom: 0.5rem;
}
.bodyText {
font-size: 1rem;
line-height: 1.5;
}
</style>
<style module="theme">
.cardTheme {
background-color: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 0.375rem;
padding: 1.5rem;
}
</style>
v-bind动态绑定CSS变量
实际应用-对于按钮、进度条、滑块等控件,根据其状态(如加载进度、激活状态、悬停效果等)动态调整样式。
javascript
<script setup>
import { ref, reactive } from 'vue';
const progressState = reactive({
percentage: 30, // 当前进度百分比
color: '#42b883'
});
// 模拟进度更新
setInterval(() => {
progressState.percentage = (progressState.percentage + 1) % 101;
if (progressState.percentage > 75) {
progressState.color = '#e74c3c'; // 进度高时变红
} else {
progressState.color = '#42b883'; // 否则保持绿色
}
}, 100);
</script>
<template>
<div class="progress-container">
<div class="progress-bar-bg">
<div
class="progress-bar-fill"
:style="{ width: progressState.percentage + '%' }"
></div>
</div>
<p>Progress: {{ progressState.percentage }}%</p>
</div>
</template>
<style scoped>
.progress-container {
width: 100%;
max-width: 400px;
margin: 20px auto;
}
.progress-bar-bg {
width: 100%;
height: 20px;
background-color: #eee;
border-radius: 10px;
overflow: hidden;
}
.progress-bar-fill {
height: 100%;
background-color: v-bind('progressState.color'); /* 动态颜色 */
transition: width 0.3s ease, background-color 0.3s ease; /* 平滑过渡 */
border-radius: inherit; /* 继承背景的圆角 */
}
p {
text-align: center;
margin-top: 10px;
}
</style>