第一个插件
认识插件:函数式插件
最简单的 IPE 的插件,就是一个接受依赖注入的普通函数。
/**
* 我们的第一个插件!
* @param {import('@inpageedit/core').InPageEdit} ctx - 插件所属的上下文
* @param {any} [config] - 可能传入的配置项
*/
function (, ) {
.(, `hello, ${.name || 'world'}`) // hello, IPE
}
// 然后加载它
.(, { : 'IPE' })
你没看错,就这么一个简单的函数,便是合法的 IPE 插件。它的第一个参数 ctx
是插件所属的上下文,你也可以接受第二个参数 config
,它是可能传入的配置项。
TIP
对于简单的插件来说,我们更推荐直接传入一个箭头函数,除了了更简洁之外,还能自动获得关于 ctx
的类型推导!
.(() => {
.(, 'hello, world')
})
你可以亲自尝试一下:打开你的浏览器控制台(F12),粘贴上面的代码,按下回车键。
就是这么简单,当你加载这个插件后,立刻就能在控制台看到 hello, world
字样。
让我们做些什么
为了更好的理解 IPE 的插件机制,我们让这个插件做点事情:
.(() => {
..({
: 'my-first-plugin',
: '👋',
: 'My First Plugin',
: () => {
('hello, world')
},
})
})
看看页面右下角的工具盒,是不是多了一个按钮?点击它,你会看到一个弹窗,上面写着 hello, world
。
真不赖,我们的插件看上去离“快速编辑”也不远嘛!
但是控制台中有一些警告:
Error: property toolbox is not registered, declare it as
inject
to suppress this warning
别紧张,这是因为我们没有在插件中注入 toolbox
服务。
依赖注入
为了解决这个问题,我们需要在插件中注入 toolbox
服务。
.(() => {
.(['toolbox'], () => {
..({
: 'my-first-plugin',
: '👋',
: 'My First Plugin',
: () => {
('hello, world')
},
})
})
})
现在没有报错了!但是,为什么要这样做?
因为 ctx.toolbox
其实是由另外一个插件提供的服务,它的加载时机是不确定的。人总有运气差的时候,万一咱们的myButtonPlugin
安装时toolbox
还没有加载,那你就只能望 undefined
而兴叹了。
而通过 ctx.inject
,IPE会确保你在插件中拿到的上下文,一定包含了 toolbox
服务。
更清晰的定义归纳:对象式插件
不过总是ctx.inject
有时候会导致难以阅读,所以我们可以换用对象式插件:
.({
: ['toolbox'],
() {
..({
: 'my-first-plugin',
: '👋',
: 'My First Plugin',
: () => {
('hello, world')
},
})
},
})
现在你学会了第二种插件的写法:IPE 插件可以是一个包含 apply
方法的对象。
apply
完全等同于函数式插件中的函数
可选的属性:
name
属性来传递插件的名称。inject
属性来传递服务列表。
OOP 爱好者:类式插件
IPE的插件可以是一个普通的类,它的 constructor 的第一个参数是所在的上下文,第二个参数是可能传入的配置项。
import { } from '@inpageedit/core'
class {
static = ['toolbox']
constructor(
public : ,
?: any
) {
..({
: 'my-first-plugin',
: '👋',
: 'My First Plugin',
: () => {
('hello, world')
},
})
}
}
.()
一般来说,TypeScript 的爱好者会很喜欢这种写法,因为它更符合面向对象编程的习惯,你可以把插件的状态保存在类的实例中,也可以把一些逻辑归纳在类的方法中。
如果你感兴趣的话,你甚至可以继承 BasePlugin
来简化一些样板代码,或者使用修饰器来声明依赖注入之类的:
import { , , } from '@inpageedit/core'
import type {} from '@inpageedit/core/plugins/toolbox/index'
@(['toolbox'])
export default class extends {
constructor(
public : ,
?: any
) {
super(, , 'MyButtonPlugin')
}
() {
this...({
: 'my-first-plugin',
: '👋',
: 'My First Plugin',
: () => {
('hello, world')
},
})
}
() {
this...('my-first-plugin')
}
}
import from './PluginMyButton.js'
.()
总结:插件的基本形式
一个插件需要是以下三种基本形式之一:
- 一个接受两个参数的函数,第一个参数是插件所属的上下文,第二个参数是可能传入的配置项
- 一个对象,其中的
apply
方法是第一种形式中所说的函数,包括可选的inject
和name
等属性 - 一个接受两个参数的类,
constructor
的第一个参数是插件所属的上下文,第二个参数是可能传入的配置项
.((, ) => {
// ...
})
.({
: [],
: (, ) => {
// ...
},
})
.(
class {
constructor(
public : ,
public ?: any
) {
// ...
}
}
)