jQuery - KISSY Rosetta Stone

快速上手

jQuery 1.8.3 KISSY 1.3
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="https://somedomain.com/path/to/plugin.js"></script>
<script src="https://somedomain.com/path/to/anotherplugin.js"></script>

<script>
$(document).ready(function() {
    // HTML 加载分析完成,DOM 树创建完毕,即 DOMContentLoaded 事件的跨浏览器支持。
    $.foo.bar()
})

// 简写
$(function() {
    $.foo.bar()
})
</script>
      

作用域:jQuery、$ 为全局变量。

插件:jQuery 以插件机制方便开发者扩展其自身所不提供的功能,插件可以静态加载, 与 jquery.js 合并,或者使用 Sea.js 之类的模块加载器动态加载。本文中的所有示例只限于 jQuery 核心功能,不讨论插件。

<script src="http://a.tbcdn.cn/s/kissy/1.3.0/seed-min.js"></script>

<script>
KISSY.ready(function(S) {
    // 同样注册 DOMContentLoaded
    // S 即 KISSY,将全局变量赋值到回调函数的第一个参数,语法糖+性能优化
    S.foo.bar()
})
</script>
      

作用域:KISSY 为全局变量。

模块:KISSY 本身也是个加载器,DOM 操作、Ajax 请求、事件机制、Base 模块等, 在 KISSY 内部都是以 KISSY 模块的形式存在。要扩展 KISSY,加上项目需要的公用库,只需按照 KISSY Loader 约定的语法,添加、使用模块即可。

KISSY 在回调函数里加 S 参数的做法,会让人想到 YUI 。但与 YUI 不同的是,KISSY 不是个构造函数,它只是个普通对象。

KISSY.isPlainObject(KISSY) // ==> true

回调函数里那个 S,正是 KISSY 对象自身。

KISSY Loader

编写模块 使用模块 注解
// 类
KISSY.add('my/dialog', function(S) {
    function Dialog() {}

    return Dialog
})
      
// 在编写时引用外部模块
KISSY.add('my/popupmanager', function(S, Dialog) {
    return {
        // 公共方法
        popup: function() {}
    }
}, {
    // 声明模块的依赖
    requires: [
        'my/dialog'
    ]
})

// 使用模块
KISSY.use('my/popupmanager', function(S, PopupManager) {
    PopupManager.popup('Hello, KISSY!')
})
      

这一套模块编写与应用的过程与时兴的其他模块加载器相若,与 Sea.js 的区别是,KISSY 不提倡匿名模块的使用。

也因为此,KISSY 的粒度比 jQuery 细,DOM 操作、Ajax 请求、事件支持等,都对应到相应的模块, 在使用时,可以有两种方式:

  1. 直接引用 kissy-min.js, 这其中已经打包了前述常用模块。
  2. 使用 KISSY Loader 提倡的方式,引用 seed-min.js, 在需要相关功能时显式声明。

方式二的代码示例如下:

// 直接 use
KISSY.use('node', function(S) {
    // 查找节点
    S.all('code')
})

// 放入 requires
KISSY.add('some-module', function(S, Node) {
    S.all('code')
}, {
    requires: ['node']
})
      

视你的项目需求复杂度而定,普通页面,直接使用方式一无妨。

选择节点

jQuery 1.8.3KISSY 1.3.0注解
$('div.foo:first')
S.one('div.foo')

jQuery 与 KISSY 的选择器语法基本相同,在 KISSY 中需要显式打开 sizzle 选择器引擎以支持 CSS 3 选择器。:first 是 jQuery 扩展,用于返回首个匹配选择器的节点, S.one 等同于此效果。

KISSY 默认仅支持 #id tag.class 常用形式,详细列表见 selector 文档

var foo = $('div.foo:first')

foo.some_method()
      
var foo = S.one('div.foo')

if (foo) {
    foo.someMethod()
}
      

假如找不到相应的节点,S.one 返回 null ,而 :first 返回的仍然是节点列表,只是为空。

$('div.foo')
S.all('div.foo')

选择所有 class 为 foo 的节点。

开启后 sizzle 引擎后, Node.all 在选择器与节点实例化上等同于 $ :

