最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

vuejs3 - How to include vuetify3 inside vue3's component using composition API - Stack Overflow

programmeradmin0浏览0评论

I would like to build a web component using Vuetify3 inside of a Vue3's component that is using composition API.

How do I add Vuetify3 to MyNavbar.ce.vue component so that it is scoped inside the component's shadow root?

This component will be dynamically loaded into applications/sites built with other frameworks/styles.

I want the component to be able to use Vuetify3 directives such v-app, v-app-bar, v-btn etc. within it.

Thank you, Oleg


I followed many online resources and arrived at the setup below but I can't get vuetify setup inside the component.

Project created:

npm create vue@latest

> npx
> create-vue

✔ Project name: … my-navbar
✔ Add TypeScript? … No
✔ Add JSX Support? … No
✔ Add Vue Router for Single Page Application development? … No
✔ Add Pinia for state management? … No
✔ Add Vitest for Unit Testing? … No
✔ Add an End-to-End Testing Solution? › No
✔ Add ESLint for code quality? › No

Scaffolding project in /path/my-navbar...

Done. Now run:

  cd my-navbar
  npm install
  npm run dev

Vuetify installation:

cd my-navbar
npm install @mdi/font
npm i vuetify

Current files

src/main.js

import { defineCustomElement } from 'vue'
import MyNavbar from './components/MyNavbar.ce.vue'

// convert into custom element constructor
const element = defineCustomElement(MyNavbar)

// register
customElements.define('my-navbar', element)

index.html

<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="UTF-8">
    <link rel="icon" href="/favicon.ico">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Custom Element</title>
  </head>
  <body>
    <my-navbar></my-navbar>
    <script type="module" src="/src/main.js"></script>
  </body>
</html>

./src/components/MyNavbar.ce.vue

<script setup>

</script>

<template>
  <v-app>
    <v-app-bar>
      <template v-slot:prepend>
        <v-app-bar-nav-icon></v-app-bar-nav-icon>
      </template>

      <v-app-bar-title>Application Bar</v-app-bar-title>
    </v-app-bar>
  </v-app>
</template>

<style scoped>
  @import 'vuetify/styles';
</style>>

I would like to build a web component using Vuetify3 inside of a Vue3's component that is using composition API.

How do I add Vuetify3 to MyNavbar.ce.vue component so that it is scoped inside the component's shadow root?

This component will be dynamically loaded into applications/sites built with other frameworks/styles.

I want the component to be able to use Vuetify3 directives such v-app, v-app-bar, v-btn etc. within it.

Thank you, Oleg


I followed many online resources and arrived at the setup below but I can't get vuetify setup inside the component.

Project created:

npm create vue@latest

> npx
> create-vue

✔ Project name: … my-navbar
✔ Add TypeScript? … No
✔ Add JSX Support? … No
✔ Add Vue Router for Single Page Application development? … No
✔ Add Pinia for state management? … No
✔ Add Vitest for Unit Testing? … No
✔ Add an End-to-End Testing Solution? › No
✔ Add ESLint for code quality? › No

Scaffolding project in /path/my-navbar...

Done. Now run:

  cd my-navbar
  npm install
  npm run dev

Vuetify installation:

cd my-navbar
npm install @mdi/font
npm i vuetify

Current files

src/main.js

import { defineCustomElement } from 'vue'
import MyNavbar from './components/MyNavbar.ce.vue'

// convert into custom element constructor
const element = defineCustomElement(MyNavbar)

// register
customElements.define('my-navbar', element)

index.html

<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="UTF-8">
    <link rel="icon" href="/favicon.ico">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Custom Element</title>
  </head>
  <body>
    <my-navbar></my-navbar>
    <script type="module" src="/src/main.js"></script>
  </body>
</html>

./src/components/MyNavbar.ce.vue

<script setup>

</script>

