Giter Site home page Giter Site logo

action's Introduction

English version is here.

Action

轻松随意绑定点击事件!

用法简介

第一步

先定义一些动作:

action.define({
    'my-action': function () {
        //do something...
    },
    /* ... */
})

第二步

在页面里创建元素:

<button data-action="my-action">btn</button>

<!-- 或这样 -->
<a href="#" data-action="my-action">link</a>

<!-- 或这样 -->
<a href="#my-action" data-action>link</a>

第三步

其实已经不需要第三步了。

点击这个元素就可以触发你定义的那个动作了!

兼容性

依赖以下类库:

  • jQuery(或兼容类库,比如 Zepto)

支持以下浏览器:

  • Chrome / Firefox / Safari 等现代浏览器
  • IE 6+(需要 jQuery 1.x)

体积

  • 源码: 2.7k
  • 压缩后: 0.4k

安装

  1. 通过 npm 3+ 安装:

    $ npm install cmui-action
  2. 在页面中加载 Action 的脚本文件及必要的依赖:

    <script src="./node_modules/jquery/dist/jquery.js"></script>
    <script src="./node_modules/cmui-action/src/action.js"></script>

API 文档

  • Action 提供了简洁易用的 API,详见此文档
  • 此外,建议阅读 Wiki 来获取更多信息。

单元测试

  1. 把本项目的代码 fork 并 clone 到本地。
  2. 在本项目的根目录运行 npm install,安装必要的依赖。
  3. 在浏览器中打开 test/test.html 即可运行单元测试。

谁在用?

移动 UI 框架 CMUI 采用 Action 作为全局的基础设施,因此所有 CMUI 用户都在使用 Action:


License

MIT License

action's People

Contributors

cssmagic avatar lyt9304 avatar paper avatar zpbx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

action's Issues

为什么 `.add()` API 没有采用队列机制?

为什么 .add() API 没有采用队列机制?

本问题摘自 C4 前端交流会的现场观众提问。

背景

大家最熟悉的 DOM 事件 API .addEventListener() 是队列机制——可以为元素的同一事件多次添加事件处理函数,当事件触发时,这些事件处理函数会被依次调用。

因此,当大家看到 action.add() 这个 API 时,很自然就会发出疑问:它的工作方式是队列式吗?如果不是,为什么?

文档

实际上 .add() API 并没有设计队列机制。对于重复添加同名动作的情况,文档是这样描述的:

如果在定义动作时使用了已经存在的动作名,则相当于用新的动作函数替换原有的动作函数。原因在于 action.add() 方法添加的是 “动作”,不是事件监听器;而每个动作名只能对应一个动作函数。

如果你觉得 .add() 这个接口名容易误解,可以自行创建并使用 .define().register() 这样的别名。

设计

从上述文档可以看出,Action 的设计力求 “简单易用”:

  • 用 “动作” 的概念屏蔽事件、冒泡、监听器等底层实现。
  • 动作采用基本的 “名值对” 模型,“一个萝卜一个坑”。

引入队列机制,会使整概念模型复杂化。作为系统中的一项基础设施,Action 必须做到简单、易理解、易排错,因为当大量上层代码依赖这个基础设施时,稳定性必定是它的首要目标。

同时,对一个通用型类库来说,不加节制地增强功能,并不会令它更加通用;相反,膨胀的体积和大多数人用不到的功能反而会限制它的适用面。一个单纯的机制,恰恰更容易被按需扩展。

扩展

每个类库都有适用场景,Action 的原生功能适用于中小型网站项目;而对于更复杂的场景,Action 也可以通过各种方式在上层被扩展。

在 C4 前端交流会上,有同学认为,由于 .add() 没有队列机制(不可以对同一动作追加多个动作函数),无法满足以下需求:

如果我有一组类似的按钮需要执行一些共同的动作、同时也有自己特有的动作,如何实现?

