Issuu on Google+

2011

李晓肆 leexiaosi@gmail.com

[ JQUERY MOBILE 进阶] 通过对 jQuery Mobile 源代码分析,详细介绍了 jQuery Mobile 的主要 API 和实现原理, 并从开发实践角度,提供了一些参考意见和实现方式。


Advance jQuery Mobile

前言 ——谢一位新交的老朋友 首先要感谢 Eddy 老兄,我们共事方才一个多月,却像一对老搭档一样,默契十足。很 多时候,都是他鼓励我去做自己喜欢的事情,一句句“你可以。。。” ,常常使我茅塞顿开,同 时他涉猎广趣,很多奇思妙想和新颖的力作,常常令我着迷,有时我不禁感叹,他心态比我 年轻,而事实上,他在 80 的开始,我在 80 的末梢。 李开复曾在微博写道: 有一本书的作者访问了一百位名人,问他们希望 25 年岁最需要知道的一件事?最多的 回答是“希望有前辈告诉我,鼓励我去追寻自己的梦想。” 而我按照家乡虚岁的计算,恰是 25 岁,正处在理想和现实的坡道上,很多时候都是一 次次拼命向理想去爬,又一次次下滑到现实的坎坷路上。 截止到今天,3 月 14 日,也恰是我来北京一年整,去年的今天,我下了火车看到的北 京是白茫茫一片,恰如我当时的心情,对北京一片陌生,既充满着期待,也加杂着迷茫。 而今,随仍处于濒临“颠沛流离”的处境,但是终究是落下脚,基本懂得了这里的生成 规则。 现实的残酷常常使我们垂头丧气,不知所措。可是北京这样的城市,一旦缺失了梦想, 支撑的身体的宛如一尊行尸走肉。与其唾骂世态,不如梦想燃烧。。 。 这篇文档的整理和归纳,也是起因于 Eddy 老兄的“怂恿” 。 于是,奋笔疾书,以谢知遇之恩。 李晓肆 2010-03-14


1. jQMobile 实现原理 1.1. 组件老祖 Widget jQuery Moile 从代码实现角度来看,与 jQuery UI 的实现源于一脉,底层都是依赖 jQuery 核心库,Widget(组件或 UI 部件)的实现都是使用了 jQuery.ui.widget.js 这个包(此处的包指的 是 jQuery UI 或 jQuery Mobile 拆解包)。强烈建议大家阅读一下这个包的内容,未压缩版只有 7K 左右, 不到 300 行代码, 通过这个包,大家基本可以了解整个 jQuery UI 或者是 jQuery Mobile 的组件实现原理。下面只做简要的描述。 jQuery.ui.widget.js 包中,实现了一个 Widget 的基本类,这个类的基本形式图 1-1

$.Widget.prototype + widgetName : String + widgetEventPrefix : String + options : Object + + + + + -

= "widget" = ""

_createWidget (Obj ect options, $Obj ect element) _getCreateOptions () _create () _init () destroy () w idget () option () _setOptions () _setOption (String key, Obj ect v alue) enable () disable () _trigger ()

: v oid : Obj ect : v oid : v oid : v oid : DomObj ect : $Widgetprototype : $Widgetprototype : $Widgetprototype : $Widgetprototype : $Widgetprototype : $Widgetprototype

图 1-1$.Widget.prototype

表 1-1Widget 类的定义

Widget options

Object { disabled=false}

配置项

widgetEventPrefix

""

未知(?)

widgetName

"widget"

控件名

_create

function()

创建方法

_createWidget

function()

创建组件的构造函数

_getCreateOptions

function()

获取创建的配置项

_init

function()

初始化

_setOption

function()

设置单个配置项

_setOptions

function()

设置多个配置项

_trigger

function()

触发事件方法

destroy

function()

销毁方法

disable

function()

使不可用

enable

function()

使可用


option

function()

配置方法

widget

function()

返回真实的 DOM 元素

附:以上是我个人翻译的,缺乏严谨性

