1 模板内容的来源
情况A,组件类的template属性,比如ActionContainer.template
javascript
/* odoo/addons/web/static/src/webclient/actions/action_container.js */
export class ActionContainer extends Component {
setup() {
..
}
}
..
ActionContainer.template = xml`
<t t-name="web.ActionContainer">
<div class="o_action_manager">
<t t-if="info.Component" t-component="info.Component" className="'o_action'" t-props="info.componentProps" t-key="info.id"/>
</div>
</t>`;
情况B,组件类的同名xml文件,比如webclient.xml
XML
<!-- /* odoo/addons/web/static/src/webclient/webclient.xml */ -->
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="web.WebClient" owl="1">
<t t-if="!state.fullscreen">
<NavBar/>
</t>
<ActionContainer/>
<MainComponentsContainer/>
</t>
</templates>
2 存放模板内容的变量
情况A,存放在owl.js文件中的globalTemplates变量中
javascript
/* odoo/addons/web/static/lib/owl/owl.js */
const globalTemplates = {};
function xml(...args) {
const name = `__template__${xml.nextId++}`;
const value = String.raw(...args);
globalTemplates[name] = value;
return name;
}
xml.nextId = 1;
情况B,通过app.addTemplates方法,将xml保存在TemplateSet的rawTemplates中
javascript
/* web.assets_backend.bundle.xml文件是由后台动态打包生成的 */
/*******************************************
* Templates *
*******************************************/
odoo.define('web.assets_backend.bundle.xml', function(require) {
'use strict';
const {loadXML} = require('@web/core/assets');
const templates = `<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
// xml文件的内容,做了省略处理
..
<t t-name="web.WebClient" owl="1">
<t t-if="!state.fullscreen">
<NavBar/>
</t>
<ActionContainer/>
<MainComponentsContainer/>
</t>
..
</templates>`;
return loadXML(templates);
});
loadXML方法将templates中的xml文本,按照t-name属性提取出来,以key/value形式保存
javascript
/* odoo/addons/web/static/src/core/assets.js */
let defaultApp;
/**
* Loads the given xml template.
*
* @param {string} xml the string defining the templates
* @param {App} [app=defaultApp] optional owl App instance (default value
* can be changed with setLoadXmlDefaultApp method)
* @returns {Promise<true>} resolved when the template xml has been loaded
*/
export const _loadXML = (assets.loadXML = function loadXML(xml, app = defaultApp) {
const doc = new DOMParser().parseFromString(xml, "text/xml");
if (doc.querySelector("parsererror")) {
throw doc.querySelector("parsererror div").textContent.split(":")[0];
}
for (const element of doc.querySelectorAll("templates > [t-name][owl]")) {
element.removeAttribute("owl");
const name = element.getAttribute("t-name");
const previous = templates.querySelector(`[t-name="${name}"]`);
if (previous) {
console.debug("Override template: " + name);
previous.replaceWith(element);
} else {
templates.documentElement.appendChild(element);
}
}
if (app || defaultApp) {
console.debug("Add templates in Owl app.");
app.addTemplates(templates, app || defaultApp);
} else {
console.debug("Add templates on window Owl container.");
}
});
/**
* Update the default app to load templates.
*
* @param {App} app owl App instance
*/
export function setLoadXmlDefaultApp(app) {
defaultApp = app;
}
这里的app就是全局开始创建的唯一app实例
javascript
/* odoo/addons/web/static/src/start.js */
export async function startWebClient(Webclient) {
..
setLoadXmlDefaultApp(app);
..
}
3 将globalTemplates作为原型来创建this.rawTemplates属性,所以以后通过rawTemplates就能访问globalTemplates(前提是rawTemplates中没有要访问的属性时,才会访问globalTemplates,这是JS的原型链原理)
javascript
/* odoo/addons/web/static/lib/owl/owl.js */
class TemplateSet {
constructor(config = {}) {
this.rawTemplates = Object.create(globalTemplates);
this.templates = {};
..
if (config.templates) {
this.addTemplates(config.templates);
}
}
..
}
因为App继承TemplateSet,并且App没有定义rawTemplates属性,所以app.addTemplates操作的是TemplateSet的rawTemplates
4 后面其他功能通过app.rawTemplates后去需要的模板