第一章:組件?

本章介紹了 Owl 框架,這是一個專為 Odoo 設計的定制化組件系統。OWL 的主要構建塊是 組件模板。

在Owl中,用戶界面的每個部分都由組件管理:它們保存邏輯并定義用于呈現用戶界面的模板。實際上,組件由一個小的JavaScript類表示,該類是 Component 類的子類。

Example

Counter 類實現了一個組件,它保存計數器的內部狀態并定義了如何遞增計數器。

const { Component, useState } = owl;

 class Counter extends Component {
     static template = "my_module.Counter";

     state = useState({ value: 0 });

     increment() {
         this.state.value++;
     }
 }

Counter 類指定要呈現的模板名稱。該模板以 XML 編寫,定義了用戶界面的一部分。

<templates xml:space="preserve">
    <t t-name="my_module.Counter" owl="1">
        <p>Counter: <t t-esc="state.value"/></p>
        <button class="btn btn-primary" t-on-click="increment">Increment</button>
    </t>
</templates>

你可能已經注意到了 owl="1" 這個臨時屬性,它允許Odoo將Owl模板與舊的JavaScript框架模板區分開來。

讓我們花些時間熟悉Owl本身。下面,您將找到一系列練習,旨在快速了解和練習Owl的基礎知識。

目標

這一章我們將要達成的目標概述如下。

../../../_images/overview.png

本章節中每個練習的解決方案都托管在 官方Odoo教程存儲庫 中。

1. 顯示計數器?

作為第一個練習,讓我們在位于 owl_playground/static/src/Playground 組件中實現一個計數器。要查看結果,您可以使用瀏覽器訪問 /owl_playground/playground 路由。

小技巧

瀏覽器下載的Odoo JavaScript文件是經過壓縮的。為了調試方便,最好不要壓縮文件。切換到 帶資源的調試模式 ,這樣文件就不會被壓縮。

Exercise

  1. 修改 playground.js ,使其像 上面的例子 一樣作為計數器。您需要使用 useState 函數,以便在此組件讀取狀態對象的任何部分被修改時重新渲染組件。

  2. 在同一組件中創建一個 increment 方法。

  3. 修改 playground.xml 中的模板,以便顯示您的計數器變量。使用 t-esc 輸出數據。

  4. 在模板中添加一個按鈕,并在按鈕中指定一個 t-on-click 屬性 <https://github.com/odoo/owl/blob/master/doc/reference/event_handling.md#event-handling> `_,以便在單擊按鈕時觸發 ` increment`方法。

../../../_images/counter.png

2. 在組件中提取計數器?

目前我們在 Playground 組件中有一個計數器的邏輯,讓我們看看如何從中創建一個 `子組件<https://github.com/odoo/owl/blob/master/doc/reference/component.md#sub-components>`_。

Exercise

  1. Playground 組件中提取計數器代碼到一個新的 Counter 組件中。

  2. 你可以先在同一個文件中完成,但完成后,請更新您的代碼,將 Counter 移動到它自己的文件中。

  3. 請確保模板在自己的文件中,并且文件名相同。

重要

不要忘記在你的JavaScript文件中添加 / ** @odoo-module ** / 。更多信息請參考 這里 。

3. 待辦事項組件?

我們將在 owl_playground/static/src/ 中創建新的組件,用于跟蹤待辦事項列表。這將在多個練習中逐步完成,介紹各種概念。

Exercise

  1. 創建一個 Todo 組件,它在 props 中接收一個 todo 對象,并將其顯示出來。它應該顯示類似于 3. 買牛奶 。

  2. 如果任務已完成,請在任務上添加Bootstrap類 text-mutedtext-decoration-line-through 。為此,您可以使用 `動態屬性<https://github.com/odoo/owl/blob/master/doc/reference/templates.md#dynamic-attributes>`_。

  3. 修改 owl_playground/static/src/playground.jsowl_playground/static/src/playground.xml ,使用一些硬編碼的屬性來顯示您的新 Todo 組件,以便先進行測試。

    Example

    setup() {
        ...
        this.todo = { id: 3, description: "buy milk", done: false };
    }
    
../../../_images/todo.png

另請參閱

Owl: 動態類屬性

4. 屬性驗證?

Todo 組件有一個隱式的API。它期望在其props中接收一個特定格式的todo對象的描述: id , descriptiondone 。讓我們使該API更加明確。我們可以添加一個props定義,讓Owl在 dev mode 中執行驗證步驟。您可以在 App配置 中激活 dev mode 。

對于每個組件進行屬性驗證是一個好的實踐。

Exercise

  1. Todo 組件添加 props 驗證。

  2. 確保在 owl_playground 中默認激活的開發模式下通過??梢酝ㄟ^修改 owl_playground/static/src/main.jsmount 函數的 config 參數中的 dev 屬性來激活或停用開發模式。

  3. 從 props 中刪除 done 并重新加載頁面。驗證應該失敗。

