Apa perbedaan antara fungsi kompilasi dan tautan di angularjs


208

Adakah yang bisa dijelaskan secara sederhana?

Dokumen itu tampaknya agak tumpul. Saya tidak mendapatkan esensi dan gambaran besar kapan harus menggunakan satu di atas yang lain. Contoh kontras keduanya akan luar biasa.


2
Mungkin gambaran yang lebih komprehensif dari fungsi direktif: Arahan arahan - kapan harus menggunakan kompilasi, controller, pra-tautan dan pasca-tautan .
Izhaki

Jawaban:


217
  • kompilasi fungsi - gunakan untuk manipulasi DOM templat (yaitu, manipulasi tElement = elemen templat), karenanya manipulasi yang berlaku untuk semua klon DOM templat yang terkait dengan arahan.

  • fungsi tautan - digunakan untuk mendaftarkan pendengar DOM (yaitu, $ watch expressions pada lingkup instance) serta instance manipulasi DOM (mis., manipulasi iElement = elemen instance individual).
    Itu dieksekusi setelah template telah dikloning. Misalnya, di dalam <li-repeat ...>, fungsi tautan dieksekusi setelah templat <li> (tElement) telah dikloning (menjadi iElement) untuk elemen <li> tertentu.
    $ Watch () memungkinkan arahan untuk diberitahu tentang perubahan properti lingkup instance (lingkup instance dikaitkan dengan setiap instance), yang memungkinkan arahan untuk memberikan nilai instance yang diperbarui ke DOM - dengan menyalin konten dari lingkup instance ke dalam DOM.

Perhatikan bahwa transformasi DOM dapat dilakukan dalam fungsi kompilasi dan / atau fungsi tautan.

Kebanyakan arahan hanya memerlukan fungsi tautan, karena sebagian besar arahan hanya berurusan dengan instance elemen DOM tertentu (dan cakupan instance-nya).

Salah satu cara untuk membantu menentukan mana yang akan digunakan: pertimbangkan bahwa fungsi kompilasi tidak menerima a scope argumen. (Saya sengaja mengabaikan argumen fungsi transclude linking, yang menerima lingkup transclude - ini jarang digunakan.) Jadi fungsi kompilasi tidak dapat melakukan apa pun yang ingin Anda lakukan yang memerlukan lingkup (contoh) - Anda dapat 't $ menonton setiap model / properti lingkup instance, Anda tidak dapat memanipulasi DOM menggunakan informasi lingkup instance, Anda tidak dapat memanggil fungsi yang didefinisikan pada lingkup instance, dll.

Namun, fungsi kompilasi (seperti fungsi tautan) memang memiliki akses ke atribut. Jadi, jika manipulasi DOM Anda tidak memerlukan lingkup instance, Anda dapat menggunakan fungsi kompilasi. Berikut adalah contoh arahan yang hanya menggunakan fungsi kompilasi, karena alasan itu. Itu memeriksa atribut, tetapi tidak perlu ruang lingkup contoh untuk melakukan tugasnya.

Berikut adalah contoh arahan yang juga hanya menggunakan fungsi kompilasi. Arahan hanya perlu mengubah DOM templat, sehingga fungsi kompilasi dapat digunakan.

Cara lain untuk membantu menentukan mana yang akan digunakan: jika Anda tidak menggunakan parameter "elemen" di fungsi tautan, maka Anda mungkin tidak memerlukan fungsi tautan.

Karena sebagian besar arahan memiliki fungsi tautan, saya tidak akan memberikan contoh - mereka harus sangat mudah ditemukan.

Perhatikan bahwa jika Anda memerlukan fungsi kompilasi dan fungsi tautan (atau fungsi tautan sebelum dan sesudah), fungsi kompilasi harus mengembalikan fungsi tautan karena atribut 'tautan' diabaikan jika atribut 'kompilasi' ditentukan.

Lihat juga


5
Penjelasan terbaik tentang kompilasi vs tautan.
Nexus23

