如何在AngularJS中包含视图/部分特定样式
对于我的应用程序使用的各种视图使用单独的样式表,正确/可接受的方式是什么?
目前,我在顶部的view / partial的html中放置了一个链接元素,但是我已经被告知这是不好的做法,尽管所有的现代浏览器都支持它,但是我可以看出为什么它会被折磨。
另一种可能是将独立的样式表放在我的index.html head
但是我希望它只在样式表的视图以性能名称加载时才加载样式表。
这是不好的做法,因为直到从服务器加载css之后,样式才会生效,从而导致在慢速浏览器中快速刷新未格式化的内容? 尽管我在本地进行测试,但我还没有目睹这一点。
有没有办法通过传递给Angular的$routeProvider.when
的对象加载CSS?
提前致谢!
我知道这个问题现在已经很老了,但是在对这个问题的各种解决方案进行了大量研究后,我想我可能会想出一个更好的解决方案。
更新1:自发布此答案以来,我已将所有这些代码添加到我发布到GitHub的简单服务中。 回购处位于此处。 随时查看更多信息。
更新2:如果您需要的只是为您的路线提供样式表的轻量级解决方案,则此答案非常好。 如果您想要在整个应用程序中管理按需样式表的更完整解决方案,您可能需要签出Door3的AngularCSS项目。 它提供了更精细的功能。
如果将来有人对此感兴趣,下面是我想到的:
1.为<head>
元素创建一个自定义指令:
app.directive('head', ['$rootScope','$compile',
function($rootScope, $compile){
return {
restrict: 'E',
link: function(scope, elem){
var html = '<link rel="stylesheet" ng-repeat="(routeCtrl, cssUrl) in routeStyles" ng-href="{{cssUrl}}" />';
elem.append($compile(html)(scope));
scope.routeStyles = {};
$rootScope.$on('$routeChangeStart', function (e, next, current) {
if(current && current.$$route && current.$$route.css){
if(!angular.isArray(current.$$route.css)){
current.$$route.css = [current.$$route.css];
}
angular.forEach(current.$$route.css, function(sheet){
delete scope.routeStyles[sheet];
});
}
if(next && next.$$route && next.$$route.css){
if(!angular.isArray(next.$$route.css)){
next.$$route.css = [next.$$route.css];
}
angular.forEach(next.$$route.css, function(sheet){
scope.routeStyles[sheet] = sheet;
});
}
});
}
};
}
]);
该指令执行以下操作:
$compile
)一个html字符串,它使用ng-repeat
和ng-href
为scope.routeStyles
对象中的每个项目创建一组<link />
标记。 <link />
元素集添加到<head>
标记中。 $rootScope
来侦听'$routeChangeStart'
事件。 对于每个'$routeChangeStart'
事件,它抓取“当前” $$route
对象(用户即将离开的路由),并从<head>
标记中删除其部分特定的css文件。 它还抓取“下一个” $$route
对象(用户即将前往的路由),并将其任何部分特定的css文件添加到<head>
标记。 <link />
标记的ng-repeat
部分根据添加到scope.routeStyles
对象中或从中删除的内容来处理所有添加和删除特定于页面的样式表。 注意:这要求你的ng-app
属性在<html>
元素上,而不在<body>
或者<html>
。
2.使用$routeProvider
指定哪些样式表属于哪些路线:
app.config(['$routeProvider', function($routeProvider){
$routeProvider
.when('/some/route/1', {
templateUrl: 'partials/partial1.html',
controller: 'Partial1Ctrl',
css: 'css/partial1.css'
})
.when('/some/route/2', {
templateUrl: 'partials/partial2.html',
controller: 'Partial2Ctrl'
})
.when('/some/route/3', {
templateUrl: 'partials/partial3.html',
controller: 'Partial3Ctrl',
css: ['css/partial3_1.css','css/partial3_2.css']
})
}]);
该配置向用于设置每个页面路由的对象添加一个自定义css
属性。 该对象以.$$route
传递给每个'$routeChangeStart'
事件。 因此,在收听'$routeChangeStart'
事件时,我们可以获取我们指定的css
属性,并根据需要追加/删除这些<link />
标签。 请注意,在路由上指定一个css
属性是完全可选的,因为它从'/some/route/2'
示例中省略。 如果路由没有css
属性,那么<head>
指令对于该路由将不起任何作用。 还要注意,甚至可以在每个路由中都有多个特定于页面的样式表,如上面的'/some/route/3'
示例所示,其中css
属性是该路由所需的样式表的相对路径数组。
3.你完成了这两件事设置了一切需要的东西,在我看来,它可以实现最干净的代码。
希望能够帮助那些可能像我一样挣扎于这个问题的其他人。
@ tennisgent的解决方案非常棒。 不过,我觉得有点有限。
Angular的模块化和封装超越了路线。 基于网络向基于组件开发的方向发展,在指令中应用这一点也很重要。
如您所知,在Angular中,我们可以在页面和组件中包含模板(结构)和控制器(行为)。 AngularCSS支持最后缺失的部分:附加样式表(演示文稿)。
对于完整的解决方案,我建议使用AngularCSS。
<html>
标记中使用ng-app
。 当您有多个应用程序在同一页面上运行时,这一点很重要 https://github.com/door3/angular-css
这里有些例子:
路线
$routeProvider
.when('/page1', {
templateUrl: 'page1/page1.html',
controller: 'page1Ctrl',
/* Now you can bind css to routes */
css: 'page1/page1.css'
})
.when('/page2', {
templateUrl: 'page2/page2.html',
controller: 'page2Ctrl',
/* You can also enable features like bust cache, persist and preload */
css: {
href: 'page2/page2.css',
bustCache: true
}
})
.when('/page3', {
templateUrl: 'page3/page3.html',
controller: 'page3Ctrl',
/* This is how you can include multiple stylesheets */
css: ['page3/page3.css','page3/page3-2.css']
})
.when('/page4', {
templateUrl: 'page4/page4.html',
controller: 'page4Ctrl',
css: [
{
href: 'page4/page4.css',
persist: true
}, {
href: 'page4/page4.mobile.css',
/* Media Query support via window.matchMedia API
* This will only add the stylesheet if the breakpoint matches */
media: 'screen and (max-width : 768px)'
}, {
href: 'page4/page4.print.css',
media: 'print'
}
]
});
指令
myApp.directive('myDirective', function () {
return {
restrict: 'E',
templateUrl: 'my-directive/my-directive.html',
css: 'my-directive/my-directive.css'
}
});
另外,您可以使用$css
服务来处理边缘情况:
myApp.controller('pageCtrl', function ($scope, $css) {
// Binds stylesheet(s) to scope create/destroy events (recommended over add/remove)
$css.bind({
href: 'my-page/my-page.css'
}, $scope);
// Simply add stylesheet(s)
$css.add('my-page/my-page.css');
// Simply remove stylesheet(s)
$css.remove(['my-page/my-page.css','my-page/my-page2.css']);
// Remove all stylesheets
$css.removeAll();
});
你可以在这里阅读更多关于AngularCSS的内容:
http://door3.com/insights/introducing-angularcss-css-demand-angularjs
可以在$routeProvider
追加一个新的样式表。 为了简单起见,我使用了一个字符串,但也可以创建新的链接元素,或为样式表创建一个服务
/* check if already exists first - note ID used on link element*/
/* could also track within scope object*/
if( !angular.element('link#myViewName').length){
angular.element('head').append('<link id="myViewName" href="myViewName.css" rel="stylesheet">');
}
在页面中预先写入的最大好处是任何背景图像都已经存在,而且FOUC FOUC
那么FOUC
上一篇: How to include view/partial specific styling in AngularJS