单击外部以使用按钮隐藏容器

时间:2016-01-06 10:28:09

标签: javascript css angularjs html5

我使用以下Angular指令在用户点击或触摸外部时隐藏div元素。

https://github.com/TheSharpieOne/angular-off-click

它正在按预期工作,但是当您在按钮上单击div的外部时,可以切换div,即可实现“角度关闭”。触发回调以隐藏容器,但随后调用附加到按钮的切换功能,重新打开div。

' off-click-filter'通过添加在调用hide函数之前使用css选择器进行检查的异常来解决这个问题。但是这被删除了,因为我们不希望在html标记中出现额外的css类异常。

当您单击容器外部

时,所需的功能是切换按钮不会触发其处理程序

更新 这只是触摸设备上的一个问题,默认情况下有300毫秒的延迟。因此,这意味着触发回调以隐藏容器,然后切换功能在300ms后运行,重新打开容器。在桌面上,单击鼠标,首先触发切换功能,然后触发回调



/* Styles go here */

.container {
  background: blue;
  color: #fff;
  height: 300px;
  width: 300px;
}

<!DOCTYPE html>
<html>

  <head>
    <script src="https://code.angularjs.org/1.4.0/angular.js"></script>
    <link rel="stylesheet" href="style.css" />
    
    
  </head>

  <body data-ng-app="myApp">
    <h1>Hello Plunker!</h1>
    <div data-ng-controller="myAppController">
      
      <button data-ng-click="toggleContainer()">Toggle Container</button>
      
      <div class="container" data-ng-show="showContainer" data-off-click="hideContainer()" data-off-click-if="showContainer">
        This is the container
      </div>
    </div>
    
  </body>

</html>
&#13;
public static void main(String[] args)throws IOException {
  String s ="12312a";
  int x = Integer.parseInt(s);
  System.out.println (x+2);
}
&#13;
&#13;
&#13;

http://jsbin.com/hibovu

1 个答案:

答案 0 :(得分:1)

问题在于,当您单击按钮时,两个功能都会触发:

    来自指令的
  1. hideContainer
  2. 来自点击事件的
  3. toggleContainer(再次显示div)。
  4. 解决方案

    在评估hide回调之前添加event.stopPropagation();

    你是怎么做到的?

    1. 将事件传递给函数data-off-click="hideContainer($event)"
    2. $event hideContainer函数的定义中添加$scope param,如下所示:$scope.hideContainer = function($event)
    3. 完整代码:

      // Angular App Code
      var app = angular.module('myApp', ['offClick']);
      
      app.controller('myAppController', ['$scope', '$timeout', function($scope,$timeout) {
        $scope.showContainer = false;
      
        $scope.toggleContainer = function() {
          $timeout(function() {
            $scope.showContainer = !$scope.showContainer;
          }, 300);
        };
      
        $scope.hideContainer = function($event) {
          $event.stopPropagation();
          $timeout(function(){
            $scope.showContainer = false;  
          });
        };
      }]);
      
      // Off Click Directive Code
      angular.module('offClick', [])
      .directive('offClick', ['$rootScope', '$parse', function ($rootScope, $parse) {
        var id = 0;
        var listeners = {};
        // add variable to detect touch users moving..
        var touchMove = false;
      
        // Add event listeners to handle various events. Destop will ignore touch events
        document.addEventListener("touchmove", offClickEventHandler, true);
        document.addEventListener("touchend", offClickEventHandler, true);
        document.addEventListener('click', offClickEventHandler, true);
      
        function targetInFilter(target, elms) {
          if (!target || !elms) return false;
          var elmsLen = elms.length;
          for (var i = 0; i < elmsLen; ++i) {
            var currentElem = elms[i];
            var containsTarget = false;
            try {
              containsTarget = currentElem.contains(target);
            } catch (e) {
              // If the node is not an Element (e.g., an SVGElement) node.contains() throws Exception in IE,
              // see https://connect.microsoft.com/IE/feedback/details/780874/node-contains-is-incorrect
              // In this case we use compareDocumentPosition() instead.
              if (typeof currentElem.compareDocumentPosition !== 'undefined') {
                containsTarget = currentElem === target || Boolean(currentElem.compareDocumentPosition(target) & 16);
              }
            }
      
            if (containsTarget) {
              return true;
            }
          }
          return false;
        }
      
        function offClickEventHandler(event) {
          // If event is a touchmove adjust touchMove state
          if( event.type === 'touchmove' ){
            touchMove = true;
            // And end function
            return false;
          }
          // This will always fire on the touchend after the touchmove runs...
          if( touchMove ){
            // Reset touchmove to false
            touchMove = false;
            // And end function
            return false;
          }
          var target = event.target || event.srcElement;
          angular.forEach(listeners, function (listener, i) {
            if (!(listener.elm.contains(target) || targetInFilter(target, listener.offClickFilter))) {
              //$rootScope.$evalAsync(function () {
              listener.cb(listener.scope, {
                $event: event
              });
              //});
            }
          });
        }
      
        return {
          restrict: 'A',
          compile: function ($element, attr) {
            var fn = $parse(attr.offClick);
            return function (scope, element) {
              var elmId = id++;
              var offClickFilter;
              var removeWatcher;
      
              offClickFilter = document.querySelectorAll(scope.$eval(attr.offClickFilter));
      
              if (attr.offClickIf) {
                removeWatcher = $rootScope.$watch(function () {
                  return $parse(attr.offClickIf)(scope);
                }, function (newVal) {
                  if (newVal) {
                    on();
                  } else if (!newVal) {
                    off();
                  }
                });
              } else {
                on();
              }
      
              attr.$observe('offClickFilter', function (value) {
                offClickFilter = document.querySelectorAll(scope.$eval(value));
              });
      
              scope.$on('$destroy', function () {
                off();
                if (removeWatcher) {
                  removeWatcher();
                }
                element = null;
              });
      
              function on() {
                listeners[elmId] = {
                  elm: element[0],
                  cb: fn,
                  scope: scope,
                  offClickFilter: offClickFilter
                };
              }
      
              function off() {
                listeners[elmId] = null;
                delete listeners[elmId];
              }
            };
          }
        };
      }]);
      .container {
        background: blue;
        color: #fff;
        height: 300px;
        width: 300px;
      }
      <!DOCTYPE html>
      <html>
        <head>
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
        </head>
        <body data-ng-app="myApp">
          <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
          <h1>Hello Plunker!</h1>
          <div data-ng-controller="myAppController">
            <button data-ng-click="toggleContainer()">Toggle Container</button>
            <div class="container" data-ng-show="showContainer" data-off-click="hideContainer($event)" data-off-click-if="showContainer">
              This is the container
            </div>
          </div>
        </body>
      </html>

      http://jsbin.com/hibovu/3/edit?html,css,js