1
Ketika Anda mengatakan if you don't use the "element" parameter in the link function, then you probably don't need a link function.maksud Anda "lingkup", bukan "elemen"?
Jason Larke

69

Aku membenturkan kepalaku ke dinding pada ini selama beberapa hari, dan aku merasa sedikit lebih banyak penjelasan.

Pada dasarnya, dokumen menyebutkan bahwa pemisahan ini sebagian besar merupakan peningkatan kinerja. Saya akan menegaskan kembali bahwa fase kompilasi terutama digunakan ketika Anda perlu memodifikasi DOM SEBELUM sub-elemen itu sendiri dikompilasi.

Untuk tujuan kita, saya akan menekankan terminologi, yang sebaliknya membingungkan:

SERVICE kompiler ($ compile) adalah mekanisme sudut yang memproses DOM dan menjalankan berbagai bit kode dalam arahan.

FUNGSI kompilasi adalah satu bit kode dalam direktif, yang dijalankan pada waktu tertentu OLEH SERVICE kompiler ($ compile).

Beberapa catatan tentang kompilasi FUNGSI:

  1. Anda tidak dapat mengubah elemen ROOT (yang mempengaruhi arahan Anda), karena sudah dikompilasi dari tingkat luar DOM (kompilasi SERVICE telah dipindai untuk arahan pada elemen itu).

  2. Jika Anda ingin menambahkan arahan lain ke elemen (bersarang), Anda dapat:

    1. Harus menambahkannya selama fase kompilasi.

    2. Harus menyuntikkan layanan kompilasi ke dalam fase penautan dan mengkompilasi elemen secara manual. TETAPI, waspadalah dalam mengkompilasi sesuatu dua kali!

Juga bermanfaat untuk melihat bagaimana panggilan bersarang dan eksplisit ke $ compile berfungsi, jadi saya telah membuat taman bermain untuk melihatnya di http://jsbin.com/imUPAMoV/1/edit . Pada dasarnya, ini hanya mencatat langkah-langkah ke console.log.

Saya akan menyatakan hasil dari apa yang Anda lihat di tong itu di sini. Untuk DOM arahan khusus, tp dan sp adalah sebagai berikut:

<tp>
   <sp>
   </sp>
</tp>

LAYANAN kompilasi sudut akan menghubungi:

tp compile
sp compile
tp pre-link
sp pre-link
sp post-link
tp post-link

Kode jsbin juga memiliki FUNGSI pasca-tautan tp secara eksplisit memanggil kompilasi SERVICE pada arahan ketiga (atas), yang melakukan ketiga langkah di akhir.

Sekarang, saya ingin membahas beberapa skenario untuk menunjukkan bagaimana seseorang dapat menggunakan kompilasi dan tautan untuk melakukan berbagai hal:

SKENARIO 1: Petunjuk sebagai MACRO

Anda ingin menambahkan arahan (misalnya ng-show) secara dinamis ke sesuatu di template Anda yang dapat Anda peroleh dari suatu atribut.

Katakanlah Anda memiliki templateUrl yang menunjuk ke:

<div><span><input type="text"></span><div>

dan Anda ingin arahan khusus:

<my-field model="state" name="address"></my-field>

yang mengubah DOM menjadi ini:

<div><span ng-show="state.visible.address"><input ng-model="state.fields.address" ...>

pada dasarnya, Anda ingin mengurangi boilerplate dengan memiliki struktur model yang konsisten yang dapat ditafsirkan oleh arahan Anda. Dengan kata lain: Anda ingin makro.

Ini adalah penggunaan yang bagus untuk fase kompilasi, karena Anda dapat mendasarkan semua manipulasi DOM pada hal-hal yang Anda tahu hanya dari atribut. Cukup gunakan jQuery untuk menambahkan atribut:

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() {}
   };
}

