精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Ember.js 的視圖層

開發 前端
本指導會詳盡闡述 Ember.js 視圖層的細節。為想成為熟練 Ember 開發者準備,且包 含了對于入門 Ember 不必要的細節。

本指導會詳盡闡述 Ember.js 視圖層的細節。為想成為熟練 Ember 開發者準備,且包 含了對于入門 Ember 不必要的細節。

Ember.js 有一套復雜的用于創建、管理并渲染連接到瀏覽器 DOM 上的層級視圖的系 統。視圖負責響應諸如點擊、拖拽以及滾動等的用戶事件,也在視圖底層數據變更時更 新 DOM 的內容。

視圖層級通常由求值一個 Handlebars 模板創建。當模板求值后,會添加子視圖。當 那些 子視圖求值后,會添加它們的子視圖,如此遞推,直到整個層級被創建。

即使你并沒有在 Handlebars 模板中顯式地創建子視圖,Ember.js 內部仍使用視圖系 統更新綁定的值。例如,每個 Handlebars 表達式 {{value}} 幕后創建一個視圖, 這個視圖知道當值變更時如何更新綁定值。

你也可以在應用運行時用 Ember.ContainerView 類對視圖層級做出修改。一個容器 視圖暴露一個可以手動修改的子視圖實例數組,而非模板驅動。

視圖和模板串聯工作提供一套用于創建任何你夢寐以求的用戶界面的穩健系統。最終用 戶應從諸如當渲染和事件傳播是的計時事件之類的復雜東西中隔離開。應用開發者應可 以一次性把他們的 UI 描述成 Handlebars 標記字符串,然后繼續完成他們的應用,而 不必煩惱于確保它一直是最新的。

它解決了什么問題?

子視圖

在典型的客戶端應用中,視圖同時在本身和 DOM 中表示嵌套的元素。在解決這個問題 的天真方案中,獨立的視圖對象表示單個 DOM 元素,專門的引用解決不同種類的視圖 保持對概念中嵌套在它們內部的視圖的跟蹤。

這里是一個簡單的例子,表示一個應用主視圖,里面有一集合嵌套視圖,且獨立的元素在集合內嵌套。

 

 這個系統第一眼看上去毫無異樣,但是想象我們要在上午 8 點而不是上午 9 點開放喬 的七鰓鰻小屋。在這種情況下,我們會想要重新渲染應用視圖。因為開發者需要構建指 向在一個特殊基礎上的子視圖的引用,這個重渲染過程存在若干問題。

為了重新渲染應用視圖,應用視圖也必須手動重新渲染子視圖并重新把它們插入到應用 視圖的元素中。如果實現得完美,這個過程會正常工作,但它依賴于一個完美的,專門 的視圖層級實現。如果任何一個視圖沒有精確地實現它,整個重新渲染過程會失敗。

為了避免這些問題,Ember 的視圖層級從概念上就帶有子視圖的烙印。 

  

 當應用時圖重新渲染時,Ember 而不是應用代碼負責重新渲染并插入子視圖。這也意味 著 Ember 可以為你執行任何內存管理,比如清理觀察者和綁定。

這不僅在一定程度上消滅了樣板代碼,也破除了有瑕疵的視圖層級實現帶來的未期失敗的可能。

#p#

事件委派

在過去,web 開發者已經用在獨立的單個元素上添加事件監聽器來獲知什么時候用戶與 它們交互。例如,你會有一個 <div> 元素,其上注冊了一個當用戶點擊它時觸發的 函數。

盡管如此,這個途徑在處理大數量交互元素上不會縮放。比如,想象一個帶有 100 個 <li><ul> ,每個項目后都有一個刪除按鈕。既然所有的這些項目行為都是一 致的,為每個刪除按鈕創建共計 100 個事件監聽器無疑是低效的。   

 

 

 

 

 

 

 

 要解決這個問題,開發者發現了一種名為“事件委派”的技術。你可以在容器元素上注冊 一個監聽器并使用 event.target 來識別哪個元素是用戶點擊的,而不是為問題中的 每個項目創建一個監聽器。

 

 

 

 

 

 

實現這有一些微妙,因為一些事件(比如 focusblurchange )不會冒 泡。幸運的是,jQuery 已經徹底解決了這個問題;用 jQuery 的 on 方法可以可靠 地處理所有原生瀏覽器事件。

其它 JavaScript 框架用兩種方法中的其一來處理這個問題。第一種是,它們要你自己 實現原生解決方案,為每個項目創建獨立的視圖。當你創建視圖,它在視圖的元素上設 置一個監聽器。如果你有一個含有 500 個項目的列表,你會創建 500 個視圖并且每個 視圖都會在它自己的元素上設置一個監聽器。

