AngularJS 指令 - 设置多个指令元素的顺序(不是指令的优先级,而是元素的优先级)

Posted

技术标签:

【中文标题】AngularJS 指令 - 设置多个指令元素的顺序(不是指令的优先级,而是元素的优先级)【英文标题】:AngularJS directive - setting order for multiple directive elements (not priority for directives, but priority for the elements) 【发布时间】:2013-08-05 16:07:47 【问题描述】:

考虑这个带有指令“foo”的标记:

<div foo run="3"></div>
<div foo run="1"></div>
<div foo run="2"></div>

使“foo”按指定顺序而不是从上到下 (3,1,2) 运行的好方法是什么? 我唯一能想到的就是跟踪已经运行的内容并在不正常的项目上返回 false,然后让 angular 尝试再次运行它们并重复直到它们全部完成。但这对我来说听起来很糟糕,因为它必须重复很多次...... Angular 有内置的东西可以使用吗?有没有理想的方法来处理这个问题?

【问题讨论】:

我认为了解更多关于您在 foo 指令中所做的事情以及顺序的重要性的信息会很有帮助。使用父指令,您可以捕获子指令,然后在单独的步骤中处理它们。 嗯。这是一个有趣的想法。我会咬紧它一会儿。我的实际指令正在做的是加载各种内容,其中一些内容比其他内容重要得多。它实际上是一个插件加载器,处理控制器/模板的延迟加载。到目前为止,它的加载速度非常快,但我也想尝试使用一个良好的优先级系统。目前,内容只是从上到下加载。如果左侧边栏优先于主要内容主体,这可能是一个问题。 我明白了,您的意思是远程请求的内容,并且您想管理加载顺序? 【参考方案1】:

好的,这是我的解决方案,虽然它更像是一个模板。

Fiddle (check the console log to see the result)

我已将 foo 指令包装在 fooParent 指令中,如下所示:

<div foo-parent>
    <div foo run="3"></div>
    <div foo run="1"></div>
    <div foo run="2"></div>
</div>

fooParent 指令的存在几乎可以做三件事:

    foo 项目公开函数,以便将它们添加到常规列表中 维护foos的列表,将在链接后排序 按指定的运行顺序处理每个foo

看起来像这样:

app.directive('fooParent', function() 
    var foos = [];
    return 
        restrict: 'A',
        controller: ['$scope', '$element', '$attrs', '$transclude', function($scope, $element, $attrs, $transclude) 
            this.addFoo = function(runOrder, element) 
                foos.push(
                    run: 1*runOrder, // make sure run is an integer
                    element: element
                );
            ;
        ],
        link: function(scope, element, attrs) 
            foos.sort(function(a, b) 
                return a.run - b.run;
            );
            // process all children here
            angular.forEach(foos, function(foo) 
                console.log(foo);
            );
        
    ;
);

foo 看起来就像:

app.directive('foo', function() 
    return 
        restrict: 'A',
        require: '^fooParent',
        link: function(scope, element, attrs, fooParent) 
            fooParent.addFoo(attrs.run, element);
        
    ;
);

显然,您必须找出处理远程加载内容的最佳方式,尤其是在您希望连续加载内容的情况下。您的foo 指令将变得更加简化,因为加载和处理必须在fooParent 中进行。

【讨论】:

看起来不错。我要在早上潜入,看看我在哪里:) 只是提醒一下,元素相互嵌套,这是不可取的。我也得到 2,1,3 而不是 3,1,2。 哦,当然。我们省略了 。哈哈,疲劳对大脑有奇效:) 我更正了嵌套问题(是的,写得太晚了),我还更正了 run 到整数的转换,这将有助于排序。最后,如果要先运行最高的运行号,请将排序功能更改为b.run - a.run(交换ab)。 我只是做了同样的事情 :) 它看起来确实很好用!我有一个想法,我也想尝试,只是为了它。一会儿我会发帖。【参考方案2】:

感谢 OverZealous 启发了我的回答。在这里测试一下。 http://jsbin.com/apumaj/21/edit

html(指令输出当然会按这个顺序显示)

<div foo run="7"></div>
<div foo run="3"></div>
<div foo run="1"></div>
<div foo run="2"></div>

并且指令(使指令输出以“运行”顺序加载)应该是不言自明的

app.directive('foo', function() 
  var foos = [];
  var foosLength = document.querySelectorAll('[foo]').length;
    return 
        restrict: 'A',
        link: function(scope, element, attrs) 
          foos.push(element:element, run:attrs.run);
          if (foos.length === foosLength) 
             foos.sort(function(a, b) 
                return a.run - b.run;
            );
            console.log('ran in this order:');
            for (var i=0; i<foosLength; ++i) 
              //process foos!
              var foo = foos[i];
              console.log(foo.run);
              foo.element.text(foo.run);
            
          
        
    ;
);

【讨论】:

我选择了这种方法而不是 OverZealous 提出的解决方案,因为它不需要非语义和其他不必要的 dom 元素和额外的指令。它更易于理解/可读,性能应该稍微好一些。 从那以后我改变了主意,开始喜欢 OverZealous 的回答 :) 选择没有父元素会强制您使用 DOM 方法 (querySelector)。旁注是当您嵌套&lt;foo&gt;s 时,这两种解决方案都不起作用,除非您想选择它们而不考虑嵌套深度。 Angular 的哲学是结合使用子/父指令和require 来定义 DOM 元素之间的依赖关系。因此我认为@OverZealous 的解决方案更优雅。 @frankvanwijk 绝对。这就是为什么我将其标记为接受。 :) 我的回答确实更巧妙地解决了我的实际问题,因为我需要它是全局的,但使用父元素使其全局化肯定更好,而不是强制它。那时我没有意识到这一点。

以上是关于AngularJS 指令 - 设置多个指令元素的顺序(不是指令的优先级,而是元素的优先级)的主要内容,如果未能解决你的问题,请参考以下文章

AngularJS 指令

AngularJS 错误:指令“XXXXXX”的模板必须只有一个根元素

AngularJs 指令

每天看懂一点:AngularJS

默认日期设置不起作用Angularjs指令

AngularJS - 指令的设置选项