Skip to content

[js] 第113天 用js写一个事件侦听器的方法 #1035

Open
@haizhilin2013

Description

@haizhilin2013
Collaborator

第113天 用js写一个事件侦听器的方法

Activity

ghost

ghost commented on Aug 7, 2019

@ghost

题面讲得有点迷惑...我瞎猜一下它要我干啥吧

事件监听器:EventListener,就是 EventEmitter 触发事件时的 handler,是一个函数。

然后给这个函数增加一个方法?

这里有一份非常短的 Event Emitter 实现(甚至支持通配符:

class Ev {
    e = { '*': [] }
    on(n, h) { this.e[n] = (this.e[n] || []).concat(h) }
    emit(n, p) { this.e['*'].concat(this.e[n]).map(h => h(p)) }
}
HCLQ

HCLQ commented on Aug 7, 2019

@HCLQ
题意不清..先写个。。
class EventBus {
  events = {};

  on(eventName, callback) {
    const events = this.events;
    if (!events[eventName]) {
      events[eventName] = [];
    }
    events[eventName].push(callback);
    return this;
  }

  emit(eventName, params) {
    const events = this.events;
    if (events[eventName]) {
      events[eventName].forEach(cb => cb(params));
    }
    return this;
  }
}
bertcai

bertcai commented on Aug 7, 2019

@bertcai
题意不清..先写个。。
class EventBus {
  events = {};

  on(eventName, callback) {
    const events = this.events;
    if (!events[eventName]) {
      events[eventName] = [];
    }
    events[eventName].push(callback);
    return this;
  }

  emit(eventName, params) {
    const events = this.events;
    if (events[eventName]) {
      events[eventName].forEach(cb => cb(params));
    }
    return this;
  }
}

events = {};这样直接赋值是不对的,需要用构造函数包裹。

 constructor() {
        this.events = {}
    }
ghost

ghost commented on Aug 7, 2019

@ghost

@bertcai

events = {};这样直接赋值是不对的,需要用构造函数包裹。

 constructor() {
        this.events = {}
    }

类内直接声明成员是一个 Stage 3 草案;见此

HCLQ

HCLQ commented on Aug 7, 2019

@HCLQ
题意不清..先写个。。
class EventBus {
  events = {};

  on(eventName, callback) {
    const events = this.events;
    if (!events[eventName]) {
      events[eventName] = [];
    }
    events[eventName].push(callback);
    return this;
  }

  emit(eventName, params) {
    const events = this.events;
    if (events[eventName]) {
      events[eventName].forEach(cb => cb(params));
    }
    return this;
  }
}

events = {};这样直接赋值是不对的,需要用构造函数包裹。

 constructor() {
        this.events = {}
    }

感谢指出..
实际可以这么写的,有babel..我本来写的ts。。删了private 之类的ㄟ( ▔, ▔ )ㄏ

LinStan

LinStan commented on Aug 7, 2019

@LinStan
<body>
  <div>
    <span id="a">点击</span>
    <a href="#" id="b">超链接</a>
    <button id="d" onclick="remove()">点击移除事件绑定</button>
    <button onclick="add()">点击添加事件绑定</button>
  </div>
  <script>
    var eventTool = {
      //获取事件 window.event兼容ie
      getEvent: function (e) {
        return e || window.event
      },
      //获取事件触发元素 srcElement ie独有
      getTarget: function (e) {
        return e.target || e.srcElement
      },
      addListener: function (e, type, hander) {
        if (e.addEventListener) {
          //兼容ie ie没有事件捕获的说法 因此设为false
          //dom2 
          e.addEventListener(type, hander, false);
        } else if (e.attachEvent) {
          //IE
          e.attachEvent('on' + type, hander)
        } else {
          //dom0
          e['on' + type] = hander
        }
      },
      removeListener: function (e, type, hander) {
        if (e.removeEventListener) {
          e.removeEventListener(type, hander, false)
        } else if (e.detachEvent) {
          e.detachEvent('on' + type, hander)
        }
        else { e['on' + type] = null }
      },
      //阻止事件冒泡
      stopPropagation: function (e) {
        if (e.stopPropagation) {
          // ie以外阻止冒泡
          e.stopPropagation()
        }
        else {
          //ie独有阻止冒泡 新版本的chrome等浏览器也支持
          e.cancelBubble = true
        }
      },
      // 阻止事件相关元素的默认事件
      preventDefault: function (e) {
        if (e.preventDefault) {
          e.preventDefault()
        }
        else {
          //ie的阻止默认事件方式
          e.returnValue = false;
        }
      }
    }
    var btn = document.getElementById('a');
    var link = document.getElementById('b');
    var fun = function (e) {
      var e = eventTool.getEvent(e);
      var t = eventTool.getTarget(e);
      console.log(e)
      console.log(t)
      eventTool.stopPropagation(e)
    }
    var add = function () {
      eventTool.addListener(btn, 'click', fun)
      eventTool.addListener(link, 'click', fun)
    }
    var remove = function () {
      console.log(btn)
      eventTool.removeListener(btn, 'click', fun)
    }
  </script>
</body>
huangguohua96

huangguohua96 commented on Aug 7, 2019

@huangguohua96

function addEvent(elem, type, handle) {
if (elem.addEventListener) { //W3C标准
elem.addEventListener(type, handle, false); //事件冒泡时触发
} else if (elem.attachEvent) { //IE独有
elem.attachEvent('on' + type, function() {
handle.call(elem); //改变this使其指向指定元素
});
} else {
elem['on' + type] = handle; // 最古老
}
}

IFmiss

IFmiss commented on Aug 13, 2019

@IFmiss

参考网上的代码加了点自己的东西

/**
 * 一个简单的发布订阅者模式
 */

interface IHandler {
  fn: Function,
  type: string,
  name: string
}

export default class EventUtils {
  /**
   * 键值对 对应事件名称以及数组的值
   */
  static handler = {}

  /**
   * on 方法 添加监听事件
   */
  static on (name: string, handler: Function): EventUtils {
    const i:IHandler = {
      fn: handler,
      type: 'on',
      name: name
    }
    if (Object.keys(EventUtils.handler).includes(name)) {
      EventUtils.handler[name].push(i)
      return EventUtils
    }
    EventUtils.handler[name] = [].concat(i)
    return EventUtils
  }

  /**
   * off 方法 移除监听事件
   */
  static off (name: string, handler: Function): EventUtils {
    const event: any[] = EventUtils.handler[name]
    if (event) {
      for (let i = event.length - 1; i >= 0; i--) {
        if (event[i].fn === handler) {
          event.splice(i, 1)
        }
      }
    }
    return EventUtils
  }

  /**
   * emit 方法 触发监听的事件
   */
  static emit (name: string, ...args: any): EventUtils {
    const event = EventUtils.handler[name]
    let newEvent = []
    event && event.length && event.forEach((item: IHandler, index: number) => {
      item.fn.call(this, ...args)

      // 如果有只监听一次的事件
      if (item.type !== 'once') {
        newEvent.push(event.slice(index, index + 1))
      }
    })

    const hasOnce = event && event.length && event.some((item: IHandler) => {
      return item.type === 'once'
    })

    if (hasOnce) {
      EventUtils.handler[name] = newEvent
    }

    // 这里做一个执行完成之后的 once代码 off 的操作
    return EventUtils
  }

  /**
   * once 方法 添加事件 只会被执行一次
   */
  static once (name: string, handler: Function): void {
    EventUtils.on(name, handler)
    EventUtils.handler[name][0]['type'] = 'once'
  }
}
xiaoqiangz

xiaoqiangz commented on Jul 5, 2022

@xiaoqiangz

class EventBus {
constructor() {
this.event = {}
}
on(type, handle) {
let event = this.event
if (!event[type]) {
event[type] = []
}
event[type].push(handle)
}
emit(type, params) {
let handles = this.event[type]
handles && handles.length && handles.forEach((cb) => {
cb(params)
})
}
off(type, handle) {
let handles = this.event[type]
handles && handles.length && handles.forEach((cb ,index) => {
if (cb == handle) {
handles.splice(index, 1)
}
})
}
}
function fn(param) {
console.log('click-----------', param)
}
const event = new EventBus()
event.on('click', fn)
event.off('click', fn)
event.on('doubleClick', (param)=>{
console.log('doubleClick------------', param)
})
setTimeout(()=> {
event.emit('click', 'click')
}, 2000)
setTimeout(()=> {
event.emit('doubleClick', 'doubleClick')
}, 3000)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    jsJavaScript

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @haizhilin2013@HCLQ@bertcai@xiaoqiangz@IFmiss

        Issue actions

          [js] 第113天 用js写一个事件侦听器的方法 · Issue #1035 · haizlin/fe-interview