在DOM树中查找最深的嵌套组件

时间:2015-05-20 06:49:16

标签: reactjs

我正在尝试实现一个键绑定mixin,让我写一些类似

的内容
createClass({
...
keybindings: function() {
    return {
      'escape' : function(event) { this._handleEscapeKey(); },
      'enter'  : function(event) { this._handleEnterKey(); },
      'up'     : function(event) { this._handleUpKey(); },
      'down'   : function(event) { this._handleDownKey(); },
      'left'   : function(event) { this._handleLeftKey(); },
      'right'  : function(event) { this._handleRightKey(); },
    };
  },

在我的组件中。但是,当多个组件包含mixin时,我遇到了问题。我需要一种方法使DOM树中嵌套最深的组件上的事件监听器优先于其祖先。

这是我到目前为止所获得的任何想法/建议/反馈非常感谢

混入:

KeybindingsMixin = {

  modifiers: {
    shift: 16,
    ctrl:  17,
    alt:   18,
    meta:  91
  },

  keyCodes: {
    escape : 27,
    up     : 38,
    down   : 40,
    left   : 37,
    right  : 39,
    enter  : 13,
    shift  : 16,
    ctrl   : 17,
    alt    : 18,
    meta   : 91,
    s      : 83,
  },

  singleModifier: {
    shift: {
      keyCode : 16,
      shift   : true,
      ctrl    : false,
      alt     : false,
      meta    : false
    }
  },

  componentDidMount: function() {
    if (this.__keybindings !== undefined) {
      var keybindings    = this.getAllKeybindings();
      this.__keybindings = _.merge(this.__keybindings, keybindings);

      $(window).on('keydown', this.__matchEvent);
    }
  },

  componentWillUnmount: function() {
    if (this.__keybindings !== undefined) {
      var keybindings    = _.keys(this.getAllKeybindings());
      this.__keybindings = _.omit(this.__keybindings, keybindings);

      $(window).off('keydown', this.__matchEvent);
    }
  },

  childContextTypes: {
    __keybindings: React.PropTypes.object
  },

  contextTypes: {
    __keybindings: React.PropTypes.object
  },

  getAllKeybindings: function() {
    return this.__getKeybindings();
  },

  getChildContext: function() {
    return {
      __keybindings: this.__getKeybindings()
    };
  },
   __getKeybindings: function() {
    var keybindings = Object.getPrototypeOf(this).keybindings();
    this.__keybindings = this.__keybindings || (this.context && this.context.__keybindings) || keybindings || {};
    return this.__keybindings;
  },

  __parseKeybindingString: function(binding) {
    var tokens    = binding.split(' ');
    var modifiers = _.keys(this.modifiers);
    var bindings  = _.keys(this.keyCodes);

    var parsedEvent = {
      keyCode: 0,
      alt:     false,
      ctrl:    false,
      shift:   false,
      meta:    false
    };

    _.each(tokens, function(token) {
      if (_.includes(modifiers, token)) {
        parsedEvent[token] = true;
      } else if (_.includes(bindings, token)) {
        parsedEvent.keyCode = this.keyCodes[token];
      }
    }, this);

    return parsedEvent;
  },

  __keybindingSpecified: function(event) {

  },

  __matchEvent: function(event) {
    var eventMatcher = {
      keyCode: event.keyCode,
      alt:     event.altKey,
      ctrl:    event.ctrlKey,
      shift:   event.shiftKey,
      meta:    event.metaKey,
    };

    var keybindings = this.__keybindings;
    _.forOwn(keybindings, function(action, binding) {
      var parsedEvent = this.__parseKeybindingString(binding);

      if (_.isEqual(eventMatcher, parsedEvent)) {
        event.preventDefault();
        return action.call(this, event);
      }
    }, this);
    return;
  },
};

1 个答案:

答案 0 :(得分:0)

如果“DOM树中深层嵌套的组件优先于其祖先”意味着事件应该仅在最深层嵌套的组件上触发而不是向上冒泡到组件,则应调用{{1} }。这会取消冒泡,进一步向上的组件将无法获得此事件。

修改

对不起,我以为你使用了Reacts事件系统,它允许event.stopPropagation(),即使他们只将一个事件处理程序附加到根元素。你可以做的是类似于React所做的事情,因为对于使用mixin的每个元素,你将一些属性附加到该DOM节点,说它正在监听事件。然后,当事件进入时,您检查stopPropagation并查看它是否具有该属性。如果没有,则检查event.target并向上递归,直到找到它为止。一旦找到该元素,就会停止向上模拟event.target.parentElement的效果。