V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
he2020
V2EX  ›  JavaScript

对 Layui 的事件监听有些疑问,求帮忙分析一下这几行代码

  •  
  •   he2020 · 2021-02-18 14:52:22 +08:00 · 2072 次点击
    这是一个创建于 1134 天前的主题,其中的信息可能已经有所发展或是发生改变。

    先看下 Layui 文档的描述,比如监听选项卡切换这一节:
    Tab 选项卡点击切换时触发,回调函数返回一个 object 参数,携带两个成员:

    element.on('tab(filter)', function(data){
      console.log(this);        //当前 Tab 标题所在的原始 DOM 元素
      console.log(data.index);  //得到当前 Tab 的所在下标
      console.log(data.elem);   //得到当前的 Tab 大容器
    });
    

    疑问在于:
    如果我们用比较原始的方法来监听 Tab 选项卡点击切换时触发,可能是这样写:

    eleTab.addEventListener("click", function(event) {
     // 点击 Tab 选项卡时触发该函数
    })
    

    可以看到与 Layui 的写法从外观形式上就有很大的差别。 Layui 做了哪些封装呢?Layui 上面的写法并没有看到它监听 click 事件啊,为啥在点击 Tab 选项卡时会触发?
    我觉得可能是与以下源码有关,但看不出重点。

    element.js https://github.com/sentsin/layui/blob/master/src/lay/modules/element.js#L29

      Element.prototype.on = function(events, callback){
        return layui.onevent.call(this, MOD_NAME, events, callback);
      };
    

    layui.js https://github.com/sentsin/layui/blob/743d498816651899a339d6e88210f6513f2b61d1/src/layui.js#L563

      //自定义模块事件
      Layui.prototype.onevent = function(modName, events, callback){
        if(typeof modName !== 'string' 
        || typeof callback !== 'function') return this;
    
        return Layui.event(modName, events, null, callback);
      };
    
      //执行自定义模块事件
      Layui.prototype.event = Layui.event = function(modName, events, params, fn){
        var that = this
        ,result = null
        ,filter = (events || '').match(/\((.*)\)$/)||[] //提取事件过滤器字符结构,如:select(xxx)
        ,eventName = (modName + '.'+ events).replace(filter[0], '') //获取事件名称,如:form.select
        ,filterName = filter[1] || '' //获取过滤器名称,,如:xxx
        ,callback = function(_, item){
          var res = item && item.call(that, params);
          res === false && result === null && (result = false);
        };
        
        //如果参数传入特定字符,则执行移除事件
        if(params === 'LAYUI-EVENT-REMOVE'){
          delete (that.cache.event[eventName] || {})[filterName];
          return that;
        }
        
        //添加事件
        if(fn){
          config.event[eventName] = config.event[eventName] || {};
    
          //这里不再对多次事件监听做支持,避免更多麻烦
          //config.event[eventName][filterName] ? config.event[eventName][filterName].push(fn) : 
          config.event[eventName][filterName] = [fn];
          return this;
        }
        
        //执行事件回调
        layui.each(config.event[eventName], function(key, item){
          //执行当前模块的全部事件
          if(filterName === '{*}'){
            layui.each(item, callback);
            return;
          }
          
          //执行指定事件
          key === '' && layui.each(item, callback);
          (filterName && key === filterName) && layui.each(item, callback);
        });
        
        return result;
      };
    
    8 条回复    2021-02-18 22:39:38 +08:00
    he2020
        1
    he2020  
    OP
       2021-02-18 15:19:34 +08:00
    Layui 监听选项卡切换,文档位于: https://www.layui.com/doc/modules/element.html#ontab
    Rhilip
        2
    Rhilip  
       2021-02-18 17:28:05 +08:00   ❤️ 1
    如果不是原生的 addEventListener,考虑到 layui 基于 jquery,应该从 .on('click', callback) 或者 .click(callback) 的角度入手搜索,这样你就会发现

    https://github.com/sentsin/layui/blob/743d498816651899a339d6e88210f6513f2b61d1/src/lay/modules/element.js#L72-L78

    ```
    //自定义 Tab 选项卡
    Element.prototype.tab = function(options){
    options = options || {};
    dom.on('click', options.headerElem, function(e){
    var index = $(this).index();
    call.tabClick.call(this, e, index, null, options);
    });
    };
    ```

    此处为 tabClick 添加了一个 click 事件,事件最终触发了 call.tabClick 方法,并在此方法中实现了选项卡切换
    azcvcza
        3
    azcvcza  
       2021-02-18 17:28:20 +08:00   ❤️ 1

    ```
    //执行自定义模块事件
    filter = (events || '').match(/../) // 提取事件过滤器字符结构 如 select(xxx)
    filterName = filter[1] || '';
    ...

    // 执行指定事件
    filterName && key === filterName && layui.each(item,callback)
    ```
    on "tab(filter)" 和 "select(xxx')" 我看没啥区别
    he2020
        4
    he2020  
    OP
       2021-02-18 20:09:22 +08:00
    @Rhilip 感谢,但 layui 的文档中写道:元素的一些事件监听,依靠的是 element.on(filter, callback); 啊 ,element.on(...)为啥能用于事件监听呢?底层做了什么呢?
    https://www.layui.com/doc/modules/element.html#base
    loading
        5
    loading  
       2021-02-18 20:21:57 +08:00 via Android   ❤️ 1
    建议早点弃坑,layui 就是刚入门用的,如果你需要折腾这些的时候,你应该换一个库了。
    我用过一次就怕了,还不如自己用 jquery 从头开始拼。
    he2020
        6
    he2020  
    OP
       2021-02-18 20:30:11 +08:00
    @loading 用来学习
    loading
        7
    loading  
       2021-02-18 21:13:22 +08:00 via Android
    可能是我太菜了吧,我觉得对着 layui 来学东西,就是走了歪路。我用 jquery 跑 bootstrap 根本没有那种难受的感觉,我觉得我现在用 vue 和 react 都比用 layui 简单。
    Rhilip
        8
    Rhilip  
       2021-02-18 22:39:38 +08:00   ❤️ 1
    @he2020

    1. Layui 上面的写法并没有看到它监听 click 事件啊,为啥在点击 Tab 选项卡时会触发?
    2. element.on(...)为啥能用于事件监听呢?底层做了什么呢?

    我觉得上面两个问题可以一起回答。首先 https://github.com/sentsin/layui/blob/743d498816651899a339d6e88210f6513f2b61d1/src/lay/modules/element.js#L466
    在加载 elements.js 时就已经使用 jquery 方法给 Tab 添加了 click 事件,事件的回调是 call.tabClick
    在 call.tabClick 中
    ```
    layui.event.call(this, MOD_NAME, 'tab('+ filter +')', {
    elem: parents
    ,index: index
    });
    ```
    又调用了 layui.event.call 函数来调用你之前使用 element.on(...) 方法定义的事件(存在底层 config.event 列表)。
    所以,他只是对 addEventListener 进行了一层代理,来保证事件顺序,实质是落实到 jquery.on() 上,再由 jquery 再回到浏览器原生的 addEventListener
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5503 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 54ms · UTC 09:03 · PVG 17:03 · LAX 02:03 · JFK 05:03
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.