扫码阅读
手机扫码阅读

手把手带你学会Odoo OWL组件开发(3):核心内容指南

132 2024-03-14

本期摘要

上一章中我们讲解了OwL起步和一个小的弹窗控件演示:手把手带你学会Odoo OWL组件开发(2):OWL的使用

这章我们通过讲解梳理OwL的核心内容部分,即挂载,数据状态,数据监听,生命周期,组件传值及hook方法来给大家讲一讲OwL相关指南。

作者

沈童 | 前端开发工程师

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

01

OwL的挂载

什么是挂载,挂载就是安装一个组件,把组件安装展示到指定的位置

//App创建

首先和需要创建一个申明式的对象,就像VUE一样,OwL和VUE一样的方式首先创建一个class类,然后通过 const App = new xxx 得到这个新的类

常见的方式

const {Component, App } = owl; class MyComponent extends Component {
...
} const app = new App(MyComponent, { props: {...}, templates: "..."});
app.mount(document.body);

//Mount组件挂载

const { mount, Component } = owl; class MyComponent extends Component { ... }
mount(MyComponent, document.body, { props: {...}, templates: "..."});

mount(Component, target, config) 有三个参数

第一个:Component,类,一个组件类(应用程序的根组件),上面定义的calss

第二个:target ,标签 ,页面上元素,组件将作为最后一个子元素挂载到该元素中

第三个:config, 配置项

  • env (object) : 如果给出,这将是给每个组件的共享公共方法 ,

  • props (object): 给根组件的方法获取根元素上定义的值 及中 count会在props中获取

  • dev (boolean, default=false):传递一个布尔值 如果为 true,则应用程序以开发模式呈现;

  • test (boolean, default=false):传递一个布尔值 测试模式与开发模式相同,只是 Owl 不会记录一条消息来警告 Owl 处于开发模式。

  • translatableAttributes (string[]):应翻译的附加属性列表

  • translateFn (function):一个将被 owl 调用以翻译模板的函数

  • templates (string | xml document):应用程序创建的组件将使用的所有模板。这里可以是上面定义好的xml 或者__manifest__.py中qweb文件(t-name根元素名)

在解压中添加挂载OwL组件

const {ComponentWrapper} = require("web.OwlCompatibility"); const {OwlConfirm }= require('owl_components');//写好的暴露的类 for (const element of this.el.querySelectorAll(".o_partner_order_summary")) { //这里循环遍历找到对于的元素然后通过mount挂载到元素上 (new ComponentWrapper(this, PartnerOrderSummary))
 .mount(element)
 } /**核心部分*/ (new ComponentWrapper(this, OwlConfirm)).mount(document.body);

02

Owl数据状态

在Owl中数据是怎么定义的呢?

这里数据修改的方法,我总结为3种

  • 第一种,先定义后赋值

//声明一个data var data = {
name: 'february',
arr: [1,2,3,4]
} //在新建这个实例后,赋值data const app = new Parent()
app.data = data;
  • 第二种,在实例化的类中定义变量

通过使用useState来定义变量

class Child extends Component { static template = 'Child';
    setup() { this.data = useState({
            age: 18,
            msg: '子组件传值给父组件' }) 
    }
}

第三种,在constructor中创建数据,可以直接上传到数据

class Child extends Component { static template = 'Child'; constructor() { super(); this.data={ age: 18, title: 'ces1',
    }
    }
}

上面这些数据修改赋值等,操作下面展示数据,与传统的vue和react中数据展示方式不同

在vue和react中是可以使用{{xxx}}或者{this.stara.dd}这样的方式直接在标签中展示数据,但是目前Owl是不行的,他需要通过value赋值或者t-esc=“state.aa”或者按钮的text=“xxx”的方式来展示数据。

03

Owl生命周期

在vue和react中都有生命周期,什么是生命周期,就是,有个Owl组件,从创建到加载到结束的整个过程。

//生命周期

  • willRender ()在渲染组件之前,会用来初始化一些数据等

  • onRendered ()在渲染组件之后,

  • mounted()在DOM结构样式渲染后并在立即执行,方法在渲染组件、添加DOM之后调用。

  • willPatch ()在发生改变时执行 方法在组件状态发生改变时调用。此方法在元素根据新状态重新渲染之前进行调用。

  • patched ()在发生改变时执行,此方法在元素根据新状态重新渲染之前进行调用。

  • willUnmount ()方法在元素从DOM中移除之前调用。

  • onWillDestroy ()在组件被销毁之前

//异步周期

  • willStart ()在第一次异步渲染开始前执行, 方法在构造方法之后及元素渲染之前调用。它是一个异步方法,可以执行一些像RPC这样的异步操作。

  • willUpdateProps()异步,在组件更新之前


class Child extends Component { static components = {LastSon,XCRadio } static template = 'Child'; constructor() { super(); console.log('CALLED:> constructor'); this.childData=useState({ ss:'sssss' })
    }
    setup() { this.data = useState({ age: 18, msg: '子组件传值给父组件' })
    }
    editFunc(){ this.childData.ss = 'ddddd';
    } async willStart() { console.log('CALLED:> willStart');
    }
    mounted(){ console.log('CALLED:> mounted');
    }
    willPatch() { console.log('CALLED:> willPatch');
    }
    patched() { console.log('CALLED:> patched');
    }
    willUnmount() { console.log('CALLED:> willUnmount');
    }
   
}

hook方法

Owl hook是定义组件公用状态操作的,Owl提供了一些hook,同时他也允许你自定义hook

//API

  • useState()

组件数据响应 底层和Vue的数据监听是一样的(通过Proxy)

示例


const { useState, Component } = owl; class Counter extends Component { static template = xml`
    "increment">
        Click Me! [<t t-esc="state.value"/>] button>`;
  state = useState({ value: 0 });
  increment() { this.state.value++;
  }
}
  • useRef ()

当我们需要一种方法与由 Owl 渲染的组件的某些内部部分进行交互时。t-ref它仅适用于由指令标记的 html 元素

示例



<input t-ref="someDiv"/> <span t-on-click="someMethod">hellospan> div> class Parent extends Component { inputRef = useRef("someDiv");  someMethod() { console.log(this.inputRef) } }

可以拿到这个输入的组件状态这里和jq的$(“#xxx”)类似

  • useSubEnv ()

在子组件上挂载公共数据包括他自己

  • useChildSubEnv()

只会在组件的子组件中挂载公共数据及方法

示例


class FormComponent extends Component { setup() {
    const model = makeModel(); // model will be available on this.env for this component and all children
    useSubEnv({ model }); // someKey will be available on this.env for all children
    useChildSubEnv({ someKey: "value" });
  }
}

  • useExternalListener()

监听组件的状态事件

示例


useExternalListener ( window , " click " , this.closeMenu ) ;
  • useEffect ()

页面状态更新后就好执行,useState里面数据变化了也会执行。

默认情况下,它在第一次渲染之后和每次更新之后都会执行。你可能会更容易接受 effect 发生在“渲染之后”这种概念,不用再去考虑“挂载”还是“更新”。允许传第二个参数,用来控制是否每次都执行。

示例


useEffect(() => { document.title = `ttttt`;
}, [count]); // 仅在 count 更改时更新

  • useComponent ()

自定hook方法拿到组件本身

示例

function useSomething() { const component = useComponent(); console.log(component ,'useComponent')
}
  • useEnv ()

在组件获取组件挂载的全部公共数据.env

示例


function useSomething() { const env = useEnv(); console.log(env ,'useEnv')
}

本篇内容就到此结束啦,有兴趣的小伙伴可以点击关注持续更新本系列。

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