2013-12-19 28 views
4

我在svg中绘制了几个元素(使用ng-switch)并在它们上处理鼠标事件。控制器看起来像这样(有更多类型的元素,更鼠标事件处理的):如何在AngularJS中检测鼠标事件的目标模型

app.controller('MainCtrl', function($scope) { 
    $scope.elements = [ 
    { "type": "circle", "x" : 100, "y" : 200 }, 
    { "type" : "rect", "x" : 50, "y" : 20 } 
    ]; 

    $scope.mousedown = function(element, $event) { 
    $scope.msg = element.type; 
    }; 
}); 

里面的鼠标事件处理程序,我需要的鼠标事件的目标模式。 我目前的解决方案是将ng-mousedown="mousedown(element, $event)"添加到每个svg元素,这是恼人的越来越多的元素类型。

<g ng-switch="p.type"> 
     <g ng-switch-when="circle"> 
     <circle ng-mousedown="mousedown(p, $event)"></circle> 
     </g> 
     <g ng-switch-when="rect"> 
     <rect ng-mousedown="mousedown(p, $event)"></rect> 
     </g> 
    </g> 

有没有办法从$event属性($event.target$event.srcElement给我点击的SVG元素,如何从这种获得模型添加ng-mousedown才根SVG元素和获取点击的元素的模型?)。

完整的示例: http://plnkr.co/edit/nfgVSBBaeJ9EFKNjYEJn

回答

2

由于element.scope()依赖于调试数据,因此它不是生产模式的解决方案。在更复杂的情况下,您必须编写一个指令来设置“事件源”,然后可以通过父元素上的另一个指令处理该事件源(如果事件冒泡起来)(请参见下面的第二个示例)。

在这种特殊情况下,解决的方法很简单,如果你把事件处理ng-repeat元素是这样的:

angular.module("app", []) 
 
\t .controller('MainController', MainController); 
 

 
function MainController() { 
 
\t var vm = this; 
 
\t vm.elements = [ 
 
    { "type": "circle", "x" : 100, "y" : 100 }, 
 
    { "type" : "rect", "x" : 50, "y" : 20 }]; 
 

 
    vm.mousedown = function(element, $event) { 
 
    vm.msg = element.type; 
 
    }; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 
 
<div ng-app="app" ng-controller="MainController as view"> 
 

 
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="120"> 
 
    <g ng-repeat="p in view.elements" ng-switch="p.type" 
 
    ng-mousedown="view.mousedown(p, $event)"> 
 

 
     <circle ng-switch-when="circle" 
 
       ng-attr-cx="{{p.x}}" ng-attr-cy="{{p.y}}" fill="red" r="20"> 
 
     </circle> 
 
     <rect ng-switch-when="rect" 
 
      ng-attr-x="{{p.x}}" ng-attr-y="{{p.y}}" width="50" height="50" fill="blue" > 
 
     </rect> 
 

 
    </g> 
 
</svg> 
 
<p> 
 
{{view.msg}} 
 
</p>  
 
</div>

更为复杂的例子

这个例子显示了两条指令eventSourceeventHandler的用法。 eventHandler侦听根元素上的事件。 eventSource在其控制器上注册“事件源”。

angular.module("app", []) 
 
    .controller('MainController', MainController) 
 
    .directive('eventSource', eventSource) 
 
    .directive('eventHandler', eventHandler); 
 

 
function MainController() { 
 
\t var vm = this; 
 
\t vm.elements = [ 
 
    { "type": "circle", "x" : 100, "y" : 80 }, 
 
    { "type" : "rect", "x" : 50, "y" : 20 } 
 
    ]; 
 
    vm.rect = { "type" : "special", "x" : 0, "y" : 40 }; 
 

 
    vm.handle = function(element, $event) { 
 
    vm.msg = $event.type + ': ' + element.type; 
 
    }; 
 
} 
 

 
function eventSource($parse) { 
 
    return { 
 
    restrict: 'A', 
 
    require: '^eventHandler', 
 
    link: function (scope, elem, attr, controller) { 
 
     var sourceAttr = attr['eventSource']; 
 
     var source = $parse(sourceAttr)(scope); 
 
     controller.register(elem, source); 
 
     scope.$on('$destroy', function() { 
 
     controller.unregister(elem); 
 
     }); 
 
    } 
 
    }; 
 
} 
 

 
function eventHandler() { 
 
    return { 
 
    restrict: 'A', 
 
    scope: { 
 
     eventHandler: '&' 
 
    }, 
 
    controller: function() { 
 
     var vm = this; 
 
     vm.sources = []; 
 

 
     this.register = function (element, source) { 
 
     vm.sources.push({element : element, source: source}); 
 
     } 
 

 
     this.unregister = function (element) { 
 
     var i = 0; 
 
     for(var e = vm.sources.length; i < e; ++i) { 
 
      if (vm.sources[i].element === element) 
 
      break; 
 
     } 
 
     vm.sources.splice(i, 1); 
 
     } 
 
    }, 
 
    link: function (scope, elem, attr, controller) { 
 

 
     elem.on('mousedown mouseup', function ($event) { 
 

 
     var target = $event.target; 
 
     while (target && !target.hasAttribute('event-source')) 
 
      target = target.parentNode; 
 
     
 
     for(var i = 0, e = controller.sources.length; i < e; ++i) { 
 
      if (controller.sources[i].element[0] === target) { 
 
       scope.eventHandler({element : controller.sources[i].source, $event : $event}); 
 
      }    
 
     } 
 
     scope.$apply(); 
 
     }); 
 
    } 
 
    }; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 
 

 
<div ng-app="app" ng-controller="MainController as view"> 
 

 
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="120" 
 
    event-handler="view.handle(element, $event)"> 
 
    
 
    <g ng-repeat="p in view.elements" ng-switch="p.type" 
 
    event-source="p"> 
 
     <circle ng-switch-when="circle" 
 
       ng-attr-cx="{{p.x}}" ng-attr-cy="{{p.y}}" fill="red" r="20"> 
 
     </circle> 
 
     <rect ng-switch-when="rect" 
 
      ng-attr-x="{{p.x}}" ng-attr-y="{{p.y}}" width="50" height="50" fill="blue" > 
 
     </rect> 
 
    </g> 
 
    <rect ng-attr-x="{{view.rect.x}}" ng-attr-y="{{view.rect.y}}" width="80" height="50" fill="green" 
 
     event-source="view.rect"> 
 
    </rect> 
 
</svg> 
 
<p> 
 
{{view.msg}} 
 
</p>  
 
</div>

5

是的,你可以使用angular.element(...).scope().p如下:

标记:

<svg xmlns="http://www.w3.org/2000/svg" ng-mousedown="mousedown2($event)"> 

JS:

$scope.mousedown2 = function($event) { 
    console.log(angular.element($event.target).scope().p); 
}); 

见分叉普拉克:http://plnkr.co/edit/7lGMphla42Chrg3X2NZl

+0

的'NG-repeat'块内部的伟大工程,但如果目前的范围没有'p'失败。任何关于'ng-repeat'之外或者嵌套'ng-repeat'内的元素的建议? – hansmaad

+0

使用范围内的相应属性。答案的本质不是'.p',而是'angular.element(...)。scope()',它允许你访问元素的范围和'$ event.target',它给你的实际元件。你如何考虑范围是另一个问题。 –

+0

现在,单元测试如何做到这一点? – FlavorScape