javascript 角度事件系统+使用服务的替代方案
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了javascript 角度事件系统+使用服务的替代方案相关的知识,希望对你有一定的参考价值。
// Angular’s $emit, $broadcast and $on fall under the common “publish/subscribe” design pattern,
// You publish an event and subscribe/unsubscribe to it somewhere else.
// $scope.$emit: fire an event UP the $scope.
//$scope.$broadcast: fire an event DOWN the $scope.
//$scope.$on: listen for these events.
// firing an event upwards
$scope.$emit('myCustomEvent', 'Data to send');
// firing an event downwards
$scope.$broadcast('myCustomEvent', {
someProp: 'Sending you an Object!' // send whatever you want
});
// listen for the event in the relevant $scope
$scope.$on('myCustomEvent', function (event, data) {
console.log(data); // 'Data to send'
});
//* Using $scope to fire your events will communicate
// only with immediate parent or child scopes
// but will miss out sibling scopes
// $rootScope is the parent of all scopes, - is how we could communicate across scopes
// work slightly different:
// $rootScope.$emit will fire an event for all $rootScope.$on listeners only.
// $rootScope.$broadcast will notify all $rootScope.$on as well as $scope.$on listeners
<div ng-controller="ParentCtrl as parent" class="ng-scope">
// ParentCtrl
<div ng-controller="SiblingOneCtrl as sib1" class="ng-scope">
// SiblingOneCtrl
</div>
<div ng-controller="SiblingTwoCtrl as sib2" class="ng-scope">
// SiblingTwoCtrl
<div ng-controller="ChildCtrl as child" class="ng-scope">
// ChildCtrl
</div>
</div>
</div>
// The above has 3 lexical scopes and 4 Angular scopes,
// ParentCtrl, SiblingOneCtrl, SiblingTwoCtrl and ChildCtrl.
// Using $scope.$emit inside ChildCtrl would result in SiblingTwoCtrl and ParentCtrl only being notified,
// as the event doesn’t hit sibling scopes only direct ancestors.
// If we used $rootScope, however, then we can target $rootScope listeners as well.
//
// Unsubscribing from events
//
// You can unsubscribe from events at any time with the $on listener (there is no $off method)
app.controller('ParentCtrl',
function ParentCtrl ($scope) {
// subscribes...
var myListener = $scope.$on('child', function (event, data) {
// do something
});
// unsubscribes...
// this would probably sit in a callback or something
myListener();
});
// UNSUBSCRIBING ON DESTROY
// When using $rootScope.$on, we need to unbind those listeners
// each time the $scope is destroyed.
// we’ll need to call the above closure manually on the $destroy event:
app.controller('ParentCtrl',
function ParentCtrl ($scope) {
// $rootScope $on
var myListener = $rootScope.$on('child', function (event, data) {
//
});
// $scope $destroy
$scope.$on('$destroy', myListener);
});
//* $scope.$on listeners are automatically unbound, and doesn't need to be destroyed manually
//
// Cancelling events
//
// If you choose to use $emit, one of your other $scope listeners can cancel it,
// so prevent it bubbling further. Using $broadcast has the opposite effect in which it cannot be cancelled!
// Cancelling an event which was sent via $emit looks like this:
$scope.$on('myCustomEvent', function (event, data) {
event.stopPropagation();
});
// $rootScope.$$listeners
// *Every Angular Object has several properties. We can take a look at $rootScope.$$listeners
// to observe the listeners lifecycle.
//
// Event namespacing
//
// Using a specific namespace for cleaner pub/subs keeps things consistent and avoid naming conflicts.
// For example, If I were building an email application with an Inbox, we might use an 'inbox' namespace
// for that specific section:
$scope.$emit('inbox:send'[, data]);
$scope.$on('inbox:send', function (event, data) {...});
$scope.$broadcast('inbox:delete'[, data]);
$scope.$on('inbox:delete', function (event, data) {...});
$scope.$emit('inbox:save'[, data]);
$scope.$on('inbox:save', function (event, data) {...});
// From ' A Better Way to Learn Angular JS'
// https://thinkster.io/a-better-way-to-learn-angularjs
// Services provide an easy way for us to share data and functionality throughout our app.
// services we create are singletons that can be injected into controllers and other services
// are the ideal place for writing reusable code.
// we'll be creating a service for storing messages, and two controllers, one for rendering a list of messages, and another for adding more messages to the list.
// Let's set up our angular module, and
// create our service and call it messages
angular.module('app', []);
angular.module('app').factory('messages', function(){
var messages = {};
messages.list = []; //we'll store here our messages
messages.add = function(message){
messages.list.push({id: messages.list.length, text: message}); //will add provided messages to our list.
};
return messages; //this is the object that dependencies of this service will receive
});
// Controller called ListCtrl that injects our messages service,
// and exposes the list from our service to our view.
angular.module('app').controller('ListCtrl', function (messages){
var self = this;
self.messages = messages.list;
});
// view
<div ng-app="app">
<h1>Services</h1>
<div ng-controller="ListCtrl as list">
<p ng-repeat="message in list.messages">{{ message.id }}: {{ message.text }}</p>
</div>
</div>
//Let's create another controller to help us populate the list.
angular.module('app').controller('PostCtrl', function (messages){
var self = this;
self.newMessage = 'Hello World!'; //default message
self.addMessage = function(message){
messages.add(message);
self.newMessage = ''; //clear
};
});
//view
<div ng-controller="PostCtrl as post">
<form ng-submit="post.addMessage(post.newMessage)">
<input type="text" ng-model="post.newMessage">
<button type="submit">Add Message</button>
</form>
</div>
// Event Emitters in AngularJS
// when you need to communicate between controllers - talk to each other, to share information.
/*
- $broadcast: trickle DOWN the controller hierarchy
- $emit: bubble UP the controller hierarch
- $on: listen for an event
As you can see, *hierarchy of controllers / $scope's is important*.
there is a direct relationship between parent and child scopes, but not between two scopes at the same level.
*/
<body ng-app="family">
<div ng-controller="Parent as darth">
{{ darth.output }}
<div ng-controller="Son as luke">
{{ luke.output }}
</div>
<div ng-controller="Daughter as leia">
{{ leia.output }}
</div>
</div>
</body>
//
// Using $broadcast to send events down the chain
//
function Parent($scope) {
var vm = this;
vm.output = "I am Darth Vader.";
// Broadcast an event called 'parent' to the children
// setTimeout is used here to mimic an asynchronous event
setTimeout(function() {
$scope.$broadcast('parent', 'I am your father');
}, 1000);
}
function Son($scope) {
var vm = this;
vm.output = "I am Luke Skywalker.";
// Listen for the parent event on $scope
$scope.$on('parent', function(event, data) {
console.log('Really?'); // outputs "Really?"
});
}
function Daughter($scope) {
var vm = this;
vm.output = "I am Princess Leia.";
// Listen for the parent event on $scope
$scope.$on('parent', function(event, data) {
console.log('Shhhh!'); // outputs "Shhh!"
});
}
//
// Using emit to send events up the chain
// Example jsbin: http://jsbin.com/fuyilo/2/edit?html,js,console,output
//
function Parent($scope) {
var vm = this;
vm.output = "I am Darth Vader.";
// Listen for an event called child
$scope.$on('child', function(event, data) {
console.log('Sadface'); // outputs Sadface
});
}
function Son($scope) {
var vm = this;
vm.output = "I am Luke Skywalker.";
// Emit an event called child to the parent
setTimeout(function() {
$scope.$emit('child', 'I\'ll never join you');
}, 1000);
}
function Daughter($scope) {
var vm = this;
vm.output = "I am Princess Leia.";
// Listen for an event called child
$scope.$on('child', function(event, data) {
console.log('Good choice'); // Doesn't output: the other child cannot hear this event - it is not emitted in their scope chain.
});
}
// So, children cannot directly communicate through events, as their scope's are not linked.
// However, children do have access to their parent's scope,
// so it is possible to broadcast an event from there
// by calling $scope.$parent.$broadcast.
// Any of the siblings - and the parent, can listen to this event.
// http://jsbin.com/wofuri/1/edit?html,js,console,output
function Parent($scope) {
var vm = this;
vm.output = "I am Darth Vader.";
// Listen for an event called child
$scope.$on('child', function(event, data) {
console.log('I heard that!'); // the siblings are able to talk to each other, but the parent overhears everything going on!
});
}
function Son($scope) {
var vm = this;
vm.output = "I am Luke Skywalker.";
// Listen for an event called child
$scope.$on('child', function(event, data) {
console.log('I\'ll say'); // Outputs I'll say
});
}
function Daughter($scope) {
var vm = this;
vm.output = "I am Princess Leia.";
// Emit an event called child to the parent
setTimeout(function() {
$scope.$parent.$broadcast('child', 'Darth Vader has a foul stench'); //Daughter calls $broadcast on $scope.$parent, thus publishing the event from the parent.
}, 1000);
}
//
// Publishing events to all controllers using $rootScope
//
//Let's add an Uncle controller to the HTML.
<div ng-controller="Parent as darth">
{{ darth.output }}
<div ng-controller="Son as luke">
{{ luke.output }}
</div>
<div ng-controller="Daughter as leia">
{{ leia.output }}
</div>
</div>
<div ng-controller="Uncle as obiwan">
{{ obiwan.output }}
</div>
// The Daughter event is outside of the Uncle's scope chain, so it can't hear it.
// Likewise, any events the Uncle controller broadcasts will not be picked up
// by the other controllers. They share no common scope.
// $rootScope is essentially the global scope. All controller scopes are nested inside it.
// So if you pass the $rootScope service into the controller you can use it's $broadcast method.
// Broadcasting on the $rootScope is at the global level and
// any controller can subscribe to the event.
// http://jsbin.com/kigono/1/edit?html,js,console,output
function Parent($scope) {
var vm = this;
vm.output = "I am Darth Vader.";
// Listen for an event called child
$scope.$on('child', function(event, data) {
console.log('I heard that!'); // outputs I heard that!
});
// Listen for an event called uncle
$scope.$on('uncle', function(event, data) {
console.log('You\'re no uncle'); // outputs You're no uncle
});
}
function Son($scope) {
var vm = this;
vm.output = "I am Luke Skywalker.";
// Listen for an event called child
$scope.$on('child', function(event, data) {
console.log('I\'ll say'); // Outputs I'll say
});
// Listen for an event called uncle
$scope.$on('uncle', function(event, data) {
console.log('I\'m running'); // outputs I'm running
});
}
function Daughter($scope) {
var vm = this;
vm.output = "I am Princess Leia.";
// Emit an event called child to the parent
setTimeout(function() {
$scope.$parent.$broadcast('child', 'Darth Vader has a foul stench');
}, 1000);
// Listen for an event called uncle
$scope.$on('uncle', function(event, data) {
console.log('I\'m not Luke'); // outputs I'm not Luke
});
}
// Pass $rootScope in to the controller
function Uncle($scope, $rootScope) {
var vm = this;
vm.output = "I am Obi-Wan Kenobi.";
// Listen for an event called child
$scope.$on('child', function(event, data) {
console.log('What was that?'); // No output
});
// Broadcast and event called uncle on the rootScope
$rootScope.$broadcast('uncle', 'Run Luke, run');
}
// * What happens if we $rootScope.$emit instead of $rootScope.$broadcast?
// it stays in $rootScope. So only the $rootScope.$on will listen to that
//
// Tidying up after $rootScope.$on
//
//- $scope event listeners are automatically unbinded when the current scope is destroyed.
//- $rootScope listeners, as it never gets destroyed, should manually be unbinded when the scope is destroyed.
function Son($scope, $rootScope) {
var vm = this;
vm.output = "I am Luke Skywalker.";
// Assign the rootScope listener to a variable
var uncleListener = $rootScope.$on('uncle', function(event, data) {
console.log('I\'m running'); // outputs I'm running
});
// Unbind the listener when the controller scope is destroyed
$scope.$on('$destroy', uncleListener); //This is slightly odd, but calling the listener variable will remove the listener
}
以上是关于javascript 角度事件系统+使用服务的替代方案的主要内容,如果未能解决你的问题,请参考以下文章
从源码角度入手实现RecyclerView的Item点击事件