Sciter中订阅事件的几种方式

来源:互联网 发布:虚拟机linux网不可用 编辑:程序博客网 时间:2024/06/05 17:06

在Sciter中,给元素绑定事件有好几种写法,每种方式都有细微的区别。

以下代码在Sciter 4.0.1.1中测试。

一、传统的方式

<html><head><script type="text/tiscript">self.subscribe("click", "button", function(evt){stdout.println("<button> " + this.text);});self.subscribe("click", "a", function(evt){stdout.println("<a> " + this.text);});self.unsubscribe("click", "button");</script></head><body><button>button A</button><button>button B</button><a>link</a></body></html>
传统的方式是通过subscribe绑定,unsubscribe用于解绑。

注意:以上代码在Sciter 4.0.2.5257以前的版本中不起作用,因为unsubscribe对第二个选择器参数没有反应,导致无法对特定元素解绑。

self.unsubscribe("click");
而如果这样写的话又会对所有元素的click事件解绑,误伤了友军。

对于上面的问题,除了用高版本的Sciter外,还可以利用事件名称空间绕过去

<html><head><script type="text/tiscript">self.on("click.first", "button", function(evt){stdout.println("<button> " + this.text);});self.on("click.second", "a", function(evt){stdout.println("<a> " + this.text);});self.off(".first");</script></head><body><button>button A</button><button>button B</button><a>link</a></body></html>
注意:上面改用了on/off写法,这和subscribe/unsubscribe是等价的。这是一个语法糖,减少字母输入。

在事件名称后加入".xxx"来声明一个名称空间,这样在后面可以对该空间下的所有事件进行解绑,而无须关心具体是什么事件,是什么元素。

<html><head><script type="text/tiscript">self.on("click.module", "button", function(evt){stdout.println("<button> " + this.text);});self.on("click.module", "a", function(evt){stdout.println("<a> " + this.text);});self.off(".module"); // 解绑".module"名称空间下的所有处理器,无须关心具体事件</script></head><body><button>button A</button><button>button B</button><a>link</a></body></html>

二、现代方式

这种方式把事件名称写在前面,且对所有匹配的元素有效。(我个人认为这里的选择器语法产生了歧义,"$"符号返回的是一个元素,而不是array,但这里却是对所有匹配到的元素生效)

<html><head><script type="text/tiscript">event click $(button) (evt, element) {if (element == self) {stdout.println("element == self");}stdout.println(this.text);}</script></head><body><button>button A</button><button>button B</button></body></html>
这种方式多了一个参数element,在全局函数中,它是根元素self。而在类中它是触发事件的元素
<html><head><style>mywidget {prototype: MyWidget;display: block;size: 100;background: green;}</style><script type="text/tiscript">class MyWidget : Element{event click(evt, element) {stdout.println(element == this);}event click $(button) (evt, element) {stdout.println(element.text);}}</script></head><body><mywidget><button>button A</button><button>button B</button></mywidget></body></html>

这种方式无法取消事件订阅,所以它一般用于类中。同时也要注意的是,第二个参数的意义在全局函数和类成员中是不同的,要注意区别。

三、本地事件处理器

在Sciter中,每个DOM元素有两组事件处理器,一是上面提到的脚本处理器,二是针对某一个DOM元素的本地处理程序。

本地事件处理程序是针对某一个DOM元素实例进行绑定的,所以它有着自己的内存区域,不会与其他元素共享该处理程序,这种写法看上去很像是前面两种方式的语法糖,但其实不是,它们是有区别的。

<html><head><script type="text/tiscript">$(#a) << event click.aaa(evt) {stdout.println("<button> " + this.text);}$(#b) << event click.ns(evt) {stdout.println("<button> " + this.text);}$(#c) << event click(evt) {stdout.println("<a> " + this.text);this >> this function; // 解绑当前处理器。意味着该处理器只会运行一次}$(#b) >> "click.ns"; // 解绑</script></head><body><button#a>button A</button><button#b>button B</button><a#c>link</a></body></html>
通过"<<"绑定处理器,通过">>"解绑。同样也支持名称空间。可以在函数内部通过"this >> this function;"这个语法解绑,达到只执行一次的目的。

前面说了,这种方式只能对某一个元素实例绑定,所以像下面这样的写法,只会绑定到第一个元素上

<html><head><script type="text/tiscript">$(button) << event click(evt) {stdout.println("<button> " + this.text);}</script></head><body><button>button A</button><button>button B</button><a>link</a></body></html>
其中button b不会订阅事件。

总结:

一般情况下,我建议在全局中使用传统的"element.on"方式去订阅事件,在类中使用"event click $(selector)"的方式去订阅事件。

而"<< event"这样的方式要根据实际情况选择是否使用,原因上面也提到了,它只能为某一个元素创建事件处理程序,而且是独立的处理程序,不会与其他元素共享。