更好的建议是, 在火狐浏览器的 firbug 或者是谷歌浏览器或者是 Safari 浏览器的 console 中输入 >>>$.Widget.prototype jQuery 中使用了很多 javascript 原型继承的方式,上面的内容如果无法理解,可以购买 一本道格拉斯(Douglas Crockford)的《JavaScript 语言精粹》,有关 javascript 的基础知识,本 文不展开讲解。 这里需要注意一点,以”_”标记的方法,表示是私有方法,最好不要尝试使用和修改。 这个组件类 Widget,就是 jQuery UI 和 jQuery Mobile 的开山老祖。几乎所有的 jQuery Widget(UI 组件或者部件,包括 jQuery UI 和 Mobile)都是直接或间接继承了$.Widget.prototype。 从 OO(面向对象)的角度上,$.Widget.prototype 是所有 UI 组件的基类。 jQuery.ui.widget.js 闭包中提供了一个$.widget 组件扩展函数,函数的定义形式如下 $.widget(name,base,prototype) name:ui 组件全称 命名空间加名成,形如”mobile.button” base:基类 protoype:扩展的原型 $.widget 会将通过$.Widget 或其子类的扩展的新 UI 组件类收归到相应的空间下。jQuery Mobile 中几乎所有的组件都是在$.Mobile 这个命名空间下。 如果你熟悉 jQuery 中插件编写常用的两个函数,$.extend 或$.fn.extend 函数,你将会非 常容易的理解$.widget,同$.extend 和$.fn.extend 的扩展形式一样,$.widget 只是提供了一种 更好的组件扩展方式。我这里就做个模拟演示。 $.widget(“猫科.老虎", ”猫” ,{“特征”:”脑袋有个王”}) 于是在 jQuery 中就会出现这样一个“$.猫科.老虎”的类,它将继承猫的特性,同时具 有值为“脑袋有个王”的“特征” 。 当然,上面纯属一种形象地演示。 真正的实现,例如在 jQuery Mobile 增加个组件叫做”leexiaosi”,可以这样扩展 $.widget(“mobile.leexiaosi” ,{email:”leexiaosi@gmail.com”,warn:”非诚勿扰!”}) (使用了$.widget 的另一种方式,直接继承自$.Widget)

于是,如图$.mobile.leexiaosi 将会继承$.Widget 的特征,此外还扩展了个属性 email, warn。

$.mobile.leexiaosi + email : String + warn : String

= "leexiaosi@gmail.com" = "非诚勿扰!"

图 1-2$.mobile.leexiaosi

熟悉 jQuery 的人都懂得,$(即 jQuery 工厂函数)上的方法都是公共方法,而非 jQuery 对 象上的方法。为了可以让 jQuery 对象可以调用方法,需要在$.fn(即 jQuery 的原型)上扩展方 法。所以 jQuery.ui.widget.js 还定义了一个函数$.widget.bridge,这个函数的作用就是往 jQuery.fn 上发布组件工厂函数的同名调用方法,函数的定义形式如下: $.widget.bridge(name,object) name:表示代理调用方法的名称,一般与组件的工厂函数相同 object:即组件对象


例如通过$.widget.bridge 可以将$.mobile.leexiaosi 发布到 jQuery.fn 上, $.widget.bridge(“leexiaosi”, $.mobile.leexiaos) 这样就会存在一个$.fn. leexiaosi,可以使用 jQuery 对象调用 leexiaosi $(“div”).leexiaosi() 好了,关于 jQueryUI 和 Mobile 的老祖宗 Widget 的实现,就讲解到这里,上面只做概要 的演示,细节上可能存在争议,敬请指正。

1.2. 组件之母$.mobile.widget 上一小节介绍的是 jQ Mobile 的老祖宗,那么现在介绍的就是 jQ Mobile 的老母亲 $.mobile.widget,jQuery Mobile 的所有 UI 组件几乎都是通过$.widget 对$.mobile.widget 的扩 展。 首先$.mobile.widget 自身就继承自$.Widget,只是重写了一个_getCreateOptions 方法, 从而支持从元素的 data 上去配置数据。jQuery Mobile 有别与 jQuery UI 的重要一点就是,组 件的生成使用 HTML 5 标记的形式,由 jQuery Mobile 自动生成。例如 <div data-role=”page”></div> 即可生成一个$.mobile.page 渲染的 ui 组件,具体的实现形式,后面的章节将会详细展 开。

1.3. 组件关系图 jQuery Mobile 通过$.widget 扩展的组件如图 1-3 $.Widget

$.mobile.widget

navbar

page

button

checkboxradio

collapsible

dialog

textinput

listview

slider

selectmenu

图 1-3jQuery Mobile 组件关系图

此外,jQuery Mobile 还有一些组件是通过插件的形式直接扩展到了 jQuery 的原型上 包括  buttonMarkup  controlGroup  fieldContain  fixHeaderFooter  grid 这五个组件的构建有别于$.Widget 的子孙类。

1.4. jQ Mobile 配置项 与 jQuery 的插件一样,jQuery Mobile 本身也提供一些可选配置,可以更改 jQuery Mobile


的一些默认配置,其命名空间都在$.mobile 下。下面主要简单介绍一下 名称

类型

默认值

简要说明

activeBtnClass

字符串

ui-btn-active

默认的 Button 激活样式

activePageClass

字符串

ui-page-active

获取当前活动的 page 页面样 式

ajaxEnabled

布尔值

true

页面是否默认启动 ajax 调用

ajaxFormsEnabled

布尔值

true

表单提交是否默认启动 ajax

ajaxLinksEnabled

布尔值

true

A 标记链接是否默认启动 ajax

autoInitialize

布尔值

true

是否自动进行初始化

defaultTransition

字符串

slide

默认的切换方式

hashListeningEnabled

布尔值

true

浏览器哈希表监听是否开启

loadingMessage

字符串

loading

Ajax 加载提示信息

metaViewportContent

字符串

width=device-width, minimum-scale=1, maximum-scale=1"

设置 viewprort 视窗的一些属 性

nonHistorySelectors

字符串

dialog

默认不记录到浏览器哈希表的 ui 组件

subPageUrlKey

字符串

ui-page

url 的子页面关键字

这里简单解释一些内容: ajaxEnabled,ajaxFormsEnabled,ajaxLinksEnabled 是设置默认启动 ajax 调用的,也就是 说页面之间的切换,以及表单的提交和 a 标记中的链接,都是采用 ajax 调用。 页面之间,已经通过 a 标记(jQuery Mobile 中很多的 a 标记被封装成了 button)单击, 都会启动 ajax 调用,这可能会使得后来者的脚本和样式失效。所以,最简单的方式是,将 一组相互直接链接或者切换的页面的脚本、样式分别提取到一个共同的 js 和 css 文件中,各 个页面都同时引用该脚本和样式文件。同事,各个页面直接的命名需要进行隔离,可以设置 主题相关的虚拟命名空间, 例如两个页面 a,b 都有 id 相同的”btn1”, 可以使用”a_btn1”,”b_btn1” 用以隔离不同的控件。避免在 jQuery 中查询出错。 loadingMessage 是 页 面 加 载 中 的 加 载 提 示 信 息 , 可 以 进 行 相 应 的 配 置 。 下 面 以 loadingMessage 的配置修改为例 默认配置的修改需要使用”mobileinit”事件,其执行是早于 ready 的。修改方法如下 $(document).bind(“mobileinit”,function(){ $.mobile.loadingMessage=”加载中”; })

1.5. jQ Mobile 的公共属性和方法 除了上面的配置项以外,在 jQuery Mobile 中还有几个重要的公共属性和方法  activePage 类型:jQuery 对象 例如:[div#mypage.ui-page] 获取当前的激活页面 这是个很好的的属性,通过这个属性,可以快速定位到激活页面,同时,有时后在前端 编程中,需要对当前页进行操作,activePage 无疑成为最快速获取的捷径


firstPage

类型:jQuery 对象 例如:[div#mypage.ui-page] 获取当前页面的第一个 page  keyCode 类型:对象 例如: >>>$.mobile.keyCode[“ALT”] 8 jQuery Mobile 对键盘按键做了映射,在相应键盘事件中,可以使用这个对象。  pageContainer 类型:jQuery 对象 例如:[body.ui-mobile-viewport] 获取页面的容器  path

类型:对象 记录着路径对象 urlHistory

类型:对象 记录着访问历史的页面对象 urlstack 类型:数组 记录着历史 url 对象 addResolutionBreakpoints()

参数:数组或者单值 增加屏幕的分辨率信息 changePage()

页面切换 这是非常重要的一个函数,可以实现自定义的页面切换。 主要的定义形式如下: $.mobile.changePage(to,transition,reverse,changHash) transtiton 类型是字符串,默认是”slide”,其含义是页面的切换方式。 reverse 类型是布尔值,默认是 false,即是否可以返回 changHash 类型是布尔值,默认是 false,即是否记录到历史记录哈希表中 to 类型有多种实现方式 方式一:字符串 如:$.mobile.changePage(“about/us.html”,”slide”,true,true) 方式二: jQuery 对象(即 page 对象) 如:$.mobile.changePage($(“#myPage”),”slide”,true,true) 方式三:对象 如:$.mobile.changePage({to:”default.aspx”,data:{name:”leexiaosi”},type:”post”},”slide”, true,true) 还有第四种是数组参数,不做介绍 这四种中,第一种适合不含数据交互的页面切换,两个页面间没有数据交互。第二种适


合在本地页面中进行 page 切换。第三种适合含有数据交互的页面切换。  gradeA() 用来做设备的支持等级  initializePage() 初始化页面,对页面 data-role 为 page 和 dialog 的 div 进行初始化。这个方法可以 用在动态加载 dom 的方法中,例如某些 dom 是通过 ajax 加载生成,则可以使用该方法 对也没再次进行初始化,以构建出 jQuery Mobile ui 效果  pageLoading()

参数:布尔值 如果值为真,则取消加载提示,如果为空或为假,则显示提示信息。 这个可以在自定义的 ajax 事件中调用,以增加友好的页面交互。 media()

css 支持程度检测 silentScroll()

参数:数值 正数表示使页面向上滑动,负数表示使页面向下滑动。数值表示滑动到纵坐标位置 的像素 updateHash() 更新历史记录哈希表

小结 本章对 jQuery Mobile 的实现原理做了简单的介绍。介于目前 jQuery mobile 尚且没有出 正式版,其官方的 api 参考文档介绍相对精简,缺乏深入的可参考内容。本章很多细节都是 我个人通过阅读源码理解写成,存在理解的偏差和个人主管臆断,实际开发中,还需要自己 动手,在实践中摸索。 要点:  理解 jQuery Mobile 的 UI 组件的实现方式  整体熟悉 jQuery Mobile 的配置项、公共属性和方法。


TEST