Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
haizhilin2013 opened this issue Aug 6, 2019 · 9 comments
Open

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

haizhilin2013 opened this issue Aug 6, 2019 · 9 comments
Labels
js JavaScript

Comments

@haizhilin2013
Copy link
Collaborator

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

@haizhilin2013 haizhilin2013 added the js JavaScript label Aug 6, 2019
@ghost
Copy link

ghost commented Aug 7, 2019

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

事件监听器: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
Copy link

HCLQ commented Aug 7, 2019

题意不清..先写个。。
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
Copy link

bertcai commented Aug 7, 2019

题意不清..先写个。。
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
Copy link

ghost commented Aug 7, 2019

@bertcai

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

 constructor() {
        this.events = {}
    }

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

@HCLQ
Copy link

HCLQ commented Aug 7, 2019

题意不清..先写个。。
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
Copy link

LinStan commented Aug 7, 2019

<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
Copy link

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
Copy link

IFmiss commented Aug 13, 2019

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

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

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
Copy link

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
Labels
js JavaScript
Projects
None yet
Development

No branches or pull requests

7 participants