KISSY.use('sizzle', function(S) {
    var $ = Node.all

    $('div.foo').each(function() {
        console.log($(this).html())
    })
})
      
.find('p.foo:first')
.find('p.foo')
      
.one('p.foo')
.all('p.foo')
      

在给定节点中查找 class 为 foo 的 p 子节点。

KISSY 中用于处理节点的类叫做 NodeList ,S.one 与 S.all 是其静态方法,同时在它的原型链上也有 NodeList#one 与 NodeList#all 方法,可与 jQuery#find 对应。

操作节点

$('<div/>')

$('<a/>', {
    href: 'http://cyj.me',
    target: '_blank',
    title: 'EVERYTHING JAKE',
    click: fn
})
      
S.DOM.create('<div/>')

S.DOM.create('<a/>', {
    href: 'http://cyj.me',
    target: '_blank',
    title: 'EVERYTHING JAKE'
    // 不能在此处传递事件绑定
})
      

创建新的 DOM 元素,暂未添加至 DOM 树。

.html()
.html('foo')

.text()
.text('foo')

.val()
.val('foo')

.attr('foo')
.attr('foo', 'bar')

.prop('disabled')
.prop('disabled', false)
      
.html()
.html('foo')

.text()
.text('foo')

.val()
.val('foo')

.attr('foo')
.attr('foo', 'bar')

.prop('disabled')
.prop('disabled', false)
      

两者一致。

在 KISSY 早前的版本中,API 更偏向于 YUI 一些,不过这些都已成为过去,就好像那浮云一样。

工具方法

$.globalEval
$.isArray
$.isEmptyObject
$.isPlainObject
$.isWindow
$.makeArray
$.merge
$.now
$.trim
      
S.globalEval
S.isArray
S.isEmptyObject
S.isPlainObject
S.isWindow
S.makeArray
S.merge
S.now
S.trim
      

jQuery 的 工具包 与 KISSY lang 模块提供的辅助方法大约有 80% 的交集。

常用的基本都覆盖到了。

$.isNumeric(4338)
S.isNumber(4338)

判断是否为数值类型。

$.grep([1, 2, 3, 4, 5], function(value, index) {
    return value % 2 === 0
})
// ==> [2, 4]
      
S.filter([1, 2, 3, 4, 5], function(value, index) {
    return value % 2 === 0
})
// ==> [2, 4]
      

过滤数组。

// 扩展 jQuery.prototype
$.fn.extend({
    check: function() {
        return this.each(function() {
            this.checked = true
        })
    }
})
      

KISSY 中自然不会有这个,KISSY 的扩展机制请看 KISSY Loader 章节。

S.isNull
S.isObject
S.isRegExp
S.isString
S.lastIndexOf
      

KISSY 中的辅助方法更多。

S.substitute('Hello, {world}!', { world: 'pandora' })
// ==> Hello pandora!
      
KISSY 中提供的字符串替换方法,可以当做一个穷人版的模板引擎来用。
$.inArray(1, [1, 2, 3])       // ==> 0

// 还可以传起始下标
$.inArray(1, [1, 2, 3], 1)    // ==> -1
      
S.inArray(1, [1, 2, 3])       // ==> true

S.indexOf(1, [1, 2, 3])       // ==> 0

S.lastIndexOf(2, [1, 2, 2, 5])      // ==> 3
      

两者的返回值有所不同。jQuery 的更像是 Array#indexOf,在 if 表达式中使用时尤其需要注意。

$.extend({ foo: 1 }, { bar: 2, foo: 3 })
// { foo: 3, bar: 2 }

// 混入多个对象至首个
$.extend(obj0, obj1, obj2, obj3 ... objN)
      
S.mix({ foo: 1 }, { bar: 2, foo: 3 })
// { foo: 3, bar: 2 }

S.mix(
    obj0,
    obj1,
    true,       // 是否覆盖,overwrite
    ['foo', 'bar'],  // 白名单,只覆盖如下属性
    true        // 是否深度混入
)
      

混入一个或者多个对象到某一特定对象,是前端代码中比较常见的操作,尤其是要为函数、类提供初始参数时。

