[javascript] AngularJS의 컴파일 기능과 링크 기능의 차이점은 무엇입니까?
누군가 간단한 용어로 설명 할 수 있습니까?
문서가 약간 둔해 보입니다. 나는 한 번에 다른 것을 사용할 때의 본질과 큰 그림을 얻지 못합니다. 이 두 가지를 대조하는 예는 대단합니다.
답변
-
컴파일 함수- 템플릿 DOM 조작 (예 : tElement = 템플릿 요소 조작)에 사용되므로 지시문과 관련된 템플릿의 모든 DOM 복제본에 적용됩니다.
-
링크 기능- 인스턴스 DOM 조작 (예 : iElement = 개별 인스턴스 요소 조작 )뿐만 아니라 DOM 리스너 (예 : 인스턴스 범위의 $ watch 표현식)를 등록하는 데 사용합니다 .
템플릿이 복제 된 후에 실행됩니다. 예를 들어, <li-ng-repeat …> 내에서 링크 함수는 <li> 템플릿 (tElement)이 특정 <li> 요소에 대해 (iElement로) 복제 된 후에 실행됩니다.
$ watch ()를 사용하면 지시문에 인스턴스 범위 속성 변경 사항 (인스턴스 범위가 각 인스턴스와 연결됨)을 알릴 수 있으며, 지시문은 인스턴스 범위의 내용을 인스턴스 범위로 복사하여 업데이트 된 인스턴스 값을 DOM으로 렌더링 할 수 있습니다. DOM.
DOM 변환은 컴파일 기능 및 / 또는 링크 기능에서 수행 될 수 있습니다.
대부분의 지시문은 링크 함수 만 필요합니다. 대부분의 지시문은 특정 DOM 요소 인스턴스 (및 해당 인스턴스 범위) 만 처리하기 때문입니다.
사용할 것을 결정하는 데 도움이되는 한 가지 방법 : 컴파일 함수가 scope
인수를 받지 않는다는 것을 고려하십시오 . (전혀 범위를받는 transclude 연결 함수 인수를 의도적으로 무시하고 있습니다. 이는 거의 사용 되지 않습니다 .) 따라서 컴파일 함수는 (인스턴스) 범위가 필요한 작업을 수행 할 수 없습니다. ‘모델 / 인스턴스 범위 속성을 보지 않고 인스턴스 범위 정보를 사용하여 DOM을 조작 할 수 없으며 인스턴스 범위에 정의 된 함수를 호출 할 수 없습니다.
그러나 링크 함수와 같은 컴파일 함수는 속성에 액세스 할 수 있습니다. 따라서 DOM 조작에 인스턴스 범위가 필요하지 않으면 컴파일 함수를 사용할 수 있습니다. 이러한 이유로 컴파일 함수 만 사용하는 지시문 의 예 는 다음과 같습니다 . 속성을 검사하지만 작업을 수행하기 위해 인스턴스 범위가 필요하지 않습니다.
다음 은 컴파일 함수 만 사용하는 지시문 의 예 입니다. 지시문은 템플릿 DOM 만 변환하면되므로 컴파일 함수를 사용할 수 있습니다.
사용할 함수를 결정하는 또 다른 방법 : 링크 함수에서 “element”매개 변수를 사용하지 않으면 링크 함수가 필요하지 않습니다.
대부분의 지시문에는 링크 기능이 있으므로 예제를 제공하지 않겠습니다. 찾기가 매우 쉬워야합니다.
컴파일 함수 및 링크 함수 (또는 사전 및 사후 링크 함수)가 필요한 경우 ‘컴파일’속성이 정의 된 경우 ‘링크’속성이 무시되므로 컴파일 함수는 링크 함수를 리턴해야합니다.
또한보십시오
- 지시문을 정의 할 때 ‘컨트롤러’, ‘링크’및 ‘컴파일’기능의 차이점
- Dave Smith의 우수한 ng-conf 2104 talk on 지시문 (링크는 컴파일 및 링크에 대한 비디오 섹션으로 이동)
답변
나는 며칠 동안 벽에 머리를 대고 조금 더 설명이 필요하다고 느낍니다.
기본적으로 문서에서는 분리가 주로 성능 향상이라고 언급합니다. 하위 요소 자체가 컴파일되기 전에 DOM을 수정해야 할 때 컴파일 단계가 주로 사용된다는 것을 반복합니다.
우리의 목적을 위해, 나는 용어를 강조 할 것이다.
컴파일러 SERVICE ($ compile)는 DOM을 처리하고 지시문에서 다양한 코드 비트를 실행하는 각도 메커니즘입니다.
컴파일 FUNCTION은 지시문 내의 한 비트의 코드이며, 컴파일러 SERVICE ($ compile)에 의해 특정 시간에 실행됩니다.
컴파일 기능에 대한 참고 사항 :
-
ROOT 요소 (지시문이 영향을받는 요소)는 이미 DOM의 외부 레벨에서 컴파일 중이므로 (컴파일 SERVICE가 이미 해당 요소에서 지시문을 스캔 했으므로) 수정할 수 없습니다.
-
(중첩 된) 요소에 다른 지시문을 추가하려면 다음 중 하나를 수행하십시오.
-
컴파일 단계에서 추가해야합니다.
-
컴파일 서비스를 연결 단계에 삽입하고 요소를 수동으로 컴파일해야합니다. 그러나 무언가를 두 번 컴파일하는 것을 조심하십시오!
-
$ compile에 대한 중첩 및 명시 적 호출이 작동하는 방법을 확인하는 것도 도움이되므로 http://jsbin.com/imUPAMoV/1/edit 에서 놀이터를 만들었습니다 . 기본적으로 단지 단계를 console.log에 기록합니다.
여기에 해당 저장소에 표시되는 결과가 나와 있습니다. 사용자 지정 지시문 tp 및 sp의 DOM의 경우 다음과 같이 중첩됩니다.
<tp>
<sp>
</sp>
</tp>
각도 컴파일 서비스는 다음을 호출합니다.
tp compile
sp compile
tp pre-link
sp pre-link
sp post-link
tp post-link
jsbin 코드에는 또한 tp post-link FUNCTION이 세 번째 지시문 (위)에서 명시 적으로 컴파일 SERVICE를 호출합니다.
이제 몇 가지 시나리오를 통해 컴파일 및 링크를 사용하여 다양한 작업을 수행하는 방법을 보여 드리겠습니다.
시나리오 1 : 매크로로서의 지시어
속성에서 파생 될 수있는 지시문 (ng-show)을 템플릿의 무언가에 동적으로 추가하려고합니다.
다음을 가리키는 templateUrl이 있다고 가정하십시오.
<div><span><input type="text"></span><div>
사용자 지정 지시문을 원합니다.
<my-field model="state" name="address"></my-field>
DOM을 이것으로 바꿉니다.
<div><span ng-show="state.visible.address"><input ng-model="state.fields.address" ...>
기본적으로 지시문이 해석 할 수있는 일관된 모델 구조를 사용하여 상용구를 줄이려고합니다. 다시 말해, 당신은 매크로를 원합니다.
이것은 컴파일 단계에서 매우 유용합니다. 모든 DOM 조작을 속성에서 알고있는 것에 기초 할 수 있기 때문입니다. jQuery를 사용하여 속성을 추가하십시오.
compile: function(tele, tattr) {
var span = jQuery(tele).find('span').first();
span.attr('ng-show', tattr.model + ".visible." + tattr.name);
...
return {
pre: function() { },
post: function() {}
};
}
작업 순서는 다음과 같습니다 (앞에서 언급 한 jsbin을 통해 확인할 수 있음).
- 컴파일 서비스가 내 필드를 찾습니다.
- 지시문에서 컴파일 FUNCTION을 호출하여 DOM을 업데이트합니다.
- 그런 다음 컴파일 서비스는 결과 DOM과 COMPILES (재귀 적으로)로 들어갑니다.
- 그런 다음 컴파일 서비스는 사전 링크 하향식을 호출합니다.
- 그런 다음 컴파일 서비스는 사후 링크 BOTTOM UP을 호출하므로 내 필드의 링크 기능을 내부 노드가 연결된 후라고합니다.
위의 예에서 모든 지시문의 작업은 컴파일 FUNCTION에서 수행되었으므로 링크가 필요하지 않습니다.
언제든지 지시문의 코드는 컴파일러 SERVICE가 추가 요소에서 실행되도록 요청할 수 있습니다.
이것은 컴파일 서비스를 주입하면 링크 함수에서 똑같은 일을 할 수 있음을 의미합니다.
directive('d', function($compile) {
return {
// REMEMBER, link is called AFTER nested elements have been compiled and linked!
link: function(scope, iele, iattr) {
var span = jQuery(iele).find('span').first();
span.attr('ng-show', iattr.model + ".visible." + iattr.name);
// CAREFUL! If span had directives on it before
// you will cause them to be processed again:
$compile(span)(scope);
}
});
$ compile SERVICE에 전달하는 요소에 원래 지시어가 없다고 확신하는 경우 (예 : 사용자가 정의한 템플릿에서 왔거나 angular.element ()로 방금 생성 한 경우) 최종 결과는 거의 같습니다 이전과 동일합니다 (일부 작업을 반복 할 수 있음). 그러나 요소에 다른 지시문이있는 경우 명령을 다시 처리하여 모든 종류의 비정상적인 동작 (예 : 이벤트 및 시계의 이중 등록)이 발생할 수 있습니다.
따라서 컴파일 단계는 매크로 스타일 작업에 훨씬 적합한 선택입니다.
시나리오 2 : 범위 데이터를 통한 DOM 구성
이것은 위의 예에서 따릅니다. DOM을 조작하는 동안 범위에 액세스해야한다고 가정하십시오. 이 경우 컴파일 섹션은 범위를 사용할 수 있기 전에 발생하므로 쓸모가 없습니다.
따라서 유효성 검사를 통해 입력을 포주로 만들고 서버 쪽 ORM 클래스 (DRY)에서 유효성 검사를 내보내고 자동으로 적용하여 해당 유효성 검사에 적합한 클라이언트 쪽 UI를 생성하려고한다고 가정하겠습니다.
모델은 다음을 추진할 수 있습니다.
scope.metadata = {
validations: {
address: [ {
pattern: '^[0-9]',
message: "Address must begin with a number"
},
{ maxlength: 100,
message: "Address too long"
} ]
}
};
scope.state = {
address: '123 Fern Dr'
};
지시문을 원할 수도 있습니다.
<form name="theForm">
<my-field model="state" metadata="metadata" name="address">
</form>
다양한 유효성 검사 오류를 표시하기 위해 적절한 지시문과 div를 자동으로 포함하는 방법 :
<form name="theForm">
<div>
<input ng-model="state.address" type="text">
<div ng-show="theForm.address.$error.pattern">Address must begin with a number</input>
...
이 경우 범위에 액세스해야합니다 (검증이 저장되어 있기 때문에) 추가를 수동으로 컴파일해야하며 다시 컴파일하지 않도록주의해야합니다. (부수적으로, 포함 양식 태그에 이름을 설정해야하며 (여기서는 양식을 가정하고 있음) iElement.parent (). controller ( ‘form’). $ name과 연결하여 액세스 할 수 있습니다) .
이 경우 컴파일 함수를 작성할 필요가 없습니다. 링크는 정말로 당신이 원하는 것입니다. 단계는 다음과 같습니다.
- 각도 지시문이 완전히없는 템플릿을 정의하십시오.
- 다양한 속성을 추가하는 링크 함수 정의
- 최상위 요소 (my-field 지시문)에서 허용 할 수있는 각도 지시문을 제거하십시오. 이미 처리되었으므로 이중 처리되지 않도록하는 방법입니다.
- 최상위 요소에서 컴파일 서비스를 호출하여 완료
이렇게 :
angular.module('app', []).
directive('my-field', function($compile) {
return {
link: function(scope, iele, iattr) {
// jquery additions via attr()
// remove ng attr from top-level iele (to avoid duplicate processing)
$compile(iele)(scope); // will pick up additions
}
};
});
물론 최상위 요소를 다시 컴파일 할 때 ng 지시문의 중복 처리에 대해 걱정할 필요가 없도록 중첩 된 요소를 하나씩 컴파일 할 수 있습니다.
이 시나리오에 대한 마지막 참고 사항 : 서버에서 유효성 검사의 정의를 추진하고 있음을 암시했으며 내 예에서는 이미 범위에있는 데이터로 표시했습니다. 독자가 REST API에서 해당 데이터를 가져와야하는 방법을 알아내는 연습으로 남겨 둡니다 (힌트 : 지연 컴파일).
시나리오 3 : 링크를 통한 양방향 데이터 바인딩
물론 가장 일반적으로 사용되는 링크는 watch / apply를 통해 양방향 데이터 바인딩을 간단히 연결하는 것입니다. 대부분의 지침은이 범주에 속하므로 다른 곳에서 적절하게 다루어집니다.
답변
컴파일러
컴파일러는 속성을 찾는 DOM을 통과하는 각도 서비스입니다. 컴파일 과정은 두 단계로 이루어집니다.
컴파일 : DOM을 순회하고 모든 지시문을 수집하십시오. 결과는 연결 기능입니다.
링크 : 지시문을 범위와 결합하고 라이브 뷰를 생성합니다. 범위 모델의 모든 변경 사항이 뷰에 반영되고 뷰와의 사용자 상호 작용이 범위 모델에 반영됩니다. 스코프 모델을 단일 진실 소스로 만듭니다.
일부 지시문
ng-repeat
은 컬렉션의 각 항목에 대해 DOM 요소를 한 번 복제합니다. 컴파일 및 링크 단계를 수행하면 복제 된 템플릿을 한 번만 컴파일 한 다음 각 복제 인스턴스마다 한 번만 링크하면되므로 성능이 향상됩니다.
따라서 적어도 어떤 경우 에는 두 단계가 최적화로 별도로 존재합니다.
DOM 변환을하려는 경우이어야합니다
compile
. 동작이 변경되는 일부 기능을 추가하려면이 기능이에 있어야합니다link
.
답변
이것은 지시에 관한 Misko의 이야기에서 나온 것입니다. http://youtu.be/WqmeI5fZcho?t=16m23s
컴파일러 함수를 템플릿에서 작동하는 것과 템플릿에 클래스를 추가하는 등 템플릿 자체를 변경할 수있는 것으로 생각하십시오. 그러나 연결 기능은 범위에 액세스 할 수 있고 특정 템플릿의 각 인스턴스화에 대해 한 번 실행되는 연결 기능이기 때문에 실제로 두 기능을 바인딩하는 연결 기능입니다. 따라서 컴파일 함수 내에 배치 할 수있는 유일한 것은 모든 인스턴스에서 공통적 인 것입니다.
답변
실에 조금 늦었다. 그러나 미래 독자들의 이익을 위해 :
Angular JS의 컴파일 및 링크를 매우 훌륭한 방식으로 설명하는 다음 비디오를 보았습니다.
https://www.youtube.com/watch?v=bjFqSyddCeA
여기에 모든 내용을 복사 / 입력하는 것이 좋지 않을 것입니다. 비디오에서 스크린 샷을 몇 장 가져 와서 컴파일 및 링크 단계의 모든 단계를 설명했습니다.
두 번째 스크린 샷은 약간 혼란 스럽습니다. 그러나 단계 번호 매기기를 따르는 경우에는 매우 간단합니다.
첫 번째 사이클 : 모든 지시문에 대해 “컴파일”이 먼저 수행됩니다.
두 번째주기 : “컨트롤러”및 “사전 링크”가 수행됩니다 (순서대로) 세 번째주기 : “사후 링크”가 역순으로 수행됩니다 (가장 안쪽부터 시작)
다음은 위의 코드를 보여줍니다.
var app = angular.module ( 'app', []); app.controller ( 'msg', [ '$ scope', 함수 ($ scope) { }]); app.directive ( 'message', function ($ interpolate) { 반환{ 컴파일 : function (tElement, tAttributes) { console.log (tAttributes.text + "-컴파일 중." "); { 사전 : function (scope, iElement, iAttributes, controller) { console.log (iAttributes.text + "-in pre .."); }, 게시물 : function (scope, iElement, iAttributes, controller) { console.log (iAttributes.text + "-In Post .."); } } }, 컨트롤러 : function ($ scope, $ element, $ attrs) { console.log ($ attrs.text + "-제어기에서 .."); }, } });
<body ng-app="app">
<div ng-controller="msg">
<div message text="first">
<div message text="..second">
<div message text="....third">
</div>
</div>
</div>
</div>
최신 정보:
동일한 비디오의 2 부 : https://www.youtube.com/watch?v=1M3LZ1cu7rw 이 비디오는 간단한 예제에서 Angular JS의 컴파일 및 링크 프로세스 중에 DOM을 수정하고 이벤트를 처리하는 방법에 대해 자세히 설명합니다. .
답변
두 단계 : 컴파일 및 링크
엮다:
지시문 (요소 / 속성 / 클래스 / 주석)을 찾는 DOM 트리를 탐색하십시오. 지시문을 컴파일 할 때마다 템플릿을 수정하거나 아직 컴파일되지 않은 내용을 수정할 수 있습니다. 지시어가 일치하면 연결 함수를 반환하며,이 함수는 이후 단계에서 요소를 서로 연결하는 데 사용됩니다. 컴파일 단계가 끝나면 컴파일 된 지시문과 해당 연결 함수의 목록이 있습니다.
링크:
요소가 링크되면 DOM 트리는 DOM 트리의 분기점에서 끊어지고 컨텐츠는 템플리트의 컴파일 된 (및 링크 된) 인스턴스로 대체됩니다. 원래 변위 된 컨텐츠는 버려지거나 변환의 경우 템플리트로 다시 링크됩니다. 번역을 사용하면 두 조각이 다시 연결됩니다 (템플릿 조각이 가운데에있는 체인과 같은 종류). 링크 함수가 호출되면 템플릿은 이미 범위에 바인딩되어 있고 요소의 자식으로 추가되었습니다. 링크 기능은 DOM을 더 조작하고 변경 리스너를 설정할 수있는 기회입니다.
답변
이 질문은 오래되었습니다. 약식 요약을 작성하고 싶습니다.
- 모든 지시문 인스턴스에 대해 한 번 호출 된 컴파일
- 컴파일의 주요 목적은 링크 (및 가능하면 사전 / 사후) 기능 / 개체를 반환 / 생성하는 것입니다. 지시문 인스턴스간에 공유되는 항목을 초기화 할 수도 있습니다.
- 제 생각에는 “링크”는이 기능의 혼동되는 이름입니다. “사전 렌더링”을 선호합니다.
- 링크는 각 지시문 인스턴스에 대해 호출되며 그 목적은 DOM에서 지시문의 렌더링을 준비하는 것입니다.