ng-repeat 中的自定义指令:为什么 ng-style 不适用?

Custom directive in ng-repeat: Why does ng-style not apply?

我有一个自定义指令 myItems,它通过 ng-repeat:

使用另一个指令 myItem 呈现项目列表
app.directive('myItems', function() {
    return {
        scope:{items:"="},
        restrict:"E",
        template:"<div my-item ng-repeat='item in items'></div>"
    };
});

每个项目都包含用于设置元素样式的信息(例如颜色)。如果我使用模板方法,到目前为止效果很好:

app.directive('myItem', function() {
    return {
        restrict:"A",
        template:"<div ng-style='{color:item.color}'>myItem: {{item.name}}</div>",
        replace:true
    };
});

为了支持更多涉及的功能,如果 my-item 我现在想通过手动创建所有需要的东西来重建相同的功能,包括 ng-style:

app.directive('myItem', function($compile) {
    return {
        restrict:"A",
        compile: function(element) {
            element.removeAttr('my-item');
            element.text('myItem: {{item.name}}');
            element.attr('ng-style', '{color:item.color}');    // Why does it have no effect?

            var compileElement = $compile(element);
            return function link(scope, elem, attr) {
                compileElement(scope);    // Why does binding with {{item.name}} even work without this statement?
            };
        }
    };
});

有趣的是,使用 {{item.name}} 的数据绑定有效,而 ng-style 无效。

这里 fiddle 显示了上述两种方法。

我知道similar question。但我认为它在这里不适用,因为我没有关于 my-item 指令范围的明确声明。

编译函数有一个问题:在 Angular 具有 "parsed" 元素之后,它会针对元素的指令调用。这意味着 compile() 函数的代码添加到包含正在编译的指令的元素的任何指令 将不会被 Angular 解析! 这就是 element.attr('ng-style', '{color:item.color}'); 被忽略的原因。

另一方面,compileElement(scope);是多余的; 包含正在编译的指令的元素内完成的任何DOM操作,将被Angular解析。

你能做什么?你的情况很简单,用手表添加样式是一个微不足道的DOM操作(即使没有手表,如果你不希望颜色发生变化):

return function link(scope, elem, attr) {
    scope.$watch('item.color', function(newval) {
        elem.css('color', newval);
    });
};

调用 compileElement 确实编译了 ng-style 元素,但是因为 $compile 在元素完全构造之前被调用,所以调用 compileElement 对元素的无效版本起作用并且ng-style 没有改变颜色。

因此您可以将 $compile 移动到 link 函数中:

var compileElement = $compile(elem);
compileElement(scope);

但随后它又重新编译了 ng-repeat 指令,这是不好的。因此,您还需要删除该属性:

element.removeAttr('ng-repeat');

检查this plunker