2013-12-19 31 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