我是AngularJS的新手,并且有一个问题,我希望有人可以指出我正确的方向来搞清楚。我创建了一个名为sizeWatcher
的指令,该指令作为属性放置在HTML中,它基本上只是获取它所放置的元素的高度,并将该高度回显到名为style
的范围变量中我通过使用ng-style="style"
设置了另一个元素。
我发现每当我打开手风琴时,$watch
就会触发指令,但它会多次发射。我的console.log
中有一个$watch
并且看到3个日志条目,前两个是相同的(猜测这是在手风琴打开之前点击发生的,然后手风琴打开,第3个日志条目是手风琴打开后的最终高度)。主要问题是style
变量仅在手风琴扩展之前被设置为较小的高度,即使日志正在注册指令被击中的最大高度 - 我怎么能忽略第一次$watch
事件发生,并且只对指令的最后和最后一次执行采取相应行动?任何对此的见解将不胜感激。相关代码如下:
<div class="content-wrap" id="height-block" ng-style="style">
<!-- Other HTML etc... -->
<uib-accordion size-watcher close-others="oneAtATime">
<!-- Accordion Directive HTML.. -->
</uib-accordion>
</div>
JavaScript的:
.directive("sizeWatcher", function () { //add size-watcher attribute to element on the page to have it echo its' height to the {{style}} scope
function link(scope, element, attrs) {
scope.$watch(function () { //watch element for changes
var height = element[0].offsetHeight;
console.log(height);
if (height > 150) {
scope.style = {
height: height + 'px'
};
}
});
}
return {
restrict: "AE", //attribute & element declarations
link: link
};
})
答案 0 :(得分:2)
我如何忽略第一个$ watch事件的发射并且只采取行动 因此,该指令的最后和最后一次贯穿?
当新值或旧值为undefined
且不相等时,您可以忽略观察者:
$scope.$watch(function () {
return element.height(); // or something else
},
function (newVal, oldVal) {
if (newVal !== undefined && oldVal !== undefined && newVal !== oldVal) {
// your stuff
if (newVal > 150) {
scope.style = {
height: newVal + 'px'
};
}
}
});
无论如何,你可以使用if语句来满足你的需求
仅供参考,提高效果$watch
会返回取消回拨,因此您可以随时停止观察:
var cancelWatch = $scope.$watch(function () {
return element.height();
},
function (newVal, oldVal) {
if (<some condition>) {
cancelWatch();
}
});
答案 1 :(得分:0)
显然,对此的回答需要指向Angular-Documentation for $watch
;)
它陈述如下:
在观察者注册范围后,
listener
fn被异步调用(通过$evalAsync
)来初始化观察者。在极少数情况下,这是不合需要的,因为在watchExpression
的结果没有改变时调用了监听器。要在listener
fn中检测此方案,您可以比较newVal
和oldVal
。如果这两个值相同(===
),则由于初始化而调用了侦听器。
这可能解释了你的第一次电话。
我猜测第二次调用是因为手风琴在初始化后被重新渲染(带有标题/或标签或任何东西),触发$digest
,从而触发高度上的$watch
表达式。 / p>
最后,当您打开手风琴并且高度实际发生变化时,会发生第三次调用。
要解决这个问题,你可以比较一下观察到的表达式的newValue和oldValue,比如Maxim Shoustin在他的回答中所说。这是一个例子(再次来自Angular-docs)
scope.$watch(
// This function returns the value being watched. It is called for each turn of the $digest loop
function() { return food; },
// This is the change listener, called when the value returned from the above function changes
function(newValue, oldValue) {
if ( newValue !== oldValue ) {
// Only increment the counter if the value changed
scope.foodCounter = scope.foodCounter + 1;
}
}
);
但是,如果您确实想要更改元素的样式,可能需要查看ng-class
而不是手动注册任何观察者!
答案 2 :(得分:0)
这种情况正在发生,因为你没有使用$ watch正确方式,
所以在你的情况下,它会是这样的
scope.$watch(
function () {
return element[0].offsetHeight;
},
function () { //watch element for changes
var height = element[0].offsetHeight;
console.log(height);
if (height > 150) {
scope.style = {
height: height + 'px'
};
}
}
)
请注意第一个函数,因此每当它返回的值发生变化时,第二个回调将执行
希望这有助于你