我是指示在屏幕尺寸小于600px时在屏幕上显示div。问题是,即使在指令中使用$apply()
,范围值也不会更新。
这是代码:
function showBlock($window,$timeout) {
return {
restrict: 'A',
scope: true,
link: function(scope, element, attrs) {
scope.isBlock = false;
checkScreen();
function checkScreen() {
var wid = $window.innerWidth;
if (wid <= 600) {
if(!scope.isBlock) {
$timeout(function() {
scope.isBlock = true;
scope.$apply();
}, 100);
};
} else if (wid > 600) {
if(scope.isBlock) {
$timeout(function() {
scope.isBlock = false;
scope.$apply();
}, 100);
};
};
};
angular.element($window).bind('resize', function(){
checkScreen();
});
}
};
}
HTML:
<div ng-if="isBlock" show-block>
//..conent to show
</div>
<div ng-if="!isBlock" show-block>
//..other conent to show
</div>
注意:如果我不使用$ timeout,我将收到错误
$ digest已在进行中
我在里面使用了控制台日志来检查它是否正在更新值,并且在指令中一切正常。但是这些变化并不适用于观点。该块未显示。
答案 0 :(得分:1)
在这种情况下,您应该使用do rule
来获得Prototypal Inheritance of AngularJS的优势。
基本上你需要创建一个具有各种属性的对象。就像你的情况一样,你可以$scope.model = {}
,然后在其中放置isBlock
属性。因此,当您进入指令时,您将可以访问父作用域。它背后的原因是,你有scope: true
,它表示在指令中创建的是原型范围继承的原型。这意味着您的子范围中可以使用所有引用类型对象。
<强>标记强>
<div ng-if="model.isBlock" show-block>
//..conent to show
</div>
<div ng-if="!model.isBlock" show-block>
//..other conent to show
</div>
<强>控制器强>
app.controller('myCtrl', function($scope){
//your controller code here
//here you can have object defined here so that it can have properties in it
//and child scope will get access to it.
$scope.model = {}; //this is must to use dot rule,
//instead of toggle property here you could do it from directive too
$scope.isBlock = false; //just for demonstration purpose
});
然后在你的指令中你应该使用scope.model.isBlock
而不是scope.isBlock
<强>更新强>
在代码中使用controllerAs
模式时,需要使用scope.ag.model.isBlock
。这将为您提供在指令中获取范围变量值的访问权限。
基本上,您可以获取父控制器值(使用controllerAs
模式)在子级内部生成可用的控制器值。您可以在$scope
内找到包含控制器别名的对象。就像这里一样,你创建了ag
作为控制器别名,所以你需要scope.ag.model
来获取指令链接函数中的model
值。
注意强>
您不需要将$apply
与$timeout
一起使用,这可能会导致错误$apply in progress
,因此$ timeout会为您运行摘要,您无需担心运行摘要。
答案 1 :(得分:0)
我怀疑它与如果ng-if =&#34; isBlock&#34;并且不会触发show-block指令这一事实有关。永远不会是真的,所以它永远不会注册resize事件。
答案 2 :(得分:0)
根据我的经验,线性代码永远不适用于动态DOM属性,例如窗口大小调整。使用寻找屏幕大小的代码,您需要将其放在某种事件/ DOM观察者中,例如角度我用$ watch来观察尺寸。所以要解决这个问题,你需要将代码放在$ watch中,例如下面。我没有测试过这段代码,只是方向性。您可以观看$ window.innerWidth或者您可以观看$ element例如身体取决于你的目标。我说这是因为屏幕将遍布整个地方但是如果你控制一个DOM元素,比如身体,你可以更好地控制。为了简洁起见,我也没有使用$ timeout。
// watch window width
showBlock.$inject = ['$window'];
function bodyOverflow($window) {
var isBlock = false;
return {
restrict: 'EA',
link: function ($scope, element, attrs) {
$scope.$watch($window.innerWidth, function (newWidth, oldWidth) {
if (newWidth !== oldWidth) {
return isBlock = newWidth <= 600;
}
})
}
};
}
// OR watch element width
showBlock.$inject = [];
function bodyOverflow() {
var isBlock = false;
return {
restrict: 'EA',
link: function ($scope, element, attrs) {
$scope.$watch($element, function (new, old) {
if (newWidth) {
return isBlock = newWidth[0].offsetWidth <= 600;
}
})
}
};
}