实际上,我们完全可以在动作函数这个层面来完成业务逻辑的抽象。为便于讨论,我们先约定场景和术语:“Btn A” 和 “Btn B” 都需要执行自己的特有行为 fnAfnB,同时它们也需要执行共同行为 fnC。那么我们可以采用以下一些的扩展方案:

  • 使用 AOP 等方式来给 fnAfnB 分别追加 fnC,得到 fnACfnBC,再把它们作为真正的动作函数传给 .add() 方法。

  • .add() 只管接收动作列表(用对象组织的名值对),至于这个动作列表是怎么来的,它是不关心的。我们完全可以用一套更高级的机制来构造出自己需要的动作列表。假设我们根据自己的业务需要实现了一套 ActionComposer,可以按需构造动作函数:

    var myActions = {
        'action-a': ActionComposer.combine('fnA', 'fnC'),
        'action-b': ActionComposer.combine('fnB', 'fnC')
    }
    action.add(myActions)

    只要 myActions 是合法的数据结构,.add() 就能正常使用。

  • 顺着上面的思路进一步拓展,我们甚至可以不用操心动作列表的产生。我们可以预先定一些原子操作(比如这里的 fnAfnBfnC),然后在 HTML 层面通过一定的命名约定来书写动作名。比如:

    <button data-action="a+c">Btn A</button>
    <button data-action="b+c">Btn B</button>

    然后使用一个构建工具来扫描 HTML,自动生成以下结构并传递给 action.add()

    {
        'a+c': ActionComposer.combine('fnA', 'fnC'),
        'b+c': ActionComposer.combine('fnB', 'fnC')
    }

    这样连定义动作这一步都可以交给程序来自动完成了。

总之,我们的思路就是把 Action 当作一种底层的基础设施来用——上层的业务逻辑可以很复杂,但底层可以很简单!

所有元素都可以用 Action 来绑定点击事件吗?

所有元素都可以用 Action 来绑定点击事件吗?

从技术上来说,Action 对 body 元素内的所有元素生效。但是,我只推荐你对 <a href="..."><button><input type="button"> 等元素使用 Action 来绑定点击事件。

这有几方面的原因,下面一一道来。

语义

上面列出的这些元素都是天生可以与用户进行交互的元素,天生承接用户的点击行为。用户点击它们就是为了触发一些动作,我将它们称为 “动作元素”。

由于这些元素天生具备可交互的特性,浏览器通常也会为它们设置特殊的默认样式,比如暗示可点击的手形鼠标光标、预设的 :hover :focus :active 样式等等。

而除此以外的其它元素大多是以呈现信息为已任,虽然它们也可以被点击、也会产生点击事件,但从语义上看,并不是最佳选择。

移动端

当使用 Action 为 “非动作元素” 绑定动作时,我们会发现在 iOS 浏览器中并不生效。

这是因为 iOS 的浏览器内核对点击事件做了一些 “优化”——如果一个元素不是天生的可交互元素,那么默认情况下:

  • 它将不会响应用户的点击操作。
  • 这个不存在的 “点击事件” 自然也不会向上冒泡。

由此可见,在这类 “非动作元素” 身上使用 Action 存在一定风险。


附:解决方案

当然 iOS 浏览器的这个问题也不是无解的,我们有一些方法可以强制这些 “非动作元素” 响应点击操作:

  • 只要对目标元素或其祖先元素绑定点击事件,浏览器内核就会对该元素另眼相待。(注:为避免副作用,这个用于 hack 的事件监听器可以为空函数;这里的 “祖先元素” 不包括 body 元素和更上层的元素。)

    但显然这个方案不适合 Action。因为找到目标元素绑个事件不仅烦琐,而且 Action 的 “元素不存在也可预先绑定” 的优势也就不存在了。

    (这个方案还有另一个问题:如果这个 hack 是用在目标元素的祖先元素身上的话,则当我们点击该元素时,其祖先元素整体会出现触摸高亮样式,很诡异,需要单独写样式把它去除。)

  • 为目标元素添加一个空的 onclick 属性,也会令浏览器内核对它另眼相待。在 HTML 里直接写或用脚本添加此属性都是可以的。但还是那个问题,需要先对该元素做手脚。

  • 为目标元素添加一个 cursor: pointer 样式,同样可以令浏览器内核意识到该元素需要响应点击操作。这个方法可以做到与 DOM 无关,比较适合 Action。

综上所述,如果你需要对非动作元素使用 Action,就需要对页面应用以下 CSS 规则:

[data-action] {
    cursor: pointer;
}

埋点的核心问题,数据传递怎么搞

我有个问题,这个action只适用于简单的埋点场景,我呆过的两家it公司,埋点上报的基本都是很复杂的数据,很多数据与业务逻辑无关,这就需要大改原来的代码,一层一层把数据数据传下来,这种改动对源码来说是毁灭性的,很多人痛疼的埋点问题应该也是这个,这个要如何解决[吃瓜]

需要为 `.add()` 方法增加键名的特殊字符过滤

