AngularJS에 뷰 / 부분 특정 스타일을 포함하는 방법
응용 프로그램에서 사용하는 다양한 뷰에 대해 별도의 스타일 시트를 사용하는 올바른 방법은 무엇입니까?
현재 상단의 view / partial html에 링크 요소를 배치하고 있지만 모든 최신 브라우저가 지원하지만 나쁜 인상을받는 이유는 알 수 있지만 이것이 나쁜 습관이라고 들었습니다.
다른 가능성은 index.html에 별도의 스타일 시트를 배치하는 head
것이지만 성능 이름으로 뷰가로드되는 경우에만 스타일 시트를로드하고 싶습니다.
CSS가 서버에서로드 될 때까지 스타일링이 적용되지 않아 느린 브라우저에서 포맷되지 않은 컨텐츠가 빠르게 플래시되기 때문에이 나쁜 습관입니까? 로컬에서 테스트하고 있지만 아직 이것을 목격하지 않았습니다.
Angular에 전달 된 객체를 통해 CSS를로드하는 방법이 $routeProvider.when
있습니까?
미리 감사드립니다!
나는이 질문이 오래되었다는 것을 알고 있지만이 문제에 대한 다양한 솔루션에 대한 많은 연구를 한 후에 더 나은 솔루션을 생각해 낼 수 있다고 생각합니다.
업데이트 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;
});
}
});
}
};
}
]);
이 지시어는 다음을 수행합니다.
- and를 사용 하여 객체의 모든 항목에 대해 태그
$compile
세트를 생성하는 html 문자열을 컴파일하여 사용합니다 .<link />
scope.routeStyles
ng-repeat
ng-href
- 컴파일 된
<link />
요소 집합을<head>
태그에 추가합니다 . - 그런 다음를 사용하여 이벤트
$rootScope
를 수신'$routeChangeStart'
합니다. 모든'$routeChangeStart'
이벤트에 대해 "현재"$$route
객체 (사용자가 떠나려는 경로)를 잡고<head>
태그 에서 부분 별 CSS 파일을 제거합니다 . 또한 "다음"$$route
객체 (사용자가 이동하려는 경로)를 가져 와서 일부 특정 CSS 파일을<head>
태그에 추가합니다. - 그리고
ng-repeat
컴파일 된<link />
태그 의 일부 는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
은 각 페이지의 경로를 설정하는 데 사용되는 객체에 사용자 정의 속성을 추가 합니다. 해당 객체는로 각 '$routeChangeStart'
이벤트에 전달 됩니다 .$$route
. 따라서 '$routeChangeStart'
이벤트를 css
들을 때 지정한 속성을 가져와 <link />
필요에 따라 해당 태그를 추가 / 제거 할 수 있습니다. css
경로 에서 속성 을 지정하는 것은 '/some/route/2'
예제 에서 생략되었으므로 완전히 선택적 입니다. 경로에 css
속성 이없는 경우 <head>
지시문은 해당 경로에 대해 아무 것도 수행하지 않습니다. 또한 속성이 해당 경로에 필요한 스타일 시트에 대한 상대 경로의 배열 인 '/some/route/3'
위 의 예와 같이 경로당 여러 페이지 별 스타일 시트를 가질 수도 있습니다 css
.
3. 당신은 그 두 가지가 필요한 모든 것을 설정하고 제 생각에는 가능한 가장 깨끗한 코드로 설정합니다.
이 문제로 어려움을 겪고있는 다른 사람에게 도움이되기를 바랍니다.
@tennisgent의 솔루션은 훌륭합니다. 그러나 나는 조금 제한적이라고 생각합니다.
Angular의 모듈화 및 캡슐화는 경로를 뛰어 넘습니다. 웹이 컴포넌트 기반 개발로 이동하는 방식에 따라이를 지시문에도 적용하는 것이 중요합니다.
아시다시피 Angular에서는 페이지와 컴포넌트에 템플릿 (구조)과 컨트롤러 (동작)를 포함시킬 수 있습니다. AngularCSS 는 마지막으로 누락 된 부분 인 스타일 시트 첨부 (프레젠테이션)를 가능하게합니다.
전체 솔루션을 위해 AngularCSS를 사용하는 것이 좋습니다.
- Angular의 ngRoute, UI 라우터, 지시문, 컨트롤러 및 서비스를 지원합니다.
- 이 필요하지 않습니다
ng-app
에<html>
태그입니다. 동일한 페이지에서 여러 앱을 실행하는 경우 중요합니다 - 헤드, 바디, 커스텀 셀렉터 등 스타일 시트가 삽입되는 위치를 사용자 지정할 수 있습니다.
- 사전로드, 지속 및 캐시 버스 팅 지원
- matchMedia API를 통해 미디어 쿼리를 지원하고 페이지로드를 최적화합니다
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
@ sz3, 오늘 충분히 재미난 나는 당신이 달성하려는 것을 정확하게해야했습니다 : ' 사용자 가 특정 페이지에 액세스 할 때만 특정 CSS 파일을로드 하십시오. 그래서 위의 솔루션을 사용했습니다.
그러나 나는 당신의 마지막 질문에 대답하기 위해 여기에 있습니다 : ' 정확히 어디에 코드를 넣어야합니까? 어떤 아이디어 ? '
resolve에 코드를 포함시키는 것이 옳았 지만 약간의 형식을 변경해야합니다.
아래 코드를 살펴보십시오.
.when('/home', {
title:'Home - ' + siteName,
bodyClass: 'home',
templateUrl: function(params) {
return 'views/home.html';
},
controler: 'homeCtrl',
resolve: {
style : function(){
/* check if already exists first - note ID used on link element*/
/* could also track within scope object*/
if( !angular.element('link#mobile').length){
angular.element('head').append('<link id="home" href="home.css" rel="stylesheet">');
}
}
}
})
방금 테스트 한 결과 제대로 작동 하고 html을 삽입하고 '/ home'경로에 도달했을 때만 'home.css'를로드합니다.
전체 설명은 여기 에서 찾을 수 있지만 기본적으로 해결됩니다. 형식으로 객체를 가져와야합니다.
{
'key' : string or function()
}
당신이 원하는대로 ' 키 '의 이름을 지정할 수 있습니다 -제 경우에는 ' 스타일 ' 이라고 불렀습니다 .
그런 다음 값에 대해 두 가지 옵션이 있습니다.
그것은 만약 문자열 , 다음은 서비스의 별칭입니다.
function 인 경우 삽입되고 리턴 값이 종속성으로 처리됩니다.
여기서 중요한 점은 컨트롤러가 인스턴스화되고 $ routeChangeSuccess 이벤트가 시작되기 전에 함수 내부의 코드가 실행된다는 것입니다.
희망이 도움이됩니다.
좋아 고마워!! ui-router와 작동하도록 몇 가지 조정을해야했습니다.
var app = app || angular.module('app', []);
app.directive('head', ['$rootScope', '$compile', '$state', function ($rootScope, $compile, $state) {
return {
restrict: 'E',
link: function ($scope, elem, attrs, ctrls) {
var html = '<link rel="stylesheet" ng-repeat="(routeCtrl, cssUrl) in routeStyles" ng-href="{{cssUrl}}" />';
var el = $compile(html)($scope)
elem.append(el);
$scope.routeStyles = {};
function applyStyles(state, action) {
var sheets = state ? state.css : null;
if (state.parent) {
var parentState = $state.get(state.parent)
applyStyles(parentState, action);
}
if (sheets) {
if (!Array.isArray(sheets)) {
sheets = [sheets];
}
angular.forEach(sheets, function (sheet) {
action(sheet);
});
}
}
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
applyStyles(fromState, function(sheet) {
delete $scope.routeStyles[sheet];
console.log('>> remove >> ', sheet);
});
applyStyles(toState, function(sheet) {
$scope.routeStyles[sheet] = sheet;
console.log('>> add >> ', sheet);
});
});
}
}
}]);
당신은 할 수 귀하의 CSS를해야하는 경우 적용되는 하나 개의 특정보기에, 나는 내 컨트롤러 내부의이 편리한 조각을 사용하고 있습니다 :
$("body").addClass("mystate");
$scope.$on("$destroy", function() {
$("body").removeClass("mystate");
});
body
상태가로드되면 내 태그에 클래스가 추가 되고 상태가 파괴되면 클래스가 제거됩니다 (예 : 누군가 페이지를 변경). 이렇게하면 응용 프로그램에서 CSS를 한 상태에만 적용해야하는 관련 문제가 해결됩니다.
'use strict'; angular.module('app') .run( [ '$rootScope', '$state', '$stateParams', function($rootScope, $state, $stateParams) { $rootScope.$state = $state; $rootScope.$stateParams = $stateParams; } ] ) .config( [ '$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$urlRouterProvider
.otherwise('/app/dashboard');
$stateProvider
.state('app', {
abstract: true,
url: '/app',
templateUrl: 'views/layout.html'
})
.state('app.dashboard', {
url: '/dashboard',
templateUrl: 'views/dashboard.html',
ncyBreadcrumb: {
label: 'Dashboard',
description: ''
},
resolve: {
deps: [
'$ocLazyLoad',
function($ocLazyLoad) {
return $ocLazyLoad.load({
serie: true,
files: [
'lib/jquery/charts/sparkline/jquery.sparkline.js',
'lib/jquery/charts/easypiechart/jquery.easypiechart.js',
'lib/jquery/charts/flot/jquery.flot.js',
'lib/jquery/charts/flot/jquery.flot.resize.js',
'lib/jquery/charts/flot/jquery.flot.pie.js',
'lib/jquery/charts/flot/jquery.flot.tooltip.js',
'lib/jquery/charts/flot/jquery.flot.orderBars.js',
'app/controllers/dashboard.js',
'app/directives/realtimechart.js'
]
});
}
]
}
})
.state('ram', {
abstract: true,
url: '/ram',
templateUrl: 'views/layout-ram.html'
})
.state('ram.dashboard', {
url: '/dashboard',
templateUrl: 'views/dashboard-ram.html',
ncyBreadcrumb: {
label: 'test'
},
resolve: {
deps: [
'$ocLazyLoad',
function($ocLazyLoad) {
return $ocLazyLoad.load({
serie: true,
files: [
'lib/jquery/charts/sparkline/jquery.sparkline.js',
'lib/jquery/charts/easypiechart/jquery.easypiechart.js',
'lib/jquery/charts/flot/jquery.flot.js',
'lib/jquery/charts/flot/jquery.flot.resize.js',
'lib/jquery/charts/flot/jquery.flot.pie.js',
'lib/jquery/charts/flot/jquery.flot.tooltip.js',
'lib/jquery/charts/flot/jquery.flot.orderBars.js',
'app/controllers/dashboard.js',
'app/directives/realtimechart.js'
]
});
}
]
}
})
);
'Programing' 카테고리의 다른 글
수행자 엔티티 직렬화 : BSON vs MessagePack (vs JSON) (0) | 2020.06.30 |
---|---|
자바 로깅 vs Log4J (0) | 2020.06.30 |
파이썬으로 BDD 연습하기 (0) | 2020.06.30 |
C ++에서 클래스를 직렬화 및 역 직렬화 할 수 있습니까? (0) | 2020.06.30 |
Google Code Subversion 저장소를 GitHub에 포크 및 동기화 (0) | 2020.06.30 |