Urutan operasi akan (Anda bisa melihat ini melalui jsbin yang disebutkan sebelumnya):

  1. Kompilasi SERVICE menemukan bidang saya
  2. Ini memanggil FUNGSI kompilasi pada arahan, yang memperbarui DOM.
  3. Kompilasi SERVICE kemudian masuk ke DOM yang dihasilkan, dan COMPILES (secara rekursif)
  4. Kompilasi SERVICE kemudian memanggil pra-tautan top-down
  5. Kompilasi SERVICE kemudian memanggil post-link BOTTOM UP, sehingga fungsi tautan my-field disebut SETELAH simpul interior telah ditautkan.

Dalam contoh di atas, tidak perlu menghubungkan, karena semua pekerjaan direktif dilakukan dalam kompilasi FUNGSI.

Pada titik mana pun, kode dalam arahan dapat meminta LAYANAN kompiler untuk dijalankan pada elemen tambahan.

Ini berarti bahwa kami dapat melakukan hal yang persis sama dalam fungsi tautan jika Anda menyuntikkan layanan kompilasi:

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);
    }
});

Jika Anda yakin bahwa elemen yang Anda lewati ke $ compile SERVICE awalnya bebas direktif (mis. Mereka datang dari templat yang Anda tentukan, atau Anda baru saja membuatnya dengan angular.element ()), maka hasil akhirnya cukup banyak sama seperti sebelumnya (meskipun Anda mungkin mengulangi beberapa pekerjaan). Namun, jika elemen memiliki arahan lain di dalamnya, Anda hanya menyebabkan mereka diproses lagi, yang dapat menyebabkan semua jenis perilaku yang tidak menentu (mis. Pendaftaran ganda acara dan jam tangan).

Jadi, fase kompilasi adalah pilihan yang jauh lebih baik untuk pekerjaan gaya makro.

SKENARIO 2: Konfigurasi DOM melalui data lingkup

Yang ini mengikuti dari contoh di atas. Misalkan Anda memerlukan akses ke ruang lingkup saat memanipulasi DOM. Nah, dalam kasus itu, bagian kompilasi tidak berguna bagi Anda, karena itu terjadi sebelum ruang lingkup tersedia.

Jadi, katakanlah Anda ingin mengeluarkan input dengan validasi, tetapi Anda ingin mengekspor validasi Anda dari kelas ORM sisi server (KERING), dan minta mereka menerapkan otomatis dan membuat UI sisi klien yang tepat untuk validasi tersebut.

Model Anda mungkin mendorong:

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'
};

dan Anda mungkin menginginkan arahan:

<form name="theForm">
  <my-field model="state" metadata="metadata" name="address">
</form>

untuk secara otomatis menyertakan arahan dan div yang tepat untuk menampilkan berbagai kesalahan validasi:

<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>
...

Dalam hal ini Anda pasti perlu akses ke ruang lingkup (karena di situlah validasi Anda disimpan), dan harus mengkompilasi penambahan secara manual, sekali lagi berhati-hati untuk tidak menggandakan kompilasi hal-hal. (sebagai catatan tambahan, Anda perlu menetapkan nama pada tag formulir yang berisi (saya berasumsi theForm di sini), dan dapat mengaksesnya di tautan dengan iElement.parent (). controller ('form'). $ name) .

Dalam hal ini tidak ada gunanya menulis fungsi kompilasi. Tautan benar-benar yang Anda inginkan. Langkah-langkahnya adalah:

  1. Tetapkan template yang sama sekali tidak memiliki arahan sudut.
  2. Tentukan fungsi tautan yang menambahkan berbagai atribut
  3. HAPUS segala arahan sudut yang mungkin Anda izinkan pada elemen tingkat atas Anda (arahan medan-saya). Mereka sudah diproses dan ini adalah cara agar mereka tidak diproses ganda.
  4. Selesai dengan memanggil kompilasi SERVICE pada elemen tingkat atas Anda

Seperti itu:

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
    }
  };
});

Anda bisa, tentu saja, mengkompilasi elemen bersarang satu demi satu untuk menghindari khawatir tentang pemrosesan duplikat ar arahan ketika Anda mengkompilasi elemen tingkat atas lagi.

