使用Windows Javascript库创建自定义控件

如果您已经用Javascript开发过windows store app程序,那么您肯定使用过Windows Javascript 库(WinJS)。这个库提供了一组CSS样式、Javascript控件以及工具, 可以帮助您快速地创建符合UX准则的windows store app。 这里工具是一组函数,您可以使用这组函数来创建自定义控件。

您可以使用任何您喜欢的模式或者库来编写JavaScript控件,WinJS提供的库函数仅仅是您的选择之一。使用WinJS库创建自定义控件的一个最大的好处是该自定义控件与其他的控件能够协同工作。且这种模式与WinJS命名空间的任何控件的创建模式是一致的。

在这篇文章中,我将会介绍如何使用winJS库构建自定义的控件。如果您对XAML控件的开发同样感兴趣的话您可以关注后续的博客。

首先,让我们来了解一下如何在页面里包含WinJS控件。有两种不同的方式:第一种是命令式的(即单独使用JavaScript);另一种是声明式的(即使用HTML元素附加的属性添加控件到HTML页面)。后一种方式提供了设计时的体检,如可以直接从工具箱拖动控件到页面,具体您可以参考MSDN的文档:MSDN quick start for
adding WinJS controls and styles

在本节中,我将会详细向您介绍如何在一个页面生成JavaScript控件,具体包含以下几个步骤:

1. 在您的HTML页面添加WinJS引用,因为您的控件需要用到这些文件中的API

Microsoft.WinJS.1.0/js/base.js

Microsoft.WinJS.1.0/js/ui.js

2. 在上述代码后,添加包含您定义的控件的脚本文件的引用:

<script src="js/hello-world-control.js"></script>

3.在您的应用程序的JavaScript代码中调用WinJS.UI.processAll()函数。该函数可以解析HTML和对页面上控件进行声明和实例化。如果您在创建windows store app的时候用的是Visual studio上所提供的模版,您会发现该函数已经在Default.js内自动调用。

4.以下列方式在页面使用控件:

<div data-win-control="Contoso.UI.HelloWorld" data-win-options="{blink: true}"></div>

一个简单的JavaScript控件

现在我们来创建一个非常简单的控件:Hello World控件。首先在您的项目中添加一个hello-world-control.js文件并将下面的JavaScript代码添加到该文件:

function HelloWorld(element) { if (element) { element.textContent = "Hello, World!"; } }; WinJS.Utilities.markSupportedForProcessing(HelloWorld);

然后在您的主页面以如下方式将该控件添加到页面:

<div data-win-control="HelloWorld"></div>

当您运行这段程序的时候,您会在主页面看到该控件已经被加载并且在页面呈现“Hello,World!”文本

这段代码的特殊之处是调用了WinJS里面的WinJS.Utilities.markSupportedForProcessing函数,您可以在HTML元素中直接调用这个函数。即相当于告诉WinJS您向页面添加了可信任的内容。更多信息请参考MSDN文档的介绍:WinJS.Utilities.markSupportedForProcessing

为什么使用WinJS工具、库来创建控件

上面代码只是向您介绍怎么来创建JavaScript控件,但是并没有使用到WinJS. 现在请看下面的代码段,该代码段声明了一个复杂的控件,其中包括事件、可配置的选项以及公共方法等:

(function (Contoso) { Contoso.UI = Contoso.UI || {}; Contoso.UI.HelloWorld = function (element, options) { this.element = element; this.element.winControl = this; this.blink = (options && options.blink) ? true : false; this._onblink = null; this._blinking = 0; element.textContent = "Hello, World!"; }; var proto = Contoso.UI.HelloWorld.prototype; proto.doBlink = function () { var customEvent = document.createEvent("Event"); customEvent.initEvent("blink", false, false); if (this.element.style.display === "none") { this.element.style.display = "block"; } else { this.element.style.display = "none"; } this.element.dispatchEvent(customEvent); }; proto.addEventListener = function (type, listener, useCapture) { this.element.addEventListener(type, listener, useCapture); }; proto.removeEventListener = function (type, listener, useCapture) { this.element.removeEventListener(type, listener, useCapture); }; Object.defineProperties(proto, { blink: { get: function () { return this._blink; }, set: function (value) { if (this._blinking) { clearInterval(this._blinking); this._blinking = 0; } this._blink = value; if (this._blink) { this._blinking = setInterval(this.doBlink.bind(this), 500); } }, enumerable: true, configurable: true }, onblink: { get: function () { return this._onblink; }, set: function (eventHandler) { if (this._onblink) { this.removeEventListener("blink", this._onblink); this._onblink = null; } this._onblink = eventHandler; this.addEventListener("blink", this._onblink); } } }); WinJS.Utilities.markSupportedForProcessing(Contoso.UI.HelloWorld); })(window.Contoso = window.Contoso || {});

许多开发者是通过上述方式来创建控件(即使用匿名函数、构造函数、属性、自定义事件),如果您的开发团队觉得使用这种方式很得心应手的话,那么您可以继续使用这个方法。但是对于大多数的开发人员来说,这些代码显得过于复杂。且许多的Web开发者并不熟悉此项技术。使用库,可以简化此类代码的编写。

除了提高程序的可读性,WinJS和其他的库也注意到了许多微妙的问题(如有效利用原型、属性和自定义事件)。通过这些库的使用,可以优化内存的使用率并帮您避免一些常见的错误。WinJS库就是这样的一个例子,但是使不使用的选择权在您。有关库给您创建控件带来的简便,建议您在看完这篇博客后重新来审视本节中的代码并且与使用WinJS后的代码来进行比较。

基于WinJS的JavaScript控件

下面是一个用WinJS来创建JavaScript控件的一个小的例子:

(function () { "use strict"; var controlClass = WinJS.Class.define( function Control_ctor(element) { this.element = element || document.createElement("div"); this.element.winControl = this; this.element.textContent = "Hello, World!" }); WinJS.Namespace.define("Contoso.UI", { HelloWorld: controlClass }); })();

并在页面中以如下方式声明控件:

<div data-win-control="Contoso.UI.HelloWorld"></div>

也许您并不熟悉这些,尤其是第一次接触WinJS,下面来我们来做下详细的解释。

1. 将代码包含在一个立即执行的函数中,这是JavaScript常见的模式:

(function () { … })();

这样做的目的是确保我们的代码是自包含的,并且不会创建任何无意义的全局变量,这是一个最佳的模式。

2. 函数起始处的“use strict”声明意味着使用ECMAScript 5 strict mode这个模式。这种做法是windows store app 的一个最佳的模式,它可以提高错误的检查效率以及与JavaScript的下一个版本的兼容性。

3. 现在我们来解释一些WinJS独有的代码。WinJS.Class.define()用来创建一个类,这个类可以帮助我们调用markSupportedForProcessing()函数,也可以简化对属性的创建。

4. 定义了一个名为Control_ctor的构造函数。WinJS.UI.processAll()是在Default.js中调用的,它会扫描页面上所有data-win-control属性中的内容, 找到我们的控件, 调用构造函数。

5. 在构造函数中,对页面元素的引用被存储在element这个参数中。然后把当前这个对象的实例(this)存储在element的winControl属性中。

·element || document.createElement("div") 用来支持命令式模型, 允许用户之后将一个控件附加在页面的某个元素上 ·这样维护页面元素的引用以及通过设置element.winControl来将该元素作为控件的一个引用来说是一个很好的方式。您不必担心对DOM对象循环引用会造成内存泄露,因为Internet Explorer 10会帮您关注这些。 ·该构造函数可以定义该控件的文本并将其设置为”Hello,World!”。

6. WinJS.Namespace.define()函数能使该控件是公共的且能被您项目中任何代码访问到。如果您不使用该函数,那么您需要在内联函数之外使用全局命名空间。

定义控件的options

