【问题标题】:AngularJS: Communication between directivesAngularJS:指令之间的通信
【发布时间】:2013-09-13 07:14:07
【问题描述】:

我正在编写一个创建 mp3/音频播放器的指令。问题是您可以在一页中拥有许多音频播放器。我想做的是当一个正在播放而你开始另一个时,当前正在播放的那个会暂停。如何使用角度指令来实现这一点?

提前致谢!

【问题讨论】:

    标签: javascript angularjs angularjs-directive


    【解决方案1】:

    Make a service 每个指令使用并保持其中的状态。

    类似这样的:

    angular.module('MyPlayer' [])
    .factory('playerState', function() {
        var players = [];
        return {
            registerPlayer: function(player) {
                players.add(player);
            },
            unregisterPlayer: function(player) {
                var i = players.indexOf(player);
                (i>-1) && players.splice(i,1);
            },
            stopAllPlayers: function() {
                for(var i=0;i<players.length;i++) {
                    players[i].stop();
                }
            }
        }
    })
    
    .directive('player', function(playerState) {
        return {
            ...
            link: function(scope, elem, attr) {
                var player = {
                    stop: function() {
                        /* logic to stop playing */
                    },
                    play = function(song) {
                        playerState.stopAllPlayers();
                        /* logic to start playing */
                    }
                }
    
                playerState.registerPlayer(player);
                scope.$on("$destroy", function() {
                    playerState.unregister(player);
                });
    
                scope.play = player.play;
                scope.stop = player.stop;
    
                ...
            }
        }
    })
    

    【讨论】:

    • 我不是这个答案的忠实拥护者,因为您基本上是在现有事件系统之上构建事件系统,为什么不直接使用内置?提供代码的道具。
    • 玩家应该在某个时候取消注册,否则在更改视图/路线等时会泄漏内存。
    • 有没有办法在路由改变时触发注销?
    • @JeanlucaScaljeri 范围被销毁时触发了一个事件:scope.$on('$destroy', ...);
    • 把服务的逻辑移到return语句上面的指令块怎么样。变量和方法仍然对链接函数可见,据我了解,实际的指令函数只调用一次?
    【解决方案2】:

    为了使答案完整,除了广播事件和公开服务之外,您还可以使用指令控制器。这些控制器通过指令定义对象的controller 属性设置,并在require 同一控制器的指令之间共享。这意味着您可以为所有媒体播放器拥有一个控制器,您可以在其中实现您提到的逻辑。请参阅documentation on directives(搜索controller:)了解更多信息。

    如果您认为会有更多的逻辑使用者,我会推荐服务方法,或者如果只有指令使用逻辑,我会推荐指令控制器方法。我建议不要在根范围内广播事件,因为它具有非耦合性和全局性。只是我的两分钱!高温

    【讨论】:

    • 请注意,控制器通常在共享相同 DOM 元素(默认行为)或嵌套结构(^ 表示法)(例如选项卡)的指令之间共享。您的建议可能与 ?符号,但可能非常棘手,容易出错且难以维护。服务/广播似乎更适应。
    • 我试图让您的解决方案在 jsfiddle 中运行。我不确定如何使用控制器执行此操作。这是我的jsfiddle。另外,我还是不明白在链接函数里放什么,在控制器里放什么
    • here 是我的工作小提琴。有什么建议如何使用控制器更新其他指令?
    • 这里用这个方法为你工作。 jsfiddle.net/joshkurz/B8x3Q 我认为总的来说这是做这样的事情的最干净的方法。比广播稍微困难一点,但最终结果是 100% 控制玩家以任何需要的方式。
    【解决方案3】:

    您的指令是如何设置的?请提供一些代码。

    这取决于你的指令的范围,我将假设一个子范围。为了在指令之间进行通信,当用户单击启动播放器时,我会调用 $scope.$parent.$broadcast() - 或 $rootScope.$broadcast() 如果指令位于不同的控制器中或使用隔离范围,但随后您需要将 $rootScope 注入您的指令中 - 将事件发送到所有子范围。我的指令将使用 $on 监视此事件,并且任何正在玩的玩家都会停止。在此广播之后,点击的播放器将开始播放。

    $broadcast() and $on() scope documentation

    【讨论】:

      【解决方案4】:

      您还可以进行$rootScope.$broadcast 活动,例如playerStarted。所有指令都可以订阅此事件,并且它们可以通过停止自己来对此事件做出反应。您需要做的一件事是传递有关正在启动的播放器的数据,以便新播放器不会自行停止,因为它也会订阅此类事件。

      【讨论】:

      • 呸,你先来了。我唯一的区别是我会在事件广播后开始播放,而不是发送更多信息并让每个玩家检查它是否是事件发起者。
      • 实际上,现在我想起来了,我不确定这是否会造成竞争条件。你知道 $broadcast() 是否在摘要循环完成之前一直阻塞吗?
      • $on 回调在$broadcast 被调用时立即执行。见the source。这意味着它们被称为同步/阻塞。
      • 是的,我会使用 $broadcast 并尝试尽可能地限制范围,所以 here 我在控制器中添加并在控制器范围上广播而不是提高效率的 rootScope。
      • 不要在 rootscope 上使用广播,只是不要。关于服务的想法,以隔离您的通信并可能以一种明确的,更重要的是,封装的方式进行状态。这将使调试变得更加容易,并允许您在测试期间拦截/模拟通信。当下一个开发人员(也就是你)必须重构东西时,这也将使他的生活变得更加轻松。
      猜你喜欢
      • 2014-10-06
      • 1970-01-01
      • 1970-01-01
      • 2015-10-29
      • 2013-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-31
      相关资源
      最近更新 更多