<template>
  <v-app>
    <v-app-bar>
      <template v-slot:prepend>
        <v-app-bar-nav-icon></v-app-bar-nav-icon>
      </template>

      <v-app-bar-title>Application Bar</v-app-bar-title>
    </v-app-bar>
  </v-app>
</template>

<style scoped>
  @import 'vuetify/styles';
</style>>

Share Improve this question asked Mar 6 at 8:41 OlegOleg 12 bronze badges 6
  • Why are you importing the Vuetify CSS into a single scoped element locally? Why not into your global CSS? – rozsazoltan Commented Mar 6 at 8:45
  • Did you registered Vuetify in the app (see docs)? – Moritz Ringler Commented Mar 6 at 9:25
  • Heya, thanks for the prompt response. @rozsazoltan re:css I'm not sure if this is the correct approach but my idea to import it inside the component is to ensure the css will be scoped to the web component alone so when I import this component the will be no collision. – Oleg Commented Mar 6 at 14:57
  • Heya @moritz-ringler thanks for the prompt response. I don't have an app only a single component this is why I'm asking the question. Because in a "standard" spa I know how to initialize vuetify and all works fine but in this case I'm not sure. – Oleg Commented Mar 6 at 15:00
  • 1 Right, have a look at stackoverflow/a/76934503/4883195 – Moritz Ringler Commented Mar 6 at 15:13
 |  Show 1 more comment

1 Answer 1

Reset to default 0

Thanks to @moritz-ringler for bringing up stackoverflow/a/76934503/4883195. I've managed to put together a working github/OnlyLoveOleg/vue3-vuetify-webcomponent example in case anyone is looking for a solution to this problem.

index.html

<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="UTF-8">
    <link rel="icon" href="/favicon.ico">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue3 Vuetify Web Component</title>
  </head>
  <body>
    <my-navbar></my-navbar>
    <script type="module" src="/src/main.js"></script>
  </body>
</html>

src/main.js

import { defineCustomElement } from './defineCustomElementWithStyles'
import '@mdi/font/css/materialdesignicons.css'
import { createVuetify } from 'vuetify';
import { aliases, mdi } from 'vuetify/iconsets/mdi'

// Import the Vue component.
import MyNavbarComponent from './components/MyNavbar.ce.vue'

const vuetify = createVuetify({
    icons: {
        defaultSet: 'mdi',
        aliases,
        sets: {
          mdi,
        },
    },
})

customElements.define(
    'my-navbar',
    defineCustomElement(MyNavbarComponent, {
        plugins: [vuetify],
    })
)

src/defineCustomElementWithStyles.js

// defineCustomElementWithStyles.js
import { defineCustomElement as VueDefineCustomElement, h, createApp, getCurrentInstance } from 'vue'

export const defineCustomElement = (component, { plugins = [] } = {}) =>
  VueDefineCustomElement({
    styles: component.styles,
    render: () => h(component),
    setup() {
      const app = createApp()

      // install plugins
      plugins.forEach(app.use)

      const inst = getCurrentInstance()
      Object.assign(inst.appContext, app._context)
      Object.assign(inst.provides, app._context.provides)
    },
  })

src/components/MyNavbar.ce.vue

<template>
  <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr/npm/vuetify@3/dist/vuetify.min.css" />
  <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr/npm/@mdi/[email protected]/css/materialdesignicons.min.css" />
  <v-app>
    <v-app-bar>
      <template v-slot:prepend>
        <v-app-bar-nav-icon></v-app-bar-nav-icon>
      </template>

      <v-app-bar-title>App title</v-app-bar-title>

      <v-spacer></v-spacer>

      <v-btn icon>
        <v-icon>mdi-magnify</v-icon>
      </v-btn>

      <v-btn icon>
        <v-icon>mdi-heart</v-icon>
      </v-btn>

      <v-btn icon>
        <v-icon>mdi-dots-vertical</v-icon>
      </v-btn>
    </v-app-bar>
  </v-app>
</template>
发布评论

评论列表(0)

  1. 暂无评论