有關自定義指令的scope參數,網上不少文章都在講這3種綁定方式實現的效果是什麼,但幾乎沒有人講到底怎麼使用,本篇但願聊聊到底怎麼用這個話題。html
自定義指令,是Angularjs
用來實現組件化的方式,相比於React
和Vue
的組件化方式,它真的很複雜,自定義指令過重了,它暴露了太多可供定製的參數,以致於普通的開發者徹底不知道要用它來作什麼而將其束之高閣,畢竟通常的業務邏輯經過controller和service就已經能夠完成了。ajax
自定義指令在Angularjs
項目中主要有兩大用途:數組
1.封裝指定組件的DOM操做框架
Angularjs
指望的開發方式是將DOM的操做盡量封裝在自定義指令中,這樣對於局部變量的操做會更容易加入到Angular本身的生命週期中。ide
2.組件化函數
Angularjs
靠自定義指令實現組件化。諸如你在React
和Vue
中看到的相似於
Angularjs
中所有都是經過自定義指令來實現的。組件化
自定義指令在定義後,須要在html文件中編寫,最經常使用的方式是將其書寫爲標籤屬性。當使用自定義指令時,經常須要將一個變量的值從controller傳遞至directive中,此時須要在scope
屬性中進行變量綁定設置,Angularjs
提供了3種不一樣的綁定方式(實際上也能夠直接傳遞True),以下所示:設計
scope: { infiniteScroll: '=', // 將infiniteScroll同父級controller中的指定對象雙向綁定 onSend: '&', // 從父級獲取一個變量的引用,經常使用做方法調用 fromName: '@' // 從父級獲取值後便只在本地做用域生效 }
關於三種綁定方式使用的方法,網上能夠搜到很是多的文章,本篇再也不贅述,今天咱們只來詳細看一下這幾種方式的使用場景和區別。雙向綁定
@綁定
能夠轉移常量賦值的位置,經常使用於爲自定義封裝組件暴露一個可設定常量參數的接口。這種綁定方式的意義,在於從自定義指令外部(通常是從html頁面上綁定一個常量或控制器中的變量)獲取一個局部變量的值。code
實際場景:
例如咱們封裝了一個分頁組件,其中指令局部做用域中的displayPaginationNums
屬性用於決定分頁組件的頁碼欄顯示多少個按鈕,而後把剩餘的按鈕收起來並添加...
按鈕,這是一個很常見的需求。
不使用@綁定
不使用@綁定,徹底能夠作到,只須要在link函數裏,初始化爲其賦值便可。
link:function(scope, elements, attrs){ scope.displayPaginationNums = 5;//用於決定分頁導航欄最多可顯示幾個數字 },
使用這樣的方式,就能夠,但咱們默認了一個前提,那就是全部調用這個組件的人,都會瀏覽這個組件的源代碼。這實際上是很不方便的,換位思考一下,你使用Angularjs
的時候,會先去源碼裏找一下對應的方法開頭都定義了哪些變量,哪些能夠修改嗎?固然不會。
這個屬性在不一樣的項目中都會須要賦值,但須要動態去修改的場景其實並很少,因此咱們須要將接口暴露至更高的開發層級,供調用者直接賦值。
使用@綁定
當使用@綁定後,咱們其實是面向調用者暴露了去設定重要參數的接口,使用起來更加方便。下面的寫法讓開發者使用這個組件時,能夠在代碼編寫時方便地傳入本身想要設定的值:
//指令定義時 scope:{ displayPaginationNums:'@' },
<!--指令調用時--> <div table-pagination display-pagination-nums="5">
面向對象程序設計原則中有一個重要的原則,叫作開放封閉原則,它的意思是說,你在程序設計中所書寫的代碼,應該對擴展開放,對修改封閉。簡單地說就是你所編寫的代碼成型之後,在後續的使用和功能擴展的時候,儘量不須要再去改動代碼,而只須要經過編寫與擴展相關的代碼便可。
此處就是從封閉轉爲開放的一個示例,雖然看起來很細小,但能夠很明確地表達這個原則。
&綁定
用於傳遞父級函數的引用,用來調用父級控制器中定義的方法。若是隻是以業務邏輯爲模塊進行封裝,這種綁定方式能夠幫咱們避免一部分代碼重複,若是是爲通用框架編寫純組件,則能夠爲調用者提供自定義函數的接口。
實際場景:
好比咱們在製做一個表格和分頁組件時,表格每一頁只顯示10條數據,分頁是後臺來完成的,那麼每一次點擊分頁組件上的頁碼按鈕時,咱們都須要向後臺發送ajax請求來獲取新一頁的數據。那麼這個發送ajax請求的方法你會寫在哪裏呢?
不使用&綁定
將方法寫在controller中
優點:這樣作的好處是若是之後咱們須要增長一個輸入框來實現精確跳轉到哪一頁時,能夠直接在模板中使用ng-change="sendAjax( )"
來綁定這個方法,方便複用,擴展,甚至修改功能。
劣勢:但這樣作的話,若是想在自定義指令中就沒法直接調用這個方法,常見的處理策略是在自定義指令中使用scope.$emit( )
將一個自定義事件發送至父級controller,在父級controller中使用$scope.$on( )
來監聽這個自定義事件,並在回調中執行$scope.sendAjax( )
這個方法。
將方法寫在指令的link函數中
優點:能夠將一些不須要用戶感知的函數封裝起來,例如數據發送前的校驗,或是響應數據的結構重組等,提升業務邏輯相關的代碼在controller中的比重,減少controller的體積。
劣勢:當其餘組件想要使用這個方法時會很困難,Angularjs並無提供一種跨directive調用方法的機制。
實際上在開發過程當中,不熟悉&綁定
的開發者在使用自定義指令時,幾乎都會選擇將方法寫在controller中並經過消息機制來觸發這個函數(也就是上文中第一個方法),他們但願指令所封裝的組件是純粹的,換句話說,它是可複用且與業務邏輯剝離的。
使用&綁定
對於業務邏輯開發而言
簡潔且容易使用,組件可直接調用controller中的業務邏輯代碼,避免了當自定義事件過多時形成的controller中充滿了事件監聽的回調方法的問題,使用方法以下:
//主模板中 <div change-page="sendAjax"></div>
//指令定義中 ... template:'<div ng-click="changePage()"></div>' scope:{ changePage: '&' }, ...
對於模塊封裝而言
從上面的示例就能夠看出,自定義指令中實際執行的changePage( )
方法,是用戶在使用這個組件時編寫在controller之中的sendAjax( )這個方法,當咱們須要封裝一個供其餘開發者調用的組件時(每每是在編寫一個組件庫),這種結構是在angular中最天然的實現方式。
當你但願給一個自定義指令暴露愈來愈多個性化定製接口時,它極可能變得臃腫,甚至一無可取。
&綁定
意義,在於將業務邏輯從組件中剝離出來,但過多的可定製性又會給開發者帶來額外的問題,你會發現,僅僅是簡單地使用一個下拉框或是勾選框之類的簡單組件時,就須要傳入一大堆自定屬性,而這本該是在交互設計標準中肯定好並編寫在項目中的指定位置的。自定義指令的可定製性越高,html模板的體積就會越大,controller中的代碼量也會隨之增大,帶來的直接問題就是:開發很方便,維護很痛苦。
=綁定
是3中綁定形式中最經常使用的一種,經常使用於將用於渲染的數組或對象傳入自定義指令中。這樣作能夠將業務邏輯分塊,使得代碼結構更具備層次性,下降維護難度。
實際場景:
一個表格組件,須要經過ajax請求從後臺獲取100條用於展現的數據,這些數據可能須要排序,過濾,分頁等操做,首先應該明確的是,即時這些代碼所有寫在controller中,程序也是能夠運行的,只是當你在其餘場合須要複用時,就須要複製粘貼不少代碼。那麼該如何來設計這樣一個功能並提取公用組件呢?排序
,過濾
,分頁
都是表格組件的通用動做,也就是說與數據對象自己的結構並無太大關係,對於一個通用型表格控件來講,咱們惟一必需要傳入的只有一項——數據源,且它是有可能會隨着用戶操做而發生變化的。
推薦的技術方案爲:
這樣的結構,使宏觀業務邏輯,先後臺信息交互,組件通用功能分別在不一樣的模塊中實現,能夠極大提升定位問題的速度。
=綁定
的雙向數據綁定在使用中是存在一些方法問題的,詳情請參考《Angularjs1.X進階筆記(1)—兩種不一樣的雙向數據綁定》
。
=綁定
—— 經常使用於傳遞從後臺獲取的用於驅動純組件的源數據。
@綁定
—— 爲自定義指令中傳遞可配置的常量參數提供設置接口。
&綁定
—— 爲自定義指令中傳遞自定義方法提供接口。