補丁代碼?

有時,我們需要自定義UI的工作方式。許多常見需求都可以通過一些支持的API來實現。例如,所有的注冊表都是很好的擴展點:字段注冊表允許添加/刪除專門的字段組件,或者主組件注冊表允許添加應始終顯示的組件。

然而,在某些情況下,這是不夠的。在這些情況下,我們可能需要直接修改一個對象或類。為了實現這一點,Odoo提供了實用函數 patch 。它主要用于覆蓋/更新某些其他組件/代碼片段的行為,這些組件/代碼片段不受我們控制。

描述?

補丁函數位于 @web/core/utils/patch

patch(obj, patchName, patchValue, options)?
參數
  • obj (Object()) – 應該被打補丁的對象

  • patchName (string()) – 描述補丁的唯一字符串

  • patchValue (Object()) – 一個將每個鍵映射到 patchValue 的對象

  • options (Object()) – 選項對象(見下文)

patch 函數會直接修改 obj 對象(或類),并應用 patchValue 對象中描述的所有鍵/值。此操作在 patchName 名稱下注冊,因此如果需要,可以稍后取消補丁。

大多數補丁操作都可以通過使用 _super 屬性來訪問父級值(請參見下面的示例)。為此, patch 方法會將每個鍵/值對都包裝在一個 getter 中,動態綁定 _super 。

唯一的選項是 pure (boolean) 。如果設置為 true ,則補丁操作不會綁定 _super 屬性。

補丁一個簡單對象?

這是一個簡單的示例,展示了如何對一個對象進行打補?。?/p>

import { patch } from "@web/core/utils/patch";

const object = {
  field: "a field",
  fn() {
    // do something
  },
};

patch(object, "patch name", {
  fn() {
    // do things
  },
});

當我們打補丁時,通常希望能夠訪問“parent”函數。由于我們使用的是補丁對象,而不是ES6類,因此我們無法使用本地的“super”關鍵字。因此,Odoo提供了一種特殊的方法來模擬這種行為: this._super :

patch(object, "_super patch", {
  fn() {
    this._super(...arguments);
    // do other things
  },
});

警告

每次調用補丁函數后, this._super 都會被重新賦值。這意味著,如果您在補丁中使用異步函數,則不能在 await 后調用 this._super ,因為它可能是您期望的函數,也可能不是。正確的方法是保留對初始 _super 方法的引用:

patch(object, "async _super patch", {
  async myAsyncFn() {
    const _super = this._super.bind(this);
    await Promise.resolve();
    await _super(...arguments);
    // await this._super(...arguments); // this._super is undefined.
  },
});

也支持 getter 和 setter:

patch(object, "getter/setter patch", {
  get number() {
    return this._super() / 2;
  },
  set number(value) {
    this._super(value * 2);
  },
});

修補 JavaScript 類?

patch 函數旨在與任何東西一起使用:對象或 ES6 類。

然而,由于JavaScript類使用原型繼承,當我們希望修補類的標準方法時,實際上需要修補 prototype

class MyClass {
  static myStaticFn() {...}
  myPrototypeFn() {...}
}

// this will patch static properties!!!
patch(MyClass, "static patch", {
  myStaticFn() {...},
});

// this is probably the usual case: patching a class method
patch(MyClass.prototype, "prototype patch", {
  myPrototypeFn() {...},
});

此外,Javascript 以一種特殊的本地方式處理構造函數,這使得它無法被修補。唯一的解決方法是調用原始構造函數中的一個方法,然后修補該方法:

class MyClass {
  constructor() {
    this.setup();
  }
  setup() {
    this.number = 1;
  }
}

patch(MyClass.prototype, "constructor", {
  setup() {
    this._super(...arguments);
    this.doubleNumber = this.number * 2;
  },
});

警告

無法直接修補類的 constructor !

補丁組件?

組件由JavaScript類定義,因此上述所有信息仍然有效。出于這些原因,Owl組件應該使用 setup 方法,以便它們也可以輕松地進行修補(請參見: 最佳實踐 )。

patch(MyComponent.prototype, "my patch", {
  setup() {
    useMyHook();
  },
});

移除一個補丁?

patch 函數有一個對應的函數 unpatch ,也位于 @web/core/utils/patch 中。

unpatch(obj, patchName)?
參數
  • obj (Object()) – 應該取消打補丁的對象

  • patchName (string()) – 描述應該被移除的補丁的字符串

從對象 obj 中移除現有的補丁。這在測試過程中非常有用,當我們在測試開始時對某些內容進行了補丁,然后在測試結束時取消補丁。

patch(object, "patch name", { ... });
// test stuff here
unpatch(object, "patch name");