Satu catatan terakhir tentang skenario ini: Saya menyiratkan Anda akan mendorong definisi validasi dari server, dan dalam contoh saya, saya telah menunjukkannya sebagai data yang sudah ada dalam cakupan. Saya meninggalkannya sebagai latihan bagi pembaca untuk mengetahui bagaimana orang mungkin perlu menarik data tersebut dari REST API (petunjuk: kompilasi ditangguhkan).

SKENARIO 3: pengikatan data dua arah melalui tautan

Tentu saja penggunaan tautan yang paling umum adalah dengan hanya menghubungkan pengikatan data dua arah melalui watch / apply. Sebagian besar arahan termasuk dalam kategori ini, sehingga cukup tercakup di tempat lain.


2
Jawaban Awsome & Keren!
Nexus23

Bagaimana cara menambahkan elemen bersarang tanpa kompilasi ganda?
Art713

50

Dari dokumen:

Penyusun

Compiler adalah layanan sudut yang melintasi DOM mencari atribut. Proses kompilasi terjadi dalam dua fase.

  1. Kompilasi: lintasi DOM dan kumpulkan semua arahan. Hasilnya adalah fungsi penautan.

  2. Tautan: menggabungkan arahan dengan ruang lingkup dan menghasilkan tampilan langsung. Setiap perubahan dalam model lingkup tercermin dalam tampilan, dan setiap interaksi pengguna dengan tampilan tercermin dalam model lingkup. Menjadikan model ruang lingkup sebagai sumber kebenaran tunggal.

Beberapa arahan ng-repeatmengkloning elemen DOM tersebut sekali untuk setiap item dalam koleksi. Memiliki fase kompilasi dan tautan meningkatkan kinerja karena templat kloning hanya perlu dikompilasi satu kali, dan kemudian ditautkan satu kali untuk setiap instance klon.

Jadi setidaknya dalam beberapa kasus, dua fase ada secara terpisah sebagai pengoptimalan.


Dari @ UmurKontacı :

Jika Anda akan membuat transformasi DOM, seharusnya begitu compile. Jika Anda ingin menambahkan beberapa fitur yang merupakan perubahan perilaku, itu harus dalam link.


46
Jika Anda akan melakukan DOMtransformasi, itu harus compilejika Anda ingin menambahkan beberapa fitur adalah perubahan perilaku, itu harus di link.
Umur Kontacı

4
+1 ke komentar di atas; ini adalah deskripsi paling ringkas yang saya temukan sejauh ini. Ini cocok dengan tutorial yang saya temukan di sini .
Benny Bottema

18

Ini dari pembicaraan Misko tentang arahan. http://youtu.be/WqmeI5fZcho?t=16m23s

Pikirkan fungsi kompiler sebagai hal yang bekerja pada templat dan hal yang diizinkan untuk mengubah templat itu sendiri dengan, misalnya, menambahkan kelas ke dalamnya atau hal-hal seperti itu. Tapi itu fungsi penghubung yang benar-benar berfungsi mengikat keduanya karena fungsi penghubung memiliki akses ke ruang lingkup dan itu adalah fungsi penghubung yang dijalankan satu kali untuk setiap instantiation dari templat tertentu. Jadi satu-satunya hal yang dapat Anda tempatkan di dalam fungsi kompilasi adalah hal-hal yang umum di semua instance.


10

Agak terlambat ke utas. Tetapi, untuk kepentingan pembaca masa depan:

Saya menemukan video berikut yang menjelaskan Kompilasi dan Tautan dalam Angular JS dengan cara yang sangat hebat:

https://www.youtube.com/watch?v=bjFqSyddCeA

Tidak akan menyenangkan untuk menyalin / mengetik semua konten di sini. Saya mengambil beberapa tangkapan layar dari video, yang menjelaskan setiap tahap fase Kompilasi dan Tautan:

Kompilasi dan Tautkan dalam Angular JS

