🧱 styled 起手式 >>>
先记住 `styled.tag`、`styled(Component)` 和 `styled('tag', propsDef)` 这三种入口,绝大多数写法都从这里展开。
创建元素组件
styled.div:直接创建原生标签组件styled(Component):为已有 Vue 组件包一层样式styled('button', buttonProps):同时声明标签和 props
import { styled } from "@vue-styled-components/core";
const buttonProps = {
variant: String,
block: Boolean,
};
const Button = styled("button", buttonProps)`
padding: 8px 14px;
border-radius: 10px;
border: none;
cursor: pointer;
width: ${(props) => (props.block ? "100%" : "auto")};
background: ${(props) =>
props.variant === "ghost" ? "#edf2f7" : "#2563eb"};
color: ${(props) =>
props.variant === "ghost" ? "#0f172a" : "#ffffff"};
`;
样式化已有组件
import { styled } from "@vue-styled-components/core";
import BaseCard from "./BaseCard.vue";
const ElevatedCard = styled(BaseCard)`
border-radius: 16px;
box-shadow: 0 12px 32px rgba(15, 23, 42, 0.12);
`;
🎛️ Props 与 attrs >>>
动态样式通常围绕 props 展开;`attrs` 负责补默认属性,`props()` 负责声明样式里会读取的字段。
声明样式用到的 props
styled('tag', propsDef):推荐,声明更集中styled.tag.props(propsDef)\:链式写法,适合已有标签入口- props 既能影响样式,也会传给目标组件
import { styled } from "@vue-styled-components/core";
const Input = styled.input.props({
invalid: Boolean,
size: String,
})`
border: 1px solid ${(props) => (props.invalid ? "#dc2626" : "#cbd5e1")};
padding: ${(props) => (props.size === "lg" ? "12px 14px" : "8px 10px")};
outline: none;
`;
预设属性
.attrs({ ... }):固定属性.attrs((props) => ({ ... })):根据 props 动态生成属性
import { styled } from "@vue-styled-components/core";
const SearchInput = styled.input
.attrs((props) => ({
type: "search",
placeholder: props.placeholder || "搜索关键字",
}))`
padding: 8px 12px;
border-radius: 999px;
border: 1px solid #cbd5e1;
`;
🎨 主题与 useTheme >>>
主题能力适合处理品牌色、语义色和间距体系;样式函数里直接读 `props.theme`,组合式逻辑里用 `useTheme()`。
ThemeProvider
import { ThemeProvider, styled } from "@vue-styled-components/core";
const theme = {
color: {
primary: "#2563eb",
text: "#0f172a",
surface: "#eff6ff",
},
};
const Panel = styled.section`
color: ${(props) => props.theme.color.text};
background: ${(props) => props.theme.color.surface};
border-left: 4px solid ${(props) => props.theme.color.primary};
padding: 16px;
`;
<template>
<ThemeProvider :theme="theme">
<Panel>主题样式</Panel>
</ThemeProvider>
</template>
在 setup 中读取主题
import { computed } from "vue";
import { useTheme } from "@vue-styled-components/core";
export function usePrimaryText() {
const theme = useTheme();
return computed(() => theme.value.color.primary);
}
♻️ 复用样式与 css >>>
当多处共享一段样式片段时,用 `css` 抽 mixin;当你要在已有组件基础上微调时,直接 `styled(Base)` 更省事。
抽出可复用片段
import { css, styled } from "@vue-styled-components/core";
const focusRing = css`
&:focus-visible {
outline: 3px solid rgba(37, 99, 235, 0.35);
outline-offset: 2px;
}
`;
const buttonBase = css`
border: none;
border-radius: 12px;
transition: transform 0.15s ease, box-shadow 0.15s ease;
&:hover {
transform: translateY(-1px);
}
`;
const PrimaryButton = styled.button`
${buttonBase}
${focusRing}
background: #2563eb;
color: #ffffff;
`;
在已有组件上继续扩展
import { styled } from "@vue-styled-components/core";
const BaseButton = styled.button`
padding: 8px 14px;
border-radius: 10px;
`;
const DangerButton = styled(BaseButton)`
background: #dc2626;
color: #ffffff;
`;
🌍 全局样式与动画 >>>
全局样式只适合放 reset、主题变量和页面级基线;动画用 `keyframes` 定义,再插入到具体组件里。
createGlobalStyle
import { createGlobalStyle } from "@vue-styled-components/core";
const GlobalStyle = createGlobalStyle`
:root {
color-scheme: light;
}
body {
margin: 0;
font-family: "Segoe UI", sans-serif;
background: #f8fafc;
color: #0f172a;
}
`;
keyframes
import { keyframes, styled } from "@vue-styled-components/core";
const fadeUp = keyframes`
from {
opacity: 0;
transform: translateY(8px);
}
to {
opacity: 1;
transform: translateY(0);
}
`;
const Toast = styled.div`
animation: ${fadeUp} 180ms ease-out;
`;
🔌 插件、前缀与性能 >>>
这一组能力偏工程向:自动前缀默认可用;插件用于介入 CSS 生成过程;性能配置适合大量动态样式场景。
自动前缀
- 默认会为需要兼容处理的 CSS 生成浏览器前缀
- 常规场景不需要手写浏览器私有前缀
import { styled } from "@vue-styled-components/core";
const FlexRow = styled.div`
display: flex;
user-select: none;
`;
注册插件
import { register } from "@vue-styled-components/core";
register({
afterBuild(css) {
return css.replaceAll("color:red", "color:#dc2626");
},
});
性能配置
import { configureStyleProcessing } from "@vue-styled-components/core";
configureStyleProcessing({
enableCache: true,
cacheSize: 2000,
enableBatchUpdates: true,
});
✅ 常见模式与坑 >>>
这几个点决定你写出来的是“可维护的动态样式”还是“难以收束的运行时 CSS”。
- props 只保留样式真正需要的字段,避免把整坨业务对象塞进样式函数
- 主题里优先放颜色、字号、间距 token,不要把页面级临时状态塞进主题对象
- createGlobalStyle 只处理全局基线,不要把组件局部规则挪进去
- 复用优先级通常是先抽 css 片段,再考虑复制大段模板字符串
- 复杂条件样式优先拆成多个小组件,而不是在一个模板字符串里塞过多三元表达式
import { css, styled } from "@vue-styled-components/core";
const ghost = css`
background: transparent;
color: #334155;
`;
const solid = css`
background: #2563eb;
color: #ffffff;
`;
const SmartButton = styled("button", {
variant: String,
})`
${(props) => (props.variant === "ghost" ? ghost : solid)}
`;