如何确定给定div中的某些内容是否具有焦点?

时间:2015-04-04 19:13:51

标签: angularjs focus

使用angularjs,我显示了像这样的2级列表

- first main item
  - first subitem of the first main item
  - second subitem of the first main item
  - AN EMPTY ITEM AS PLACEHOLDER TO ENTER THE NEXT SUBITEM
- second main item
  - first subitem of the second main item
  - second subitem of the second main item
  - AN EMPTY ITEM AS PLACEHOLDER TO ENTER THE NEXT SUBITEM

为了节省空间,我希望只有在相应的div中的任何内容具有焦点时才显示PLACEHOLDER,以便只有一个这样的占位符。我知道那里有ngFocus,但我更喜欢比创建大量事件处理程序更简单的东西。也许是这样的:

<div ng-focus-model="mainItem.hasFocus" ng-repeat="mainItem in list">
   ... main item line
   ... all subitems
</div>

单向绑定就足够了,因为我不需要设置焦点。

3 个答案:

答案 0 :(得分:9)

这里的问题如下:我们希望避免向每个子节点添加事件侦听器,但只将其添加到父节点。家长将负责采取适当的行动。对此的一般解决方案是使用均匀传播(委托)。我们只向父节点附加一个侦听器,当子节点上发生事件时(在此示例中关注输入元素),它将冒泡到父节点,父节点将执行侦听器。

这是指令:

app.directive('ngFocusModel', function () {
    return function (scope, element) {

      var focusListener = function () {
          scope.hasFocus = true;
          scope.$digest();
      };

      var blurListener = function () {
          scope.hasFocus = false;
          scope.$digest();
      };


      element[0].addEventListener('focus', focusListener, true);
      element[0].addEventListener('blur', blurListener, true);
   };
});

该指令侦听事件并相应地设置范围的值,因此我们可以进行条件更改。

这里有几点需要注意。

focusblur事件不会“冒泡”,我们需要使用“事件捕获”来捕获它们。这就是为什么不使用element.on('focus/blur')(它不允许捕获,afaik)而是addEventListener方法的原因。此方法允许我们通过相应地将第三个参数设置为falsetrue来指定是否将在“事件冒泡”或“事件捕获”上执行侦听器。

我们本可以使用“冒泡”的focusinfocusout事件,但不幸的是,这些事件在Firefox(focusinfocusout)中不受支持。

这是实施的plunker

<强>更新 在我看来,这可以使用:focus伪类使用纯CSS来完成,唯一的缺点是占位符需要相对于输入元素处于适当的位置(兄弟)。请参阅codepen

答案 1 :(得分:2)

不幸的是,做出你想要的唯一坚实的方法是回应输入上的焦点\模糊事件......这是获得通知的唯一方式。

您可以将隐藏输入作为每个div中的第一个元素并将NgFocus属性放在其上,但只有在用户选中它时才有效。

答案 2 :(得分:2)

DEMO

我创建了一个可以用于所需内容的小指令:

app.directive('childFocus', function($window){

  var registered = [];

  // observing focus events in single place
  $window.addEventListener('focus', function(event){
    registered.forEach(function(element){
      if(element.contains(event.target)){
        // if element with focus is a descendant of the 
        // element with our directive then action is triggered
        element._scope.$apply(element._scope.action);
      } 
    });
  }, true)

  return {
    scope : {
      action : '&childFocus' // you can pass whatever expression here
    },
    link : function(scope, element){

      // keep track ref to scope object
      element[0]._scope = scope;

      // (probably better would be to register
      // scope with attached element)
      registered.push(element[0]);

      scope.$on('destroy', function(){
        registered.splice(registered.indexOf(element[0]),1);
      }); 
    }
  }
});