您好,登錄后才能下訂單哦!
這篇文章主要講解了“Ember.js的視圖層分析”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Ember.js的視圖層分析”吧!
Ember.js 有一套復雜的用于創建、管理并渲染連接到瀏覽器 DOM 上的層級視圖的系 統。視圖負責響應諸如點擊、拖拽以及滾動等的用戶事件,也在視圖底層數據變更時更 新 DOM 的內容。
視圖層級通常由求值一個 Handlebars 模板創建。當模板求值后,會添加子視圖。當 那些 子視圖求值后,會添加它們的子視圖,如此遞推,直到整個層級被創建。
即使你并沒有在 Handlebars 模板中顯式地創建子視圖,Ember.js 內部仍使用視圖系 統更新綁定的值。例如,每個 Handlebars 表達式 {{value}}
幕后創建一個視圖, 這個視圖知道當值變更時如何更新綁定值。
你也可以在應用運行時用 Ember.ContainerView
類對視圖層級做出修改。一個容器 視圖暴露一個可以手動修改的子視圖實例數組,而非模板驅動。
視圖和模板串聯工作提供一套用于創建任何你夢寐以求的用戶界面的穩健系統。最終用 戶應從諸如當渲染和事件傳播是的計時事件之類的復雜東西中隔離開。應用開發者應可 以一次性把他們的 UI 描述成 Handlebars 標記字符串,然后繼續完成他們的應用,而 不必煩惱于確保它一直是最新的。
它解決了什么問題?
子視圖
在典型的客戶端應用中,視圖同時在本身和 DOM 中表示嵌套的元素。在解決這個問題 的天真方案中,獨立的視圖對象表示單個 DOM 元素,專門的引用解決不同種類的視圖 保持對概念中嵌套在它們內部的視圖的跟蹤。
這里是一個簡單的例子,表示一個應用主視圖,里面有一集合嵌套視圖,且獨立的元素在集合內嵌套。
這個系統第一眼看上去毫無異樣,但是想象我們要在上午 8 點而不是上午 9 點開放喬 的七鰓鰻小屋。在這種情況下,我們會想要重新渲染應用視圖。因為開發者需要構建指 向在一個特殊基礎上的子視圖的引用,這個重渲染過程存在若干問題。
為了重新渲染應用視圖,應用視圖也必須手動重新渲染子視圖并重新把它們插入到應用 視圖的元素中。如果實現得完美,這個過程會正常工作,但它依賴于一個完美的,專門 的視圖層級實現。如果任何一個視圖沒有精確地實現它,整個重新渲染過程會失敗。
為了避免這些問題,Ember 的視圖層級從概念上就帶有子視圖的烙印。
當應用時圖重新渲染時,Ember 而不是應用代碼負責重新渲染并插入子視圖。這也意味 著 Ember 可以為你執行任何內存管理,比如清理觀察者和綁定。
這不僅在一定程度上消滅了樣板代碼,也破除了有瑕疵的視圖層級實現帶來的未期失敗的可能。
在過去,web 開發者已經用在獨立的單個元素上添加事件監聽器來獲知什么時候用戶與 它們交互。例如,你會有一個 <div>
元素,其上注冊了一個當用戶點擊它時觸發的 函數。
盡管如此,這個途徑在處理大數量交互元素上不會縮放。比如,想象一個帶有 100 個 <li>
的 <ul>
,每個項目后都有一個刪除按鈕。既然所有的這些項目行為都是一 致的,為每個刪除按鈕創建共計 100 個事件監聽器無疑是低效的。
要解決這個問題,開發者發現了一種名為“事件委派”的技術。你可以在容器元素上注冊 一個監聽器并使用 event.target
來識別哪個元素是用戶點擊的,而不是為問題中的 每個項目創建一個監聽器。
實現這有一些微妙,因為一些事件(比如 focus
、 blur
和 change
)不會冒 泡。幸運的是,jQuery 已經徹底解決了這個問題;用 jQuery 的 on
方法可以可靠 地處理所有原生瀏覽器事件。
其它 JavaScript 框架用兩種方法中的其一來處理這個問題。第一種是,它們要你自己 實現原生解決方案,為每個項目創建獨立的視圖。當你創建視圖,它在視圖的元素上設 置一個監聽器。如果你有一個含有 500 個項目的列表,你會創建 500 個視圖并且每個 視圖都會在它自己的元素上設置一個監聽器。
第二種方法是,框架在視圖層內置事件委派。當創建一個視圖,你可以提供一個事件列 表來在事件發生時委派一個方法來調用。這只剩下識別接受事件的方法的點擊上下文 (比如,列表中的哪個項目)。
你現在要面對兩個令人不安的選擇:為每個項目創建一個新視圖,這樣會喪失事件委派 的優勢,或是為所有項目創建單個視圖,這樣必須存儲 DOM 中底層 JavaScript 的信息。
要解決這個問題,Ember 用 jQuery 把所有事件委派到應用的根元素(通常是文檔的 body
)。當一個事件發生,Ember 識別出最近的處理事件視圖并調用它的事件處理 器。這意味著你可以創建視圖來保存一個 JavaScript 上下文,但仍然從事件委派上受 益。
進一步地,因為 Ember 只為整個 Ember 應用注冊一個事件,創建新視圖永遠都不需要 設置事件監聽器,這使得重渲染高效且免于出錯。當視圖有一個子視圖,這也意味著不 需要手動取消委派重新渲染過程中替換掉的視圖。
渲染管道
大多數 web 應用用特殊的模板語言標記來指定它們的用戶界面。對于 Ember.js,我們 已經完成用可在值修改的時候自動更新模板的 Handlebars 模板語言來編寫模板。
雖然顯示模板的過程對開發者是自動的,但其遮蓋了把原始模板轉換為最終模板、生成 用戶可見的 DOM 表示的一系列必要步驟。
這是 Ember 視圖的近似生命周期:
1. 模板編譯
應用的模板通過網絡加載或以字符串形式作為應用的載荷。當應用加載時,它發送模板 字符串到 Handlebars 來編譯成函數。一經編譯,模板函數會被保存,且可以被多個視 圖重復使用,每次都它們都需重新編譯。
這個步驟會在應用中服務器預編譯模板的地方發出。在那些情況下,模板不作為原始的 人類可讀的模板傳輸,而是編譯后的代碼。
因為 Ember 負責模板編譯,你不需要做任何額外的工作來保證編譯后的模板可以重用。
2. 字符串的連接
當應用在視圖上調用 append
或 appendTo
時,一個視圖渲染過程會被啟動。 append
或 appendChild
調用 安排 視圖渲染并在之后插入。這允許應用中的 延遲邏輯(譬如綁定同步)在渲染元素之前執行。
要開始渲染過程,Ember 創建一個 RenderBuffer
并把它呈遞給視圖來把視圖的內容 附加到上面。在這個過程中,視圖可以創建并渲染子視圖。當它這么做時,父視圖創建 并分配一個 RenderBuffer
給子視圖,并把它連接到父視圖的 RenderBuffer
上。
Ember 在渲染每個視圖前刷新綁定同步隊列。這樣,Ember 保障不會渲染需要立即替換 的過期數據。
一旦主視圖完成渲染,渲染過程會創建一個視圖樹(即“視圖層級”),連接到緩沖區樹 上。通過向下遍歷緩沖區樹并把它們轉換為字符串,我們就有了一個可以插入到 DOM 的字符串。
這里是一個簡單的例子:
除子節點之外(字符串和其它 RenderBuffer
), RenderBuffer
也會封裝元素標 簽名稱、id、class、樣式和其它屬性。這使得渲染過程修改這些屬性(例如樣式)成 為可能,即使在子字符串已經渲染完畢。因為這些屬性的許多都可以通過綁定(例如用 bindAttr
)控制,這使得渲染過程穩健且透明。
3. 元素的創建和插入
在渲染過程的最后,根視圖向 RenderBuffer
請求它的元素。 RenderBuffer
獲得 它的完整字符串并用 jQuery 把它轉換成一個元素。視圖把那個元素分配到它的 element
屬性并把把它放置到 DOM 中正確的位置( appendTo
指定的位置,如果 應用使用 append
即是應用的根元素)。
雖然父視圖直接分配它的元素,但每個子視圖惰性查找它的元素。它通過查找 id
匹 配它的 elementId
屬性的元素來完成這。除非顯式提供,渲染過程生成一個 elementId
屬性比你更分配它的值給視圖的 RenderBuffer
,RenderBuffer
允 許視圖按需查找它的元素。
4. 重新渲染
在視圖把自己插入到 DOM 后,Ember 和應用都會要重新渲染視圖。它們可以在視圖上 調用 rerender
方法來出發一次重渲染。
重新渲染會重復上面的步驟 2 和步驟 3,有兩點例外:
rerender
用新元素替換已有的元素,而不是把元素插入到顯式定義的位置。
除了渲染新元素,它也刪除舊元素并銷毀它的子元素。這允許 Ember 在重新渲染視 圖時自動處理撤銷合適的綁定和觀察者。這使得路徑上的觀察者可行,因為注冊和撤銷 注冊所有的嵌套觀察者都是自動的。
最常見的導致視圖重新渲染的原因是當綁定到 Handlebars 表達式( {{foo}}
)變 更。Ember 內部為每個表達式創建一個簡單的視圖,并且在路徑上注冊一個觀察者。當 路徑變更時,Ember 用新值更新那個區域的 DOM。
另一個常見的情況是一個 {{#if}}
或 {{#with}}
塊。當渲染一個模板時,Ember 為這些塊輔助標創建虛擬的視圖。這些虛擬的視圖不會出現在公共可訪問的視圖層級里 (當從視圖獲取 parentView
和 childViews
時),但它們的存在啟用了一致的重 渲染。
當傳遞到 {{#if}}
或 {{#with}}
的路徑變更,Ember 自動重新渲染虛擬視圖替換 它的內容,重要的是,也會銷毀所有的子視圖來釋放內存。
除了這些情景,應用有時也會要顯式地重新渲染視圖(通常是一個 ContainerView
,見下)。在這種情況下,應用可以直接調用 rerender
,且 Ember 會把一項重渲染工作加入隊列,用相同的語義元素。
這個過程像是這樣:
視圖層級
父與子
當 Ember 渲染一個模板化的視圖,它會生成一個視圖層級。讓我們假設已有一個模板 form
。
原文鏈接:
{{view App.Search placeholder="Search"}} {{#view Ember.Button}}Go!{{/view}}
然后我們像這樣把它插入到 DOM 中:
var view = Ember.View.create({ templateName: 'form' }).append();
這會創建一個如下小巧的視圖等級:
你可以用 parentView
和 childViews
屬性在視圖層級中游走。
var children = view.get('childViews') // [ <App.Search>, <Ember.Button> ] children.objectAt(0).get('parentView') // 視圖
一個常見的 parentView
使用方法是在子視圖的實例里。
App.Search = Ember.View.extend({ didInsertElement: function() { // this.get('parentView') 指向 `view` } })
生命周期鉤子
為了容易地在視圖的生命周期的不同點上執行行為,有若干你可以實現的鉤子。
willInsertElement
: 這個鉤子在視圖渲染后插入 DOM 之前調用。它不提供對視圖的 element
的訪問。
didInsertElement
: 這個鉤子在視圖被插入到 DOM 后立即調用。它提供到視圖的 element
的訪問,且對集成到外部庫非常有用。任何顯式的 DOM 設置代碼應限于這個鉤子。
willDestroyElement
: 這個鉤子在元素從 DOM 移除前立即調用。這提供了銷毀任何與 DOM 節點關聯的外部狀態的機會。像 didInsertElement
一樣,它對于集成外部庫非常有用。
willRerender
: 這個鉤子在視圖被重新渲染前立即調用。如果你想要在視圖被重新渲染前執行一些銷毀操作,這會很有用。
becameVisible
: 這個鉤子在視圖的 isVisible
或它的祖先之一的 isVisible
變為真值,且關聯的元素也變為可見后調用。注意這個鉤子只在所有可見性由 isVisible
屬性控制的時候可靠。
becameHidden
: 這個鉤子在視圖的 isVisible
或它的祖先之一的 isVisible
變為假值,且關聯的元素也變為隱藏后調用。注意這個鉤子只在所有可見性由 isVisible
屬性控制的時候可靠。
應用可以通過在視圖上定義一個與鉤子同名的方法來實現鉤子。或者,在視圖上為鉤子 注冊一個監聽器也是可行的。
view.on('willRerender', function() { // do something with view });
虛擬視圖
正如上文所述,Handlebars 在視圖層級內創建視圖來表現綁定值。每次你使用 Handlebars 表達式,無論是一個簡單值還是一個諸如 {{#with}}
或 {{#if}}
的 塊表達式,Handlebars 會創建一個新視圖。
因為 Ember 只把這些視圖用于內部簿記,它們對于視圖的公共 parentView
和 childViews
API 是隱藏的。公共視圖層級只反射用 {{view}}
輔助標記或通過 ContainerView
創建的視圖(見下)。
例如,考慮下面的 Handlebars 模板:
<h2>Joe's Lamprey Shack</h2> {{controller.restaurantHours}} {{#view App.FDAContactForm}} 如果你在喬的七鰓鰻小屋用餐后不適,請用下面的表格向 FDA 提交申訴。 {{#if controller.allowComplaints}} {{view Ember.TextArea valueBinding="controller.complaint"}} <button {{action submitComplaint}}>提交</button> {{/if}} {{/view}}
渲染這個模板會創建這樣的層級:
幕后,Ember 跟蹤為 Handlebars 表達式創建的額外的虛擬視圖:
在TextArea
中, parentView
會指向 FDAContactForm
,并且 FDAContactForm
的 childViews
會是一個只包含 TextArea
的數組。
你可以通過 _parentView
和 _childViews
來查看內部視圖層級,這會包含虛擬視 圖:
var _childViews = view.get('_childViews'); console.log(_childViews.objectAt(0).toString()); //> <Ember._HandlebarsBoundView:ember1234>
警告! 你不應該在應用代碼中依賴于這些內部 API。它們會在任何時候更改并且 沒有任何公共合約。返回值也不能被觀察或被綁定。它可能不是 Ember 對象。如果覺 得有使用它們的需求,請聯系我們,這樣我們可以為你的使用需求暴露一個更好的公共 API。
底線:這個 API 就像是 XML。如果你覺得你需要用到它,那么你很可能沒有足夠理解 問題。三思!
事件冒泡
視圖的一個任務是響應原始用戶事件并把它們翻譯成對你應用而言有語義的事件。
例如,一個刪除按鈕把原始的 click
事件翻譯成應用特定的“把這個元素從數組中刪 除”。
為了響應用戶事件,創建一個視圖的子類來把事件實現為方法:
App.DeleteButton = Ember.View.create({ click: function(event) { var stateManager = this.getPath('controller.stateManager'); var item = this.get('content'); stateManager.send('deleteItem', item); } });
當你創建一個新的 Ember.Application
實例,它用 jQuery 的事件委派 API 給每個 原生瀏覽器事件注冊一個事件處理器。當用戶觸發一個事件,應用事件分配器會找出離 事件最近的視圖并實現那個事件。
一個視圖通過定義與事件同名的方法來實現事件。當事件名稱由多個詞組成(如 mouseup
)方法名會用 Camel 命名法把事件名作為方法名( mousUp
)。
事件會在視圖層級中冒泡,直到事件到達根視圖。一個事件處理器可以用與常規 jQuery 事件處理器相同的技術來停止事件傳播:
在視圖中 return false
event.stopPropagation
例如,假設你已經定義了如下的視圖類:
App.GrandparentView = Ember.View.extend({ click: function() { console.log('Grandparent!'); } }); App.ParentView = Ember.View.extend({ click: function() { console.log('Parent!'); return false; } }); App.ChildView = Ember.View.extend({ click: function() { console.log('Child!'); } });
這是使用它們的 Handlebars 模板。
{{#view App.GrandparentView}} {{#view App.ParentView}} {{#view App.ChildView}} <h2>點擊這里!</h2> {{/view}} {{/view}} {{/view}}
如果你點擊 <h2>
,你會在瀏覽器控制臺里看見下面的輸出:
Child! Parent!
你可以看出 Ember 在接受事件的最深層級視圖上調用了處理器。事件繼續上浮到 ParentView
,但不會到達 GrandparentView
因為 ParentView
從它的事件處理 器中返回了 false
。
你可以使用常規事件冒泡技術來實現常見的模式。例如,你可以實現一個帶有 submit
方法的 FormView
。因為瀏覽器在用戶向文本域輸入回車的時候會觸發 submit
事件,在表單視圖上定義一個 submit
方法會“剛好完成任務”。
App.FormView = Ember.View.extend({
tagName: "form",
submit: function(event) {
// 會在任何用戶觸發瀏覽器的
// `submit` 方法時被調用
}
});
{{#view App.FormView}} {{view Ember.TextFieldView valueBinding="controller.firstName"}} {{view Ember.TextFieldView valueBinding="controller.lastName"}} <button type="submit">確定</button> {{/view}}
添加新事件
Ember 內置了如下原生瀏覽器事件的支持:
事件名 | 方法名 |
---|---|
touchstart | touchStart |
touchmove | touchMove |
touchend | touchEnd |
touchcancel | touchCancel |
keydown | keyDown |
keyup | keyUp |
keypress | keyPress |
mousedown | mouseDown |
mouseup | mouseUp |
contextmenu | contextMenu |
click | click |
dblclick | doubleClick |
mousemove | mouseMove |
事件名 | 方法名 |
---|---|
focusin | focusIn |
focusout | focusOut |
mouseenter | mouseEnter |
mouseleave | mouseLeave |
submit | submit |
change | change |
dragstart | dragStart |
drag | drag |
dragenter | dragEnter |
dragleave | dragLeave |
dragover | dragOver |
drop | drop |
dragend | dragEnd |
當你創建一個新應用時,你可以向事件分配器添加額外的事件:
App = Ember.Application.create({ customEvents: { // 添加 loadedmetadata 媒體播放器事件 'loadedmetadata': "loadedMetadata" } });
要使這能對自定義事件奏效,HTML5 規范必須定義事件為“bubbling”,否則 jQuery 必 須為這個事件提供一個事件委派折中方案。
模板化視圖
如同迄今你在本指導中所見,你在應用中會用的大多數視圖是依靠模板的。當使用模板 時,你不需要編寫你的視圖層級,因為模板會為你創建它。
渲染時,視圖模板可以把視圖附加到它的子視圖數組中。模板的 {{view}}
輔助標記 內部會調用視圖的 appendChild
方法。
調用 appendChild
會做兩件事:
把視圖添加到 childViews
數組。
立即渲染子視圖并把它添加到父視圖的渲染緩沖區。
你不應該在視圖離開渲染狀態后調用 appendChild
。模板渲染出“混合內容”(包含 視圖和純文本),所以當渲染過程完成后,父視圖不知道到底把新的子視圖插入到哪 里。
在上例中,想象試圖把一個新視圖插入到父視圖的 childViews
數組中。它應該立即 放在 App.MyView
的閉合標簽 </div>
后?還是在整個視圖的閉合標簽 </div>
后?這個答案不總是正確的。
因為這種含糊性,創建視圖層級的唯一方法就是用模板的 {{view}}
輔助標記,它總 是把視圖插入到相對任何純文本的正確位置。
雖然這個機制對大多數情景奏效,偶爾你也會想要直接程序控制一個視圖的子視圖。在 這種情況下,你可以用 Ember.ContainerView
,它顯式地暴露了實現此目的的 API。
容器視圖
容器視圖不包含純文本。它們完全由子視圖(可能依靠模板)構成。
ContainerView
暴露兩個用于修改本身內容的公共 API:
一個可寫的 childViews
數組,你可以把 Ember.View
實例插入到其中。
一個 currentView
屬性,設置時會把新值插入到子視圖數組。如果存在早先的 currentView
值,它會被從 childViews
數組刪除。
這里是一個用 childViews
API 創建新視圖的例子,由假想的 DescriptionView
開始,并可以在任何時候用 addButton
方法添加一個新按鈕:
App.ToolbarView = Ember.ContainerView.create({ init: function() { var childViews = this.get('childViews'); var descriptionView = App.DescriptionView.create(); childViews.pushObject(descriptionView); this.addButton(); return this._super(); }, addButton: function() { var childViews = this.get('childViews'); var button = Ember.ButtonView.create(); childViews.pushObject(button); } });
如你在上例中所見,我們以兩個視圖初始化 ContainerView
,并且可以在運行時添 加額外的視圖。存在一個方便的捷徑來設置視圖,而不用覆蓋 init
方法:
App.ToolbarView = Ember.ContainerView.create({ childViews: ['descriptionView', 'buttonView'], descriptionView: App.DescriptionView, buttonView: Ember.ButtonView, addButton: function() { var childViews = this.get('childViews'); var button = Ember.ButtonView.create(); childViews.pushObject(button); } });
如上,當用這個速記方法時,你把 childViews
指定為一個字符串數組。在初始化 時,每個字符串會作為在查找視圖實例或類的關鍵字。那個視圖會被自動實例化,如果 必要,會加入到 childViews
數組中。
{{#if controller.isAuthenticated}} <h2>歡迎 {{controller.name}}</h2> {{/if}} {{#with controller.user}} <p>你有 {{notificationCount}} 條通知。</p> {{/with}}
在上面的模板中,當 isAuthenticated
屬性從 false
變為 true
時,Ember 會 重新渲染這個塊,用原始的外部作用域作為它的上下文。
{{#with}}
輔助標記把它的塊的上下文修改為當前控制器的 user
屬性。當 user
屬性被修改。Ember 重新渲染塊,并用 controller.user
的新值作為它的上 下文。
視圖作用域
除了 Handlebars 上下文,Ember 中的模板也有當前視圖的概念。無論當前上下文是什 么, view
屬性總是引用到最近的視圖。
注意 view
屬性不會引用由 {{#if}}
之類的塊表達式創建的內部視圖。這允許你 區分 Handlebars 上下文,在 Handlebars 中和在視圖層級中的工作方式是一樣的。
因為 view
指向一個 Ember.View
實例,你可以用 view.propertyName
之類的 表達式訪問視圖上的任何屬性。你可以用 view.parentView
訪問視圖的父視圖。
例如,想象你有一個帶有如下屬性的視圖:
App.MenuItemView = Ember.View.create({ templateName: 'menu_item_view', bulletText: '*' });
……和下面的模板:
{{#with controller}} {{view.bulletText}} {{name}} {{/with}}
盡管 Handlebars 上下文已經變為當前的控制器,你仍然可以用 view.bulletText
訪問視圖的 bulletText
。
模板變量
迄今為止,我們已經在 Handlebars 模板中邂逅了 controller
屬性。它是從哪來的呢?
Ember 中的 Handlebars 上下文可以繼承它們的父上下文中的變量。在 Ember 在當前 上下文中查找變量之前,它首先檢查它的模板變量。當一個視圖創建了一個新的 Handlebars 作用域,它們自動繼承它們父作用域的變量。
Ember 定義了這些 view
和 controller
變量,所以當一個表達式使用 view
或 controller
變量名,它們總是最先被找到。
如上所述,Ember 設置了 Handlebars 上下文中的 view
變量,無論何時模板中使用 了 {{#view}}
輔助標記。起初,Ember 把 view
變量設置為正在渲染模板的視 圖。
Ember 設置了 Handlebars 上下文中的 controller
變量,無論已渲染的視圖是否存 在 controller
屬性。如果視圖沒有 controller
屬性,它從時間上最近的擁有該 屬性的視圖上繼承 controller
變量。
其它變量
Ember 中的 Handlebars 輔助標記也會指定變量。例如, {{#with controller.person as tom}}
形式指定一個 tom
變量,它的后代作用域 是可訪問的。即使一個子上下文有 tom
屬性,這個 tom
變量會廢除它。
這個形式的最大好處是,它允許你簡寫長路徑,而不喪失對父作用域的訪問權限。
在 {{#each}}
輔助標記中,提供 {{#each person in people}}
形式尤其重要。 在這個形式中,后代上下文可以訪問 person
變量,但在模板調用 each
的地方 保留相同的作用域。
{{#with controller.preferences}} <h2>Title</h2> <ul> {{#each person in controller.people}} {{! prefix here is controller.preferences.prefix }} <li>{{prefix}}: {{person.fullName}}</li> {{/each}} <ul> {{/with}}
注意這些變量繼承了 ContainerView
中的那些,即使它們不是 Handlebars 上下文 層級中的一部分。
從視圖中訪問模板變量
在大多數情況下,你會需要從模板中訪問這些模板變量。在一些不尋常的情景下,你會 想要在視圖的 JavaScript 代碼中訪問范圍內的變量。
你可以訪問視圖的 templateVariables
屬性來達成此目的,它會返回一個包含當視 圖渲染后存在于其作用于的變量的 JavaScript 對象。 ContainerView
也可以訪問 這個屬性,它指向時間上最近的模板依賴的視圖的模板變量。
目前,你不能觀察或綁定一個包含 templateVariables
的路徑。
感謝各位的閱讀,以上就是“Ember.js的視圖層分析”的內容了,經過本文的學習后,相信大家對Ember.js的視圖層分析這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。