英文:
How to use Vuetify 3 components in an own programmatically called component, e.g. open a dialog?
问题
我想使用this.$dialog.open('一些消息')
来调用一个自定义对话框。
我的自定义对话框组件使用了一些 Vuetify 组件。
我一直遇到错误 Error: [Vuetify] Could not find defaults instance
。
有人有例子如何定义一个组件,以便它可以使用 Vuetify 吗?
这是我尝试的内容(缩短版):
主要文件(不包括导入等)
const app = createApp(App)
app.use(createVuetify())
app.use(dialog)
对话框文件
export default {
install: (app) => {
const instance = createInstance()
app.config.globalProperties.$dialog = instance
app.provide('$dialog', instance)
},
}
function createInstance() {
return {
open(message) {
const instance = createComponent(Dialog, { message }, document.body)
return {
dismiss: instance.ctx.dismiss
}
}
}
}
function createComponent(component, props, parent, slots = {}) {
const vNode = h(component, props, slots)
render(vNode, parent)
return vNode.component
}
dialog.vue 文件
<template>
<v-dialog v-model="dialog" persistent width="auto">
<v-card>
{{ message }}
</v-card>
</v-dialog>
</template>
<script>
import { defineComponent } from 'vue'
export default defineComponent({
name: 'Dialog',
props: {
message: { type: String, required: true },
},
data: () => ({ dialog: true }),
methods: {
dismiss() {},
},
})
</script>
英文:
I want to call a custom dialog with this.$dialog.open('some message')
My own dialog component uses some vuetify components.
I always got the error Error: [Vuetify] Could not find defaults instance
Did somebody has an example how to define a component, that it could use vuetify?
This is what i try (shortened version):
main (without imports, etc.)
const app = createApp(App)
app.use(createVuetify())
app.use(dialog)
dialog
export default {
install: (app) => {
const instance = createInstance()
app.config.globalProperties.$dialog = instance
app.provide('$dialog', instance)
},
}
function createInstance() {
return {
open(message) {
const instance = createComponent(Dialog, { message }, document.body)
return {
dismiss: instance.ctx.dismiss
}
}
}
}
function createComponent(component, props, parent, slots = {}) {
const vNode = h(component, props, slots)
render(vNode, parent)
return vNode.component
}
dialog.vue
<template>
<v-dialog v-model="dialog" persistent width="auto">
<v-card>
{{ message }}
</v-card>
</v-dialog>
</template>
<script>
import { defineComponent } from 'vue'
export default defineComponent({
name: 'Dialog',
props: {
message: { type: String, required: true },
},
data: () => ({ dialog: true }),
methods: {
dismiss() {},
},
})
</script>
答案1
得分: 1
你的代码几乎正确。只有在你的 createComponent()
函数中创建的 VNode 没有注册到当前应用程序,因此它无法访问到 Vuetify 组件(或来自应用程序的任何数据)。为了让它可以访问,你可以在 VNode 中注册应用程序,只需将应用程序传递给 createComponent()
,然后设置 appContext
属性:
vNode.appContext = app._context
总之,这给你:
function createComponent(app, component, props, parent, slots = {}) {
const vNode = h(component, props, slots)
vNode.appContext = app._context
render(vNode, parent)
return vNode.component
}
以下是代码片段:
const { createApp, ref, defineComponent, h, render } = Vue;
const { createVuetify } = Vuetify
const vuetify = createVuetify()
const App = {
inject:['$dialog'],
methods: {
showDialog(){
console.log(this)
this.$dialog.open('go go go')
}
}
}
const Dialog = {
template: `
<v-dialog v-model="dialog" persistent width="auto">
<v-card>
<v-card-text>{{ message }}</v-card-text>
</v-card>
</v-dialog>
`,
name: 'Dialog',
props: {
message: { type: String, required: true },
},
data: () => ({ dialog: true }),
methods: {
dismiss() {},
},
}
const dialog = {
install: (app) => {
const instance = createInstance(app)
app.config.globalProperties.$dialog = instance
app.provide('$dialog', instance)
},
}
function createInstance(app) {
return {
open(message) {
const instance = createComponent(app, Dialog, { message }, document.body)
return {
dismiss: instance.ctx.dismiss
}
}
}
}
function createComponent(app, component, props, parent, slots = {}) {
const vNode = h(component, props, slots)
vNode.appContext = app._context
render(vNode, parent)
return vNode.component
}
const app = createApp(App)
app.use(vuetify)
app.use(dialog)
app.mount('#app')
以下是HTML部分:
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/vuetify@3/dist/vuetify.min.css" />
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@5.x/css/materialdesignicons.min.css" rel="stylesheet">
<div id="app">
<v-app>
<v-main>
<v-btn @click="showDialog">Show</v-btn>
</v-main>
</v-app>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify@3/dist/vuetify.min.js"></script>
英文:
You are very close. Only the VNode you create in your createComponent()
function is not registered to the current app, so it does not have access to the Vuetify components (or any data from app). To give it access, you can register the app in the VNode, all you have to do is to pass the app to createComponent()
and then set the appContext
property:
vNode.appContext = app._context
all in all, this gives you:
function createComponent(app, component, props, parent, slots = {}) {
const vNode = h(component, props, slots)
vNode.appContext = app._context
render(vNode, parent)
return vNode.component
}
Here it is in a snippet:
<!-- begin snippet: js hide: true console: false babel: false -->
<!-- language: lang-js -->
const { createApp, ref, defineComponent, h, render } = Vue;
const { createVuetify } = Vuetify
const vuetify = createVuetify()
const App = {
inject:['$dialog'],
methods: {
showDialog(){
console.log(this)
this.$dialog.open('go go go')
}
}
}
const Dialog = {
template: `
<v-dialog v-model="dialog" persistent width="auto">
<v-card>
<v-card-text>{{ message }}</v-card-text>
</v-card>
</v-dialog>
`,
name: 'Dialog',
props: {
message: { type: String, required: true },
},
data: () => ({ dialog: true }),
methods: {
dismiss() {},
},
}
const dialog = {
install: (app) => {
const instance = createInstance(app)
app.config.globalProperties.$dialog = instance
app.provide('$dialog', instance)
},
}
function createInstance(app) {
return {
open(message) {
const instance = createComponent(app, Dialog, { message }, document.body)
return {
dismiss: instance.ctx.dismiss
}
}
}
}
function createComponent(app, component, props, parent, slots = {}) {
const vNode = h(component, props, slots)
vNode.appContext = app._context
render(vNode, parent)
return vNode.component
}
const app = createApp(App)
app.use(vuetify)
app.use(dialog)
app.mount('#app')
<!-- language: lang-html -->
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/vuetify@3/dist/vuetify.min.css" />
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@5.x/css/materialdesignicons.min.css" rel="stylesheet">
<div id="app">
<v-app>
<v-main>
<v-btn @click="showDialog">Show</v-btn>
</v-main>
</v-app>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify@3/dist/vuetify.min.js"></script>
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论