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 角度事件系统+使用服务的替代方案的主要内容,如果未能解决你的问题,请参考以下文章

IT运维系统-服务建模从业务角度来管理IT

角度 2:使用服务广播事件

从源码角度入手实现RecyclerView的Item点击事件

Xampp 替代 Ubuntu

在主干js中有“onDomRefresh”事件(在Marionette中)有什么替代方案吗?

反应 16.9.0“javascript:;” href替代品? [复制]