用于粘性状态的 ui-router-extras示例向我们展示了我们需要使用 ng-show 结合 $state 自己显示/隐藏视图。因此,我们需要使 $state 以某种方式可访问,在示例中通过将 $state 全局注入 $rootScope 来完成。
我不喜欢这个变量在我的范围内全局爬行并从本地所有控制器注入该变量的想法听起来也不是最优的。我怎样才能更优雅地解决这个问题?
用于粘性状态的 ui-router-extras示例向我们展示了我们需要使用 ng-show 结合 $state 自己显示/隐藏视图。因此,我们需要使 $state 以某种方式可访问,在示例中通过将 $state 全局注入 $rootScope 来完成。
我不喜欢这个变量在我的范围内全局爬行并从本地所有控制器注入该变量的想法听起来也不是最优的。我怎样才能更优雅地解决这个问题?
这是自定义指令的完美应用。这是一个简单的指令,您可以将其添加到您的 ui-view 标签:
app.directive("showWhenStateActive", function($state) {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
var stateChangedFn = function stateChanged() {
var addOrRemoveFnName = $state.includes(attrs.showWhenStateActive) ? "removeClass" : "addClass";
elem[addOrRemoveFnName]("ng-hide");
};
scope.$on("$stateChangeSuccess", stateChangedFn);
}
}
});
要使用它,只需将其作为属性添加到标签中,并提供您要检查的状态名称。
例如,在ui-router-extras Sticky State 示例中,您将对此进行更改:
<div class="tabcontent well-lg" ui-view="peopletab" ng-show="$state.includes('top.people')" class="col-sm-6"></div>
<div class="tabcontent well-lg" ui-view="invtab" ng-show="$state.includes('top.inv')" class="col-sm-6"></div>
<div class="tabcontent well-lg" ui-view="custtab" ng-show="$state.includes('top.cust')" class="col-sm-6"></div>
对此:
<div class="tabcontent well-lg" ui-view="peopletab" show-when-state-active="top.people" class="col-sm-6"></div>
<div class="tabcontent well-lg" ui-view="invtab" show-when-state-active="top.inv" class="col-sm-6"></div>
<div class="tabcontent well-lg" ui-view="custtab" show-when-state-active="top.cust" class="col-sm-6"></div>
我研究了ui-sref 指令的源代码,以确定我是否可以构建一个类似的指令,但不能根据当前状态设置活动类,而是更改当前元素的可见性。
不幸的是,ui-router 看起来并不打算以这种方式扩展。但是我可以一起破解我自己的指令。请注意,parseStateRef
和stateContext
是从 ui-router 源代码复制和粘贴的函数,其他代码无法访问。
源代码按预期在我当前的项目中工作,但是我不知道它会错过哪些我在项目中没有考虑/不需要的情况。
无论如何:用法将是<... show-on-sref="targetState">
. 我成功地使用子相关链接(以点开头的链接,例如.someState
)测试了该指令。
var attributeName = 'showOnSref';
function parseStateRef(ref, current) {
var preparsed = ref.match(/^\s*({[^}]*})\s*$/), parsed;
if (preparsed) ref = current + '(' + preparsed[1] + ')';
parsed = ref.replace(/\n/g, " ").match(/^([^(]+?)\s*(\((.*)\))?$/);
if (!parsed || parsed.length !== 4) throw new Error("Invalid state ref '" + ref + "'");
return { state: parsed[1], paramExpr: parsed[3] || null };
}
function stateContext(el) {
var stateData = el.parent().inheritedData('$uiView');
if (stateData && stateData.state && stateData.state.name) {
return stateData.state;
}
}
angular
.module('showOnSref', [])
.directive(attributeName, ['$state', function($state) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var ref = parseStateRef(attrs[attributeName], $state.current.name),
linkedState = $state.get(ref.state, stateContext(element)),
params = angular.copy(scope.$eval(ref.paramExpr)),
inactiveClass = 'ng-hide',
bind = angular.bind,
show = bind(element, element.removeClass, inactiveClass),
hide = bind(element, element.addClass, inactiveClass),
update = function() {
$state.includes(linkedState.name, params) ? show() : hide();
};
scope.$on('$stateChangeSuccess', update);
}
};
}]);