目的

防止用户把链接的 href 值(hash 或 hashbang)直接复制到 actionList 的键名(即 action name)处。

做法

  • 去除首尾空格
  • 去除开头的所有 #! 字符
  • 再次去除开头的空格

最终达到的效果应该和从链接 href 值取 action name 的方式完全一致(新建一个私有方法来做这件事吧)。

添加 UMD 包

创建 dist/ 目录,并增加 UMD 包。以便通过 Browserify、RequireJS 或 spm 使用。

完成此任务之后,即可发布 v0.4.0 到 spm

相关 PR: #24


  • 增加构建系统
  • 增加对 UMD 包的测试。

关于 DEBUG_INFO 的疑惑?

看了源码,
请问能否设置一个开关,关闭 console 不必要的提示?

文档说支持 IE6+,那么

// 这里的 console 不会报错么?
if (fn && $.isFunction(fn)) {
    /** DEBUG_INFO_START **/
    console.log('[Action] Executing action `%s`.', actionName)
   /** DEBUG_INFO_END **/

   return fn.call(context || window)
}

在移动浏览器当中, 使用事件委托,绑定在 body 元素上,有的时候会冒泡不上去

在移动浏览器当中, 使用delegate(或on、live),
绑定在$wrapper(指父级元素),
有的时候会冒泡不上去,特别是层级复杂、伴有定位的时候

// 举个简单的例子;
// 但这个例子并不会发生上述问题,怪我比较罗嗦;

<body>
    <div id='view'>
        <a href='javascript:;' data-action='nothingToDo'>btn</a>
    </div>


</body>
// 直接绑定在body上,无效
$(document.body).on('click', '[data-action]' , function(){ 
    console.log(this) ;
});

// 绑定在较近的父级元素上,有效
$('#view').on('click', '[data-action]' , function(){ 
    console.log(this) ;
});

请问这个有没有比较好的解决方案;

动作函数的执行上下文(`this` 指向)是如何处理的?

动作函数的执行上下文(this 指向)是如何处理的?

误解

在 C4 前端交流会上播放的 幻灯片 里有这样一段代码:

$body.on('click', '[data-action]', function () {
    var actionName = $(this).data('action')
    var action = actionList[actionName]

    if ($.isFunction(action)) action()
})

估计很多同学看到这里,可能会误以为这就是 Action 的实现。实际上幻灯片里的所有代码都只是示意性的——出于对演示效果的考虑,过滤了很多细节。

Action 的实现

在初始化阶段,Action 的统一绑定是这样做的(简化代码):

$body.on('click', '[data-action]', function () {
    // get `actionName`
    // ...
    _handle(actionName, this)
})

可以看到当前点击事件的触发元素(this)会被传递给 _handle() 函数。而 _handle() 在调用动作函数时是这样做的(简化代码):

function _handle(actionName, context) {
    var fn = _actionList[actionName]
    if (fn && $.isFunction(fn)) {
        return fn.call(context || window)
    }
}

请注意这个 fn.call(context || window),动作元素会成为动作函数的执行上下文。

因此,在编写动作函数时,不需要特意考虑上下文绑定的事情,其内部的 this 总是会指向触发动作的元素(这跟事件回调函数的执行上下文是类似的,符合开发习惯)。

关于 .trigger() 方法

对于这些在内部使用了 this 的动作函数,直接调用会出现 this 指向错误的问题。因此,.trigger() 方法在设计时,就允许传入第二个参数,用于在触发指定动作函数时指定执行上下文。

但这只是一条万不得已的后路,在实际开发中应该避免大量使用。两点原因:

  • 每次都要找到合适的函数执行上下文传进去,不方便。写出来的代码也必然是不够清爽的。
  • 理论上需要在 JS 中触发的动作,应该是与 DOM 元素无关的,或者不是那么严格相关的(即是否把一个 DOM 元素作为执行上下文传进去不应该影响到动作执行的正确性)。

如果确实需要在 JS 层面对某个特定元素触发特定动作(通常在 HTML 中这个元素已经声明了自己的动作),我会建议这样做:

$('[data-action="my-action"]').first().trigger('click')

原理是利用 JS 来模拟用户的点击行为,后面的事情就自然而然地发生了。这样代码的表现力也会更好。

简介

简介

轻松随意绑定点击事件!

第一步

先定义一些动作:

action.add({
    'my-action': function () {
        //do something...
    },
    ...
})

第二步

