我正在开发一个小型库,用于显示 vue 3 的通知/toast。我的想法是在插件注册期间为我的通知附加一个不可见的容器。因此最终用户不应该关心渲染该区域。有可能吗?
我当前的插件如下所示:
export const plugin = {
install: (app: App, options?) => {
options = reactive(options || defaultOptions);
app.provide(symbol, instance);
app.component('vue3-notification', Notification);
app.component('vue3-notifications', Overlay);
console.log('app', app); // app._component is null at this point
var test = Overlay.render({ notifications: instance });
console.log('test', test); // how to attach Overlay component to app?
}
};
Run Code Online (Sandbox Code Playgroud)
似乎安装插件后,vue 根容器还不可用。我设法渲染我的组件,提供所需的依赖项(至少我希望如此,它在最后一行记录到控制台),但我不知道如何安装它并与主应用程序集成。
我想从插件自动渲染的覆盖组件如下所示:
<div class="notifications-overlay">
<Teleport to="body">
<vue3-notification
v-for="(n, index) in notifications.stack.value"
:key="n.id"
v-bind="n"
v-bind:hide="() => hide(n.id)"
></vue3-notification>
</Teleport>
</div>
Run Code Online (Sandbox Code Playgroud)
并且它有固定的位置:
.notifications-overlay {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
pointer-events: none;
}
Run Code Online (Sandbox Code Playgroud)
所以它在哪里准确渲染并不重要,我只想在使用我的插件后它在 vue 应用程序中自动可用。
有什么想法吗?
在 Vue 2 中,我们Vue.extend可以创建基本 Vue 构造函数的“子类”,它还允许您将实例挂载到元素上,这对于此目的非常有用。
然而,这个 API 已经在 Vue 3 中被删除了。阅读RFC 以了解全局 API 更改。
由于全局 Vue 不再是可 new 的构造函数,因此 Vue.extend 在构造函数扩展方面不再有意义。
createApp好消息是,我们仍然可以通过利用将插件组件渲染mount到 DOM 元素来实现几乎相同的目标。
如果您不喜欢实例化多个 Vue 实例的想法,您可能需要查看这个名为 的非官方库mount-vue-component。我自己没有尝试过,但它允许您在不使用createApp. 虽然,它似乎使用一些内部属性(如_context)来完成任务。我想说,任何未记录的内容都可能会改变。但是嘿。
那么,回到createApp方法。我们不会Teleport在这里使用。以下步骤只是我的偏好,因此请随意根据您的用例进行调整。
import { ComponentPublicInstance } from 'vue';
export interface INotify {
(message: string): void;
}
export type CustomComponentPublicInstance = ComponentPublicInstance & {
notify: INotify;
}
Run Code Online (Sandbox Code Playgroud)
我们为自定义组件实例使用交集类型。
import { App, createApp } from 'vue';
import Notifier from './path/to/component/Notifier.vue';
export const injectionKeyNotifier = Symbol('notifier');
export default {
install(app: App) {
const mountPoint = document.createElement('div');
document.body.appendChild(mountPoint);
const notifier = createApp(Notifier).mount(mountPoint) as CustomComponentPublicInstance;
app.provide(injectionKeyNotifier, notifier.notify);
}
}
Run Code Online (Sandbox Code Playgroud)
此时,我们只需要从INotify目标组件 ( Notifier.vue) 公开一个公共方法(见上文)。我正在调用这个方法notify。它需要一个字符串参数作为消息。
Notify.vue<template>
<div class="my-notifier">
<div class="msg" v-text="message"></div>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent(() => {
const message = ref('');
function notify(msg: string) {
message.value = msg;
}
return {
message,
notify
}
})
</script>
Run Code Online (Sandbox Code Playgroud)
请注意一个名为 的命名函数notify。这是我们之前讨论过的公共方法,我们需要将其导出。
use()它在您的条目文件上(例如main.ts):
import { createApp } from 'vue'
import App from './App.vue'
import Notifier from 'my-custom-notifier'; // Assumes a library from the NPM registry (if you mean to publish it)
createApp(App)
.use(Notifier)
.mount('#app');
Run Code Online (Sandbox Code Playgroud)
显示随机通知的示例用法:
<template>
<div class="home">
<button @click="showNotifs">Show notification</button>
</div>
</template>
<script lang="ts">
import { defineComponent, inject } from 'vue';
import { INotify, injectionKeyNotifier } from 'my-custom-notifier';
export default defineComponent({
name: 'Home',
setup() {
const notify = inject(injectionKeyNotifier) as INotify;
function showNotifs() {
notify('You have x unread messages.');
}
return {
showNotifs
}
}
})
</script>
Run Code Online (Sandbox Code Playgroud)
就是这样!我们会自动注册组件,而用户无需手动将其添加到模板上。
| 归档时间: |
|
| 查看次数: |
3435 次 |
| 最近记录: |