5. 待辦事項清單?

現在,讓我們顯示一個待辦事項列表,而不僅僅是一個待辦事項?,F在,我們仍然可以硬編碼列表。

Exercise

  1. 將代碼更改為顯示待辦事項列表而不僅僅是一個,并在模板中使用 t-foreach <https://github.com/odoo/owl/blob/master/doc/reference/templates.md#loops>`_。

  2. 考慮如何使用 t-key 指令進行鍵控。

../../../_images/todo_list.png

6. 添加一個待辦事項?

到目前為止,我們列表中的待辦事項是硬編碼的。讓我們通過允許用戶向列表中添加待辦事項使其更加有用。

Exercise

  1. 在任務列表上方添加一個輸入框,占位符為“輸入新任務”(Enter a new task)。

  2. keyup 事件上添加名為 addTodoevent handler <https://github.com/odoo/owl/blob/master/doc/reference/event_handling.md>`_。

  3. 實現 addTodo 函數,檢查是否按下了回車鍵 ( ev.keyCode === 13 ),如果是,則使用輸入框當前的內容作為描述創建一個新的待辦事項。

  4. 請確保它有一個唯一的ID。它可以只是一個在每個待辦事項中遞增的計數器。

  5. 然后,清除輸入框中的所有內容。

  6. 獎勵分:如果輸入為空,則不執行任何操作。

注解

注意到UI中沒有任何更新:這是因為Owl不知道它應該更新UI??梢酝ㄟ^在待辦事項列表中包裝 useState 鉤子來解決這個問題。

this.todos = useState([]);
../../../_images/create_todo.png

另請參閱

Owl: 響應性

7. 聚焦輸入框?

讓我們看看如何使用 t-refuseRef 來訪問 DOM。

Exercise

  1. 當儀表板 mounted 時,將焦點放在上一個練習中的 input

  2. 獎勵分:將代碼提取到專門的 hook useAutofocus 中。

8. 切換待辦事項?

現在,讓我們添加一個新功能:將待辦事項標記為已完成。這實際上比人們想象的要棘手。狀態的所有者與顯示它的組件不同。因此, Todo 組件需要向其父組件通信,表示待辦事項狀態需要切換。一種經典的方法是使用 回調屬性 <https://github.com/odoo/owl/blob/master/doc/reference/props.md#binding-function-props> _ toggleState`。

Exercise

  1. 在任務的id之前添加一個帶有屬性 type="checkbox" 的輸入框,如果狀態為 done ,則必須選中。

  2. 添加一個回調屬性 toggleState 。

  3. Todo 組件的輸入框上添加一個 click 事件處理程序,并確保它使用 todo id 調用 toggleState 函數。

  4. 讓它工作起來!

../../../_images/toggle_todo.png

9. 刪除待辦事項?

最后一步是讓用戶刪除待辦事項。

Exercise

  1. 添加一個新的回調屬性 removeTodo 。

小技巧

如果你正在使用數組來存儲待辦事項清單,你可以使用 JavaScript 的 splice 函數來從中刪除一個待辦事項。

// find the index of the element to delete
const index = list.findIndex((elem) => elem.id === elemId);
if (index >= 0) {
      // remove the element at index from list
      list.splice(index, 1);
}
  1. Todo 組件的模板中插入 <span class="fa fa-remove"> 。

  2. 每當用戶點擊它時,它應該調用 removeTodo 方法。

../../../_images/delete_todo.png

10. 具有插槽的通用組件?

Owl擁有一個強大的 `slot <https://github.com/odoo/owl/blob/master/doc/reference/slots.md>`_系統,允許您編寫通用組件。這對于在界面的不同部分之間因式分解常見布局非常有用。

Exercise

  1. 使用以下Bootstrap HTML結構編寫 Card 組件:

    <div class="card" style="width: 18rem;">
        <img src="..." class="card-img-top" alt="..." />
        <div class="card-body">
        <h5 class="card-title">Card title</h5>
        <p class="card-text">
            Some quick example text to build on the card title and make up the bulk
            of the card's content.
        </p>
        <a href="#" class="btn btn-primary">Go somewhere</a>
        </div>
    </div>
    
  2. 這個組件應該有兩個插槽:一個用于標題,一個用于內容(默認插槽)。

    Example

    以下是如何使用它的方法:

    <Card>
       <t t-set-slot="title">Card title</t>
       <p class="card-text">Some quick example text...</p>
       <a href="#" class="btn btn-primary">Go somewhere</a>
    </Card>
    
  3. 獎勵分:如果未提供 title 插槽,則根本不應該呈現 h5 。

../../../_images/card1.png

11. 更進一步?

Exercise

  1. Card 組件上添加屬性驗證。

  2. 嘗試在 props 驗證系統中表達需要一個 default 插槽和一個可選的 title 插槽。