Directive เป็นวิธีการสอน HTML ให้เล่นกลอุบายใหม่ ๆ ในระหว่างการรวบรวม DOM คำสั่งจับคู่ HTML และดำเนินการ สิ่งนี้ช่วยให้พฤติกรรมการลงทะเบียนคำสั่งหรือการแปลงโครงสร้าง DOM
Angular มาพร้อมกับชุดคำสั่งในตัวซึ่งมีประโยชน์มากสำหรับการสร้างเว็บแอป หากคุณขยายตัวต่อไปคุณสามารถกำหนดภาษาเฉพาะของโดเมน (DSL) ใน HTML
1. คำสั่งอ้างอิงใน HTML
Directive มีการตั้งชื่อสไตล์อูฐแบบ cased เช่น ngbind (ดูเหมือนว่าจะใช้ไม่ได้ในคุณสมบัติ ~) อย่างไรก็ตามคำสั่งสามารถตั้งชื่อด้วยประเภทด้านล่างงู (กรณีงู) ซึ่งจำเป็นต้องเชื่อมต่อผ่าน: (ลำไส้ใหญ่), - (ลบ) หรือ _ (ขีดล่าง) เป็นตัวเลือกตัวเลือกคำสั่งสามารถนำหน้าด้วย "X-" หรือ "data-" เพื่อตอบสนองความต้องการการตรวจสอบ HTML นี่คือชื่อทางกฎหมายของคำสั่ง:
คำสั่งสามารถวางไว้ในชื่อองค์ประกอบแอตทริบิวต์คลาสและความคิดเห็น ต่อไปนี้เป็นวิธีที่เทียบเท่าในการอ้างถึง mydir คำสั่ง (แต่คำสั่งมากมาย จำกัด เฉพาะการใช้ "คุณสมบัติ")
<span my-dir = "exp"> </span> <span> </span> <my-dir> </y-dir> <!-คำสั่ง: my-dir exp->
คำสั่งสามารถอ้างถึงได้หลายวิธีและรายการต่อไปนี้เทียบเท่าวิธี:
<! doctype html> <html lang = "zh-cn" ng-app> <head> <meta charset = "utf-8"> <title> revoke-directive </title> <style type = "css"> .ng-cloak {แสดง: ไม่มี; } </style> </head> <body> <div ng-controller = "myctrl"> สวัสดี <อินพุต ng-model = "ชื่อ"/> <hr/> ngbind = "ชื่อ" ไม่สามารถใช้ ~~ <span ngbind = "ชื่อ"> </span> ng_bind = "name" <span ng_bind = "name"> </span> <br/> ng-bind = "name" <span ng-bind = "name"> </span> <br/> data-ng-bind = "name" <span data-ng-bind = "ชื่อ"> x-ng-bind = "name"> </span> <br/> </div> <script src = "../ angular-1.0.1.js" type = "text/javascript"> </script> <script type = "text/javascript"> ฟังก์ชั่น myctrl ($ scope) } </script> </body> </html>2. การแก้ไขสตริง
ในระหว่างกระบวนการรวบรวมคอมไพเลอร์จับคู่ข้อความกับนิพจน์ฝังตัวในแอตทริบิวต์ (เช่น {{บางสิ่งบางอย่าง}}) ผ่านบริการ $ Interpolate นิพจน์เหล่านี้จะถูกลงทะเบียนเป็นนาฬิกาและจะได้รับการปรับปรุงร่วมกันเป็นส่วนหนึ่งของวัฏจักรย่อย (มันไม่ใช่การย่อย-ลูปมาก่อนหรือไม่!) นี่คือการแก้ไขอย่างง่าย:
<img src = "img/{{username}}. jpg"/> hello {{username}}!
3. กระบวนการรวบรวมและการจับคู่คำสั่ง
สามขั้นตอนในการ "รวบรวม" HTML:
1. อันดับแรกแปลง HTML เป็นวัตถุ DOM ผ่าน API มาตรฐานของเบราว์เซอร์ นี่เป็นขั้นตอนที่สำคัญมาก เพราะเทมเพลตจะต้องสามารถแยกได้ (สอดคล้องกับข้อกำหนด) สิ่งนี้สามารถนำมาเปรียบเทียบกับระบบเทมเพลตส่วนใหญ่ซึ่งโดยทั่วไปจะขึ้นอยู่กับสตริงไม่ใช่องค์ประกอบ DOM
2. การรวบรวม DOM ทำได้โดยเรียกวิธี $ Comple () วิธีนี้สำรวจ DOM และตรงกับคำสั่ง หากการแข่งขันประสบความสำเร็จจะถูกเพิ่มลงในรายการคำสั่งพร้อมกับ DOM ที่เกี่ยวข้อง ตราบใดที่มีการระบุคำสั่งทั้งหมดที่เกี่ยวข้องกับ DOM ที่ระบุไว้พวกเขาจะถูกจัดเรียงตามลำดับความสำคัญและดำเนินการฟังก์ชั่น Compile () ในลำดับนั้น ฟังก์ชั่นการคอมไพล์ Directive มีโอกาสในการปรับเปลี่ยนโครงสร้าง DOM และรับผิดชอบในการสร้างการแยกวิเคราะห์ของฟังก์ชันลิงก์ () เมธอด $ compile () ส่งคืนฟังก์ชั่นการเชื่อมโยงแบบรวมซึ่งเป็นคอลเลกชันของฟังก์ชั่นที่เชื่อมโยงที่ส่งคืนโดยฟังก์ชั่นคอมไพล์ของคำสั่ง
3. เชื่อมต่อเทมเพลตเข้ากับขอบเขตผ่านฟังก์ชั่นการเชื่อมโยงที่ส่งคืนในขั้นตอนก่อนหน้า ฟังก์ชั่นการเชื่อมโยงของ Directive นี้ทำให้พวกเขาสามารถลงทะเบียนผู้ฟังบางส่วนในองค์ประกอบและสร้างนาฬิกาที่มีขอบเขต ผลลัพธ์ในนี้คือการเชื่อมโยงสองทางระหว่างขอบเขตและ DOM เมื่อขอบเขตเปลี่ยนแปลง DOM จะได้รับการตอบกลับที่สอดคล้องกัน
var $ compile = ... ; // ฉีดเข้าไปในรหัส var ขอบเขตของคุณ = ... ; var html = '<div ng-bind =' exp '> </div>'; // ขั้นตอนที่ 1: แยกวิเคราะห์ HTML ลงในเทมเพลตองค์ประกอบ DOM = Angular.Element (HTML); // ขั้นตอนที่ 2: รวบรวมเทมเพลต var linkfn = $ compile (เทมเพลต); // ขั้นตอนที่ 3: เชื่อมโยงเทมเพลตที่รวบรวมกับขอบเขต linkfn (ขอบเขต);
4. เหตุผลที่อยู่เบื้องหลังการแยก/การแยกลิงค์
ในเวลานี้คุณอาจสงสัยว่าทำไมกระบวนการรวบรวมแบ่งออกเป็นสองขั้นตอน: คอมไพล์และลิงก์ เพื่อให้เข้าใจสิ่งนี้ลองมาดูตัวอย่างจริง (repeater)
สวัสดี {{user}} คุณมีการกระทำเหล่านี้: <ul> <li ng-repeat = "การกระทำใน user.actions"> {{action.description}} </li> </ul>พูดง่ายๆคือเหตุผลที่เราแยกสองขั้นตอนของการคอมไพล์และลิงก์คือบางครั้งโครงสร้าง DOM ที่สอดคล้องกันจะต้องมีการเปลี่ยนแปลงหลังจากเปลี่ยนโมเดลเช่นซ้ำ
เมื่อรวบรวมตัวอย่างด้านบนคอมไพเลอร์จะวนซ้ำผ่านโหนดทั้งหมดเพื่อค้นหาคำสั่ง {{user}} เป็นตัวอย่างของคำสั่งการแก้ไข NGREPEAT เป็นอีกหนึ่งคำสั่ง แต่ NGREPEAT มีปัญหา มันต้องการความสามารถในการสร้าง LI ใหม่อย่างรวดเร็วสำหรับทุกการกระทำในผู้ใช้ ซึ่งหมายความว่าเพื่อให้เป็นไปตามวัตถุประสงค์ของการโคลนนิ่ง LI และฝังการกระทำที่เฉพาะเจาะจง (ที่นี่หมายถึงหนึ่งในค่าของการกระทำของผู้ใช้) มันจำเป็นต้องเก็บสำเนาที่สะอาดขององค์ประกอบ LI ซึ่งจำเป็นต้องโคลนและแทรกเข้าไปในองค์ประกอบ UL แต่การโคลนองค์ประกอบ LI นั้นไม่เพียงพอ Li ยังต้องมีการรวบรวมเพื่อให้คำสั่ง ({{action.descriptions}}) สามารถแยกวิเคราะห์ได้ในขอบเขตที่ถูกต้อง วิธีดั้งเดิมโดยทั่วไปเพียงแค่แทรกสำเนาขององค์ประกอบ LI แล้วรวบรวม อย่างไรก็ตามการรวบรวมสำเนาของแต่ละองค์ประกอบ LI จะช้าลงเนื่องจากกระบวนการรวบรวมต้องการให้เราสำรวจทรีโหนด DOM ค้นหาคำสั่งและเรียกใช้ หากเรามีการคอมไพล์ที่ต้องประมวลผล 100 รายการผ่าน repeater เราจะติดอยู่กับปัญหาด้านประสิทธิภาพ
การแก้ปัญหาคือการแบ่งกระบวนการรวบรวมออกเป็นสองขั้นตอน ขั้นตอนการคอมไพล์จะรับรู้คำสั่งทั้งหมดและเรียงลำดับตามลำดับความสำคัญผูกขอบเขตเฉพาะกับ LI เฉพาะในระหว่างขั้นตอนการเชื่อมโยง
NGREPEAT รวบรวมแต่ละ LIS แยกต่างหากเพื่อป้องกันไม่ให้กระบวนการรวบรวมตกอยู่ในองค์ประกอบ LI ผลการรวบรวมขององค์ประกอบ LI เป็นฟังก์ชั่นการเชื่อมโยงคำสั่งที่มีคำสั่งทั้งหมดที่มีอยู่ในองค์ประกอบ LI พร้อมที่จะเชื่อมต่อกับสำเนาขององค์ประกอบ LI ที่เฉพาะเจาะจง ที่รันไทม์ NGREPEAT จะตรวจสอบการแสดงออกและถูกเพิ่มเป็นรายการในอาร์เรย์ของสำเนาองค์ประกอบ LI สร้างขอบเขตใหม่สำหรับองค์ประกอบ LI ที่ถูกโคลนและเรียกฟังก์ชันลิงก์ที่สอดคล้องกับสำเนา
สรุป:
1. ฟังก์ชั่นคอมไพล์ - ฟังก์ชั่นการรวบรวมค่อนข้างหายากในคำสั่งเพราะคำสั่งส่วนใหญ่สนใจเฉพาะการทำงานกับองค์ประกอบ DOM ที่ระบุแทนที่จะเปลี่ยนเทมเพลตขององค์ประกอบ DOM (DOM และโครงสร้างภายใน) เพื่อเพิ่มประสิทธิภาพประสิทธิภาพการดำเนินงานบางอย่างที่สามารถแชร์ได้โดยอินสแตนซ์คำสั่งสามารถย้ายไปยังฟังก์ชั่นคอมไพล์ได้
2. ฟังก์ชั่นลิงค์ - คำสั่งน้อยมากไม่มีฟังก์ชั่นลิงก์ ฟังก์ชั่นลิงค์อนุญาตให้ Directive ลงทะเบียนผู้ฟังในสำเนาที่ระบุของอินสแตนซ์องค์ประกอบ DOM หรือเพื่อคัดลอกเนื้อหาเฉพาะจากขอบเขตลงใน DOM
5. เขียนคำสั่ง (เวอร์ชันง่าย ๆ )
ในตัวอย่างนี้เราจะสร้างคำสั่งที่แสดงเวลาปัจจุบันตามรูปแบบอินพุต
<! doctype html> <html lang = "zh-cn" ng-app = "timeFormat"> <head> <meta charset = "utf-8"> <title> รูปแบบเวลา </title> </head> <body> <div ng-controller = "myctrl" <!-แอตทริบิวต์ X-Current-Time ต่อไปนี้คือลองการตั้งชื่อตามกฎหมายที่กล่าวถึงข้างต้น ~~ ปัจจุบัน: เวลา, เวลาปัจจุบัน, current_time, กระแสข้อมูลกระแส-_- !!! -> เวลาปัจจุบันคือ: <span x-current-time = "format" id = "myformat"> </span> <br/> <button ng-click = "remove ()"> ลบ span </button> </div> <script src = "../ angular-1.0.1.js" type = "text/javascript" type = "text/javascript"> angular.module ("TimeFormat", []) // ลงทะเบียนวิธีการกำกับโรงงานของ "currenttime" ในแอปพลิเคชัน TimeFormat // ดังที่กล่าวไว้ข้างต้นการฉีดพึ่งพาสามารถเขียนได้โดยตรงในพารามิเตอร์ฟังก์ชัน เพิ่มฟังก์ชั่นคอมไพล์, ทำไม? ... ) ฟังก์ชั่นการส่งคืน (ขอบเขต, องค์ประกอบ, attr) {var intervalid; ขอบเขต $ watch (attr.currenttime, ฟังก์ชั่น (ค่า) {scope.format = value; updateTime ();}); }). คอนโทรลเลอร์ ("myctrl", ฟังก์ชัน ($ scope, $ rootscope) {$ scope.format = "m/d/yy h: mm: ss a"; $ scope.remove = function () {var oformat = document.getElementById ("myformat"); เหตุการณ์ $ ทำลายสามารถถูกเรียกได้!6. เขียนคำสั่ง (เวอร์ชันโดยละเอียด)
ด้านล่างคือการสร้างตัวอย่างของคำสั่ง (เทมเพลตคำจำกัดความของวัตถุคำสั่ง) หากคุณต้องการดูรายละเอียดรายการโปรดอ่านต่อ
var mymodule = angular.module (... ); myModule.directive ('directiveName', ฟังก์ชั่นโรงงาน (injectables) {var directivedEfinitionObject = {ลำดับความสำคัญ: 0, เทมเพลต: '<div> </div>', templateurl: 'directive.html', แทนที่: เท็จ prelink (ขอบเขต, iElement, iATTRS, คอนโทรลเลอร์) {... }, โพสต์: ฟังก์ชั่น postlink (ขอบเขต, iElement, IATTRS, คอนโทรลเลอร์) {... }}}, ลิงก์: ฟังก์ชั่น postlinkในสถานการณ์ส่วนใหญ่เราไม่จำเป็นต้องมีการควบคุมที่แม่นยำดังนั้นคำจำกัดความข้างต้นสามารถทำให้ง่ายขึ้น การกำหนดแต่ละส่วนของเทมเพลตจะถูกอธิบายในบทต่อไปนี้ ในบทนี้เรามุ่งเน้นเฉพาะไอโซเมอร์ของโครงกระดูกนี้ที่กำหนดเทมเพลต (ไอโซเมอร์ของโครงกระดูกนี้ฉันไม่เข้าใจ ... รอคอยที่จะเพิ่มทุกคน)
ขั้นตอนแรกในการทำให้รหัสของคุณง่ายขึ้นคือการพึ่งพาค่าเริ่มต้น ดังนั้นรหัสข้างต้นสามารถทำให้ง่ายขึ้นเพื่อ:
var mymodule = angular.module (... ); mymodule.directive ('directiveName', ฟังก์ชั่นโรงงาน (injectables) {var directivedEfinitionObject = {Compile: ฟังก์ชั่นการรวบรวม (การถ่ายทอดทางไกล, tattrs) {return function postlink (ขอบเขต, iElement, iattrs) {... }}};คำสั่งส่วนใหญ่สนใจเฉพาะอินสแตนซ์ไม่ใช่การแปลงเทมเพลตดังนั้นพวกเขาจึงสามารถทำให้ง่ายขึ้น (แปลยากมาก ... รอคอยที่จะเพิ่มของทุกคน):
var mymodule = angular.module (... ); myModule.directive ('directiveName', ฟังก์ชั่นโรงงาน (injectables) {return function postlink (ขอบเขต, iElement, iattrs) {... }});7. วิธีโรงงาน
วิธีการโรงงานมีหน้าที่สร้างคำสั่ง มันถูกใช้เพียงครั้งเดียวเมื่อคอมไพเลอร์ตรงกับคำสั่ง คุณสามารถดำเนินการเริ่มต้นได้ที่นี่ วิธีการโรงงานดำเนินการผ่าน $ injector.invoke ทำให้สามารถปฏิบัติตามกฎการประกาศการฉีดทั้งหมด (กฎของคำอธิบายประกอบการฉีด) ทำให้สามารถฉีดได้
8. คำอธิบายวัตถุคำสั่งคำสั่ง
วัตถุคำนิยามคำสั่งให้โครงสร้างคอมไพเลอร์ คุณสมบัติมีดังนี้:
1.name - ชื่อของขอบเขตปัจจุบัน ค่าเริ่มต้นสามารถใช้เมื่อลงทะเบียน (ไม่กรอกข้อมูล)
2. ความสำคัญ- เมื่อมีคำสั่งหลายคำที่กำหนดไว้ในองค์ประกอบ DOM เดียวกันบางครั้งก็จำเป็นต้องชี้แจงลำดับการดำเนินการของพวกเขา คุณสมบัตินี้ใช้ในการเรียงลำดับก่อนการเรียกฟังก์ชันคอมไพล์ Directive หากลำดับความสำคัญเหมือนกันคำสั่งการดำเนินการไม่แน่นอน (หลังจากการทดลองเบื้องต้นผู้ที่มีลำดับความสำคัญสูงกว่าจะถูกดำเนินการก่อนและระดับเดียวกันจะคล้ายกับการดำเนินการ "โพสต์ที่มีข้อผูกมัด" ก่อน "นอกจากนี้ฉันยังไม่สนใจเล็กน้อยในระหว่างการทดสอบ
3.Terminal (กลุ่มสุดท้าย) - หากตั้งค่าเป็น "จริง" หมายความว่าลำดับความสำคัญปัจจุบันจะกลายเป็นคำสั่งของกลุ่มการดำเนินการสุดท้าย หากคำสั่งใด ๆ นั้นเหมือนกับลำดับความสำคัญปัจจุบันพวกเขาจะยังคงดำเนินการอยู่ แต่คำสั่งนั้นไม่แน่นอน (แม้ว่าคำสั่งจะไม่แน่นอน แต่โดยทั่วไปจะเหมือนกับคำสั่งลำดับความสำคัญหลังจากลำดับความสำคัญปัจจุบันเสร็จสิ้นลำดับความสำคัญต่ำจะไม่ถูกดำเนินการอีกครั้ง)
4.Scope - ถ้าตั้งค่าเป็น:
1) .true - ขอบเขตใหม่จะถูกสร้างขึ้นสำหรับคำสั่งนี้ หากมีหลายคำสั่งในองค์ประกอบเดียวกันที่ต้องใช้ขอบเขตใหม่มันจะยังคงสร้างขอบเขตเดียวเท่านั้น กฎขอบเขตใหม่ไม่ได้ใช้กับเทมเพลตรูทดังนั้นเทมเพลตรูทจึงมีขอบเขตใหม่
2). {} (แฮชวัตถุ) - จะสร้างขอบเขตใหม่แยกได้ ความแตกต่างระหว่างขอบเขต "ไอโซเลท" และขอบเขตทั่วไปคือมันไม่ได้รับมรดกจากขอบเขตหลักผ่านต้นแบบ สิ่งนี้มีประโยชน์มากสำหรับการสร้างส่วนประกอบที่สามารถนำกลับมาใช้ใหม่ได้และสามารถป้องกันการอ่านหรือแก้ไขข้อมูลจากขอบเขตหลักได้อย่างมีประสิทธิภาพ ขอบเขตอิสระนี้สร้างแฮชวัตถุด้วยชุดคุณสมบัติขอบเขตท้องถิ่นที่ได้มาจากขอบเขตหลัก คุณสมบัติในท้องถิ่นเหล่านี้มีประโยชน์สำหรับค่านามแฝงสำหรับเทมเพลต -_-! คำจำกัดความของคนในท้องถิ่นเป็นแฮชของคุณสมบัติขอบเขตท้องถิ่นไปยังแหล่งที่มา#&) $ &@#) ($ &@#_):
3). @ หรือ @attr - สร้างคุณสมบัติขอบเขตท้องถิ่นไปยังคุณสมบัติ DOM เนื่องจากค่าคุณสมบัติเป็นประเภทสตริงเสมอค่านี้จะส่งคืนสตริงเสมอ หากไม่ได้ระบุชื่อแอตทริบิวต์ผ่าน @ATTR ชื่อท้องถิ่นจะอยู่กับชื่อของแอตทริบิวต์ DOM เสมอ ตัวอย่างเช่น <วิดเจ็ต my-attr =” สวัสดี {{name}} "> ขอบเขตของวิดเจ็ตถูกกำหนดเป็น: {localname: '@myattr'} จากนั้นชื่อท้องถิ่นของคุณสมบัติขอบเขตวิดเจ็ตจะแมปมูลค่าจริงที่แปลงโดย "สวัสดี {{name}}" หลังจากการเปลี่ยนแปลงค่าแอตทริบิวต์ชื่อแอตทริบิวต์ LocalName ของขอบเขตวิดเจ็ตจะเปลี่ยนไปตาม (เพียงทางเดียวเท่านั้นที่แตกต่างจาก "=" ด้านล่าง) แอตทริบิวต์ชื่อถูกอ่านในขอบเขตหลัก (ไม่ใช่ขอบเขตส่วนประกอบ)
4). = หรือ = นิพจน์ (อาจจะอยู่ที่นี่) - ตั้งค่าการเชื่อมโยงแบบสองทิศทางระหว่างแอตทริบิวต์ขอบเขตท้องถิ่นและแอตทริบิวต์ขอบเขตหลัก หากไม่ได้ระบุชื่อ Attr ชื่อท้องถิ่นจะสอดคล้องกับชื่อแอตทริบิวต์ ตัวอย่างเช่น <widget my-attr =” parentModel”>, ขอบเขตที่กำหนดโดยวิดเจ็ตคือ: {localModel: '= myattr'} จากนั้นคุณสมบัติของวิดเจ็ตขอบเขต "ชื่อท้องถิ่น" จะแมปขอบเขต "ParentModel" หากการเปลี่ยนแปลงใด ๆ เกิดขึ้นใน ParentModel LocalModel จะเปลี่ยนไปและในทางกลับกัน (มีผลผูกพันสองทาง)
5). & หรือ & attr - จัดเตรียมวิธีในการดำเนินการนิพจน์ในบริบทขอบเขตหลัก หากไม่ได้ระบุชื่อ Attr ชื่อท้องถิ่นจะสอดคล้องกับชื่อแอตทริบิวต์ ตัวอย่างเช่น <widget my-attr =” count = count + value”> ขอบเขตของวิดเจ็ตถูกกำหนดเป็น: {localfn: 'เพิ่ม ()'} จากนั้นจึงแยกคุณสมบัติขอบเขต "localfn" จะชี้ไปที่ฟังก์ชั่นที่ห่อด้วยนิพจน์ที่เพิ่มขึ้น () โดยทั่วไปแล้วเราต้องการส่งข้อมูลจากขอบเขตไอโซเลทไปยังขอบเขตหลักผ่านการแสดงออก ซึ่งสามารถทำได้โดยผ่านแผนที่ของค่าคีย์ของตัวแปรท้องถิ่นลงในฟังก์ชัน wrapper ของนิพจน์ ตัวอย่างเช่นหากนิพจน์เพิ่มขึ้น (จำนวนเงิน) เราสามารถโทรหา localfn ผ่าน localfn ({จำนวน: 22}) เพื่อระบุค่าของจำนวน (ตัวอย่างข้างต้นไม่เข้าใจจริงๆและคุณไปที่ไหน?)
5. Controller - คอนโทรลเลอร์คอนสตรัคเตอร์ คอนโทรลเลอร์จะเริ่มต้นก่อนขั้นตอนการเชื่อมโยงก่อนและอนุญาตให้คำสั่งอื่น ๆ แบ่งปันผ่านที่จำเป็นด้วยชื่อที่ระบุ (ดูคุณสมบัติที่ต้องการด้านล่าง) สิ่งนี้จะช่วยให้คำสั่งสามารถสื่อสารซึ่งกันและกันและเพิ่มพฤติกรรมร่วมกัน คอนโทรลเลอร์ฉีดวัตถุท้องถิ่นต่อไปนี้โดยค่าเริ่มต้น:
1). $ SCOPE - ขอบเขตรวมกับองค์ประกอบปัจจุบัน
2). $ องค์ประกอบ - องค์ประกอบปัจจุบัน
3). $ attrs - วัตถุแอตทริบิวต์ขององค์ประกอบปัจจุบัน
4). $ transclude - ฟังก์ชั่นการเชื่อมโยง transpose ล่วงหน้าไปยังขอบเขตการแปลงสภาพปัจจุบัน: ฟังก์ชั่น (clonelinkingfn) (ฟังก์ชั่นการเชื่อมโยง transclude ล่วงหน้าไปยังขอบเขตการแปลที่ถูกต้อง)
6. Require - ขอให้คอนโทรลเลอร์อื่นส่งผ่านไปยังฟังก์ชั่นการเชื่อมโยงคำสั่งปัจจุบัน ต้องการให้ชื่อของคอนโทรลเลอร์โดยตรงถูกส่งผ่านหากไม่พบคอนโทรลเลอร์ที่สอดคล้องกับชื่อนี้จะพบข้อผิดพลาด ชื่อสามารถนำหน้าด้วยสิ่งต่อไปนี้:
1).? - อย่าโยนข้อยกเว้น สิ่งนี้ทำให้การพึ่งพานี้เป็นตัวเลือก
2).^ - คอนโทรลเลอร์ที่อนุญาตการค้นหาองค์ประกอบหลัก
7. การ จำกัด - สตริงของชุดย่อยของ EACM ซึ่ง จำกัด คำสั่งไปยังวิธีการประกาศที่ระบุ หากละเว้นคำสั่งจะอนุญาตให้มีการประกาศผ่านแอตทริบิวต์เท่านั้น:
1) E-ชื่อองค์ประกอบ: <my-directive> </firective>
2) .a - ชื่อแอตทริบิวต์: <div my -directive =” exp”> </div>
3). C - ชื่อคลาส: <div class = "my -directive: exp;"> </div>
4) .M-ความคิดเห็น: <!-คำสั่ง: exp ของฉัน-->>
8.Template - หากแทนที่เป็นจริงให้แทนที่เนื้อหาเทมเพลตด้วยองค์ประกอบ HTML ปัจจุบันและโยกย้ายคุณสมบัติและคลาสขององค์ประกอบดั้งเดิมเข้าด้วยกัน หากเท็จองค์ประกอบเทมเพลตจะถือเป็นองค์ประกอบลูกขององค์ประกอบปัจจุบัน สำหรับข้อมูลเพิ่มเติมโปรดตรวจสอบบท "การสร้างวิดเจ็ต" (ที่ไหน ... ที่ ... การสร้างส่วนประกอบมีอยู่ ... )
9.templateurl - โดยทั่วไปเหมือนกับเทมเพลต แต่เทมเพลตจะถูกโหลดผ่าน URL ที่ระบุ เนื่องจากการโหลดเทมเพลตเป็นแบบอะซิงโครนัสการรวบรวมและการเชื่อมโยงจะถูกหยุดชั่วคราวและจะถูกดำเนินการหลังจากการโหลด
10. การแทนที่ - หากตั้งค่าเป็นจริงเทมเพลตจะแทนที่องค์ประกอบปัจจุบันแทนที่จะถูกเพิ่มลงในองค์ประกอบปัจจุบันเป็นองค์ประกอบลูก (หมายเหตุ: เมื่อเป็นจริงเทมเพลตจะต้องมีโหนดรูท)
11.transclude - รวบรวมเนื้อหาขององค์ประกอบเพื่อให้สามารถใช้งานได้โดย Directive จำเป็น (ในเทมเพลต) ที่จะใช้ (อ้างอิง) ข้อได้เปรียบของการเปลี่ยนแปลงคือฟังก์ชั่นการเชื่อมโยงสามารถรับฟังก์ชั่นการแปลที่ถูกผูกไว้ล่วงหน้ากับขอบเขตปัจจุบัน โดยทั่วไปให้สร้างวิดเจ็ตและสร้างขอบเขตแยก การแปลไม่ใช่เด็ก แต่เป็นพี่ชายของขอบเขตไอโซเลต สิ่งนี้จะทำให้วิดเจ็ตมีสถานะส่วนตัวและการเชื่อมต่อจะถูกผูกไว้กับขอบเขตของผู้ปกครอง (ก่อน-ไอโซเลต) (ฉันไม่เข้าใจย่อหน้าข้างต้น แต่ในการทดลองจริงถ้า myDirective ถูกเรียกผ่าน <ใด ๆ ของ my-directive> {{name}} </ใด ๆ ของ my-directive> และ transclude ถูกตั้งค่าเป็น true หรือสตริงและเทมเพลตที่มีเนื้อหาของ Ng-transclude> จะเป็นช่วงเวลาพิเศษในบางครั้ง
1) .true - แปลงเนื้อหาของคำสั่งนี้ (ในแง่นี้มันคือการรวบรวมเนื้อหาโดยตรงและย้ายไปยังสถานที่ที่กำหนด)
2). 'องค์ประกอบ' - แปลงองค์ประกอบทั้งหมดรวมถึงคำสั่งอื่น ๆ ที่มีลำดับความสำคัญต่ำกว่า (ตัวอย่างเช่นหลังจากรวบรวมเนื้อหาทั้งหมดแล้วจะได้รับการปฏิบัติโดยรวม
12. Compile - นี่คือฟังก์ชั่นคอมไพล์ซึ่งจะอธิบายรายละเอียดในบทต่อไปนี้
13.link - นี่คือฟังก์ชั่นลิงค์ซึ่งจะอธิบายรายละเอียดในบทต่อไปนี้ คุณสมบัตินี้จะใช้เฉพาะในกรณีที่ไม่ได้กำหนดคุณสมบัติการคอมไพล์
9. ฟังก์ชั่นคอมไพล์
ฟังก์ชั่นคอมไพล์ (โทร., tattrs, transclude) {…}
ฟังก์ชั่นคอมไพล์ใช้เพื่อจัดการการแปลงของแม่แบบ DOM เนื่องจากคำสั่งส่วนใหญ่ไม่จำเป็นต้องใช้เทมเพลตการแปลงการรวบรวมจะไม่ถูกใช้บ่อย คำสั่งที่ต้องใช้ฟังก์ชั่นการคอมไพล์โดยทั่วไปที่จำเป็นต้องแปลงเทมเพลต DOM (เช่น NGREPEAT) หรือผู้ที่ต้องการโหลดเนื้อหาแบบอะซิงโครนัส (เช่น NGVIEW) ฟังก์ชั่นคอมไพล์มีพารามิเตอร์ต่อไปนี้:
1.TELEMENT - องค์ประกอบเทมเพลตใช้องค์ประกอบคำสั่งปัจจุบัน มันปลอดภัยที่จะทำการแปลงเทมเพลตภายใต้องค์ประกอบปัจจุบันหรือองค์ประกอบลูกองค์ประกอบปัจจุบัน
2.Tattrs - แอตทริบิวต์เทมเพลต - แอตทริบิวต์มาตรฐานที่ประกาศในองค์ประกอบปัจจุบันสามารถใช้ร่วมกันระหว่างคำสั่งต่างๆ สำหรับรายละเอียดโปรดดูบทแอตทริบิวต์
3. อ่านฟังก์ชั่นการเชื่อมโยงสำหรับการแปลง: ฟังก์ชั่น (ขอบเขต, clonelinking)
หมายเหตุ: หากเทมเพลตถูกโคลนอินสแตนซ์เทมเพลตและอินสแตนซ์ลิงก์ไม่สามารถเป็นวัตถุเดียวกันได้ ในการทำเช่นนี้มันไม่ปลอดภัยที่จะทำสิ่งอื่นนอกเหนือจากการแปลง DOM ในฟังก์ชั่นคอมไพล์ซึ่งจะนำไปใช้กับโคลนทั้งหมด โดยเฉพาะอย่างยิ่งการดำเนินการลงทะเบียนของผู้ฟังเหตุการณ์ DOM ควรดำเนินการในฟังก์ชั่นการเชื่อมโยงไม่ใช่ฟังก์ชั่นคอมไพล์
ฟังก์ชั่นคอมไพล์สามารถมีค่าส่งคืนและประเภทสามารถเป็นฟังก์ชันหรือวัตถุ
1. ฟังก์ชั่นการส่งคืนมักจะใช้เมื่อไม่จำเป็นต้องใช้ฟังก์ชั่นคอมไพล์ (ว่าง) ซึ่งเทียบเท่ากับการลงทะเบียนฟังก์ชั่นการเชื่อมโยงผ่านลิงก์ (กำหนดคุณลักษณะของเทมเพลตโดยตรง)
2. ส่งคืนวัตถุที่มีคุณสมบัติก่อนและหลัง - ช่วยให้เราสามารถควบคุมได้เมื่อเรียกใช้ฟังก์ชันการเชื่อมโยงระหว่างเฟสการเชื่อมโยง สำหรับรายละเอียดโปรดดูบทต่อไปนี้เกี่ยวกับฟังก์ชั่นการเชื่อมโยงล่วงหน้าและการเชื่อมโยงหลัง
10. ฟังก์ชั่นการเชื่อมโยง
ลิงก์ฟังก์ชั่น (ขอบเขต, iElement, iATTRS, คอนโทรลเลอร์) {…}
ฟังก์ชั่นลิงก์มีหน้าที่รับผิดชอบในการลงทะเบียนฟังเหตุการณ์ DOM และยังสามารถดำเนินการอัปเดต DOM ได้ ฟังก์ชั่นลิงค์จะถูกดำเนินการหลังจากการดำเนินการโคลนเทมเพลตเสร็จสมบูรณ์ ตรรกะส่วนใหญ่ของคำสั่งถูกเก็บไว้ที่นี่
1.Scope - ขอบเขต - ใช้ในการลงทะเบียนนาฬิกา (http://docs.angularjs.org/api/ng.$rootscope.scope#$watch)
2.Element - อินสแตนซ์องค์ประกอบ - องค์ประกอบที่ใช้โดย Directive มันปลอดภัยที่จะทำงานกับองค์ประกอบเด็กในฟังก์ชั่น postlink เพราะองค์ประกอบของเด็กได้รับการเชื่อมโยง (เชื่อมต่อกับโมเดล?!)
3.IATTRS - อินสแตนซ์แอตทริบิวต์ - รายการแอตทริบิวต์ขององค์ประกอบปัจจุบันมาตรฐาน แบ่งปันระหว่างฟังก์ชั่นการเชื่อมโยงคำสั่งทั้งหมด
4.Controller - อินสแตนซ์คอนโทรลเลอร์ - หากตัวควบคุมตัวใดตัวหนึ่งถูกกำหนดไว้ในคำสั่งขององค์ประกอบปัจจุบันคุณสามารถรับอินสแตนซ์ของคอนโทรลเลอร์ได้ที่นี่ คอนโทรลเลอร์นี้มีการแบ่งปันระหว่างคำสั่งทั้งหมดทำให้แต่ละคำสั่งสามารถปฏิบัติต่อคอนโทรลเลอร์เป็นช่องทางการสื่อสารระหว่างพวกเขา
ฟังก์ชั่น pre-link
ดำเนินการก่อนที่องค์ประกอบลูกเชื่อมโยง ไม่ปลอดภัยที่จะทำการแปลง DOM ที่นี่เนื่องจากฟังก์ชั่นการเชื่อมโยงของคอมไพเลอร์อาจไม่พบองค์ประกอบที่ถูกต้องเมื่อเชื่อมโยง
ฟังก์ชั่นโพสต์ลิงค์
ดำเนินการหลังจากองค์ประกอบลูกเชื่อมโยง มันปลอดภัยที่จะทำการแปลง DOM ที่นี่
11. คุณลักษณะ
วัตถุแอตทริบิวต์ - เป็นอาร์กิวเมนต์ในลิงค์ () หรือคอมไพล์ () - เป็นวิธีการเข้าถึงสิ่งต่อไปนี้:
1. ชื่อแอตทริบิวต์ที่ได้มาตรฐาน: เนื่องจากคำสั่งเช่น ngbind สามารถปรากฏในหลายรูปแบบเช่น "ng: bind", "x-ng-bind" ... วัตถุแอตทริบิวต์นี้ช่วยให้เราสามารถเข้าถึงแอตทริบิวต์ผ่านการตั้งชื่อมาตรฐาน (อูฐ)
2. การสื่อสารระหว่างคำสั่ง: คำสั่งทั้งหมดแบ่งปันอินสแตนซ์วัตถุแอตทริบิวต์เพื่อให้คำสั่งสามารถสื่อสารระหว่างคำสั่งผ่านวัตถุแอตทริบิวต์
3. การสนับสนุนการแก้ไข: แอตทริบิวต์การแก้ไขถูกกำหนดให้กับวัตถุแอตทริบิวต์ช่วยให้คำสั่งอื่น ๆ สามารถอ่านค่าการแก้ไข
4. สังเกตแอตทริบิวต์การแก้ไข: สังเกตการเปลี่ยนแปลงในค่าแอตทริบิวต์ผ่าน attr. $ observe รวมถึงการแก้ไข (ตัวอย่างเช่น src =” {{bar}} ") ไม่เพียง แต่จะมีประสิทธิภาพมาก แต่ยังเป็นวิธีเดียวที่จะได้รับคุณค่าที่แท้จริง เนื่องจากในระหว่างขั้นตอนการเชื่อมโยงการแก้ไขยังไม่ได้รับมอบหมาย (แทนที่ด้วยมูลค่าจริง) ดังนั้นเมื่อเข้าถึงในเวลานี้ผลลัพธ์จะไม่ได้กำหนด
<! doctype html> <html lang = "zh-cn" ng-app = "directiveProperty"> <head> <meta charset = "utf-8"> <title> directive-attribute-test </title> } </style> </head> <body ng-controller = "myctrl"> <อินพุต type = "text" ng-model = "name" value = "myName"/> <p my-attr = "123" directive-p2 attr-dd = "{{name}}"> </p> type = "text/javascript"> </script> <script type = "text/javascript"> var app = angular.module ("DirectiveProperty", []); app.controller ("myctrl", ฟังก์ชั่น ($ scope) {$ scope.name = "My Little Dada";}); var directivep2 = app.directive ("directivep2", function () {return {link: function postlink (ขอบเขต, lele, lattr) {console.log ("myattr:" + lattr.myattr); // 123 console.log ("myattr:" console.log ('attrdd ได้เปลี่ยนค่าเป็น' + ค่า);12. เข้าใจการเปลี่ยนแปลงและขอบเขต
เรามักจะต้องการส่วนประกอบที่นำกลับมาใช้ใหม่ได้ นี่คือรหัสหลอกแสดงให้เห็นว่าส่วนประกอบโต้ตอบง่าย ๆ สามารถทำงานได้อย่างไร
<button ng-click = "show = true"> แสดง </button> <dialog isible = "show" on-cancel = "show = false" on-ok = "show = false; dosomething ()"> ร่างกายไปที่นี่: {{username}} คือ {{title}}. </dialog>.การคลิกปุ่ม "แสดง" จะเปิดกล่องโต้ตอบ กล่องโต้ตอบมีชื่อเรื่องที่ผูกพันกับข้อมูล "ชื่อผู้ใช้" และยังมีย่อหน้าที่เราต้องการวางไว้ในกล่องโต้ตอบ
ต่อไปนี้เป็นคำจำกัดความของเทมเพลตที่เขียนขึ้นสำหรับกล่องโต้ตอบ:
<div ng-show = "show ()"> <h3> {{title}} </h3> <div ng-transclude> </div> <div> <button ng-click = "onok ()"> บันทึกการเปลี่ยนแปลง </button> <button ng-click = "oncancel ()"สิ่งนี้จะไม่ถูกต้องเว้นแต่เราจะทำการรักษาพิเศษเกี่ยวกับขอบเขต
ปัญหาแรกที่เราต้องแก้ไขคือเทมเพลตการโต้ตอบคาดว่าจะมีการกำหนดชื่อและจะถูกผูกไว้กับชื่อผู้ใช้เมื่อเริ่มต้น นอกจากนี้ปุ่มต้องใช้สองฟังก์ชั่น Onok และ Oncancel ที่จะปรากฏในขอบเขต นี่เป็นการ จำกัด ประโยชน์ของวิดเจ็ต .. ) เพื่อแก้ปัญหาการแมปตัวแปรท้องถิ่นที่คาดว่าจะถูกสร้างขึ้นโดยวิธีการในท้องถิ่นต่อไปนี้ (ท้องถิ่นซึ่งคาดว่าจะเป็นขอบเขตในเทมเพลตคำจำกัดความคำสั่ง):
ขอบเขต: {title: 'bind', // ตั้งค่าชื่อเรื่องเพื่อยอมรับการเชื่อมต่อข้อมูล onok: 'นิพจน์', // สร้างฟังก์ชั่นตัวแทน Onok OnCancel: 'นิพจน์', // สร้างฟังก์ชั่นตัวแทน OnCancel แสดง: 'accessor' // สร้างฟังก์ชัน Getter/Setterการสร้างคุณสมบัติท้องถิ่นในขอบเขตการควบคุมทำให้เกิดปัญหาสองประการ:
1. การแยก (การแยกแอตทริบิวต์?) - หากผู้ใช้ลืมที่จะตั้งค่าชื่อแอตทริบิวต์องค์ประกอบในเทมเพลตควบคุมชื่อจะถูกผูกไว้กับแอตทริบิวต์ "ชื่อ" ของขอบเขตบรรพบุรุษ (ถ้ามี) นี่เป็นสิ่งที่คาดเดาไม่ได้และไม่พึงปรารถนา
2. Transclusion - DOM ที่แปลสามารถดูคนในท้องถิ่น (Isolate Scope?) ของการควบคุม ชาวบ้านจะแทนที่คุณสมบัติที่จำเป็นต้องถูกผูกไว้ในการเปลี่ยนแปลง ในตัวอย่างของเราคุณสมบัติชื่อในปลั๊กอินจะทำลายคุณสมบัติชื่อเรื่องของ transclusion
เพื่อแก้ปัญหาการขาดการแยกแอตทริบิวต์นี้เราจำเป็นต้องกำหนดขอบเขตที่แยกได้สำหรับคำสั่งนี้ ขอบเขตของ Isoloted ไม่ได้รับการสืบทอดมาจากต้นแบบจากขอบเขตเด็ก (ทำไมขอบเขตเด็กจึงไม่ใช่ขอบเขตของผู้ปกครอง?) ดังนั้นเราไม่จำเป็นต้องกังวลเกี่ยวกับปัญหาความขัดแย้งของคุณลักษณะ (เป็นพี่ชายของขอบเขตปัจจุบัน)
อย่างไรก็ตามขอบเขตที่แยกได้นำมาซึ่งปัญหาใหม่: หาก DOM ที่แปลเป็นลูกของขอบเขตที่แยกออกจากวิดเจ็ตมันจะไม่สามารถผูกกับสิ่งใดได้ ดังนั้นขอบเขตที่แปลเป็นขอบเขตเด็กของขอบเขตดั้งเดิมที่สร้างขึ้นก่อนที่การควบคุมจะสร้างขอบเขตที่แยกได้สำหรับทรัพย์สินในท้องถิ่น ขอบเขตที่แปลและแยกต่างหากเป็นของโหนดพี่น้อง (ในทรีขอบเขต)
สิ่งนี้อาจดูซับซ้อนโดยไม่คาดคิด แต่การทำเช่นนั้นทำให้เกิดความประหลาดใจอย่างน้อยในการควบคุมผู้ใช้และนักพัฒนาควบคุม (ปัญหาได้รับการแก้ไข)
ดังนั้นคำจำกัดความคำสั่งสุดท้ายมีดังนี้:
transclude: จริง, ขอบเขต: {title: 'bind', // ตั้งชื่อชื่อเพื่อยอมรับการทำงาน data-binding onok: 'นิพจน์', // สร้างฟังก์ชั่นตัวแทน Onok OnCancel: 'นิพจน์', // สร้างฟังก์ชั่นตัวแทน OnCancel แสดง: 'Accessor' // สร้างฟังก์ชั่น Getter/Setter // ฉันได้ลองสิ่งนี้แล้ว แต่มันล้มเหลว ... โปรดอ่านต่อไป}ฉันพยายามที่จะรวมรหัสด้านบนเข้าด้วยกันเป็นตัวอย่างที่สมบูรณ์ หากคุณคัดลอกโดยตรงผลลัพธ์ที่คาดหวังจะไม่สามารถทำได้ แต่หลังจากการดัดแปลงเล็กน้อยปลั๊กอินสามารถเรียกใช้ได้
<! doctype html> <html ng-app = "กล่องโต้ตอบ"> <head> <meta http-equiv = "content-type" content = "text/html; charset = utf-8"/> <title> directive-dialog src = "../ angular.js" type = "text/javascript"> </script> </head> <body> <div ng-controller = "myctrl"> <button ng-click = "show = true"> แสดง </button> on-ok = "show = false; methodInparentscope ();"> <!-ด้านบนของ Cancel และ On-OK นั้นอ้างอิงโดย & ในขอบเขต Directive Isoloate หากนิพจน์มีฟังก์ชั่นคุณจะต้องผูกฟังก์ชันในขอบเขตหลัก (ปัจจุบันขอบเขต myctrl) -> ร่างกายไปที่นี่: ชื่อผู้ใช้: {{username}}, ชื่อ: {{title}} <ul> <!-คุณสามารถเล่นแบบนี้ได้ที่นี่ ~ ชื่อคือขอบเขตหลัก-> <li ng-repeat = "ชื่อในชื่อ"> {{ชื่อ}} </li> </ul> </dialog> </div> <script type = "text/javascript"> var mymodule = angular.module mymodule.controller ("myctrl", ฟังก์ชั่น ($ scope) {$ scope.names = ["name1", "name2", "name3"]; $ scope.show = false; $ scope.username = "lclao"; เล่นในขอบเขตหลัก !!! ");};}); mymodule.directive ('Dialog', Function Factory () {return {ลำดับความสำคัญ: 100, เทมเพลต: ['<div ng-show = "มองเห็นได้">', '<h3> {{title}} </h3>', <div ng-transclude> </div> ' ng-click = "oncancel ()"> ปิด </pution> ',' </div> ',' </div> ',' </div> ']. เข้าร่วม (""), แทนที่: เท็จ, transclude: จริง, จำกัด :' e ', ขอบเขต: {title: "@" รูปแบบของฟังก์ชั่น wrapper oncancel: "&", // ใช้แบบฟอร์มฟังก์ชั่น wrapper อ้างอิงเนื้อหาของคุณสมบัติ on-cancel ของแท็กกล่องโต้ตอบที่มองเห็นได้: "@" // หมายถึงค่าของคุณสมบัติที่มองเห็นได้ของแท็กกล่องโต้ตอบ}}; </script> </body> </html>13. การสร้างส่วนประกอบ
เรามักจะคาดหวังว่าจะแทนที่คำสั่งผ่านโครงสร้าง DOM ที่ซับซ้อน (องค์ประกอบอยู่หรือไม่วัตถุประสงค์อาจจะทำให้จุดที่ซับซ้อนภายในคำสั่งซึ่งดูยอดเยี่ยม @_ @) สิ่งนี้ทำให้คำสั่งเป็นทางลัดในการสร้างแอปพลิเคชันโดยใช้ส่วนประกอบที่นำกลับมาใช้ใหม่ได้
นี่คือตัวอย่างขององค์ประกอบที่นำกลับมาใช้ใหม่ได้:
<! doctype html> <html ng-app = "zippymodule"> <head> <meta http-equiv = "เนื้อหาประเภท" เนื้อหา = "ข้อความ/html; charset = utf-8"/> <title> zippymodule </title> <style type = "text/css"> .zippy {border: 1px solid black; แสดง: Inline-Block; ความกว้าง: 250px; } .zippy.opened> .title: ก่อน {เนื้อหา: ''; } .zippy.opened> .body {display: block; } .zippy.closed > .title:before { content: '► '; } .zippy.closed > .body { display: none; } .zippy > .title { background-color: black; สี: สีขาว; padding: .1em .3em; เคอร์เซอร์: ตัวชี้; } .zippy > .body { padding: .1em .3em; } </style> <script src="../angular.js" type="text/javascript"></script></head><body> <div ng-controller="MyCtrl"> Title: <input ng-model="title" type="text"><br/> Text: <textarea ng-model="text"></textarea> <hr/> <div zippy-title="Details: {{title}}...">{{text}}</div> </div> <script type="text/javascript"> var myModule = angular.module("ZippyModule", []); myModule.controller("MyCtrl", function ($scope) { $scope.title = "Here is the title"; $scope.text = "Here is the content... "; }); myModule.directive('zippy', function () { return { template: '<div>' + ' <div>{{title}}</div>' +//This title belongs to the property of the current direct isolate scope ' <div ng-transclude></div>' + //What is here, what is obtained is the property of the parent scope '</div>', replace:true, transclude: true, restrict:'C', scope:{ title:"@zippyTitle"//Bind the zippy-title attribute on the directive element}, link:function(scope,element,attrs) { var title = angular.element(element.children()[0]), opened = false; title.bind("click", toogle); element.addClass("closed"); function toogle() { opened = !opened; element.removeClass(opened ? "closed" : "opened"); element.addClass(opened ? "opened" : "closed"); } } }; }); </script></body></html>