Vite + Vue 3 项目中使用 Shoelace
在 Vite + Vue 3 项目中使用 Shoelace 非常简单,它基于 Web Components,可直接以原生方式集成到 Vue 项目中,无需额外封装。
✅ 使用 Shoelace 的步骤(适用于 Vite + Vue 3 项目)
1️⃣ 安装 Shoelace
npm install @shoelace-style/shoelace2️⃣ 在 main.ts 中引入 Shoelace 样式和组件定义
// main.ts
import { createApp } from 'vue'
import App from './App.vue'
// 样式引入
import '@shoelace-style/shoelace/dist/themes/light.css'
// 全局注册 Shoelace 组件(方式一:全部引入)
import { setBasePath } from '@shoelace-style/shoelace/dist/utilities/base-path.js'
import '@shoelace-style/shoelace/dist/shoelace.js'
// 设置资源路径(图标、动态样式等)
setBasePath('/node_modules/@shoelace-style/shoelace/dist')
createApp(App).mount('#app')3️⃣ 在组件中直接使用 Web Components 语法
<!-- AccordionDemo.vue -->
<template>
<sl-details summary="点击展开">
<p>这是 Shoelace 折叠面板的内容。</p>
</sl-details>
</template>4️⃣ Vue 警告处理(可选)
在 shims-vue.d.ts 中添加 Shoelace 的自定义元素类型支持(避免警告):
// shims-vue.d.ts
declare namespace JSX {
interface IntrinsicElements {
'sl-details': any
}
}或者在 tsconfig.json 中设置:
"compilerOptions": {
"types": ["vite/client", "@shoelace-style/shoelace"]
}🔧 如果你使用 <script setup> 并想要更智能的类型提示
可以使用 defineCustomElement 配合 ref 来操作 Shoelace 组件(需要时再补)。
🧪 示例效果
使用 <sl-details summary="More info">...</sl-details> 组件后会看到一个美观可展开的面板,带动画和样式。
🏆 接下来我们实现一个折叠面板中放入vue3组件的示例
在 Shoelace 的折叠面板 <sl-details> 中放入 Vue 3 组件**,因为 Shoelace 是基于 Web Components 构建的,它的 slot 支持和原生 DOM 一致,而 Vue 的模板最终渲染的也是 DOM 元素。
✅ 示例:Shoelace 折叠面板中嵌套 Vue 组件
1️⃣ 先定义一个 Vue 组件,例如 MyCard.vue
<!-- MyCard.vue -->
<template>
<div class="my-card">
<h3>{{ title }}</h3>
<p>{{ content }}</p>
</div>
</template>
<script setup lang="ts">
defineProps<{
title: string
content: string
}>()
</script>
<style scoped>
.my-card {
border: 1px solid #ccc;
padding: 12px;
border-radius: 8px;
}
</style>2️⃣ 在父组件中使用 <sl-details> 包裹 MyCard
<!-- AccordionWithComponent.vue -->
<template>
<sl-details summary="点击展开 Vue 组件">
<MyCard title="Vue 卡片" content="这是一段嵌套在折叠面板中的 Vue 组件内容。" />
</sl-details>
</template>
<script setup lang="ts">
import MyCard from './MyCard.vue'
</script>⚠️ 注意事项
✅ 正确渲染 Vue 插槽到 Web Components 的 slot
Shoelace 使用原生的 <slot>,Vue 的子组件会自动被渲染进去,只要不是用到 Shadow DOM 隔离的奇特用法,就不会有问题。
⚠️ 动态组件或 Teleport 需要注意作用域和 DOM 附着位置,建议放在非 Shadow DOM 的 Web Components 中。
✅ 若有动画失效、样式错乱问题,可以:
- 检查组件是否作用于 shadow DOM(Shoelace 默认不影响内部插槽)
- 使用
v-cloak或v-show控制内容加载节奏
🧪 动态内容更新也 OK!
你甚至可以在 <sl-details> 中放动态列表、表单、Tabs,只要是普通 Vue 内容都能工作。
如果你遇到嵌套组件内容不显示、样式不生效、动画卡顿等问题,可以把代码发我,我可以帮你排查。
Shoelace 的 Shadow DOM 隔离
Shoelace 本身的组件默认就是使用 Shadow DOM 的,因为它是基于 Web Components 的规范构建的,而规范建议隔离样式和结构,因此大多数 Shoelace 组件都开启了 Shadow DOM。
❓那么重点来了:可以关闭 Shadow DOM 吗?
❌ Shoelace 不支持关闭 Shadow DOM
Shoelace 的组件是通过底层 Lit 框架构建的,每个组件都明确指定了 this.attachShadow(...),无法通过配置关闭 Shadow DOM。
✅ 解决方式:你仍然可以在 Shoelace 的插槽里正常使用 Vue 组件
虽然 Shoelace 自身是 Shadow DOM,但它保留了插槽(slot)机制,所以Vue 组件内容是插入在 Shadow DOM 外部的。换句话说:
Shoelace 是 Shadow DOM,但插槽里的内容不在 Shadow DOM 内,所以你的 Vue 组件不会被隔离掉。
✅ 这意味着你可以放心地这么写:
<sl-details summary="这是标题">
<MyComponent />
</sl-details><MyComponent /> 的 DOM 是在 Shoelace 的 Shadow DOM 外部插槽中,不会被遮蔽或隔离,样式也能正常继承。
🔧 如果你确实不想用 Shadow DOM
那可以考虑用以下方案:
| 方案 | 描述 |
|---|---|
| ❗自己写 Accordion | 使用 <details> 或 <transition> 自己实现折叠效果,完全控制 DOM |
| ✅ 使用非 Shadow DOM 框架 | 比如:VueUse/motion、Headless UI(你控制样式) |
| 🧱 自定义 Lit 组件 | 如果你自己用 Lit 写组件,可以重写 createRenderRoot(),返回 this 来关闭 Shadow DOM(Shoelace 源码里不支持这么干) |
✅ 总结
- Shoelace 默认启用 Shadow DOM,无法关闭
- 但你在折叠面板插槽中使用 Vue 组件是完全没问题的
- Vue 组件的 DOM 是插在 Shadow DOM 外部,样式、交互正常工作
如果你遇到的是样式穿透问题(比如想让 Vue 的样式影响 Shoelace 内部组件),可以试试:
::part(base) {
border: 1px solid red;
}Shoelace 支持 ::part 让你从外部样式影响其 Shadow DOM 内部样式。
