我正在开发一个在服务器渲染的HTML之上使用角度的Web应用程序。
我正在尝试将呈现的 HTML 的一部分用作可重用组件(指令),因此我在返回的 HTML 中的相应标记上附加了一个属性指令。此指令需要具有独立作用域,并且它将进一步包含应是此隔离指令中的子作用域的子指令。
不幸的是,angular 没有从返回的 HTML 创建具有正确作用域层次结构的指令。独立作用域内的子指令是独立作用域的同级指令(而不是子指令)。现在,如果我将这些指令更改为使用客户端模板,它可以正常工作。因此,似乎angular 不喜欢从服务器生成的 HTML 构造这种形式的指令。
为了更好地说明我的问题,我创建了几个 plunker - 一个工作正常(客户端模板),另一个工作不正确(服务器渲染的 HTML)。
服务器渲染的 plunker
索引.html
<body>
<div isolate-dir>
Content from the server
<div child-dir>
More content from the server: <span ng-bind="testVar">server data</span>
</div>
</div>
</body>
脚本.js
angular.module('test', []);
angular.module('test').directive('isolateDir', function() {
return {
restrict: 'A',
scope: {},
link: function(scope, element, attr) {
console.log('isolate dir scope [' + scope.$id + ' -> ' + scope.$parent.$id + ']');
}
}
});
angular.module('test').directive('childDir', function() {
return {
restrict: 'A',
scope: true,
link: function(scope, element, attr) {
console.log('child dir scope [' + scope.$id + ' -> ' + scope.$parent.$id + ']');
scope.testVar = "client data";
}
}
});
输出
child dir scope [3 -> 1]
isolate dir scope [2 -> 1]
客户端模板 Plunker
索引.html
<body>
<div isolate-dir></div>
</body>
脚本.js
angular.module('test', []);
angular.module('test').directive('isolateDir', function() {
return {
restrict: 'A',
scope: {},
link: function(scope, element, attr) {
console.log('isolate dir scope [' + scope.$id + ' -> ' + scope.$parent.$id + ']');
},
template: "Content from the server <div child-dir></div>"
}
});
angular.module('test').directive('childDir', function() {
return {
restrict: 'A',
scope: true,
link: function(scope, element, attr) {
console.log('child dir scope [' + scope.$id + ' -> ' + scope.$parent.$id + ']');
scope.testVar = "client data";
},
template: "More content from the server: <span ng-bind='testVar'>server data</span>"
}
});
输出
child dir scope [3 -> 2]
isolate dir scope [2 -> 1]
运行 plunkers 并观察控制台输出时,您可以看到范围层次结构在客户端模板化版本中是正确的,而在服务器呈现版本中不正确。
为什么服务器呈现的内容的范围层次结构不正确,解决此问题的最佳方法是什么?
好消息是这与"服务器"渲染无关。
问题来自您对指令的理解。隔离指令(isolate-dir
)确实会有一个孤立的作用域,这会影响它的模板和控制器。但是,HTML 层次结构与 Angular 范围层次结构没有关系:只有 <div isolate-dir>
具有隔离的作用域,但不是其所有子元素。
如果您希望子元素继承自该父div
的作用域,则应将这些子元素放入隔离指令的模板中(这是在您的第一个示例中完成的,因此它有效),或者使用提供给link
函数的transclusion
参数将父作用域传播到其内部元素。
这是使用此方法的 plunkr:
plnkr.co/edit/n0ws7pPqOS8dt6IMKYMl?p=info
如果这仍然让您感到困惑,您可以在此处阅读更多相关信息:
http://angular-tips.com/blog/2014/03/transclusion-and-scopes/