你們好,javascript
本文將進一步解釋odoo widget 的相關原理,其中首先會講述:1. 什麼是widgets 中的繼承;2. 爲何有不少 init : function 語法;3. widgets 系統結構;前端
首先,讓咱們來看看結構:(來自 /addons/web/ 目錄)java
問題一:apps.js 是幹啥的?web
下面是 app.js 的結構:(說明見圖)編程
下面是 core 目錄的結構:promise
這裏,咱們來回答一下最開始的問題:1. 什麼是widgets 中的繼承;2. 爲何有不少 init : function 語法;3. widgets 系統結構;app
問題1(解答): 由於前端原本是沒有繼承的,因此,odoo 應用了 commonjs 規範(Javascript模塊化編程"全球規範」),這樣咱們在前端編程中,就能夠開始使用繼承與_include() /_extend() 等等。dom
問題2(解答): 這裏首先要了解,mixin在javascript是什麼。minxin能夠看做是一種從別的對象」借用」功能的方法。每個新定義的對象都有一個 prototype屬性,其餘的對象就能夠從這裏」借用」功能。這裏的功能能夠是一個屬性,也能夠是一個方法。異步
mixins這種借用在 javascript裏很是的適用。在重用代碼的時候可使用mixins來實現繼承,也能夠達到相似多繼承的效果。假設咱們定義了這麼一個對象:
ide
var myMixins = { moveUp: function(){ console.log( "move up" ); }, moveDown: function(){ console.log( "move down" ); }, stop: function(){ console.log( "stop! in the name of love!" ); } };
咱們能夠很是容易的使用一個helper來擴展示有的對象。好比使用Underscore.js
的extend()
方法:
// carAnimator 構建器的一個骨架 function carAnimator(){ this.moveLeft = function(){ console.log( "move left" ); }; } // personAnimator構建器的一個骨架 function personAnimator(){ this.moveRandomly = function(){ /*..*/ }; } // 用咱們的 Mixin拓展這些類 _.extend( carAnimator.prototype, myMixins ); _.extend( personAnimator.prototype, myMixins ); // 建立carAnimator 的新實例 var myAnimator = new carAnimator(); myAnimator.moveLeft(); myAnimator.moveDown(); myAnimator.stop(); // 輸出: // move left // move down // stop! in the name of love!
從代碼能夠看到,這個mixins實現的很是簡單。在下一個例子中咱們會使用兩個構造函數:一個Car
,一個Mixin
。咱們要作的就是使用一個自定義的argument方法來擴展Car,這樣Car
能夠從Mixin
裏」借用」某些特定的方法。好比,driveForward()
和driveBackword()
。此次咱們不使用Underscore.js
。這裏例子會很是清楚的展現argument方法是怎麼達到」借用」效果的:
// 定義一個簡單的 Car 構建器 var Car = function ( settings ) { this.model = settings.model || "no model provided"; this.color = settings.color || "no colour provided"; }; // Mixin var Mixin = function () {}; Mixin.prototype = { driveForward: function () { console.log( "drive forward" ); }, driveBackward: function () { console.log( "drive backward" ); }, driveSideways: function () { console.log( "drive sideways" ); } }; // 使用另外一個方法擴展示有對象 function augment( receivingClass, givingClass ) { // 只提供某些方法 if ( arguments[2] ) { for ( var i = 2, len = arguments.length; i < len; i++ ) { receivingClass.prototype[arguments[i]] = givingClass.prototype[arguments[i]]; } } // 提供全部方法 else { for ( var methodName in givingClass.prototype ) { // 檢查以確保接收類沒有相同的名稱 if ( !Object.hasOwnProperty(receivingClass.prototype, methodName) ) { receivingClass.prototype[methodName] = givingClass.prototype[methodName]; } // 或者: // if ( !receivingClass.prototype[methodName] ) { // receivingClass.prototype[methodName] = givingClass.prototype[methodName]; // } } } } // Augment the Car constructor to include "driveForward" and "driveBackward" augment( Car, Mixin, "driveForward", "driveBackward" ); // Create a new Car var myCar = new Car({ model: "Ford Escort", color: "blue" }); // 測試以確保咱們如今能夠訪問這些方法 myCar.driveForward(); myCar.driveBackward(); // 輸出: // drive forward // drive backward // 咱們還能夠增長 Car 類來包含咱們 mixin 中的全部方法 // 而不是僅僅監聽某些增強( Car, Mixin ); var mySportsCar = new Car({ model: "Porsche", color: "red" }); mySportsCar.driveSideways(); // 輸出: // drive sideways
Mixins能夠減小代碼的重複增長代碼的複用。
問題3(解答):
var MyWidget = Widget.extend({ // 用於渲染的QWeb模板的名稱 template: "MyQWebTemplate", init: function (parent) { this._super(parent); // 渲染前要初始化的內容 }, willStart: function () { // 在小部件準備就緒以前須要完成的異步工做 // 此方法應返回延遲 }, start: function() { // 渲染後要製做的內容, `this.$el` 保持正確的值 this.$(".my_button").click(/* 事件綁定示例 * /); // 若是您有一些異步操做,最好在start()返回一個Promise對象,它表明了一個異步操做的最終完成或者失敗 // 固然這不多見, and if you // 若是您想獲取一些數據,這個步驟可能須要在 // willStart 方法中完成 var promise = this._rpc(...); return promise; } });