在页面里创建元素:

<button data-action="my-action">btn</button>

<!-- 或这样 -->
<a href="#" data-action="my-action">link</a>

<!-- 或这样 -->
<a href="#my-action" data-action>link</a>

第三步

其实已经不需要第三步了。

点击这个元素就可以触发你定义的那个动作了!

所有点击都要冒泡到 body 元素再处理,性能如何?

所有点击都要冒泡到 body 元素再处理,性能如何?

本问题摘自 C4 前端交流会的现场观众提问。

担忧

运行性能对于类库来说,是一个非常重要的指标。性能优劣往往会左右开发者对于类库的选择。

对 Action 的性能担忧主要在于以下两点:

  • body 元素要处理所有动作。
  • 点击事件触发后要等到冒泡到 body 元素时才会被处理。

前提

在分析性能问题之前,我们需要了解一个概念——“累积效应”。

很多性能测试都是利用大量重复来放大差异,比如分别把两个函数重复执行数万次,再比较两者的耗时长短。这种性能测试方式对数据处理的场景是合适的,因为此时程序的运行模式是同步的,且性能与执行次数(或数据的复杂度)正相关,存在“累积效应”。

举个例子。我写了一个性能不佳的数组 map() 方法,在处理小数组时可能察觉不到异常,但在处理大数组时,性能问题就会突显。在这种存在累积效应的场景下,单次执行的性能差异往往直接影响最终性能。

分析

好,接下来我们来分析上述两种对于性能的担忧。

第一个问题相对简单,实际上我们只会在 body 身上绑定一个事件监听器。这个事件监听器就像是一个中转站,它会根据事件源头来匹配需要执行的动作函数并执行。这意味着,不论页面上有多少个动作元素,事件监听器的数量都不会额外增加。

Action 的这种机制相对于 “对每个动作元素绑定一个事件监听器” 的方案,在资源消耗方面反而有明显优势——因为后者有累积效应。

再来看第二个担忧。

当动作元素被点击后,动作函数并不会 “立即触发”;只有当事件通过 DOM 向上冒泡到 body 元素时,才会查找动作函数并执行。由于 body 元素已经位于 DOM 的顶端了,这样一路冒泡上去,给人感觉似乎存在性能隐患。

从设计上来说,Action 只能选择 bodydocumentElemnt 这样较顶端的元素来注册统一的事件监听器。尽管如此,我们还是来看一下性能对比。

从绝对差异上来看,把事件监听器绑定在 body 上,肯定比绑定在动作元素自身或离它较近的祖先元素上要慢,但这个差异本身是微乎其微的。更重要的是,UI 交互这个场景不存在累积效率,单次性能差距并不会被放大

由此可见,对于 “事件冒泡” 这个性能担忧点,事实上是不必要的。

Summary

Summary

An easy and lazy solution for click-event-binding.

Step 1

Define some actions:

action.add({
    'my-action': function () {
        //do something...
    },
    ...
})

Step 2

Create an element like this:

<button data-action="my-action">btn</button>

<!-- or -->
<a href="#" data-action="my-action">link</a>

<!-- or -->
<a href="#my-action" data-action>link</a>

Step 3

You've done everything.

Clicking the element will trigger the action you defined.

My Story / 我的故事

Video / 视频

Slides / 幻灯片

此分享的幻灯片实验性地采用了纯 JS 代码的形式。

// MY STORY ABOUT CLICK-EVENT-BINDING

// @CSSMAGIC



// BACKGROUND




// ONE DAY...

// REQUIREMENT: LUCKY DRAW?



var btn = document.getElementById('lucky-draw')

btn.onclick = function () {
    BX.luckyDraw()
}



// TRACKING?




btn.onclick = function () {
    BX.luckyDraw()
    BX.track('lucky-draw')
}



// BUT...




btn.onclick = function () {
    BX.luckyDraw()
}

// some code...

btn.onclick = function () {
    BX.track('lucky-draw')
}

btn.addEventListener('click', function () {
    BX.luckyDraw()
}, false)

// some code...

btn.addEventListener('click', function () {
    BX.track('lucky-draw')
}, false)

// A/B TEST?

// HALF OF USERS HAVE NO BTN?



var btn = document.getElementById('lucky-draw')

// A FIFTY-FIFTY CHANCE:
btn === null



if (btn) {
    btn.addEventListener('click', function () {
        BX.luckyDraw()
    }, false)
}

// some code...