第二種方法是,框架在視圖層內置事件委派。當創建一個視圖,你可以提供一個事件列 表來在事件發生時委派一個方法來調用。這只剩下識別接受事件的方法的點擊上下文 (比如,列表中的哪個項目)。

你現在要面對兩個令人不安的選擇:為每個項目創建一個新視圖,這樣會喪失事件委派 的優勢,或是為所有項目創建單個視圖,這樣必須存儲 DOM 中底層 JavaScript 的信息。

要解決這個問題,Ember 用 jQuery 把所有事件委派到應用的根元素(通常是文檔的 body )。當一個事件發生,Ember 識別出最近的處理事件視圖并調用它的事件處理 器。這意味著你可以創建視圖來保存一個 JavaScript 上下文,但仍然從事件委派上受 益。

進一步地,因為 Ember 只為整個 Ember 應用注冊一個事件,創建新視圖永遠都不需要 設置事件監聽器,這使得重渲染高效且免于出錯。當視圖有一個子視圖,這也意味著不 需要手動取消委派重新渲染過程中替換掉的視圖。

渲染管道

大多數 web 應用用特殊的模板語言標記來指定它們的用戶界面。對于 Ember.js,我們 已經完成用可在值修改的時候自動更新模板的 Handlebars 模板語言來編寫模板。

雖然顯示模板的過程對開發者是自動的,但其遮蓋了把原始模板轉換為最終模板、生成 用戶可見的 DOM 表示的一系列必要步驟。

這是 Ember 視圖的近似生命周期: 

 

 

 

 

 

1. 模板編譯

應用的模板通過網絡加載或以字符串形式作為應用的載荷。當應用加載時,它發送模板 字符串到 Handlebars 來編譯成函數。一經編譯,模板函數會被保存,且可以被多個視 圖重復使用,每次都它們都需重新編譯。

這個步驟會在應用中服務器預編譯模板的地方發出。在那些情況下,模板不作為原始的 人類可讀的模板傳輸,而是編譯后的代碼。

因為 Ember 負責模板編譯,你不需要做任何額外的工作來保證編譯后的模板可以重用。

#p#

2. 字符串的連接

當應用在視圖上調用 appendappendTo 時,一個視圖渲染過程會被啟動。 appendappendChild 調用 安排 視圖渲染并在之后插入。這允許應用中的 延遲邏輯(譬如綁定同步)在渲染元素之前執行。

要開始渲染過程,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 為這些塊輔助標創建虛擬的視圖。這些虛擬的視圖不會出現在公共可訪問的視圖層級里 (當從視圖獲取 parentViewchildViews 時),但它們的存在啟用了一致的重 渲染。