Kompilasi dan Tautan dalam Angular JS - Nested Directive

Tangkapan layar kedua agak membingungkan. Tetapi, jika kita mengikuti langkah penomoran, itu cukup lurus ke depan.

Siklus pertama: "Kompilasi" dilakukan pada semua arahan terlebih dahulu.
Siklus kedua: "Controller" dan "Pre-Link" dilakukan (hanya satu demi satu) Siklus ketiga: "Post-Link" dilakukan dalam urutan terbalik (mulai dari yang paling dalam)

Berikut ini adalah kode, yang menunjukkan hal di atas:

var app = angular.module ('app', []);

app.controller ('msg', ['$ scope', function ($ scope) {

}]);

app.directive ('message', function ($ interpolate) {
    kembali{

        kompilasi: function (tElement, tAttributes) { 
            console.log (tAttributes.text + "-Dalam kompilasi ..");
            kembali {

                pre: function (lingkup, iElement, iAttributes, controller) {
                    console.log (iAttributes.text + "-In pre ..");
                },

                post: function (lingkup, iElement, iAttributes, controller) {
                    console.log (iAttributes.text + "-In Post ..");
                }

            }
        },

        controller: function ($ scope, $ element, $ attrs) {
            console.log ($ attrs.text + "-In controller ..");
        },

    }
});
<body ng-app="app">
<div ng-controller="msg">
    <div message text="first">
        <div message text="..second">
            <div message text="....third">

            </div>              
        </div>  
    </div>
</div>

MEMPERBARUI:

Bagian 2 dari video yang sama tersedia di sini: https://www.youtube.com/watch?v=1M3LZ1cu7rw Video ini menjelaskan lebih lanjut tentang cara memodifikasi DOM dan menangani acara selama proses Kompilasi dan Tautan Angular JS, dalam contoh sederhana .


Digunakan compiledan postuntuk memodifikasi DOM sebelum dimodifikasi pada templatebagian dari arahan vendor.
jedi

6

Dua Fase: Kompilasi dan Tautan

Menyusun:

Lintasi pohon DOM untuk mencari arahan (elemen / atribut / kelas / komentar). Setiap kompilasi arahan dapat memodifikasi templatnya, atau memodifikasi isinya yang belum dikompilasi. Setelah direktif dicocokkan, ia mengembalikan fungsi penautan, yang digunakan pada fase selanjutnya untuk menautkan elemen bersama-sama. Pada akhir fase kompilasi, kami memiliki daftar arahan yang dikompilasi dan fungsi tautannya yang sesuai.

Tautan:

Ketika sebuah elemen ditautkan, pohon DOM rusak pada titik cabang di pohon DOM, dan konten diganti oleh instance template yang dikompilasi (dan ditautkan). Konten asli yang dipindahkan dibuang, atau dalam hal transklusi, ditautkan kembali ke dalam templat. Dengan transklusi, kedua potongan dihubungkan kembali bersama-sama (semacam rantai, dengan potongan templat berada di tengah). Ketika fungsi tautan dipanggil, templat sudah terikat ke cakupan, dan ditambahkan sebagai anak elemen. Fungsi tautan adalah kesempatan Anda untuk memanipulasi DOM lebih lanjut dan mengatur pendengar perubahan.


3

Pertanyaan ini sudah tua karena saya ingin membuat ringkasan singkat yang dapat membantu:

  • Kompilasi dipanggil sekali untuk semua contoh direktif
  • Kompilasi tujuan utama adalah untuk mengembalikan / membuat tautan (dan mungkin pra / post) fungsi / objek. Anda juga dapat init hal-hal yang dibagikan antara contoh direktif.
  • Menurut pendapat saya, "tautan" adalah nama yang membingungkan untuk fitur ini. Saya lebih suka "pre-render".
  • tautan dipanggil untuk setiap instance arahan dan tujuannya adalah untuk mempersiapkan rendering arahan dalam DOM.

1
satu plus untuk nama saran: "pra-render"
Hailong Cao
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.