角度一次绑定没有手表



Angular的一次性绑定遇到问题。

假设我想使用一次性绑定的ngIf,类似于这样的东西:

<div ng-if="::showImage">
<img src="somesource" img-preloader/>
</div>

在这种情况下,angular会为if内部的表达式创建一个手表。一旦它被解析为无未定义的值,手表就会被移除。

如果它只被解析为一个truthly值,那么子代html树将被添加到DOM中,然后进行渲染。

现在这一切都很好,但我真的想避免最初的监视,只需解析表达式,如果它未定义,则只需设置一个监视。原因是在我的场景中相当复杂,但基本上我有一些机制可以暂时禁用不需要的手表。。。

所以我在寻找内置angular的一次性绑定的替代品,并遇到过angular一次。

Angular一旦以不同的方式实现了一次绑定,它只在表达式被解析为未定义时设置临时监视,因此如果它在初始尝试中解析,则不会创建监视。听起来不错。

所以我可以做这样的事情:

<div once-if="showImage">
<img src="somesource" img-preloader/>
</div>

但是,问题是这样的——显然,子代HTML树首先在默认情况下呈现,然后如果一旦if解析为false,则从DOM中删除子代节点。

以下是实现这一点的片段:

{
name: 'onceIf',
priority: 600,
binding: function (element, value) {
if (!value) {
element.remove();
}
}
},

这对我来说是不好的行为,因为创建子代树是不可能的,还会导致其他问题,例如,在上面的例子中,img将被下载。

因此,我正在寻找一种在ngIf等指令中执行一次性绑定的方法,如果表达式解析成功,则无需设置监视,也无需预渲染子代树。

我曾试图避免这种情况,但目前我最终实现了基于Angular标准指令的自定义指令,但添加了必要的功能。

ngIf派生指令:

app.directive('watchlessIf', ['$animate', '$compile', '$parse', function($animate, $compile, $parse) {
return {
multiElement: true,
transclude: 'element',
priority: 600,
terminal: true,
restrict: 'A',
$$tlb: true,
link: function($scope, $element, $attr, ctrl, $transclude) {
function valueChangedAction(value) {
if (value) {
if (!childScope) {
$transclude(function(clone, newScope) {
childScope = newScope;
clone[clone.length++] = $compile.$$createComment('end watchlessIf', $attr.watchlessIf);
block = {
clone: clone
};
$animate.enter(clone, $element.parent(), $element);
});
}
} else {
if (previousElements) {
previousElements.remove();
previousElements = null;
}
if (childScope) {
childScope.$destroy();
childScope = null;
}
if (block) {
previousElements = getBlockNodes(block.clone);
$animate.leave(previousElements).then(function() {
previousElements = null;
});
block = null;
}
}
}
var block, childScope, previousElements;
if ($attr.watchlessIf.startsWith("::")) {
var parsedExpression = $parse($attr.watchlessIf)($scope);
if (parsedExpression != null) {
valueChangedAction(parsedExpression);
return;
}
}
$scope.$watch($attr.watchlessIf, valueChangedAction);
}
};
}]);

ngBind派生指令:

app.directive('watchlessBind', ['$compile', '$parse', function($compile, $parse) {
return {
restrict: 'AC',
compile: function watchlessBindCompile(templateElement) {
$compile.$$addBindingClass(templateElement);
return function watchlessBindLink(scope, element, attr) {
function valueChangedAction(value) {
element.textContent = (typeof value == "undefined") ? '' : value;
}
$compile.$$addBindingInfo(element, attr.watchlessBind);
element = element[0];
if (attr.watchlessBind.startsWith("::")) {
var parsedExpression = $parse(attr.watchlessBind)(scope);
if (parsedExpression != null) {
valueChangedAction(parsedExpression);
return;
}
}
scope.$watch(attr.watchlessBind, valueChangedAction);
};
}
};
}]);

注:

  • 不幸的是,使用这种方法,我将不得不为其他Angular指令实现类似的指令,因为我希望支持潜在的无监视一次性绑定。

  • 我在指令中使用了私人角度的东西,比如$$tlb选项,尽管我真的不应该。。。

最新更新