Odoo的网页模块QWEB简述.docx
- 文档编号:28135988
- 上传时间:2023-07-08
- 格式:DOCX
- 页数:17
- 大小:21.57KB
Odoo的网页模块QWEB简述.docx
《Odoo的网页模块QWEB简述.docx》由会员分享,可在线阅读,更多相关《Odoo的网页模块QWEB简述.docx(17页珍藏版)》请在冰豆网上搜索。
Odoo的网页模块QWEB简述
Odoo/OpenERP的网页模块QWEB简述
1.web模块
注意,OpenERP模块中web部分用到的所有文件必须被放置在模块内的static文件夹里。
这是强制性的,出于安全考虑。
事实上,我们创建的文件夹CSS,JS和XML,仅仅是一个习惯。
static文件夹
oepetstore/static/css/petstore.css是我们的CSS文件。
oepetstore/static/xml/petstore.xml是一个XML文件,将包含我们QWeb的模板。
oepetstore/static/js/petstore.js包含应用程序的JavaScript代码。
像OpenERP的XML文件包含了视图或数据一样,必须在__openerp__.py文件内标明这些文件。
下面是我们增加的行,它告诉webclient必须记载这些文件:
'js':
['static/src/js/*.js'],
'css':
['static/src/css/*.css'],
'qweb':
['static/src/xml/*.xml'],
OpenERP内,默认会把所有的JavaScript文件连接为一个文件。
然后,我们执行一个叫minification的操作。
minification将移除文件中的所有的注释、空格和换行符。
最后,发送这个文件给用户浏览器。
但这么做的缺点,是无法调试应用程序。
为了避免这种副作用,仍然能够调试的解决办法是:
在OpenERP的URL后面添加一个参数?
debug.
添加后的URL:
http:
//localhost:
8069/?
debug
当您使用带debug参数的URL,应用程序将不会执行串联所有minification的JavaScript文件这个过程。
应用程序也将需要更多的时间来加载,但你能进
行调试开发了。
在前面的章节中,我们解释了JavaScript缺少命名空间机制,来分割在不同的JavaScript文件中声明的变量。
并且我们提出了模块模式这个简单方法。
模块模式(如app.js文件):
(function(){
app={};
function main(){
console.log("launchapplication");
};
app.main=main;
})();
在OpenERP的web框架内,有个类似于模块模式的等价物,集成了该框架的其余部分。
请注意,OpenERP的Web模块与其他OpenERP的addon模块概念上是不同的,一个addon模块是一个包含很多文件的文件夹,web模块仅仅是一个有命名空间概念的JavaScript。
1)模块
oepetstore/static/js/petstore.js声明了这样的模块:
openerp.oepetstore=function(instance){
instance.oepetstore={};
instance.oepetstore.XXX=......;
}
在OpenERP的Web框架内,通过声明一个函数来声明一个JavaScript模块,并把这个函数放在全局变量openerp的属性内.这个属性名称必须和OpenERPaddon模块名称一致(这addon模块名为oepetstore,我应把函数赋值给openerp.oepetstore属性。
如果换成openerp.petstore属性,则无法正常运行)。
当Web客户端转载这个addon模块时,该函数将被调用。
将传入一个名为instance的参数,这个参数代表当前OpenERP的Web客户端实例,包含了所有相关当前会话数据,以及所有Web模块的变量。
在instance对象内创建与addon模块名称一致的新命名空间是个惯例。
这就是为什么我们在instance.oepetstore设置一个空dictionary。
这个dictionary就是命名空间,用来声明我们模块内自己使用的所有类和变量。
2)类
JavaScript不像其他面向对象编程语言那样有类机制。
更确切地说,它提供了面向对象编程语言元素,但你必须自己定义,自己选择如何做。
OpenERP Web框架提供工具来简化这个过程,让程序员以类似其他编程语言,如Java的方式编码。
定义一个新类,你需要从instance.web.Class类继承。
语法如下:
instance.oepetstore.MyClass=instance.web.Class.extend({
say_hello:
function(){
console.log("hello");
},
});
类的实例化:
varmy_object=newinstance.oepetstore.MyClass();
my_object.say_hello();
类可以有一个构造函数,它方法名为init()。
你可以像大多数开发语言那样,传递参数给构造器:
instance.oepetstore.MyClass=instance.web.Class.extend({
init:
function(name){
this.name=name;
},
say_hello:
function(){
console.log("hello",this.name);
},
});
类的继承
类可以被继承
instance.oepetstore.MySpanishClass=instance.oepetstore.MyClass.extend({
say_hello:
function(){
this._super();
console.log("hola",this.name);
},
});
var my_object=new instance.oepetstore.MySpanishClass("Nicolas");
my_object.say_hello();
this._super()不是常用的类方法
3)WidgetsBasics(基础部件)
OpenERP中Widget部件,是一个通用组件,专门用来向用户显示内容。
oepetstore实例中的petstore.js内容:
openerp.oepetstore=function(instance){
var_t=instance.web._t,
_lt=instance.web._lt;
var QWeb=instance.web.qweb;
instance.oepetstore={};
--部件-->
instance.oepetstore.HomePage=instance.web.Widget.extend({
start:
function(){
console.log("petstorehomepageloaded");
},
});
instance.web.client_actions.add('petstore.homepage','instance.oepetstore.HomePage');
}
最后一行代码,把这个部件注册为客户端的action。
当我们点击‣PetStore‣PetStore‣Home Page菜单项时,客户端action让部件显示出来。
HomePage部件有一个start()方法。
在部件初始化后,这方法被自动调用。
它已接接受指令去显示其内容。
我们将用它向用户显示一些内容。
要做到这一点,我们使用所有部件都有的$el属性。
该属性是一个jQuery对象,表示部件对应的HTML标签的根标签。
部件包含了多个HTML标签,这些HTM标签有一个统一的根标签。
默认情况下,部件都有一个空的根标签:
一个
一个
这也解释了为什么显示instance.oepetstore.HomePage时,是个空白区域,它根本没有任何内容。
要想显示些内容,我们用jQuery该对象上的一些简单方法,在根标签中添加一些HTML标签:
instance.oepetstore.HomePage=instance.web.Widget.extend({
start:
function(){
this.$el.append("
},
});
常用方法:
appendTo()方法
var pettoys=new instance.oepetstore.PetToysList(this);//实例化PetToysList()部件
pettoys.appendTo(this.$(".oe_petstore_homepage_left"));//把pettoys添加到当前部件的class=.oe_petstore_homepage_left的标签中
注意:
new instance.oepetstore.PetToysList(this),其中参数this,代表调用此部件的实例,表示部件的隶属关系。
addClass()方法
this.$el.addClass("oe_petstore_homepage");//添加样式
getParent()方法
用于获取父部件
getChildren()方法
用来获取子部件列表:
this.getChildren()[0].$el
当你在部件中重载init()时,必须以父部件作为第一参数传入,并调用传入给this._super(),例如:
instance.oepetstore.GreetingsWidget=instance.web.Widget.extend({
init:
function(parent,name){
this._super(parent);
this.name=name;
},
});
最后,如果一个部件没有父部件(即:
在你的应用实例化时是第一个部件),传入null参数:
newinstance.oepetstore.GreetingsWidget(null);
销毁部件:
destroy()方法:
当一个部件被销毁,它会先调用所有子部件的destroy()。
然后,它在DOM中清楚自己。
通过部件隶属关系的递归调用,避免了内存泄漏,这对容易产生内
存泄露的大型JavaScript应用程序来说是非常有用的。
2.Qweb
在OpenERP中,使用Qweb模板引擎,专门用于Web客户端开发。
Qweb是一种基于XML的模板语言,类似Genshi,Thymeleaf或Facelets。
有如下几个特点:
①在浏览器中完全用JavaScript执行。
②每个模板文件(XML文件)包含了多个模板,而其他模板引擎通常做法是,模板文件和模板之间1:
1的关系。
③在OpenERP的Web的instance.web.Widget特别支持了QWeb。
虽然QWeb可以用于OpenERP的Web客户端以外的地方(同时instance.web.Widget也可以不依赖于Qweb)。
之所以没用用其他JavaScript模板引擎,而是选择了QWeb,是因为QWeb的扩展机制与OpenERP的视图继承机制很相似。
就像OpenERP的视图一样,QWeb模版也是个XML树结构,因此很容易在模版执行XPath或DOM操作。
在部件内使用QWeb
首先,在文件oepetstore/static/src/xml/petstore.xml里我们定义一个简单的QWeb模板。
xml version="1.0"encoding="UTF-8"?
> space="preserve"> red;">ThisissomesimpleHTML
现在,修改HomePage类:
var QWeb=instance.web.qweb;
我们建议在所有的OpenERPweb模块复制粘贴这行代码。
这个对象提供访问被Web客户端加载的所有模版文件中的模版的功能。
下面是我们使用XML模板文件定义的模版的例子:
instance.oepetstore.HomePage=instance.web.Widget.extend({
start:
function(){
this.$el.append(QWeb.render("HomePageTemplate"));
},
});
解释:
QWeb.render()方法用来渲染指定标识名称的具体模版,第一个参数就是模版标识名称。
另外一个常用地方是,在部件内集成Qweb:
instance.oepetstore.HomePage=instance.web.Widget.extend({
template:
"HomePageTemplate",
start:
function(){
...
},
});
当你在部件内设置类属性template时,部件就知道它需要调用QWeb.render()来呈现该模板。
请注意这两个语法是有区别的。
当在部件内集成Qweb时,QWeb.render()调用在部件调用start()之前发生,并用模版的根标签替换了部件的默认根标签。
这会导致不同的结果,所以你应该记住它。
Qweb上下文(Context)
像所有的模板引擎一样,Qweb模板可以包含操纵传递给模板的数据的代码。
1)使用QWeb.render()的第二个参数传递数据给模版:
QWeb.render("HomePageTemplate",{name:
"Nicolas"});
输出结果:
2)当部件整合QWeb时,就不能直接传入数据了。
替换办法是,模板有一个唯一变量widget,这个变量引用了当前部件:
instance.oepetstore.HomePage=instance.web.Widget.extend({
template:
"HomePageTemplate",
init:
function(parent){
this._super(parent);
this.name="Nicolas";
},
start:
function(){
},
});
输出结果:
模版声明
Qweb的语法:
Qweb指令使用前缀t-的XML属性来声明新模板,我们在XML文件的根元素内添加一个
Escaping————转义
用t-esc:
在HTML中放置文本
这将输出变量name,并转义变量的上下文,这上下文也许是类似HTML的字符串。
请注意,该属性t-esc可包含各种JavaScript表达式:
输出HTML
如果你明确知道变量会包含一些HTML标签,使用t-raw代替的t-esc:
条件
QWeb的条件关键字是t-if:
trueistrue
trueisnottrue
Qweb条件分支没有“else”这个分支结构。
循环
遍历列表,使用t-foreach和t-as
Hello
设置任意XML属性值
Qweb有一个特定语法设置属性值。
您必须使用t-att-xxx并用属性名替换xxx:
Inputyourname:
3.部件事件和属性
1)事件
部件类似现有大部分图形用户界面库(Qt,GTK,Swing,...)那样,触发事件,
处理事件。
例如:
instance.oepetstore.ConfirmWidget=instance.web.Widget.extend({
start:
function(){
var self=this;
this.$el.append("
"
"
this.$el.find("button.ok_button").click(function(){
self.trigger("user_choose",true);
});
this.$el.find("button.cancel_button").click(function(){
self.trigger("user_choose",false);
});
},
});
instance.oepetstore.HomePage=instance.web.Widget.extend({
start:
function(){
var widget=new instance.oepetstore.ConfirmWidget(this);
widget.on("user_choose",this,this.user_choose);
widget.appendTo(this.$el);
},
user_choose:
function(confirm){
if(confirm){
console.log("Theuseragreedtocontinue");
}else{
console.log("Theuserrefusedtocontinue");
}
},
});
注意:
var self=this;请记住,在JavaScript中,变量this会隐含传递给所有函数。
如果函数像对象引用方法那么用,通过this我们知道当前的对象是什么。
每个已声明的函数都有自己的this。
所以,当我们在一个函数内声明了另一个函数,这个新功能将有自己的this,这和父函数this含义不同。
如果我们要用原来的对象this,最简单的方法是把引用存储在一个本地变量。
在OpenERP内,按照Python的习惯,通常该变量命名为self。
由于这个部件应该是通用的,它本身不应执行任何具体action。
所以,我们用trigger()方法设置了名字叫"user_choose"的触发器和事件。
Widget.trigger(event_name[,...])方法的第一个参数是待触发的事件名,也接受任何数量的其他参数。
这些参数将被传递到所有的事件侦听器。
然后,我们修改部件HomePage去实例化一个部件ConfirmWidget,通过on()方法监听"user_choose"事件。
Widget.on(event_name,object,func)允许绑定一个事件event_name触发时调用的函数func。
如果func是个方法,则object是func函数的引用关联对象。
当func被调用时,trigger()的其他参数会传递给它。
例如:
start:
function(){
var widget=...
widget.on("my_event",this,this.my_event_triggered);
widget.trigger("my_event",1,2,3);
},
my_event_triggered:
function(a,b,c){
console.log(a,b,c);
//willprint"123"
}
2)属性
属性类似与普通对象的属性。
可以在对象上设置数据,但有个额外的功能:
属性值改变时将触发事件。
start:
function(){
this.widget=...
this.widget.on("change:
name",this,this.name_changed);
this.widget.set("name","Nicolas");
},
name_changed:
function(){
console.log("Thenewvalueoftheproperty'name'is",this.widget.get("name"));
}
Widget.set(name,value)方法设置某个属性的值。
如果该值改变(或以前没有值),对象将触发一个事件change:
xxx。
xxx是属性名称。
4.部件辅助工具
1)部件的jQeruy选择器
find()方法
this.$el.find("input.my_input")
$()方法
this.$("input.my_input")
说明:
我们强烈建议你也不要使用,全局jQuery函数$()。
这种全局选择器满足简单应用,但在真正的大型web应用程序中不好。
原因很简单:
当你创建一个新部件,你永远不知道它会实例化多少次。
由于$()全局函数是操作浏览器中的全部HTML,如果你实例化一个部件两次,该函数会搞混两个部件的个内容。
这就是为什么,大部分时间里,你在定位部件里的HTML时,必须限制jQuery选择器的选择范围。
出于同样的逻辑,你也可以猜测到,不能够在部件里使用HTMLid。
如果widget被实例化的两次,在应用程序里将有两个相同id,但却是不同的HTML元素的情况。
而这本身就是一个错误。
所以,在所有的情况下,你应该坚持使用用CSS类去标记HTML标签。
2)简易DOM事件绑定
在前面的一部分,我们必须用click()或change()等事件绑定HTML元素。
现在,我们用$()来简化代码,让我们看看如何做:
instance.oepetstore.MyWidget=instance.web.Widget.extend(
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Odoo 网页 模块 QWEB 简述