當傳遞到 {{#if}}{{#with}} 的路徑變更,Ember 自動重新渲染虛擬視圖替換 它的內容,重要的是,也會銷毀所有的子視圖來釋放內存。

除了這些情景,應用有時也會要顯式地重新渲染視圖(通常是一個 ContainerView ,見下)。在這種情況下,應用可以直接調用 rerender ,且 Ember 會把一項重渲染工作加入隊列,用相同的語義元素。

這個過程像是這樣:

 

 

  #p#

視圖層級

父與子

當 Ember 渲染一個模板化的視圖,它會生成一個視圖層級。讓我們假設已有一個模板 form

原文鏈接:

  1. {{view App.Search placeholder="Search"}} 
  2. {{#view Ember.Button}}Go!{{/view}} 

然后我們像這樣把它插入到 DOM 中:

  1. var view = Ember.View.create({ 
  2.   templateName: 'form' 
  3. }).append(); 

這會創建一個如下小巧的視圖等級:  

 

 

 

你可以用 parentViewchildViews 屬性在視圖層級中游走。

  1. var children = view.get('childViews') // [ <App.Search><Ember.Button> ] 
  2. children.objectAt(0).get('parentView') // 視圖 

一個常見的 parentView 使用方法是在子視圖的實例里。

  1. App.Search = Ember.View.extend({ 
  2.   didInsertElement: function() { 
  3.     // this.get('parentView') 指向 `view` 
  4.   } 
  5. }) 

生命周期鉤子

為了容易地在視圖的生命周期的不同點上執行行為,有若干你可以實現的鉤子。

  • willInsertElement: 這個鉤子在視圖渲染后插入 DOM 之前調用。它不提供對視圖的 element 的訪問。
  • didInsertElement: 這個鉤子在視圖被插入到 DOM 后立即調用。它提供到視圖的 element 的訪問,且對集成到外部庫非常有用。任何顯式的 DOM 設置代碼應限于這個鉤子。
  • willDestroyElement: 這個鉤子在元素從 DOM 移除前立即調用。這提供了銷毀任何與 DOM 節點關聯的外部狀態的機會。像 didInsertElement 一樣,它對于集成外部庫非常有用。
  • willRerender: 這個鉤子在視圖被重新渲染前立即調用。如果你想要在視圖被重新渲染前執行一些銷毀操作,這會很有用。
  • becameVisible: 這個鉤子在視圖的 isVisible 或它的祖先之一的 isVisible變為真值,且關聯的元素也變為可見后調用。注意這個鉤子只在所有可見性由 isVisible 屬性控制的時候可靠。
  • becameHidden: 這個鉤子在視圖的 isVisible 或它的祖先之一的 isVisible變為假值,且關聯的元素也變為隱藏后調用。注意這個鉤子只在所有可見性由 isVisible 屬性控制的時候可靠。

應用可以通過在視圖上定義一個與鉤子同名的方法來實現鉤子?;蛘?,在視圖上為鉤子 注冊一個監聽器也是可行的。

  1. view.on('willRerender', function() { 
  2.   // do something with view 
  3. }); 

虛擬視圖

正如上文所述,Handlebars 在視圖層級內創建視圖來表現綁定值。每次你使用 Handlebars 表達式,無論是一個簡單值還是一個諸如 {{#with}}{{#if}} 的 塊表達式,Handlebars 會創建一個新視圖。

因為 Ember 只把這些視圖用于內部簿記,它們對于視圖的公共 parentViewchildViews API 是隱藏的。公共視圖層級只反射用 {{view}} 輔助標記或通過 ContainerView 創建的視圖(見下)。

例如,考慮下面的 Handlebars 模板:

  1. <h1>Joe's Lamprey Shack</h1> 
  2. {{controller.restaurantHours}} 
  3. {{#view App.FDAContactForm}} 
  4.   如果你在喬的七鰓鰻小屋用餐后不適,請用下面的表格向 FDA 提交申訴。 
  5.   {{#if controller.allowComplaints}} 
  6.     {{view Ember.TextArea valueBinding="controller.complaint"}} 
  7.     <button {{action submitComplaint}}>提交</button> 
  8.   {{/if}} 
  9. {{/view}} 

渲染這個模板會創建這樣的層級:  

 

 

 幕后,Ember 跟蹤為 Handlebars 表達式創建的額外的虛擬視圖:  

 

 

 

 #p#

TextArea 中, parentView 會指向 FDAContactForm ,并且 FDAContactFormchildViews 會是一個只包含 TextArea 的數組。

你可以通過 _parentView_childViews 來查看內部視圖層級,這會包含虛擬視 圖:

  1. var _childViews = view.get('_childViews'); 
  2. console.log(_childViews.objectAt(0).toString()); 
  3. //> <Ember._HandlebarsBoundView:ember1234> 

警告! 你不應該在應用代碼中依賴于這些內部 API。它們會在任何時候更改并且 沒有任何公共合約。返回值也不能被觀察或被綁定。它可能不是 Ember 對象。如果覺 得有使用它們的需求,請聯系我們,這樣我們可以為你的使用需求暴露一個更好的公共 API。

底線:這個 API 就像是 XML。如果你覺得你需要用到它,那么你很可能沒有足夠理解 問題。三思!

事件冒泡

視圖的一個任務是響應原始用戶事件并把它們翻譯成對你應用而言有語義的事件。

例如,一個刪除按鈕把原始的 click 事件翻譯成應用特定的“把這個元素從數組中刪 除”。

為了響應用戶事件,創建一個視圖的子類來把事件實現為方法:

  1. App.DeleteButton = Ember.View.create({ 
  2.   click: function(event) { 
  3.     var stateManager = this.getPath('controller.stateManager'); 
  4.     var item = this.get('content'); 
  5.     stateManager.send('deleteItem', item); 
  6.   } 
  7. }); 

當你創建一個新的 Ember.Application 實例,它用 jQuery 的事件委派 API 給每個 原生瀏覽器事件注冊一個事件處理器。當用戶觸發一個事件,應用事件分配器會找出離 事件最近的視圖并實現那個事件。

一個視圖通過定義與事件同名的方法來實現事件。當事件名稱由多個詞組成(如 mouseup )方法名會用 Camel 命名法把事件名作為方法名( mousUp )。

事件會在視圖層級中冒泡,直到事件到達根視圖。一個事件處理器可以用與常規 jQuery 事件處理器相同的技術來停止事件傳播:

  • 在視圖中 return false
  • event.stopPropagation

例如,假設你已經定義了如下的視圖類:

  1. App.GrandparentView = Ember.View.extend({ 
  2.   click: function() { 
  3.     console.log('Grandparent!'); 
  4.   } 
  5. }); 
  6. App.ParentView = Ember.View.extend({ 
  7.   click: function() { 
  8.     console.log('Parent!'); 
  9.     return false
  10.   } 
  11. }); 
  12. App.ChildView = Ember.View.extend({ 
  13.   click: function() { 
  14.     console.log('Child!'); 
  15.   } 
  16. }); 

這是使用它們的 Handlebars 模板。

  1. {{#view App.GrandparentView}} 
  2.   {{#view App.ParentView}} 
  3.     {{#view App.ChildView}} 
  4.       <h1>點擊這里!</h1> 
  5.     {{/view}} 
  6.   {{/view}} 
  7. {{/view}} 

如果你點擊 <h1> ,你會在瀏覽器控制臺里看見下面的輸出:

  1. Child! 
  2. Parent! 

你可以看出 Ember 在接受事件的最深層級視圖上調用了處理器。事件繼續上浮到 ParentView ,但不會到達 GrandparentView 因為 ParentView 從它的事件處理 器中返回了 false 。

你可以使用常規事件冒泡技術來實現常見的模式。例如,你可以實現一個帶有 submit 方法的 FormView 。因為瀏覽器在用戶向文本域輸入回車的時候會觸發 submit 事件,在表單視圖上定義一個 submit 方法會“剛好完成任務”。

  1. App.FormView = Ember.View.extend({ 
  2.   tagName: "form"
  3.   submit: function(event) { 
  4.     // 會在任何用戶觸發瀏覽器的 
  5.     // `submit` 方法時被調用 
  6.   } 
  7. });
  1. {{#view App.FormView}} 
  2.   {{view Ember.TextFieldView valueBinding="controller.firstName"}} 
  3.   {{view Ember.TextFieldView valueBinding="controller.lastName"}} 
  4.   <button type="submit">確定</button> 
  5. {{/view}} 

#p#

添加新事件

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

當你創建一個新應用時,你可以向事件分配器添加額外的事件:

  1. App = Ember.Application.create({ 
  2.   customEvents: { 
  3.     // 添加 loadedmetadata 媒體播放器事件 
  4.     'loadedmetadata'"loadedMetadata" 
  5.   } 
  6. }); 

要使這能對自定義事件奏效,HTML5 規范必須定義事件為“bubbling”,否則 jQuery 必 須為這個事件提供一個事件委派折中方案。

模板化視圖

如同迄今你在本指導中所見,你在應用中會用的大多數視圖是依靠模板的。當使用模板 時,你不需要編寫你的視圖層級,因為模板會為你創建它。

渲染時,視圖模板可以把視圖附加到它的子視圖數組中。模板的 {{view}} 輔助標記 內部會調用視圖的 appendChild 方法。

調用 appendChild 會做兩件事:

  1. 把視圖添加到 childViews 數組。
  2. 立即渲染子視圖并把它添加到父視圖的渲染緩沖區。

 

 

 

 

你不應該在視圖離開渲染狀態后調用 appendChild 。模板渲染出“混合內容”(包含 視圖和純文本),所以當渲染過程完成后,父視圖不知道到底把新的子視圖插入到哪 里。

 在上例中,想象試圖把一個新視圖插入到父視圖的 childViews 數組中。它應該立即 放在 App.MyView 的閉合標簽 </div> 后?還是在整個視圖的閉合標簽 </div> 后?這個答案不總是正確的。

因為這種含糊性,創建視圖層級的唯一方法就是用模板的 {{view}} 輔助標記,它總 是把視圖插入到相對任何純文本的正確位置。

雖然這個機制對大多數情景奏效,偶爾你也會想要直接程序控制一個視圖的子視圖。在 這種情況下,你可以用 Ember.ContainerView ,它顯式地暴露了實現此目的的 API。

#p#

容器視圖

容器視圖不包含純文本。它們完全由子視圖(可能依靠模板)構成。

ContainerView 暴露兩個用于修改本身內容的公共 API:

  • 一個可寫的 childViews 數組,你可以把 Ember.View 實例插入到其中。
  • 一個 currentView 屬性,設置時會把新值插入到子視圖數組。如果存在早先的 currentView 值,它會被從 childViews 數組刪除。

這里是一個用 childViews API 創建新視圖的例子,由假想的 DescriptionView 開始,并可以在任何時候用 addButton 方法添加一個新按鈕:

  1. App.ToolbarView = Ember.ContainerView.create({ 
  2.   init: function() { 
  3.     var childViews = this.get('childViews'); 
  4.     var descriptionView = App.DescriptionView.create(); 
  5.     childViews.pushObject(descriptionView); 
  6.     this.addButton(); 
  7.     return this._super(); 
  8.   }, 
  9.   addButton: function() { 
  10.     var childViews = this.get('childViews'); 
  11.     var button = Ember.ButtonView.create(); 
  12.     childViews.pushObject(button); 
  13.   } 
  14. }); 

如你在上例中所見,我們以兩個視圖初始化 ContainerView ,并且可以在運行時添 加額外的視圖。存在一個方便的捷徑來設置視圖,而不用覆蓋 init 方法:

  1. App.ToolbarView = Ember.ContainerView.create({ 
  2.   childViews: ['descriptionView''buttonView'], 
  3.   descriptionView: App.DescriptionView, 
  4.   buttonView: Ember.ButtonView, 
  5.   addButton: function() { 
  6.     var childViews = this.get('childViews'); 
  7.     var button = Ember.ButtonView.create(); 
  8.     childViews.pushObject(button); 
  9.   } 
  10. }); 

如上,當用這個速記方法時,你把 childViews 指定為一個字符串數組。在初始化 時,每個字符串會作為在查找視圖實例或類的關鍵字。那個視圖會被自動實例化,如果 必要,會加入到 childViews 數組中。  

 

          

  1. {{#if controller.isAuthenticated}} 
  2.   <h1>歡迎 {{controller.name}}</h1> 
  3. {{/if}} 
  4. {{#with controller.user}} 
  5.   <p>你有 {{notificationCount}} 條通知。</p> 
  6. {{/with}} 

在上面的模板中,當 isAuthenticated 屬性從 false 變為 true 時,Ember 會 重新渲染這個塊,用原始的外部作用域作為它的上下文。

{{#with}} 輔助標記把它的塊的上下文修改為當前控制器的 user 屬性。當 user 屬性被修改。Ember 重新渲染塊,并用 controller.user 的新值作為它的上 下文。

#p#

視圖作用域

除了 Handlebars 上下文,Ember 中的模板也有當前視圖的概念。無論當前上下文是什 么, view 屬性總是引用到最近的視圖。

注意 view 屬性不會引用由 {{#if}} 之類的塊表達式創建的內部視圖。這允許你 區分 Handlebars 上下文,在 Handlebars 中和在視圖層級中的工作方式是一樣的。

因為 view 指向一個 Ember.View 實例,你可以用 view.propertyName 之類的 表達式訪問視圖上的任何屬性。你可以用 view.parentView 訪問視圖的父視圖。

例如,想象你有一個帶有如下屬性的視圖:

  1. App.MenuItemView = Ember.View.create({ 
  2.   templateName: 'menu_item_view'
  3.   bulletText: '*' 
  4. }); 

……和下面的模板:

  1. {{#with controller}} 
  2.   {{view.bulletText}} {{name}} 
  3. {{/with}} 

盡管 Handlebars 上下文已經變為當前的控制器,你仍然可以用 view.bulletText 訪問視圖的 bulletText 。

模板變量

迄今為止,我們已經在 Handlebars 模板中邂逅了 controller 屬性。它是從哪來的呢?

Ember 中的 Handlebars 上下文可以繼承它們的父上下文中的變量。在 Ember 在當前 上下文中查找變量之前,它首先檢查它的模板變量。當一個視圖創建了一個新的 Handlebars 作用域,它們自動繼承它們父作用域的變量。

Ember 定義了這些 viewcontroller 變量,所以當一個表達式使用 viewcontroller 變量名,它們總是最先被找到。

如上所述,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 的地方 保留相同的作用域。

  1. {{#with controller.preferences}} 
  2.   <h1>Title</h1> 
  3.   <ul> 
  4.   {{#each person in controller.people}} 
  5.     {{! prefix here is controller.preferences.prefix }} 
  6.     <li>{{prefix}}: {{person.fullName}}</li> 
  7.   {{/each}} 
  8.   <ul> 
  9. {{/with}} 

注意這些變量繼承了 ContainerView 中的那些,即使它們不是 Handlebars 上下文 層級中的一部分。

從視圖中訪問模板變量

在大多數情況下,你會需要從模板中訪問這些模板變量。在一些不尋常的情景下,你會 想要在視圖的 JavaScript 代碼中訪問范圍內的變量。

你可以訪問視圖的 templateVariables 屬性來達成此目的,它會返回一個包含當視 圖渲染后存在于其作用于的變量的 JavaScript 對象。 ContainerView 也可以訪問 這個屬性,它指向時間上最近的模板依賴的視圖的模板變量。

目前,你不能觀察或綁定一個包含 templateVariables 的路徑。

原文鏈接:http://emberjs.torriacg.org/guides/view_layer/#toc_

 

責任編輯:陳四芳 來源: emberjs.torriacg.org
相關推薦

2013-12-24 11:11:27

ember.jsJavascript

2013-12-24 15:56:20

2013-12-24 14:50:39

Ember.js框架

2013-12-20 14:47:23

ember.js

2013-09-10 14:01:40

WebEmber.jsAngular.js

2016-11-14 15:51:42

JavaScriptAngular.jsReact.js

2013-10-16 10:11:35

JavaScript項目框架

2014-03-13 11:22:00

JavaScriptJS框架

2013-12-25 09:53:22

Ember.js應用

2013-12-25 10:08:42

ember.js異步處理

2013-12-24 13:20:28

EmberEmber.js

2013-05-30 15:16:26

javaScriptMVC模式

2021-11-29 00:17:41

JS符串轉換

2024-04-09 16:19:16

2015-02-09 10:43:00

JavaScript

2023-03-15 08:03:31

2021-12-24 15:46:23

鴻蒙HarmonyOS應用

2010-07-19 09:31:53

SQL Server系

2010-11-16 10:42:45

Oracle創建視圖

2010-11-12 11:19:19

SQL Server視
點贊
收藏

51CTO技術棧公眾號

一区二区三区在线看| 久久国产尿小便嘘嘘| 亚洲成人精品视频在线观看| 日韩网站在线免费观看| 男女污视频在线观看| 日本不卡视频在线观看| 欧美成人午夜免费视在线看片 | 久久国产视频网| 欧美激情第一页xxx| 3d动漫精品啪啪一区二区下载 | 欧美日韩高清在线| 免费特级黄色片| 成人欧美亚洲| 国产91露脸合集magnet| 国产精品流白浆视频| 久草视频在线资源站| 少妇精品久久久| 日韩西西人体444www| 日韩福利视频在线| 超碰在线中文字幕| 亚洲女人****多毛耸耸8| 韩国成人动漫在线观看| 国产人妖在线播放| 秋霞午夜鲁丝一区二区老狼| 久久免费视频在线| 一区二区三区在线播放视频| 欧美一区二区三区红桃小说| 欧美一级免费观看| mm131国产精品| 日韩电影免费观看高清完整版| 一区二区三区波多野结衣在线观看 | 中文字幕欧美日韩va免费视频| 中文字幕人妻无码系列第三区| 四虎成人在线| 一本久久a久久免费精品不卡| 精品人妻大屁股白浆无码| 69av在线| 中文字幕在线一区| 亚洲mv在线看| 国产女主播在线直播| 91丨九色丨蝌蚪丨老版| 成人av免费在线看| 午夜精品久久久久久久91蜜桃| 美女视频黄久久| 国产精品成人一区| 中文字幕在线观看视频免费| 国产一区二区三区成人欧美日韩在线观看 | 最新在线黄色网址| 美国成人xxx| 欧美精品一区二区在线观看| 在线视频日韩欧美| 玖玖玖视频精品| 日韩一区二区三区电影在线观看| 粉色视频免费看| 色噜噜成人av在线| 555夜色666亚洲国产免| 九九久久久久久| 国产精品va视频| 日韩欧美激情在线| 在线中文字日产幕| 国产欧美一区二区三区米奇| 亚洲成年人在线| 亚洲av网址在线| 国产毛片一区二区三区| 中国china体内裑精亚洲片| 欧美偷拍一区二区三区| 波多野结衣一区| 日韩视频第一页| 欧美三级小视频| 亚洲国产91| 91成人国产在线观看| 天堂网中文字幕| 美女任你摸久久| 1卡2卡3卡精品视频| 亚洲国产精品成人久久蜜臀| 不卡一二三区首页| 日本三级中国三级99人妇网站| 成人18在线| 亚洲精品高清在线观看| 精品少妇一区二区三区在线| 全球最大av网站久久| 欧美放荡的少妇| 欧美性生交xxxxx| 伊人精品一区| 不卡中文字幕av| 日本熟女一区二区| 热久久一区二区| 99在线国产| 国内精品在线视频| 亚洲乱码国产乱码精品精可以看 | 国产视频网站一区二区三区| 亚洲高清在线观看| 18精品爽国产三级网站| 激情久久一区| 国产精品一区二区三区久久| 亚洲xxx在线| 国产婷婷色一区二区三区四区| 国产高清免费在线| 中文字幕在线中文字幕在线中三区| 欧美午夜精品免费| 日本不卡视频一区| 久久亚洲国产| 77777少妇光屁股久久一区| 在线观看中文字幕网站| 99精品视频一区二区| 中文字幕乱码一区二区三区| 福利小视频在线| 欧美日韩激情一区二区| a视频免费观看| 欧美一区国产在线| 国产精品久久久久久久久久三级 | 青青草国产一区二区三区| 欧美精品一区二区三区很污很色的 | 免费观看国产精品视频| 亚洲伦理久久| 亚洲欧美综合v| 精品91久久久| 国产精品白丝jk黑袜喷水| 日本在线高清视频一区| 国产一二在线播放| 精品国产一区久久| 国产探花在线播放| 蜜桃视频一区二区三区在线观看| 九九久久99| 欧美野外wwwxxx| 欧美高清dvd| 亚洲图片第一页| 天堂va蜜桃一区二区三区| 好看的日韩精品| 日韩另类在线| 日韩一本二本av| 国产午夜精品理论片在线| 日韩电影免费一区| 久久久精彩视频| www555久久| 精品国产亚洲一区二区三区在线观看| 女人18毛片毛片毛片毛片区二| 久久久噜噜噜| 欧美精品二区三区四区免费看视频 | 亚洲影视在线播放| 深夜做爰性大片蜜桃| 亚州av乱码久久精品蜜桃| 国产美女直播视频一区| porn亚洲| 欧美高清激情brazzers| 成人在线观看高清| 国产一区二区看久久| 午夜在线视频免费观看| 国产日韩中文在线中文字幕| 久久这里有精品| 亚洲av无码一区二区三区dv| 亚洲图片欧美综合| 人妻av一区二区| 久久不射2019中文字幕| 欧美日韩最好看的视频| 成人免费网站www网站高清| 国产一区二区动漫| 中文字幕在线观看高清| 国产精品久久精品日日| 日本77777| 欧美日韩天堂| 精品免费国产| 精品日韩视频| 北条麻妃一区二区三区中文字幕 | 亚洲精品动漫100p| 日韩黄色在线播放| 国产欧美视频在线观看| 久久久久久久久久一区二区| 午夜视频一区| 老司机精品福利在线观看| 日韩影片中文字幕| 最近日韩中文字幕中文| 国产男女猛烈无遮挡| 亚洲综合色视频| 爱爱的免费视频| 美女视频网站黄色亚洲| 99视频精品全部免费看| 日本妇女一区| 国产欧美va欧美va香蕉在线| 午夜激情在线| 亚洲欧美日韩一区二区在线| 国产精品国产三级国产aⅴ| 亚洲国产精品精华液网站| 国产精品毛片一区二区| 精一区二区三区| 青青草精品视频在线| 成人精品视频| 国产精品久久久久久久久久久久午夜片 | 一本色道久久综合亚洲91| 尤物在线免费视频| 99国产精品国产精品久久| 牛夜精品久久久久久久| 欧美日韩一卡| 日韩一区免费观看| 国产劲爆久久| 成人黄色在线观看| 日韩精品极品| 久久精品人人做人人爽| 欧美xxx.com| 日韩欧美国产电影| 国产精品无码粉嫩小泬| 亚洲一区国产视频| 欧美成人短视频| 97成人超碰视| 人妻巨大乳一二三区| 日本欧洲一区二区| aa在线观看视频| 自拍偷拍欧美| 亚洲视频电影| 国产一区二区三区不卡视频网站| 99高清视频有精品视频| 免费在线成人激情电影| 午夜精品久久久久久久99黑人 | 久久美女精品| 欧美成ee人免费视频| 大奶在线精品| 91入口在线观看| 激情中国色综合| 日韩免费在线观看视频| av岛国在线| 欧美精品在线观看| 日韩毛片久久久| 夜夜嗨av色一区二区不卡| 亚洲欧美综合在线观看| 精品国产电影一区二区| 99久久久国产精品无码免费| 欧美亚洲国产一区在线观看网站| 日本特级黄色片| 午夜国产不卡在线观看视频| 中文字幕手机在线观看| 中文字幕一区二区不卡| 中文字幕av久久爽一区| 久久午夜老司机| 久久久久国产精品区片区无码| 成人高清av在线| 国产ts在线观看| 成人激情av网| 国产一线在线观看| 99久久99久久综合| 北京富婆泄欲对白| 成人国产精品免费观看| xxxxwww一片| 成人在线视频一区二区| 又色又爽又黄18网站| 成人免费黄色在线| 一级少妇精品久久久久久久| 成人在线综合网| 久久久久成人精品无码中文字幕| 成人黄页在线观看| 影音先锋黄色资源| 久久综合精品国产一区二区三区| aa一级黄色片| 国产日韩欧美电影| 日韩精品一区二区三区在线视频| 中文字幕一区二区三区av| 三级影片在线看| 亚洲一区二区三区四区在线| 国产精品23p| 福利二区91精品bt7086| 懂色av蜜臀av粉嫩av分享吧最新章节| 色综合网站在线| 中文文字幕一区二区三三| 欧美三级午夜理伦三级中视频| 国产一区二区自拍视频| 91麻豆精品国产| 人妻一区二区三区| 亚洲色图五月天| 黄色网址在线免费观看| 欧美激情一区二区久久久| 蜜桃麻豆影像在线观看| 国产福利视频一区| 精品精品视频| 韩国成人一区| 青草国产精品| 国产二区视频在线| 西西人体一区二区| 深夜黄色小视频| 风流少妇一区二区| 国产精品无码久久久久一区二区| 国产精品久久久久一区| 黄色小视频在线免费看| 在线观看亚洲a| www香蕉视频| 亚洲欧美国产日韩中文字幕| 麻豆传媒在线观看| 97av在线视频| 日韩一区二区三免费高清在线观看| 91沈先生播放一区二区| 国产精品一区二区av日韩在线 | 麻豆精品网站| 色婷婷综合在线观看| 久久品道一品道久久精品| 亚洲怡红院在线观看| 午夜视频在线观看一区二区| 欧美成人一区二区三区四区| 日韩三级在线免费观看| 欧美新色视频| 欧美高清在线播放| 开心久久婷婷综合中文字幕| 好吊色欧美一区二区三区视频 | 国产精品久久久久久久久免费樱桃| 永久免费看黄网站| 欧美视频一二三区| 亚洲 欧美 精品| 欧美成人在线影院| 成人精品电影在线| 国产精品免费区二区三区观看| 日韩免费av| 成年网站在线免费观看| 国产精品99久久久| 成人欧美一区二区三区黑人一 | 无人在线观看的免费高清视频| 国产成a人亚洲| 欧美性x x x| 欧美特级限制片免费在线观看| 天天操天天干天天插| 免费av一区二区| 日韩免费大片| 亚洲国产一区二区精品视频| 久久亚洲精品伦理| 性欧美丰满熟妇xxxx性久久久| 一区二区三区久久| 99国产精品欲| 久久久www成人免费精品| 成人国产网站| 欧美在线日韩精品| 国产亚洲亚洲| 国产白嫩美女无套久久| 五月天激情综合| 成人毛片在线精品国产| 欧美成人精品一区二区| av日韩在线免费观看| 在线成人性视频| 狠狠色狠狠色综合| 婷婷社区五月天| 欧美精品乱码久久久久久按摩| 成全电影播放在线观看国语| 国产精品成人久久久久| 欧美一级本道电影免费专区| 虎白女粉嫩尤物福利视频| 久久蜜桃av一区二区天堂| 欧美黑人一区二区| 亚洲欧美制服丝袜| 美女100%一区| 日韩欧美一区二区三区四区五区| 老司机午夜免费精品视频| 中文字幕第20页| 欧美日韩在线精品一区二区三区激情| av大全在线免费看| 成人激情视频在线| 欧美 日韩 国产 一区| 少妇极品熟妇人妻无码| 午夜国产精品影院在线观看| 视频国产在线观看| 国产精品99蜜臀久久不卡二区| 禁断一区二区三区在线| 538任你躁在线精品免费| 成人免费在线视频| wwwav网站| 91av在线播放视频| 欧美伦理在线视频| 999久久久精品视频| 亚洲一区二区三区四区不卡| 无码h黄肉3d动漫在线观看| 国产成人91久久精品| 日韩免费视频| 丰满饥渴老女人hd| 欧美性猛交xxxx富婆弯腰| 91视频在线观看| 高清不卡日本v二区在线| 99精品国产一区二区青青牛奶 | 日本精品久久久久| 国产成人精品免高潮在线观看| 日韩免费一区| 午夜免费福利影院| 欧美视频完全免费看| 性欧美videos高清hd4k| 欧美xxxx黑人又粗又长密月| 精品一区二区三区不卡| 日韩少妇裸体做爰视频| 怡红院精品视频| 51vv免费精品视频一区二区 | 国模少妇一区二区三区| 日韩精品成人一区| 主播福利视频一区| 国产精品x8x8一区二区| 最近中文字幕一区二区| 亚洲综合一区在线| av在线第一页| 国产另类第一区| 久久99精品久久久久久国产越南 | 欧美一级黄色大片| 自拍偷拍亚洲视频| 奇米777四色影视在线看| 久久九九影视网| 东京干手机福利视频| 国产精品视频久久| 国产婷婷精品| 亚洲熟女www一区二区三区| 亚洲色图25p|