分享 在 Opal 中包装 Js 库的方法

mizuhashi for Shopper+ · 发布于 2016年8月30日 · 最后由 flemon1986 回复于 2016年10月24日 · 482 次阅读
23529

Opal是一个Ruby2Js编译器,从语言的角度来说实现得相当不错,例如你可以在浏览器里用method_missing等等。

虽然opal没什么文档,但是它本身算是一个less suprise的东西,这里主要介绍一下怎样wrap js库到ruby。

最小环境

一个最简单的opal rack server在https://github.com/opal/opal/tree/0-10-stable/examples/rack

git clone https://github.com/opal/opal.git
git checkout 0-10-stable
cd opal/examples/rack
bundle
bundle exec rackup

修改application.rb后刷新就能看到改动。在application.rb里可以用require引入其他rb文件,和普通ruby是一样的,详见http://opalrb.org/docs/guides/v0.10.1/compiler_directives.html

内联Js

puts `window.title` #=> 'opal example'
`console.log(1)`

使用反引号会把语句直接插入到生成的js中,不进行编译。

第一次用到这个的时候很容易迷惑,

a = `{a: 1}`
puts a.class

这里的a是什么呢?

当我们打印a的class时,会提示Uncaught TypeError: a.$class is not a function

这里的a是一个原生js对象,所以并没有ruby对象的方法。从报错也可以发现,class的调用是翻译成$class的。所以opal对象就是特殊的js对象,包含了很多以$为前缀命名的ruby方法。记住这一点,理解之后的内容就非常简单了。

Native模块

puts Native(`{a: 1}`).a      #=> 1
puts Native(`{a: 1}`).class  #=> Native::Object

Native可以把js对象直接包装成opal对象,并且将ruby的方法调用直接代理到js对象上。

对于更严谨的封装,可以使用include Native。

class B
  include Native

  def val
    `#@native.v`  #tips: #@native 等同 #{@native}
  end
end

class A
  include Native
  alias_native :b, as: B
end

a = A.new(`{b: {v: 1}}`)
puts a.b.val #=> 1

include Native的类,initialize会接受一个js对象,并存放在@native,如果自己定义了initialize,需要super一下。

alias_native可以将一个ruby方法调用转发到js对象上,as: B的意思是用B类去初始化返回值(可选)。

Native模块的例子:opal stdlib对console的封装。详细的Native和Native::Object可参阅Native的实现

.JS调用

opal中.JS是一个关键字,用于调用js对象方法。

a = `{a: function(){return 1}, b: 2}`
puts a.JS.a #=> 1
puts a.JS[:b] #=> 2

同名冲突

opal中的局部变量是按同名翻译成js的,所以同名的ruby变量有可能会和js中的冲突。 例如:

document = Native(`document`)

看上去是把js的native document赋给局部变量document,但实际上编译出来的是:

var document = Opal.nil;
document = self.$Native(document);

不难想象document会为空。

闭包作用域

opal中的class和module实际上都是function闭包,所以可以直接在module作用域里写内联js,然后定义方法去调用,一个例子是opal stdlib的base64实现。这个是不区分类作用域和实例作用域的,想想翻译的js就清楚了。

另外,opal是不分symbol和string的,对于不看文档就开搞的,这个需要注意一下。

共收到 1 条回复
18898

加一个不容易找到的贴士: Element.expose :extra_plugin_method

因为其他jQuery插件的方法不自动转成opal ruby方法,你需要一个一个expose...我还在寻找有没有更方便的,直接expose插件里所有方法

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册