Skip to content

Vite + Vue 3 项目中使用 Shoelace

在 Vite + Vue 3 项目中使用 Shoelace 非常简单,它基于 Web Components,可直接以原生方式集成到 Vue 项目中,无需额外封装。


✅ 使用 Shoelace 的步骤(适用于 Vite + Vue 3 项目)

1️⃣ 安装 Shoelace

bash
npm install @shoelace-style/shoelace

2️⃣ 在 main.ts 中引入 Shoelace 样式和组件定义

ts
// 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 语法

vue
<!-- AccordionDemo.vue -->
<template>
  <sl-details summary="点击展开">
    <p>这是 Shoelace 折叠面板的内容。</p>
  </sl-details>
</template>

4️⃣ Vue 警告处理(可选)

shims-vue.d.ts 中添加 Shoelace 的自定义元素类型支持(避免警告):

ts
// shims-vue.d.ts
declare namespace JSX {
  interface IntrinsicElements {
    'sl-details': any
  }
}

或者在 tsconfig.json 中设置:

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
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
vue
<!-- 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-cloakv-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 组件不会被隔离掉。

✅ 这意味着你可以放心地这么写:

vue
<sl-details summary="这是标题">
  <MyComponent />
</sl-details>

<MyComponent /> 的 DOM 是在 Shoelace 的 Shadow DOM 外部插槽中,不会被遮蔽或隔离,样式也能正常继承。


🔧 如果你确实不想用 Shadow DOM

那可以考虑用以下方案:

方案描述
❗自己写 Accordion使用 <details><transition> 自己实现折叠效果,完全控制 DOM
✅ 使用非 Shadow DOM 框架比如:VueUse/motionHeadless UI(你控制样式)
🧱 自定义 Lit 组件如果你自己用 Lit 写组件,可以重写 createRenderRoot(),返回 this 来关闭 Shadow DOM(Shoelace 源码里不支持这么干)

✅ 总结

  • Shoelace 默认启用 Shadow DOM,无法关闭
  • 但你在折叠面板插槽中使用 Vue 组件是完全没问题的
  • Vue 组件的 DOM 是插在 Shadow DOM 外部,样式、交互正常工作

如果你遇到的是样式穿透问题(比如想让 Vue 的样式影响 Shoelace 内部组件),可以试试:

css
::part(base) {
  border: 1px solid red;
}

Shoelace 支持 ::part 让你从外部样式影响其 Shadow DOM 内部样式。

Released under the MIT License.