Atom的view框架SpacePen
来源:互联网 发布:余弦相似度 网络 编辑:程序博客网 时间:2024/06/06 04:59
虽然现在SpacePen已经不被官方支持了,但是在Atom团队退出新的view系统之前,他还是最好的选择。
例子
space-pen定义了一套生成HTML的DSL,只要继承View类,并且写一个content类方法,就可以在这个类方法中使用这套DSL:
class Spacecraft extends View @content: -> @div => @h1 "Spacecraft" @ol => @li "Apollo" @li "Soyuz" @li "Space Shuttle"
这个DSL还是比较明义的,有div,h1,ol这些方法加上参数构成。
View继承自jQuery,所以View子类的实力上可以使用所有jQuery方法:
view = new Spacecraftview.find('ol').append('<li>Star Destroyer</li>')view.on 'click', 'li', -> alert "They clicked on #{$(this).text()}"
原理
SpacePen的View是JQuery的子类。SpacePen的任务就是根据content函数中的定义构造出一个对应的JQuery对象。
class View extends jQuery
SpacePen的构造函数如下:
constructor: (args...) -> if @element? //如果设置了element,则用element实例化。这里调用jQuery.fn.init.call,可以理解为“调用父类构造函数” jQuery.fn.init.call(this, @element) else //否则使用子类定义的content函数来生成HTML,并实例化 [html, postProcessingSteps] = @constructor.buildHtml -> @content(args...) jQuery.fn.init.call(this, html) throw new Error("View markup must have a single root element") if @length != 1 @element = @[0] @element.attached = => @attached?() @element.detached = => @detached?() //处理outlet标签 @wireOutlets(this) //处理事件标签 @bindEventHandlers(this) //在所有子元素上添加spacePenView属性,设置为this @element.spacePenView = this treeWalker = document.createTreeWalker(@element, NodeFilter.SHOW_ELEMENT) while element = treeWalker.nextNode() element.spacePenView = this //触发后置处理步骤(subview是在这个步骤才添加上的) if postProcessingSteps? step(this) for step in postProcessingSteps //如果定义了额外的初始化函数,则调用 @initialize?(args...)
最为核心的是buildHtml,也就是生成这个View的HTML。这是通过Builder这个类实现的。代码不长:
class Builder constructor: -> @document = [] @postProcessingSteps = [] buildHtml: -> [@document.join(''), @postProcessingSteps] //@div,@xxx什么的其实是转化到调用这个方法,name就是"div"等 tag: (name, args...) -> options = @extractOptions(args) @openTag(name, options.attributes) if SelfClosingTags.hasOwnProperty(name) if options.text? or options.content? throw new Error("Self-closing tag #{name} cannot have text or content") else options.content?() @text(options.text) if options.text @closeTag(name) openTag: (name, attributes) -> if @document.length is 0 attributes ?= {} attributes.is ?= registerElement(name) attributePairs = for attributeName, value of attributes "#{attributeName}=\"#{value}\"" attributesString = if attributePairs.length " " + attributePairs.join(" ") else "" @document.push "<#{name}#{attributesString}>" closeTag: (name) -> @document.push "</#{name}>" text: (string) -> escapedString = string .replace(/&/g, '&') .replace(/"/g, '"') .replace(/'/g, ''') .replace(/</g, '<') .replace(/>/g, '>') @document.push escapedString raw: (string) -> @document.push string subview: (outletName, subview) -> subviewId = "subview-#{++idCounter}" @tag 'div', id: subviewId @postProcessingSteps.push (view) -> view[outletName] = subview subview.parentView = view view.find("div##{subviewId}").replaceWith(subview) extractOptions: (args) -> options = {} for arg in args switch typeof(arg) when 'function' options.content = arg when 'string', 'number' options.text = arg.toString() else options.attributes = arg options
总体上,Builder使用了递归的思想来生成HTML。
技巧
把确定/显示/隐藏的逻辑放在View里
space-pen只是一个view系统,负责输出HTML,怎么用她不管。但是如果我们实现的是一个对话框,可以吧显示/隐藏的逻辑放在View类中,方便使用。DEMO代码如下(参考了md-writer插件):
//初始化,绑定默认快捷键initialize: -> atom.commands.add @element, "core:confirm": => @onConfirm() "core:cancel": => @detach()//确认onConfirm: -> ...//显示display: -> @panel ?= atom.workspace.addModalPanel(item: this, visible: false) @previouslyFocusedElement = $(document.activeElement) @panel.show() ...//隐藏detach: -> return unless @panel.isVisible() @panel.hide() @previouslyFocusedElement?.focus() super
需要注意的就是,显示前获取当前激活的元素,对话框结束后,恢复之前激活的元素。
关于对话框设计的思想
看了一些插件的源码,对话框类设计的思想主要有两种:
- 逻辑在对话框类中
- 逻辑在对话框外,通过回调的方式,对话框来触发
目的性很强的对话框,可以使用第一种。通用的,则用第二种。
参考网址
- atom-archive/space-pen
- Let’s choose a view framework for docs, generated packages, etc. · Issue #5756 · atom/atom
0 0
- Atom的view框架SpacePen
- Atom的view框架2-SpacePenViews
- REST:Atom的开源框架Apache Abdera
- Atom Editor 插件 atom-less 的使用方法
- html view的基本框架
- 自定义View的框架学习
- Qt 的Graphics View框架
- Qt的Graphics/View框架
- blogger 的 atom api
- 15nm的atom?
- Erlang的atom
- atom lock的实现
- atom编辑器的使用
- Atom 编辑器的使用
- 我的atom插件
- atom的插件必备
- atom的插件必备
- Atom使用的技巧
- 深入理解共享元素变换(Shared Element Transition)-上
- AIX5.3中将Oracle SGA PIN在内存中的步骤
- UVa 12108 Extraordinarily Tired Students(特别困的学生)
- UFLDL教程答案(4):Exercise:Softmax Regression
- Manacher算法
- Atom的view框架SpacePen
- Received CISSP Lapel PIN
- MySQL的timeout超时你遇到过几种情况
- Auto Layout(Storyboard)
- 实例详解机器学习如何解决问题
- START WITH CONNECT BY PRIOR子句实现递归查询
- nginx Makefile中添加编译自定义模块
- C#中使用DotNetZip选择指定文件并解压
- 从框架看PHP的五种境界及各自的薪资待遇