你们好,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; } });