使用layui的同学,不知道大家是不是跟我一样其实基本不会用到layui提供的onevent和event这两个方法。但是其实我们每天都跟他们打交道,因为组件的事件监听基本都是基于onevent做的,只不过是在它的基础上又给加了一个“糖衣”,但是平时的话还是基本不会用onevent监听什么事件的。
今天社区有个问题 http://fly.layui.com/jie/27137/ 就是定义了onevent然后执行调用了一下layui.event结果出现执行了两次监听的情况。追了一下发现可能还是源码的一个处理逻辑有点问题。改一下自己定义onevent和执行event中带了(filter)然后就正常了。
看似问题解决了,但是也引起了我的好奇,对原先的设计有了一个大胆的猜想,是不是事件也有母子关系,不带filter的为母带filter的为子?动起手验证一下,确实达到了我猜想的效果,就是不知道是不是设计者的设计思路就不知道了,因为确实官方没有对onevent和event做什么介绍,只说了阅读源码,只能自行理解了。
代码如下,如果想在本地试一下的同学请到这 https://pan.baidu.com/s/1uD7M84CwMTBzeLZBkOFd8A 下载,不要拷贝社区的代码,不敢保证社区的代码发出去会不会被控件转义了
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>layui</title> <meta name="renderer" content="webkit"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <link rel="stylesheet" href="js/layui/src/css/layui.css" media="all"> <!-- 注意:如果你直接复制所有代码到本地,上述css路径需要改成你本地的 --> </head> <body> <div style="margin: 10px;"> <div class="layui-inline"> <label class="layui-form-label">小明:</label> <div class="layui-input-inline"> <input name="phone" autocomplete="off" class="layui-input" style="width: 240px;"> </div> </div> <button class="layui-btn" lay-even="sendMessageA">发送</button> </div> <div style="margin: 10px;"> <div class="layui-inline"> <label class="layui-form-label">小红:</label> <div class="layui-input-inline"> <input name="phone" autocomplete="off" class="layui-input" style="width: 240px;"> </div> </div> <button class="layui-btn" lay-even="sendMessageB">发送</button> </div> <div style="margin: 10px;"> <div class="layui-inline"> <label class="layui-form-label">系统时间</label> <button class="layui-btn" lay-data="{align: 'center'}" lay-even="sendMessageS">发送</button> </div> </div> <div id="messageView" style="width: 480px; height: 300px;border: 1px solid #1E9FFF;margin-left: 120px;padding: 10px;overflow: auto;"></div> <script src="js/layui/src/layui.js" charset="utf-8"></script> <!-- 注意:如果你直接复制所有代码到本地,上述js路径需要改成你本地的 --> <script> layui.use(['jquery', 'util'], function ($, util) { var active = { sendMessageA: function () { layui.event("message", "send(A)", { align: 'left', user: '小明', msg: $(this).prev().find('input').val() }); $(this).prev().find('input').val(''); }, sendMessageB: function () { layui.event("message", "send(B)", { align: 'right', user: '小红', msg: $(this).prev().find('input').val() }); $(this).prev().find('input').val(''); }, sendMessageS: function () { layui.event("message", "send", { align: 'center' }); } }; var divElem = $('#messageView'); // 母事件,所有message.send(*)都会触发这个 layui.onevent("message", "send", function (params) { divElem.append('<div style="text-align: ' + (params.align || 'center') + ';">' + util.toDateString(null, 'yyyy-MM-dd HH:mm:ss') + '</div>'); var timer = setTimeout(function () { if (timer) { clearTimeout(timer); } divElem.scrollTop(divElem[0].scrollHeight) }, 50) }); // 子事件A layui.onevent("message", "send(A)", function (params) { divElem.append('<div style="margin: 6px 0;text-align: left;">' + (params.msg || '<span style="color: #1E9FFF">没有输入,只是想你了一下</span>') + '</div>') }); // 子事件B layui.onevent("message", "send(B)", function (params) { divElem.append('<div style="margin: 6px 0;text-align: right;color: pink;">' + (params.msg || '<span style="color: #1E9FFF">没有输入,只是想你了一下</span>') + '</div>') }); $('.layui-btn').click(function () { var elem = $(this), event = elem.attr('lay-even'); typeof active[event] === 'function' && active[event].apply(this); }); }); </script> </body> </html>
页面功能和代码相应的解析
首先定义了3个message的send事件一个“母事件”send(姑且这么叫,瞎编的可能不合适 ),负责在聊天面板中追加系统时间,两个子事件send(A), send(B),分别就是小明和小红的聊天内容的输出啦。可以看到子事件中没有去操作调用母事件(输出发消息的时间);
然后就是三个人了,一个小明,一个小红,还有一个系统按钮,触发的方法就是去执行layui.event来触发我们定义的对应的layui.onevent事件,同样可以看到,小明或者小红发送消息的时候也没有去调用系统按钮的功能。
最终的效果就是,小明或者小红输入信息发送,会首先触发母事件然后再触发子事件,也就是先输出一个发送消息的时间然后再是发送的内容。而系统时间按钮就只触发了自身的事件。
到此感觉这可能是一个以后可以好好利用的机制。 但是!还不能高兴太早!
首先如果小伙伴有兴趣的可以把我的测试代码下下来换个layui的路径跑一下试一下。应该就会很快发现一个问题,点击系统时间发送的时候会有两个连着输出了,不要怀疑是不是双击了,不是,这个就是最开始说的那个问题,不在赘叙,我说的源码的不太合理的地方是event的最后片段。
可见如果是一个母事件,filter为空那么会执行两次回调。改成下面的
就正常了,其他的子事件也没有问题。
到此觉得很顺利,但是同时也觉得有一个隐患,如果定义事件的时候子事件早于母事件定义会是什么情况呢?比如把onevent send(A)的代码段放到send的前面,那么问题就来了,小明发送消息的时候会是消息在前时间在后面。
来几个表情压压惊,其实也是可以接受理解的,假如,真把他们当成母子事件,那是不是应该先有母事件才能有子事件呢?OK,这回顺利,总不能先有了孩子再有妈妈吧。当然所谓的母子事件纯粹周末空闲倒腾出来的,是不是设计者设计的时候就考虑进去了这个只能官方的才能解密了。