将可配置的选项添加到自定义控件中会使我们的例子显得更有趣。下面的例子中会添加一个选项来控制内容以闪烁的形式出现。

var controlClass = WinJS.Class.define( function Control_ctor(element, options) { this.element = element || document.createElement("div"); this.element.winControl = this; // Set option defaults this._blink = false; // Set user-defined options WinJS.UI.setOptions(this, options); element.textContent = "Hello, World!" }, { _blinking: 0, blink: { get: function () { return this._blink; }, set: function (value) { if (this._blinking) { clearInterval(this._blinking); this._blinking = 0; } this._blink = value; if (this._blink) { this._blinking = setInterval(this._doBlink.bind(this), 500); } } }, _doBlink: function () { if (this.element.style.display === "none") { this.element.style.display = "block"; } else { this.element.style.display = "none"; } }, }); WinJS.Namespace.define("Contoso.UI", { HelloWorld: controlClass });

接下来,我们将这个控件添加到页面,您可以在data-with-option属性里面配置以上选项:

<div data-win-control="Contoso.UI.HelloWorld" data-win-options="{blink: true}"> </div>

为了使控件支持可配置选项,我们对代码作了如下更改:

1. 该选项是作为构造函数的参数来传递给控件的

2. 该选项的默认值是该类的私有属性的值

3. 调用WinJs.UI.SetOptions()函数可以重写该选项的默认配置

4. 添加一个公共属性(名为blink)作为新的选项

5. 通过添加一个函数来将控件的文本与blink选项相关联,从而控制文本以闪烁的形式出现。

在此示例中担当重任的部分是对WinJS.UI.setOptions()函数的调用。该函数能将选项中每个字段的值赋值到目标对象,目标对象是该函数的第一个参数。

在上述例子中,我们通过data-with-options来将控件的blink选项值设置为”true”。通过在构造函数中对setOptions()函数的调用就可以将该值传递给控件。即我们定义了一个名为blink的属性并定义了setter函数。该setter函数会被setOptions()调用并且将blink属性值赋值到控件。

为控件添加事件

我们已将为控件添加了一个blink选项,现在我们来为控件添加一个事件,该事件在blink的属性值改变时触发。

var controlClass = WinJS.Class.define( function Control_ctor(element, options) { this.element = element || document.createElement("div"); this.element.winControl = this; // Set option defaults this._blink = false; // Set user-defined options WinJS.UI.setOptions(this, options); element.textContent = "Hello, World!" }, { _blinking: 0, _blinkCount: 0, blink: { get: function () { return this._blink; }, set: function (value) { if (this._blinking) { clearInterval(this._blinking); this._blinking = 0; } this._blink = value; if (this._blink) { this._blinking = setInterval(this._doBlink.bind(this), 500); } } }, _doBlink: function () { if (this.element.style.display === "none") { this.element.style.display = "block"; } else { this.element.style.display = "none"; } this._blinkCount++; this.dispatchEvent("blink", { count: this._blinkCount }); }, }); WinJS.Namespace.define("Contoso.UI", { HelloWorld: controlClass }); // Set up event handlers for the control WinJS.Class.mix(Contoso.UI.HelloWorld, WinJS.Utilities.createEventProperties("blink"), WinJS.UI.DOMEventMixin);

现在我们给元素添加一个id,这样我们可以通过该id访问该元素。

<div id="hello-world-with-events" data-win-control="Contoso.UI.HelloWorld" data-win-options="{blink: true}"> </div>

添加一个事件监听器来监听“blink”事件:

$("hello-world-with-events").addEventListener("blink", function (event) { console.log("blinked element this many times: " + event.count); });

当您运行这段代码的时候,您会在visual studio 的JS控制台窗口看到一条每隔500毫秒输出的消息。

以下四个更改使得控件支持这个行为:

1. 调用了WinJS.Class.mix(Contoso.UI.HelloWorld,WinJS.Utilities.createEventProperties("blink"));创建了一个”onblink”属性,用户可以通过后台代码改变它或者可以在html页面的声明中绑定它。

2. 对WinJS.Class.mix(Contoso.UI.HelloWorld, WinJS.UI.DOMEventMixin)的调用将addEventListener, removeEventListener, 与dispatchEvent函数添加到了控件。

3. 通过对that.dispatchEvent("blink", {element: that.element})的调用blink事件就会被触发。并且该自定义事件是由元素的某个字段创建的。

4. 附加事件处理程序以监听blink事件。且对dispatchEvent()的调用仅仅在您已经在控件的构造函数中设置this.element时才会有效。

创建公共事件

下面我们来创建一个公共的函数即doBlink()函数来改变blink的值:

var controlClass = WinJS.Class.define( function Control_ctor(element, options) { this.element = element || document.createElement("div"); this.element.winControl = this; // Set option defaults this._blink = false; // Set user-defined options WinJS.UI.setOptions(this, options); element.textContent = "Hello, World!" }, { _blinking: 0, _blinkCount: 0, blink: { get: function () { return this._blink; }, set: function (value) { if (this._blinking) { clearInterval(this._blinking); this._blinking = 0; } this._blink = value; if (this._blink) { this._blinking = setInterval(this.doBlink.bind(this), 500); } } }, doBlink: function () { if (this.element.style.display === "none") { this.element.style.display = "block"; } else { this.element.style.display = "none"; } this._blinkCount++; this.dispatchEvent("blink", { count: this._blinkCount }); }, }); WinJS.Namespace.define("Contoso.UI", { HelloWorld: controlClass }); // Set up event handlers for the control WinJS.Class.mix(Contoso.UI.HelloWorld, WinJS.Utilities.createEventProperties("blink"), WinJS.UI.DOMEventMixin);

如果您需要通过javascript来调用doBlink()函数,那么您需要引用该控件。如果您是命令式的创建该控件,那么您可能已经添加了该控件的引用。如果您是以声明性的方式来进行的,那么您可以通过html元素的winControl属性访问该控件。例如,你可以通过以下代码访问:

$("hello-world-with-events").winControl.doBlink();

总结与回顾

通过上面的讨论我们为建立自定义控件做了以下工作:

将控件包含到页面 为控件创建options 为控件创建事件并响应该事件 为控件创建公共方法

时间: 2024-11-02 21:34:33

使用Windows Javascript库创建自定义控件的相关文章

《JavaScript忍者秘籍》——第1章 进入忍者世界 1.1即将探索的JavaScript库

第1章 进入忍者世界 本章涵盖以下内容: 介绍本书的目的和结构 将要关注的库 什么才是JavaScript高级编程 跨浏览器编程 测试套件示例 如果你正在阅读本书,应该知道,没有什么简单方法可以创建有效且跨浏览器的JavaScript 代码,除了编写整洁代码的常规挑战外,我们还要额外应对各种浏览器的差异和复杂性.为了应对这些挑战,JavaScript开发人员通常使用JavaScript库来实现通用和可重用的功能. 这些库虽然在方法.内容和复杂性方面有很大差异,但唯一不变的是:它们都需要简单易用,

使用Rico JavaScript库、ColdFusion MX 7和Windows Indexing Service构建一个

使用Rico JavaScript库.ColdFusion MX 7和Windows Indexing Service构建一个启用Ajax的搜索页面 几个月前,我和一些同事讨论关于将一个搜索工具添加到 Intranet 中(作 为一个向导)并将其扩展到企业网站中的可能性.此提议的主要目标之一是弄清 楚哪些访问者在查找 Web 内容并相应地改变了内容.我们中的一些人构想了一 个完全自定义的解决方案(我不是在开玩笑).他们建议在数据库服务器上构建 表以存放关键字以及与其相关的页面地址.关键字的提取将

Google排名中的10个最著名的 JavaScript库_javascript技巧

JavaScript 是 Web 开发与设计中不可或缺的东西,不管是一个简单的网页还是一个专业的站点,也不管你是高手还是菜鸟,如今 JavaScript 库越来越强大,可以胜任许多复杂的工作,然而同时,人们在众多 JavaScript 库面前又觉得无所适从,本文,我们将使用 Google 搜索出排名前 10 位的 JavaScript 库,并对它们逐一进行介绍. 1. jQuery: The Write Less, Do More, JavaScript Library jQuery 是一个很新

开发者必备的 12 个 JavaScript 库

现在 web 设计是最有趣的了,做好 web 设计不仅要熟练使用 Javascript,css 和 html 等,还要有自己的创意设计.为了方便大家发挥自己的创意,就产生了很多 JS 框架,Node.js 扩展等等.有了这些工具,开发者们就能专注于创意设计了,而不用为某个功能而花费太多精力.这里我们介绍的是 12 个开发者们必备的 JavaScript 库,都是一些很基础功能很强大的库.有了这些库,开发者们可以节省很多时间,大大提高开发的效率,所以大家赶紧收藏起来吧:) 1) Headroom.

Google 排名中的10 个最著名的JavaScript 库

中介交易 SEO诊断 淘宝客 云主机 技术大厅 JavaScript 是 Web 开发与设计中不可或缺的东西,不管是一个简单的网页还是一个专业的站点,也不管你是高手还是菜鸟,如今 JavaScript 库越来越强大,可以胜任许多复杂的工作,然而同时,人们在众多 JavaScript 库面前又觉得无所适从,本文,我们将使用 Google 搜索出排名前 10 位的 JavaScript 库,并对它们逐一进行介绍. 1. jQuery: The Write Less, Do More, JavaScr

开发者不容错过的12款开源JavaScript库

JavaScipt几乎是所有前端http://www.aliyun.com/zixun/aggregation/7155.html">开发人员必会的编程语言,并且,随着各种移动APP的串红,JavaScript还可以用来开发移动应用.除此以外,为了丰富前端/移动开发,有不少开发者推出了各种基于JavaScript的库,这些几乎能实现任何你需要的功能,并且有些库可以用来开发某些特定的功能,非常强大. 本文推荐了12款开源的JavaScript库,这些库可以帮助大家快速开发各种前端/移动应用,

WEBJX分享最有用的轻巧和独特的JavaScript库

文章简介:简化web开发者复杂任务的25个有用的javascript库. 在web开发当中,为了制作一个吸引人的动态网站,开发者往往需要使用复杂的编程来实现一些浏览器效果,复杂的数据验证,等等,这个时候使用javascript变得是非常有用的,javascript是具有特殊功能的与正常的html网页结合使用的编码语言,随着许多技术的进步,许多著名的JavaScript库应运而生,像 Dojo, Moo Tools 和其他工具,他对于网页开发者来说确实使工作变得更加容易,许多复杂的任务可以在几分钟

Javascript资源分享:WEBJX分享最新的JavaScript库

文章简介:JavaScript库已经成为了一个web开发人员的工具包的重要组成部分,在这里为大家推荐15个最新的JavaScript库,来增强您的Web体验. JavaScript库已经成为了一个web开发人员的工具包的重要组成部分,在这里为大家推荐15个最新的JavaScript库,来增强您的Web体验. 1. Pikaday : Standalone JavaScript Datepicker 这是一个令人耳目一新的JavaScript日期选择器 轻量轻(压缩和gzip后小于5KB) 没有依

使用 &amp;lt;multimap&amp;gt; 库创建重复键关联容器

摘要:标准库的 multimap 容器与 map 关联容器非常类似--但是, multimap 允许重复键.这个特性使得 multimap 比想象的要有用得多.本文将对之进行探讨 . 在"使用 <map> 库创建关联容器"一文中,我们讨论了标准库 中的 map 关联容器.但那只是 map 容器的一部分.标准库还定义了一个 multimap 容器, 它与 map 类似,所不同的是它允许重复键.这个属性使得 multimap 比预想的要更有用:比 如在电话簿中相同的人可以有两个