Atom插件开发入门教程(三)
2017-01-09 16:24
609 查看
插件: 文本计数器
让我们开始写一个非常简单的而又实用的插件吧。文本计数插件:统计当前缓冲里有多少文字,并用一个小窗口把结果显示出来。
插件包生成器(Package
Generator)
创建插件最简单的方法是用Atom内置的插件包生成器( package generator)。 你可能已经猜到了, package generator 自己也是一个插件包。(详情参见:package-generator)你可以在command palette里搜索 "Generate Package"来运行它。这时会弹出一个对话框,让你输入插件的名字,建议输入:
your-name-word-count.
Atom 会创建一个目录并插入默认的插件代码。默认位置是:
%USERPROFILE%\.atom\packages,这样重启Atom时,就会自动加载这个插件了。
注意: 如果你的插件包没有被加载。那很可能是因为有一个相同名称的插件已经被上传到了atom.io 。所以建议大家建立插件时,加上自己名字的缩写或者公司缩写,来保证插件名称的唯一性。
如上图, Atom 已经创建了插件包的基础代码。下面我们来介绍插件包的代码是怎样构成的:
最基础的路径结构如下:
my-package/ ├─ grammars/ ├─ keymaps/ ├─ lib/ ├─ menus/ ├─ spec/ ├─ snippets/ ├─ styles/ ├─ index.coffee └─ package.json
不是每个插件都需要这些文件,自动创建的代码里,也没有
snippets和
grammars目录。
package.json
类似于 Node modules, Atom 插件包的根目录必须有一个
package.json文件。这里包含了插件包的基础信息,比如
"main" 模块的路径,依赖库, 和指定的资源加载顺序。
下面介绍
package.json文件中各个参数的意义:
main: CoffeeScript(JavaScript)代码文件的路径,如果不填写此项目, Atom 会自动寻找
index.coffee或
index.js。
styles: 一个字符串数组,说明Styles文件的加载顺序,如果不填写,Atom会自动在styles目录下按文件名字母排序的方式去加载样式文件。注意,样式支持css和less文件。
keymaps:
一个字符串数组,说明keymaps文件的加载顺序,如果不填,则Atom自动在
keymaps目录下按字母排序的方式去加载。
menus: 一个字符串数组,说明memus配置文件在哪里加载。如果不填, 则Atom自动在
menus目录下按字母排序的方式加载。
snippets: 一个字符串数组,说明插件中使用的snippets从哪里加载。如果不填,则Atom自动在
snippets目录下按字母排序的方式去加载。
activationCommands: 一个对象, 说明哪个命令来激活你的插件。如果不填写, 则Atom会在插件激活时,自动调用
activate()函数。
activationHooks: 一个字符串数组,说明使用哪种语法来解释脚本。一般来说,我们填写:
language-package-name:grammar-used(e.g.,
language-javascript:grammar-used)
下面是一个
package.json的例子:
{ "name": "wordcount", "main": "./lib/wordcount", "version": "0.0.0", "description": "A short description of your package", "activationCommands": { "atom-workspace": "wordcount:toggle" }, "repository": "https://github.com/atom/your-name-word-count", "license": "MIT", "engines": { "atom": ">=1.0.0 <2.0.0" }, "dependencies": { } }
如果使用了 activationHooks, 代码是:
{ "name": "wordcount", "main": "./lib/wordcount", "version": "0.0.0", "description": "A short description of your package", "activationHooks": ["language-javascript:grammar-used", "language-coffee-script:grammar-used"], "repository": "https://github.com/atom/your-name-word-count", "license": "MIT", "engines": { "atom": ">=1.0.0 <2.0.0" }, "dependencies": { } }
首先,要填写这些基本信息。
Warning: 切记要更新 repository URL. 否则你的更改将无法分享给他人。
源代码
首先你的插件必须包含一个[top-level]模块, 在
package.json文件里的main字段下声明它。对于我们这个例子来说,[top-level]文件是
lib/wordcount.coffee.
你编写的源代码应该放在
lib目录下,并且用[top-level]文件中required它。 如果
main没写,则Atom自动选择
index.coffee或
index.js作为[top-level]文件。
插件的[top-level] 模块是一个单例类。生命周期由 Atom来管理。 不论你创建多少Dom或者View, 它们全部由[top-level]来管理。
插件的[top-level] 模块可以实现下列的基本接口:
activate(state): 插件激活时被调用。如果你实现了
serialize()接口,它会传递窗口上次的state.
一般用这个接口来初始化插件。
initialize(state): (Atom 1.14以后的版本支持) 与
activate()功能类似,不过被调用的更早,可以说在所有操作之前被调用。 如果你想等环境运行完毕了再初始化,请用
activate()。如果需要在画面构造前执行什么,请用
initialize()。
serialize(): 在窗口被关闭的时候,允许你返回 JSON 序列,来保存当前的状态。你保存的信息,可以传递给
activate()接口,来在下次启动时恢复你的窗口状态。
deactivate(): 窗口关闭时会调用这个接口,如果你的插件正在使用某些资源,或关联着某些文件,请在这里释放他们。
样式
之前说过,插件的样式应该放在
styles目录里。 支持 CSS 或 Less,
推荐使用Less。
理想的来说, 你不需要这种方式来做样式。Atom提供了基础的UI样式。 打开 command palette Ctrl+Shift+P + Ctrl+Shift+G来查找Atom默认提供的插件UI样式吧。
如果你需要特别的UI样式,建议只保留结构样式。如果你要使用特别的颜色、字体等,建议使用Atom提供的主题样式。参见 ui-variables.less.
快捷键
插件可以绑定多个快捷键, 举例参见
keymaps/wordcount.cson文件:
'atom-workspace': 'ctrl-alt-o': 'wordcount:toggle'
这将快捷键 Alt+Ctrl+O,
设置为运行
your-name-word-count:toggle命令。创建插件时,Atom会自动分配一个快捷键给它,当然你也可以自行定义。
快捷键配置文件在
keymaps子路径中。默认的所有快捷键配置文件按字母排序来加载。如果需要特别的加载顺序,请在
package.json文件中配置。
快捷键的启动,也受到当前Dom元素(当前正在操作的View)是哪个的影响。在本例中
your-name-word-count:toggle命令是在
atom-workspace元素上按下Alt+Ctrl+O 时会被执行。因为
atom-workspace是整个
Atom UI的上级。这意味着,任何时候按下Alt+Ctrl+O 都会被执行。
如果想更深入的了解快捷键有关的内容,请参见 Keymaps in Depth.
菜单
菜单在
menus子目录下。它定义了右键弹出菜单和工具栏菜单。
菜单默认按字母排序加载。 你可以在
package.json中编写自定义的加载顺序。
Application
菜单
如果你的插件不是对特定元素使用的,建议你在Packages菜单下创建一个application菜单项。 在
menus/your-name-word-count.cson文件中,我们能看到如下代码片段:
'menu': [ { 'label': 'Packages' 'submenu': [ 'label': 'Word Count' 'submenu': [ { 'label': 'Toggle' 'command': 'your-name-word-count:toggle' } ] ] } ]
上述代码在Packages菜单下,添加了WorkCount子项,并在其中添加了Toggle项目。
如果选择这个选项,会执行
your-name-word-count:toggle命令。
菜单项会自动和其他菜单项合并,他们按照加载的顺序来显示。
环境菜单(右键弹出的菜单)
建议为插件制作一些环境菜单。 在
menus/your-name-word-count.cson文件中,你会看到一些默认的代码片段。
'context-menu': 'atom-text-editor': [ { 'label': 'Toggle Word Count' 'command': 'your-name-word-count:toggle' } ]
在编辑页面点击右键,我们会看到这个菜单项。
点击它,会执行
your-name-word-count:toggle方法。
环境菜单也可以添加子项目, 如下:
'context-menu': 'atom-workspace': [ { label: 'Text' submenu: [ {label: 'Inspect Element', command: 'core:inspect'} {type: 'separator'} {label: 'Selector All', command: 'core:select-all'} {type: 'separator'} {label: 'Deleted Selected Text', command: 'core:delete'} ] } ]
开发插件
在我们之前创建的插件框架基础上,运行 your-name-word-count:toggle我们会看到一个弹窗: "The Wordcount package is Alive!
It's ALIVE!".
理解自动生成的代码
看一下
lib目录。
在
lib目录下,现在有两个文件。其中 (
lib/your-name-word-count.coffee)是主文件,
在
package.json文件中我们指定它为主文件。它负责整个插件的逻辑。
第二要注意的是 View class文件
lib/your-name-word-count-view.coffee, 这里主要是插件的UI代码
module.exports = class YourNameWordCountView constructor: (serializedState) -> # Create root element @element = document.createElement('div') @element.classList.add('your-name-word-count') # Create message element message = document.createElement('div') message.textContent = "The Your Name Word Count package is Alive! It's ALIVE!" message.classList.add('message') @element.appendChild(message) # Returns an object that can be retrieved when package is activated serialize: -> # Tear down any state and detach destroy: -> @element.remove() getElement: -> @element
代码的具体含义这里不在赘述。
这里重点要注意的是 DOM methods:
createElement()和
appendChild().两个函数的用法。
第二个文件有两个主入口,它们是在
package.json文件里配置的.文件代码如下:
YourNameWordCountView = require './your-name-word-count-view' {CompositeDisposable} = require 'atom' module.exports = YourNameWordCount = yourNameWordCountView: null modalPanel: null subscriptions: null activate: (state) -> @yourNameWordCountView = new YourNameWordCountView(state.yourNameWordCountViewState) @modalPanel = atom.workspace.addModalPanel(item: @yourNameWordCountView.getElement(), visible: false) # Events subscribed to in atom's system can be easily cleaned up with a CompositeDisposable @subscriptions = new CompositeDisposable # Register command that toggles this view @subscriptions.add atom.commands.add 'atom-workspace', 'your-name-word-count:toggle': => @toggle() deactivate: -> @modalPanel.destroy() @subscriptions.dispose() @wordcountView.destroy() serialize: -> yourNameWordCountViewState: @yourNameWordCountView.serialize() toggle: -> console.log 'YourNameWordCount was toggled!' if @modalPanel.isVisible() @modalPanel.hide() else @modalPanel.show()
首先,我们看到这里定义了4个方法,其中只有
activate. 是必要的。
deactivate是
serializeAtom推荐但可选的。
toggle方法不是由Atom调用的,我们必须手动或者配置的方式去调用它。一般来说,都是在
activationCommandssection
(
package.json文件中)或者菜单中。
deactivate函数只负责销毁,
serialize只负责序列化View的信息,建议不要在这两个函数里做其他事情。
activate函数不是在Atom启动时就被调用的。它仅在
activationCommands(package.json中声明)中定义的方法被调用时
才会被调用。所以
activate仅当
togglecommand被调用时,才会被调用。如果没人点菜单,则它永远不会被调用。
对于本例来说,它做了两件事:一、创建了一个窗口并把这个窗口插入到 Atom workspace中。
@yourNameWordCountView = new YourNameWordCountView(state.yourNameWordCountViewState) @modalPanel = atom.workspace.addModalPanel( item: @yourNameWordCountView.getElement(), visible: false )
这里我们可以无视state 参数 本例中并没有用到它。
二、创建了一个CompositeDisposable 的实例,以注册插件中所有可以被调用的命令。
# Events subscribed to in atom's system can be easily cleaned up with a CompositeDisposable @subscriptions = new CompositeDisposable # Register command that toggles this view @subscriptions.add atom.commands.add 'atom-workspace', 'your-name-word-count:toggle': => @toggle()
下一步,我们来编写
toggle函数。这个函数仅仅是把我们在
activate函数中声明的View做了显示/隐藏
处理。
toggle: -> console.log 'YourNameWordCount was toggled!' if @modalPanel.isVisible() @modalPanel.hide() else @modalPanel.show()
现在,我们来验证一下插件是否有效。
The
Flow
现在,我们来回顾一下整个包的执行流程:
Atom 运行
Atom 开始加载插件
Atom 读取你编写的
package.json
Atom 读取 keymaps, menus, styles 和main 模块
Atom 完成加载插件
用户通过
your-name-word-count:toggle来运行你的插件
Atom 运行你main模块中的
activate函数(本例中,插入了一个窗口)
用户再次点击
your-name-word-count:toggle时,Atom隐藏了你的插件窗口。
用户再次点击
your-name-word-count:togglecommand ,Atom再次显示你的插件窗口
Atom 中途不会释放你的插件
最终, Atom 关闭时会 调用所有的插件定义的serializations
提示: 注意,如果你用了
activationCommands,流程会有所不同。
插件:单词计数器
现在,我们已经理解了Atom插件的基本工作原理,让我们来修改代码,实现一个小插件吧。
当插件被激活时,我们来数一数Atom当前正在编辑的文档窗口里,有多少个单词吧。
toggle: -> if @modalPanel.isVisible() @modalPanel.hide() else editor = atom.workspace.getActiveTextEditor() words = editor.getText().split(/\s+/).length @yourNameWordCountView.setCount(words) @modalPanel.show()
atom.workspace.getActiveTextEditor().获得了当前Atom编辑窗口。
getText()获得了字符串。
最后,我们调用
setCount()(在view中我们稍后会声明它),来把结果显示出来。
在
your-name-word-count-view.coffee文件中,我们声明了函数setCount()
setCount: (count) -> displayText = "There are #{count} words." @element.children[0].textContent = displayText
运行结果如下:
基础的Debugging
你应该注意到了代码中的 console.log因为Atom是基于 Chromium 开发的,所以有一些常规的调试工具供你使用。
用快捷键 Ctrl+Shift+I打开开发者模式,激活开发者工具。
对于做过Web开发的同学们来说,这应该是很熟悉的。
测试
建议测试一下你的插件,如果把插件放置到 spec目录下,Atom就可以运行它。
Jasmine v1.3 可以用来执行测试
运行测试
点击 Alt+Ctrl+P 或通过菜单的 View
> Developer > Run Package Specs 项目。
也可以在控制台用
atom --test spec命令来运行它。
总结
现在,你已经完成了你的第一个插件,现在来发布它吧。详见 publish
相关文章推荐
- Atom插件开发入门教程(一)
- Atom插件开发入门教程(四)
- Atom插件开发入门教程(二)
- xbmc视频插件开发入门教程
- Chrome插件开发入门教程
- 基于jquery插件开发入门教程
- 使用 ADD-ON SDK 开发 基于 Html JQuery 和 CSS 的 firefox 插件入门教程1: 创建一个简单的 Add-on
- [手把手教]【整理一些discuz插件开发制作入门级教程】
- 插件__[手把手教]【整理一些discuz插件开发制作入门级教程】
- Chrome插件开发入门教程
- Atom插件开发入门教学(五)
- K3BOS插件开发入门教程
- [手把手教]【整理一些discuz插件开发制作入门级教程】
- xbmc视频插件开发入门教程
- Firefox扩展开发 (插件开发) Extension开发 入门教程 5步走 五步走
- IntelliJ IDEA插件开发入门教程(一)
- JavaBeans 程序开发从入门到精通教程
- PHP开发入门教程之面向对象
- Hibernate入门教程2--Hibernate3在Eclipse3.2下的简单开发
- Jigloo 开发 SWT 的入门教程