如何为用 svelte.js 编写的应用程序创建插件?
How to create a plugin for an application written in svelte.js?
如果我用纯 JS 编写应用程序,我会像这样建立插件连接:
App.js
var App = function(){ /* ... */ };
//...
App.prototype.regPlugin= function ( atr1, atr2, ... ) { /* ... */ };
//...
App.prototype.sendToEventBus = function ( atr1, ... ) { /* ... */ };
//...
var app = new App();
//...
var appModules = {};
//...
document.onreadystatechange = function () {
if ( document.readyState === 'complete' ){
for ( var module in AppModules ) {
if ( AppModules[ module ] ) {
try {
AppModules[ module ].init( app );
} catch(er) {
//...
}
}
}
}
//...
plugin.js
var MyPlugin = function (){ /*...*/ };
//...
MyPlugin.prototype.init = function ( app ) {
this.app = app;
//...
app.regPlugin( plugAtr0 );
//...
};
//...
MyPlugin.prototype.handleAny = function(){
this.app.sendToEventBus( /* my event */ );
};
//...
appModules.myPlugin = new MyPlugin();
如何为 svelte.js 上的应用程序制作类似的插件?
自定义元素不太适合这个。
那种类型的插件设置仍然有效,查看 Client-side component API
使用 component.$set
,您可以将插件中的道具更改为 svelte 组件。
当您从 svelte 内部向 plugin/app 添加侦听器时,您可能需要额外的分配 data = myPlugin.data
以便 svelte 能够对更改做出反应。
好吧,如果您愿意,可以做一些非常相似的事情。 Svelte 只为您提供了一个 UI 组件,您可以在页面上的任何位置呈现。它不会接管你的整个 JS。
一件事是您的 Svelte 应用程序很可能会使用 ES import
语句进行捆绑(Rollup 或 Webpack)。这意味着您的代码将存在于 ES 模块中,并且局部变量不会自动附加到 ES 模块中的 window
对象。所以你必须明确这一点。所以你的代码会变成这样:
App.js (presumably your application entry point)
import App from './App.svelte'
const app = new App({
target: document.body,
props: {
name: 'world',
},
})
const appModules = {}
// expose appModules as a global variable
window.appModules = appModules
document.onreadystatechange = function() {
if (document.readyState === 'complete') {
debugger
for (var module in appModules) {
if (appModules[module]) {
try {
appModules[module].init(app)
} catch (er) {
//...
}
}
}
}
}
现在,app
是您的根 Svelte 组件。它会存在于 App.svelte
文件中。 Svelte 允许您通过 exporting const
or function
.
向组件添加实例方法
App.svelte
您可以导出 const
或 function
以在 Svelte 组件上使用实例方法。
<script>
export function regPlugin(...) { ... }
// or
export const sentToEventBus(...) { ... }
</script>
...
还有……瞧?您的代码中还有其他内容吗?
上述代码的一个问题可能是 App
组件将在您的插件有机会注册之前呈现。
您可以使用 App
组件中的道具来解决此问题。为了能够从您的 "controller code" 更改此道具的值,您可以使用 $set
method of the component. You can also set the accessors
option on your component. You can do this globally with a bundler plugin option, or you can enable it on individual components with <svelte:options>
.
如果您需要一些自定义逻辑 运行 只有在应用准备就绪后,您可以在 "reactive statement".
中执行此操作
App.svelte
<svelte:options accessors={true} />
<script>
export function regPlugin() {}
export function sentToEventBus() {}
export let ready = false
$: if (ready) {
// code to run when ready
}
</script>
{#if ready}
<!-- content to show when ready (all plugins initialized) -->
<!-- most likely, you'd put other Svelte components in there -->
{:else}
<div>Loading...</div>
{/if}
您可以在应用准备好启动时切换此道具:
App.js
document.onreadystatechange = function() {
if (document.readyState === 'complete') {
for (var module in appModules) {
...
}
app.$set({ ready: true })
// or
app.ready = true
}
}
或者,您可能更愿意在 App 组件中移动插件初始化代码。因为你在这里有一个 "static" 状态,在 appModules
变量中,你必须将它放入组件的静态 <script context="module">
部分:
App.svelte
<script context="module">
// this block only runs once, when the module is loaded (same as
// if it was code in the root of a .js file)
// this variable will be visible in all App instances
const appModules = {}
// make the appModules variable visible to the plugins
window.appModules = appModules
// you can also have static function here
export function registerPlugin(name, plugin) {
appModules[name] = plugin
}
</script>
<script>
// in contrast, this block will be run for each new instance of App
...
let ready
document.onreadystatechange = function() {
if (document.readyState === 'complete') {
// NOTE appModules bellow is the same as the one above
for (var module in appModules) {
// ...
}
ready = true
}
}
</script>
{#if ready}
...
{/if}
静态函数 addPlugin
可以作为其他模块的命名导出访问:
import { addPlugin } from './App.svelte'
这可能更适合捆绑应用程序/带模块的应用程序的上下文,而不是将内容附加到 window
(因此 运行 在全局命名空间中存在冲突风险)。取决于你在做什么...
如果我用纯 JS 编写应用程序,我会像这样建立插件连接:
App.js
var App = function(){ /* ... */ };
//...
App.prototype.regPlugin= function ( atr1, atr2, ... ) { /* ... */ };
//...
App.prototype.sendToEventBus = function ( atr1, ... ) { /* ... */ };
//...
var app = new App();
//...
var appModules = {};
//...
document.onreadystatechange = function () {
if ( document.readyState === 'complete' ){
for ( var module in AppModules ) {
if ( AppModules[ module ] ) {
try {
AppModules[ module ].init( app );
} catch(er) {
//...
}
}
}
}
//...
plugin.js
var MyPlugin = function (){ /*...*/ };
//...
MyPlugin.prototype.init = function ( app ) {
this.app = app;
//...
app.regPlugin( plugAtr0 );
//...
};
//...
MyPlugin.prototype.handleAny = function(){
this.app.sendToEventBus( /* my event */ );
};
//...
appModules.myPlugin = new MyPlugin();
如何为 svelte.js 上的应用程序制作类似的插件?
自定义元素不太适合这个。
那种类型的插件设置仍然有效,查看 Client-side component API
使用 component.$set
,您可以将插件中的道具更改为 svelte 组件。
当您从 svelte 内部向 plugin/app 添加侦听器时,您可能需要额外的分配 data = myPlugin.data
以便 svelte 能够对更改做出反应。
好吧,如果您愿意,可以做一些非常相似的事情。 Svelte 只为您提供了一个 UI 组件,您可以在页面上的任何位置呈现。它不会接管你的整个 JS。
一件事是您的 Svelte 应用程序很可能会使用 ES import
语句进行捆绑(Rollup 或 Webpack)。这意味着您的代码将存在于 ES 模块中,并且局部变量不会自动附加到 ES 模块中的 window
对象。所以你必须明确这一点。所以你的代码会变成这样:
App.js (presumably your application entry point)
import App from './App.svelte'
const app = new App({
target: document.body,
props: {
name: 'world',
},
})
const appModules = {}
// expose appModules as a global variable
window.appModules = appModules
document.onreadystatechange = function() {
if (document.readyState === 'complete') {
debugger
for (var module in appModules) {
if (appModules[module]) {
try {
appModules[module].init(app)
} catch (er) {
//...
}
}
}
}
}
现在,app
是您的根 Svelte 组件。它会存在于 App.svelte
文件中。 Svelte 允许您通过 exporting const
or function
.
App.svelte
您可以导出 const
或 function
以在 Svelte 组件上使用实例方法。
<script>
export function regPlugin(...) { ... }
// or
export const sentToEventBus(...) { ... }
</script>
...
还有……瞧?您的代码中还有其他内容吗?
上述代码的一个问题可能是 App
组件将在您的插件有机会注册之前呈现。
您可以使用 App
组件中的道具来解决此问题。为了能够从您的 "controller code" 更改此道具的值,您可以使用 $set
method of the component. You can also set the accessors
option on your component. You can do this globally with a bundler plugin option, or you can enable it on individual components with <svelte:options>
.
如果您需要一些自定义逻辑 运行 只有在应用准备就绪后,您可以在 "reactive statement".
中执行此操作App.svelte
<svelte:options accessors={true} />
<script>
export function regPlugin() {}
export function sentToEventBus() {}
export let ready = false
$: if (ready) {
// code to run when ready
}
</script>
{#if ready}
<!-- content to show when ready (all plugins initialized) -->
<!-- most likely, you'd put other Svelte components in there -->
{:else}
<div>Loading...</div>
{/if}
您可以在应用准备好启动时切换此道具:
App.js
document.onreadystatechange = function() {
if (document.readyState === 'complete') {
for (var module in appModules) {
...
}
app.$set({ ready: true })
// or
app.ready = true
}
}
或者,您可能更愿意在 App 组件中移动插件初始化代码。因为你在这里有一个 "static" 状态,在 appModules
变量中,你必须将它放入组件的静态 <script context="module">
部分:
App.svelte
<script context="module">
// this block only runs once, when the module is loaded (same as
// if it was code in the root of a .js file)
// this variable will be visible in all App instances
const appModules = {}
// make the appModules variable visible to the plugins
window.appModules = appModules
// you can also have static function here
export function registerPlugin(name, plugin) {
appModules[name] = plugin
}
</script>
<script>
// in contrast, this block will be run for each new instance of App
...
let ready
document.onreadystatechange = function() {
if (document.readyState === 'complete') {
// NOTE appModules bellow is the same as the one above
for (var module in appModules) {
// ...
}
ready = true
}
}
</script>
{#if ready}
...
{/if}
静态函数 addPlugin
可以作为其他模块的命名导出访问:
import { addPlugin } from './App.svelte'
这可能更适合捆绑应用程序/带模块的应用程序的上下文,而不是将内容附加到 window
(因此 运行 在全局命名空间中存在冲突风险)。取决于你在做什么...