扫码阅读
手机扫码阅读

手把手带你学会Odoo OWL组件开发(2):OWL的使用

74 2024-03-14

本期摘要

上一篇我们对odoo owl做了一个简单介绍,从本篇开始我们将手把手教你如何通过owl开发odoo项目,今天我们通过一个简单的“hello world”示例来看下owl 在odoo中如何使用。

感兴趣的小伙伴可以复习一下上一篇内容:手把手带你学习Odoo OWL组件开发(1):认识 OWL

作者

沈童 | 前端开发工程师

默默无闻,走向人生巅峰,激流勇进,退居幕后黑手

01

odoo中使用owl

//Step 1

首先创建一个father.js文件,然后创建一个templates.xml文件,并且清单文件__manifest__.py中引用templates.xml文件

demo.js示例:

odoo.define('owl_demo_view', function (require) { //必须引入部分 const { Component, useState ,hooks} = owl; const { xml } = owl.tags; const { useRef, onMounted, onWillStart} = hooks; const {ComponentWrapper} = require("web.OwlCompatibility"); //qweb,单页面渲染引入部分 var core = require('web.core'); var AbstractAction = require('web.AbstractAction'); //创建元素并展示 class Parent extends Component { //static template = 'owl_demo' //方案一 xml綁定 //方案二 xml,编写 static template = xml`
                
"owl-father">                     "state.title">                 
`         setup() {             this.state = useState({                 title:'Hello World' });         }     } //实例化qweb页面 var test_owl = AbstractAction.extend({         start: function () { self = this             $(document).ready(function () { for(const element of self.el.querySelectorAll(".o_content")){ //创建实例并挂载到对应元素中 (new ComponentWrapper(self, Parent)).mount(element);                 }             }); //第二种实例化挂载方式 const app = new Parent();             console.log(app,'owl实例') //挂载在页面的那个位置 ,这里的document.body是可以换的 for(const element of self.el.querySelectorAll(".o_content")){ //创建实例并挂载到对应元素中 app.mount(element);             }                       },     })     core.action_registry.add('owl_demo_view', test_owl); return test_owl     })

templates.xml示例:


xml version="1.0" encoding="utf-8"?> <odoo> <template id="aa" name="FrStorageExtendReportKanBanExtend" inherit_id="web.assets_backend"> <xpath expr="script[last()]" position="after"> <script type="text/javascript" src="/xc_quotation/static/src/js/demo.js"/> xpath> template> odoo>

__manifest__.py示例:

'data': [ 'views/templates.xml',
], 'qweb': [ 'static/src/xml/demo.xml',
],

//Step 2:创建一个模板xml文件

我这里创建的是demo.xml。这里的xml文件就是你想要渲染的东西, 其中t-name是对应js中渲染实例需要的模板名称,是唯一的,不然浏览器会不知道渲染那个模板,同时这里模板通过demo.js关联后就能拿到类中的数据。

?xml version="1.0" encoding="UTF-8"?> "preserve">
     "owl_demo" owl="1">
         
"owl-father">            "state.title">          
 

当然你也可以不需要创建模板文件,在执行js中编写template也是可以的,这里和vue中的jsx,都是一样的,在demo.js中有讲解。

02

重点

demo.js中单页需要使用到core,和AbstractAction所以必须引入 var core = require('web.core'); 和var AbstractAction = require('web.AbstractAction');

在odoo中你想创建一个单页,是必须通过odoo已有的模块来完成的,必须将类通过命名的方式,注册到odoo中,不然是没办法渲染,并拿到页面的,

这样注册后,odoo中的菜单, menuitem 和action跳转到这个挂载的页面。

这里的 name=“tag”标签中的owl_demo_view,是需要和core.action_registry.add('owl_demo_view', test_owl);这个名字是一样的,odoo才能获取到对应的页面,然后你点击菜单的时候就会渲染

效果如图

这里可以看到t-sec="state"是直接可以获取js中的数据的,通过关联实例 template "owl_demo_father",

这里是通过声明式的渲染方式,将hello world渲染到 t 标签中。

03

什么是声明式渲染

我的理解就是,声明一个变量,并且能直接获取并渲染到页面模板中。


比较官方的说法是:声明式:只告诉程序想要什么结果,如何达成由程序完成,开发者不用关心。


声明式渲染实现的是,DOM 随状态(数据)更新而更新。


而对应的就是有命令式: 一步一步告诉程序如何去做,能否达成结果取决于开发者的设计。


jq的直接操作dom的方式就是命令式的,一步步的告诉浏览器该如何将数据渲染上去

////为什么前端主流框架都是声明式的渲染方式?


我们首先需要声明一个变量,声明变量并渲染

1.声明一个app的常量,并通过新建一个类

const app = new Parent();

2.挂载,并实例化这个类

app.mount(document.body); console.log(app,'owl实例')

//为什么前端主流框架都是声明式的渲染方式?

在VUE和React中都是声明式的渲染方式,为什么呢,因为这样,编写的代码会更少,逻辑和渲染会分离开来,更容易读懂,和拓展。

下面我打印了app这个实例,一起来看看实例中有哪些东西吧,简单的实例当然就是你new class的集合里面的数据,方法, 在这些的同时,owl也封装了一些odoo自有的方法到owl中,这些会在后期与大家讲解。

这里可以打印这个app 可以看到里面的实例化数据, 如果我在这个时候去操作修改声明的变量也是可以的.

app.data.Name='声明变量修改后'

可以看到这里的这个展示的也会同步修改.

当然不建议这样修改,建议通过方法去修改变量,这也是大家常做的方式。

04

弹窗案例(owl)

因为owl是odoo贴合自己本身开发的,所以owl也是使用的qweb的语法,这里有个小的弹窗案例.

1.首先创一个owl的弹窗主体内容的xml(我这里交owl_components.xml,为后面的多组件做准备)

xml version="1.0" encoding="utf-8" ?> <templates xml:space="preserve"> 
         <div> <div class="owl-popup-mask">div> <div class="owl-confirm-xl" id="owlConfirm"> <div class="owl-confirm-title"> <p t-esc="state.title" class="owl-confirm-text">p> div> <div class="owl-confirm-btn"> <div t-on-click="confimrBtn" class="btn btn-primary">确定div> <div t-on-click="closeConfim" class="btn btn-white ml20">取消div> div> div> div> 
         
    
         <div calss="owl-radios"> 測試 div> 
 
 templates>

2.创建对应xml组件的owl_components.js文件同样需要引入到清单文件__manifest__.py和template.xml中

owl_components.js示例:

odoo.define('owl_components', function (require) {  "use strict"; const { Component, useState ,hooks} = owl; const { xml } = owl.tags; const { useRef, onMounted, onWillStart} = hooks; const {ComponentWrapper} = require("web.OwlCompatibility"); class OwlConfirm extends Component{ static template= "owl_confirm";
        setup() { this.state = useState({ title: "測試", row:this.__owl__.parent.parentWidget.recordData
            }); this.state.title = 'xxxxxxxx内容部分' }
        confimrBtn(url){ console.log(this.state.row,'确定'); let self = this; let paramsData = { id:(this.state.row.id).toString()
            } ; console.log(this,'aaaaasss') console.log(this.env,'ssss') this.rpc({ route: 'xxxxx/xxxxx', params: paramsData
            }).then(res=>{ console.log(res,'sss') this.env.services.notification.notify({ title:'系统提示', message: res['msg'], type: 'success',
                }); // self.destroy(); })
 
 
        } //关闭 closeConfim(){ this.destroy();
        }
    } class OwlRadios extends Component{ static template= "owl_radios";
    } return {
        OwlConfirm,
        OwlRadios
    }
});

这里直接return两个类,然后再你需要使用的页面,对应位置实例化挂载这个类

//需要引入的两个模块 const {ComponentWrapper} = require("web.OwlCompatibility");//实例化模块 const {OwlConfirm }= require('owl_components');//组件模块 然后我这里是点击后渲染 //修改数据 editRows: function (){
    (new ComponentWrapper(this, OwlConfirm)).mount(document.body);
},

css样式

/*弹窗*/ .owl-confirm-xl{ width: 400px; height: 200px; padding: 20px; position: fixed; top: 50%; left:50% ; transform: translateX(-50%); background-color: #fff; z-index: 999; border-radius: 5px; display: flex; flex-direction: column; justify-content: space-between;
} .owl-confirm-title{ flex: 1;
} .owl-confirm-btn{ height: 30px; display: flex; justify-content: flex-end;
} .owl-confirm-text{ font-size: 22px; text-align: center;
} .owl-popup-mask{ display: block; position: fixed; left: 0; top: 0; width: 100%; height: 100%; opacity: 0.5; background: #000000; z-index: 998;
}

效果如图

今天的分享就到这里啦!

原文链接: http://mp.weixin.qq.com/s?__biz=Mzg5MzUyOTgwMQ==&mid=2247524867&idx=1&sn=e1fdc8605591e20d4493394a2b5fb24e&chksm=c02f59a5f758d0b317fcd7412b80d0530145d42315107776d66c4f1e5e49687d9eeb22b1d452#rd