jQuery 提供的方法是 extend,KISSY 则叫 mix,两者的可变参数完全不同,使用时需注意。

// 混入方法、属性到构造器的原型链
S.augment(function Class() {}, {
    egg: function() {},
    ham: function() {}
})

// 继承类,同时混入自定义方法
S.extend(
    function SubClass() {},
    function BaseClass() {},
    {
        egg: function() {},
        ham: function() {}
    }
)
      

在 mix 的基础上,KISSY 还提供了 augment 与 extend 方法,方便扩展构造函数。

$.each(['foo', 'bar'], function(index, value) {
    console.log(index, value)
    // ==> 0 foo
    // ...
})

$.each({ foo: 1, bar: 2 }, function(key, value) {
    console.log(key, value)
    // ==> foo 1
    // ...
})
      
S.each(['foo', 'bar'], function(value, index) {
    console.log(index, value)
    // ==> 0 foo
    // ...
})

S.each({ foo: 1, bar: 2 }, function(value, key) {
    console.log(key, value)
    // ==> foo 1
    // ...
})
      

两者唯一的差别就是给回调函数的参数顺序不一样, KISSY 的更贴近 Array#forEach

$.map([1, 2, 3, 4], function(value, index) {
    return value + index
})
// ==> [1, 3, 5, 7]

$.map({ foo: 1, bar: 2 }, function(value, key) {
    return key + value
})
// ==> ['foo1', 'bar2']
      
S.map([1, 2, 3, 4], function(value, index) {
    return value + index
})
// ==> [1, 3, 5, 7]

// 不支持传入对象
      

KISSY 不支持传入对象,两者表现都与 Array#map 一致。

$.proxy(fn, context[, additionalArguments])

$.proxy(context, name)
      
S.bind(fn, context[, additionalArguments])
      

创建绑定上下文的匿名函数,参见 Function#bind

jQuery 还提供另一种调用形式,只需写一遍 context。

事件绑定

jQuery 1.8.3 KISSY 1.3 注解
$('#foo').click(fn)
$('#foo').focus(fn)
$('#foo').blur(fn)
$('#foo').mouseout(fn).mouseover(fn)

// 一次绑定多个的语法糖
$('#foo').on({
    click: function() {},
    hover: function() {}
})
      
S.one('#foo').on('click', fn)
S.one('#foo').on('focus', fn)
S.one('#foo').on('blur', fn)
S.one('#foo')
    .on('mouseout', fn)
    .on('mouseover', fn)

// 可以同时绑定到多个事件
S.one('#foo').on('mouseenter mouseleave', fn)
      

KISSY 不支持 .click 这种语法糖,确实也没有多少必要。

$('#foo').on('click', '.item', fn)
      
S.delegate('click', '.item', fn)

// 绑定事件监听函数执行时的上下文
S.delegate('click', '.item', fn, this)
      
事件代理。
$('#foo').click()
$('#foo').trigger('click')

// 仅触发绑定或者代理到 #foo 节点的 click 事件的监听函数
$('#foo').triggerHandler('click')
      
S.one('#foo').fire('click')

S.one('#foo').fireHandler('click')
      

触发事件,jQuery 中的 #triggerHandler 比较特殊。

KISSY 1.3版本中增加的#fireHandler

异步请求

jQuery 1.8.3 KISSY 1.3 注解
$.get(
    'http://example.com/items',
    function(items) {
        console.log(items)
    },
    dataType: 'json'
)
      
S.IO.get(
    'http://example.com/items',
    function(items) {
        console.log(items)
    },
    dataType: 'json'
)
      

普通 Ajax GET 请求。

$.get(
    'http://example.com/items',
    function(items) {
        console.log(items)
    },
    dataType: 'jsonp'
)
      
S.IO.jsonp(
    'http://example.com/items',
    function(items) {
        console.log(items)
    }
)
      

JSONP 请求。

致谢

模仿 jQuery - YUI Rosetta Stone 搞了这么个对照表, 希望对熟悉 jQuery,但初次接触 KISSY 的同学有所帮助。

如有纰漏,欢迎 fork