if (btn) {
    btn.addEventListener('click', function () {
        BX.track('lucky-draw')
    }, false)
}
// "USE JQUERY, YOU IDIOT!"




var $btn = $('#lucky-draw')
$btn.on('click', function () {
    BX.luckyDraw()
})

// some code...

$btn.on('click', function () {
    BX.track('lucky-draw')
})

// SO FAR SO GOOD!

// BUT...




// SPA?

// HTML LAZY LOAD?

// HTML RENDERED BY JS?



$('.tabs > .surprise').on('click', function () {
    var htmlTab = [
        '<div>',
            '<button id="lucky-draw">Lucky Draw</button>',
        '</div>'
    ].join('')
    $('.tab-panels > .surprise').html(htmlTab)

    // EVENT-BINDING HERE...
})

// WHAT A MESS...




// EVENT DELEGATION?




$('body').on('click', '#lucky-draw', function () {
    BX.luckyDraw()
})



// WHAT IF MORE AND MORE BTNS?




$body = $('body')
$body.on('click', '#lucky-draw', function () {
    BX.luckyDraw()
})


$body.on('click', '#some-btn', function () {
    // do something...
})
$body.on('click', '#another-btn', function () {
    // do something else...
})
// ...

// NEED TO IMPROVE THIS!




// GROUP ALL THESE EVENT DELEGATION?




// FIRST, THE SAME CLASS NAME.

var btn1 = '<button class="action" id="lucky-draw">Lucky Draw</button>'
var btn2 = '<button class="action" id="some-action">Button</button>'
var link1 = '<a href="#" class="action" id="another-action">Link</a>'
var link2 = '<a href="#" class="action" id="another-action-2">Link</a>'

// THEN, ONLY ONE LISTENER.

$body.on('click', '.action', function () {

    // WHEN CLICK ANY '.action', WE COME HERE.

})

$body.on('click', '.action', function () {

    // DISPATCH ACTION
    // USE `id` TO IDENTIFY EACH BTN...

    switch (this.id) {
        case 'lucky-draw':
            BX.luckyDraw()
            break
        case 'some-btn':
            // do something...
            break
        // ...
    }

})
// `ID`?




// WHY NOT HTML5 DATASET?




// USE A CUSTOM DATA ATTRIBUTE -- 'data-action'!

var btn1 = '<button class="action" data-action="lucky-draw">Lucky Draw</button>'
var btn2 = '<button class="action" data-action="some-action">Button</button>'
var link1 = '<a href="#" class="action" data-action="another-action">Link</a>'
var link2 = '<a href="#" class="action" data-action="another-action-2">Link</a>'

// WAIT, CLASS NAMES ARE UNNECESSARY!




// SIMPLIFIED!

var btn1 = '<button data-action="lucky-draw">Lucky Draw</button>'
var btn2 = '<button data-action="some-action">Button</button>'
var link1 = '<a href="#" data-action="another-action">Link</a>'
var link2 = '<a href="#" data-action="another-action-2">Link</a>'

$body.on('click', '[data-action]', function () {
    var actionName = $(this).data('action')

    switch (actionName) {
        case 'lucky-draw':
            BX.luckyDraw()
            break
        case 'some-btn':
            // do something...
            break
        // ...
    }
})
// NO UGLY 'switch'!




var actionList = {
    'lucky-draw': function () {
        BX.luckyDraw()
    },
    'some-btn': function () {
        // do something...
    }
    // ...
}

$body.on('click', '[data-action]', function () {
    var actionName = $(this).data('action')
    var action = actionList[actionName]

    if ($.isFunction(action)) action()
})
// DEFINE MORE ACTION LATER?




// HTML
$body.append('<a href="#" data-action="more">Link</a>')

// JS
$.extend(actionList, {
    'more': function () {
        // ...
    }
})

// MAYBE THIS FITS MORE PEOPLE...

// OPEN-SOURCE IT!



// `ACTION`
// EASY AND LAZY SOLUTION FOR CLICK-EVENT-BINDING.


// GITHUB: CSSMAGIC/ACTION


// API

// DEFINE ACTIONS
action.add({
    'my-action': function () {
        // ...
    }
    // ...
})

// TRIGGER ACTION MANUALLY
action.trigger('my-action')
// WHO'S USING IT?


// CMUI USES `ACTION` AS A CORE SERVICE.
// GITHUB: CMUI/CMUI


// EVERYONE USING CMUI IS USING `ACTION`:

// - M.BAIXING.COM
// - M.VICHY.COM.CN
// - M.UEMALL.COM


// USE CASE: CMUI




CMUI.dialog = {
    template: [
        '<div class="dialog">',
            '<a href="#" data-action="close-dialog">×</a>',
            '<h2><%= data.title %></h2>',
            '<div class="content"><%- data.html %></div>',
        '</div>'
    ].join(''),

    init: function () {
        action.add({
            'close-dialog': function () {
                $(this).closest('.dialog').hide()
            }
        })
    },
    open: function (config) {
        var html = render(this.template, config)
        $(html).appendTo('body').show()
    }
}
// NO EVENT-BINDING CODE NEEDED!




// Q & A

// THX!



  • 幻灯片内的所有代码均为示意代码。
  • 关于 Action 的实际实现,请参阅文档和源码。

API Documentation / API 文档

如果你还不清楚这个库的用处,请参阅《简介》

术语约定

  • 动作 -- 你有一件特定的事情要做,可以将它定义为一个 “动作”,以便在必要时触发它。
  • 动作名 -- 每个动作都需要有一个名字,即 “动作名”。
  • 动作函数 -- 每个动作的行为使用函数来描述,即 “动作函数”。

HTML 接口

页面中的 DOM 元素可以通过 data-action 属性来声明自己被点击时要执行的动作。比如点击下面的链接和按钮就可以分别触发名为 foobar 的动作(即执行对应的动作函数)。

<a href="#" data-action="foo">Link</a>
<button data-action="bar">Button</button>

(值得一提的是,动作函数将以触发元素作为执行上下文。这跟事件的回调函数是类似的。)

对于链接元素,你还可以这样声明它的动作(似乎看起来更有语义,对用户也更友好一些):

<a href="#foo" data-action>Link</a>

注意事项

  • 只要元素具有 data-action 属性,其点击事件的默认行为就会被阻止。
  • 如果元素声明的动作名还没有定义,则不会执行任何动作函数。
  • 如果链接元素同时指定了 hrefdata-action 属性的值,则只有后者会被视为动作名声明。
  • 如果链接元素通过 href 属性来声明动作名,则 href 属性值必须以 # 开头。
  • 元素声明的动作名的开头所有 #! 和空白符都将被忽略,结尾的空白符也将被忽略,这意味着 #foo#!foo ## !! foo 都会被视为 foo

JavaScript 接口

action.define(actions)

定义一个或多个动作。

参数

  • actions -- 纯对象。需要定义的动作。对象的键名为动作名,键值为动作函数。

返回值

(无)

示例

以下代码将定义两个名为 foobar 的动作。

action.define({
    'foo': function () {
        alert('You triggered action `foo`!')
    },
    'bar': function () {
        this.bar = true
        alert('You triggered action `bar`!')
    }
})

注意事项

  • 在定义动作时,动作名的开头所有 #! 和空白符都将被忽略,结尾的空白符也将被忽略。
  • 无法定义一个动作名为空字符串的动作。
  • 如果在定义动作时使用了已经存在的动作名,则相当于用新的动作函数替换原有的动作函数。原因在于每个动作名只能对应一个动作函数。

action.add() ⚠️

此方法系 action.define() 的别名。

⚠️ 注意:从 v0.4 起不建议使用 .add(),请使用 .define() 代替。


action.trigger(actionName, [context])

除了页面元素可以触发动作外,这个方法还允许你在 JS 代码中触发指定动作(甚至你还可以指定动作函数的执行上下文)。

这个方法可能并不常用,只是提供了另一种途径来调用你定义的动作。

参数

  • actionName -- 字符串。动作名。
  • context -- 可选。对象。动作函数的执行上下文,默认为 window

返回值

  • 返回动作函数执行后的返回值。
  • 触发一个不存在的动作时,返回值为 undefined

示例

如果你已经在上面定义了 foobar 两个动作,那么以下代码将会触发名为 foo 的动作。

action.trigger('foo')

以下代码将会触发名为 bar 的动作,而且动作函数将以 <body> 元素作为执行上下文(即函数内部的 this 在此次执行时会指向 document.body)。

//document.body.bar === undefined
action.trigger('bar', document.body)
//document.body.bar === true

注意事项

  • 在触发指定动作时,动作名的开头所有 #! 和空白符都将被忽略,结尾的空白符也将被忽略。
  • 如果触发一个不存在的动作,则不会执行任何动作函数。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.