当前位置: 首页 > news >正文

来宾 网站建设太原seo推广优化

来宾 网站建设,太原seo推广优化,wordpress 长微博,seo网络培训机构odoo16前端框架源码阅读——启动、菜单、动作 目录#xff1a;addons/web/static/src 1、main.js odoo实际上是一个单页应用#xff0c;从名字看#xff0c;这是前端的入口文件#xff0c;文件内容也很简单。 /** odoo-module **/import { startWebClient } from addons/web/static/src 1、main.js odoo实际上是一个单页应用从名字看这是前端的入口文件文件内容也很简单。 /** odoo-module **/import { startWebClient } from ./start; import { WebClient } from ./webclient/webclient;/*** This file starts the webclient. It is in its own file to allow its replacement* in enterprise. The enterprise version of the file uses its own webclient import,* which is a subclass of the above Webclient.*/startWebClient(WebClient); 关键的是最后一行代码 调用了startWebClient函数启动了一个WebClient。 非常简单而且注释也说明了企业版可以启动专有的webclient。 2、start.js 这个模块中只有一个函数startWebClient注释也说明了它的作用就是启动一个webclient而且企业版和社区版都会执行这个函数只是webclient不同而已。 这个文件大概干了这么几件事 1、定义了odoo.info 2、生成env并启动相关服务 3、定义了一个app对象并且把Webclient 做了构造参数传递进去并且将app挂载到body上 4、根据不同的环境给body设置了不同的class 5、最后设置odoo.readytrue 总体来说就是准备环境启动服务生成app。 这个跟vue的做法类似。 /** odoo-module **/import { makeEnv, startServices } from ./env; import { legacySetupProm } from ./legacy/legacy_setup; import { mapLegacyEnvToWowlEnv } from ./legacy/utils; import { localization } from web/core/l10n/localization; import { session } from web/session; import { renderToString } from ./core/utils/render; import { setLoadXmlDefaultApp, templates } from web/core/assets; import { hasTouch } from web/core/browser/feature_detection;import { App, whenReady } from odoo/owl;/*** Function to start a webclient.* It is used both in community and enterprise in main.js.* Its meant to be webclient flexible so we can have a subclass of* webclient in enterprise with added features.** param {Component} Webclient*/ export async function startWebClient(Webclient) {odoo.info {db: session.db,server_version: session.server_version,server_version_info: session.server_version_info,isEnterprise: session.server_version_info.slice(-1)[0] e,};odoo.isReady false;// setup environmentconst env makeEnv();await startServices(env);// start web clientawait whenReady();const legacyEnv await legacySetupProm;mapLegacyEnvToWowlEnv(legacyEnv, env);const app new App(Webclient, {env,templates,dev: env.debug,translatableAttributes: [data-tooltip],translateFn: env._t,});renderToString.app app;setLoadXmlDefaultApp(app);const root await app.mount(document.body);const classList document.body.classList;if (localization.direction rtl) {classList.add(o_rtl);}if (env.services.user.userId 1) {classList.add(o_is_superuser);}if (env.debug) {classList.add(o_debug);}if (hasTouch()) {classList.add(o_touch_device);}// delete odoo.debug; // FIXME: some legacy code rely on thisodoo.__WOWL_DEBUG__ { root };odoo.isReady true;// Update Faviconsconst favicon /web/image/res.company/${env.services.company.currentCompany.id}/favicon;const icons document.querySelectorAll(link[rel*icon]);const msIcon document.querySelector(meta[namemsapplication-TileImage]);for (const icon of icons) {icon.href favicon;}if (msIcon) {msIcon.content favicon;} } 3、WebClient 很明显webclient是一个owl组件这就是我们看到的odoo的主界面值得好好分析。 这里的重点就是 在onMounted钩子中调用了 this.loadRouterState(); 而这个函数呢一开始就获取了两个变量 let stateLoaded await this.actionService.loadState();let menuId Number(this.router.current.hash.menu_id || 0);后面就是根据这两个变量的值的不同的组合进行处理。 如果menuId 为false则返回第一个应用。 /** odoo-module **/import { useOwnDebugContext } from web/core/debug/debug_context; import { DebugMenu } from web/core/debug/debug_menu; import { localization } from web/core/l10n/localization; import { MainComponentsContainer } from web/core/main_components_container; import { registry } from web/core/registry; import { useBus, useService } from web/core/utils/hooks; import { ActionContainer } from ./actions/action_container; import { NavBar } from ./navbar/navbar;import { Component, onMounted, useExternalListener, useState } from odoo/owl;export class WebClient extends Component {setup() {this.menuService useService(menu);this.actionService useService(action);this.title useService(title);this.router useService(router);this.user useService(user);useService(legacy_service_provider);useOwnDebugContext({ categories: [default] });if (this.env.debug) {registry.category(systray).add(web.debug_mode_menu,{Component: DebugMenu,},{ sequence: 100 });}this.localization localization;this.state useState({fullscreen: false,});this.title.setParts({ zopenerp: Odoo }); // zopenerp is easy to grepuseBus(this.env.bus, ROUTE_CHANGE, this.loadRouterState);useBus(this.env.bus, ACTION_MANAGER:UI-UPDATED, ({ detail: mode }) {if (mode ! new) {this.state.fullscreen mode fullscreen;}});onMounted(() {this.loadRouterState();// the chat window and dialog services listen to web_client_ready event in// order to initialize themselves:this.env.bus.trigger(WEB_CLIENT_READY);});useExternalListener(window, click, this.onGlobalClick, { capture: true });}async loadRouterState() {let stateLoaded await this.actionService.loadState();let menuId Number(this.router.current.hash.menu_id || 0);if (!stateLoaded menuId) {// Determines the current actionId based on the current menuconst menu this.menuService.getAll().find((m) menuId m.id);const actionId menu menu.actionID;if (actionId) {await this.actionService.doAction(actionId, { clearBreadcrumbs: true });stateLoaded true;}}if (stateLoaded !menuId) {// Determines the current menu based on the current actionconst currentController this.actionService.currentController;const actionId currentController currentController.action.id;const menu this.menuService.getAll().find((m) m.actionID actionId);menuId menu menu.appID;}if (menuId) {// Sets the menu according to the current actionthis.menuService.setCurrentMenu(menuId);}if (!stateLoaded) {// If no action falls back to the default appawait this._loadDefaultApp();}}_loadDefaultApp() {// Selects the first root menu if anyconst root this.menuService.getMenu(root);const firstApp root.children[0];if (firstApp) {return this.menuService.selectMenu(firstApp);}}/*** param {MouseEvent} ev*/onGlobalClick(ev) {// When a ctrl-click occurs inside an a href/ element// we let the browser do the default behavior and// we do not want any other listener to execute.if (ev.ctrlKey !ev.target.isContentEditable ((ev.target instanceof HTMLAnchorElement ev.target.href) ||(ev.target instanceof HTMLElement ev.target.closest(a[href]:not([href]))))) {ev.stopImmediatePropagation();return;}} } WebClient.components {ActionContainer,NavBar,MainComponentsContainer, }; WebClient.template web.WebClient; 4、web.WebClient webclient的模板文件简单的狠用了三个组件 NavBar 顶部的导航栏 ActionContainer 除了导航栏之外的其他可见的部分 MainComponentsContainer 这其实是不可见的包含了通知之类的东东在一定条件下可见 ?xml version1.0 encodingUTF-8? templates xml:spacepreservet t-nameweb.WebClient owl1t t-if!state.fullscreenNavBar//tActionContainer/MainComponentsContainer//t/templates 5、menus\menu_service.js Webclient中用到了menuservice现在来看看这个文件 /** odoo-module **/import { browser } from ../../core/browser/browser; import { registry } from ../../core/registry; import { session } from web/session;const loadMenusUrl /web/webclient/load_menus;function makeFetchLoadMenus() {const cacheHashes session.cache_hashes;let loadMenusHash cacheHashes.load_menus || new Date().getTime().toString();return async function fetchLoadMenus(reload) {if (reload) {loadMenusHash new Date().getTime().toString();} else if (odoo.loadMenusPromise) {return odoo.loadMenusPromise;}const res await browser.fetch(${loadMenusUrl}/${loadMenusHash});if (!res.ok) {throw new Error(Error while fetching menus);}return res.json();}; }function makeMenus(env, menusData, fetchLoadMenus) {let currentAppId;return {getAll() {return Object.values(menusData);},getApps() {return this.getMenu(root).children.map((mid) this.getMenu(mid));},getMenu(menuID) {return menusData[menuID];},getCurrentApp() {if (!currentAppId) {return;}return this.getMenu(currentAppId);},getMenuAsTree(menuID) {const menu this.getMenu(menuID);if (!menu.childrenTree) {menu.childrenTree menu.children.map((mid) this.getMenuAsTree(mid));}return menu;},async selectMenu(menu) {menu typeof menu number ? this.getMenu(menu) : menu;if (!menu.actionID) {return;}await env.services.action.doAction(menu.actionID, { clearBreadcrumbs: true });this.setCurrentMenu(menu);},setCurrentMenu(menu) {menu typeof menu number ? this.getMenu(menu) : menu;if (menu menu.appID ! currentAppId) {currentAppId menu.appID;env.bus.trigger(MENUS:APP-CHANGED);// FIXME: lock API: maybe do something like// pushState({menu_id: ...}, { lock: true}); ?env.services.router.pushState({ menu_id: menu.id }, { lock: true });}},async reload() {if (fetchLoadMenus) {menusData await fetchLoadMenus(true);env.bus.trigger(MENUS:APP-CHANGED);}},}; }export const menuService {dependencies: [action, router],async start(env) {const fetchLoadMenus makeFetchLoadMenus();const menusData await fetchLoadMenus();return makeMenus(env, menusData, fetchLoadMenus);}, };registry.category(services).add(menu, menuService); 重点是这个函数 async selectMenu(menu) {menu typeof menu number ? this.getMenu(menu) : menu;if (!menu.actionID) {return;}await env.services.action.doAction(menu.actionID, { clearBreadcrumbs: true });this.setCurrentMenu(menu);它调用了action的doAction。 6、actions\action_service.js 这里只截取了该文件的一部分根据不同的action类型进行不同的处理。 /*** Main entry point of a doAction request. Loads the action and executes it.** param {ActionRequest} actionRequest* param {ActionOptions} options* returns {Promisenumber | undefined | void}*/async function doAction(actionRequest, options {}) {const actionProm _loadAction(actionRequest, options.additionalContext);let action await keepLast.add(actionProm);action _preprocessAction(action, options.additionalContext);options.clearBreadcrumbs action.target main || options.clearBreadcrumbs;switch (action.type) {case ir.actions.act_url:return _executeActURLAction(action, options);case ir.actions.act_window:if (action.target ! new) {const canProceed await clearUncommittedChanges(env);if (!canProceed) {return new Promise(() {});}}return _executeActWindowAction(action, options);case ir.actions.act_window_close:return _executeCloseAction({ onClose: options.onClose, onCloseInfo: action.infos });case ir.actions.client:return _executeClientAction(action, options);case ir.actions.report:return _executeReportAction(action, options);case ir.actions.server:return _executeServerAction(action, options);default: {const handler actionHandlersRegistry.get(action.type, null);if (handler ! null) {return handler({ env, action, options });}throw new Error(The ActionManager service cant handle actions of type ${action.type});}}}action是一个Component 这个函数会返回一个action然后塞到页面上去。 我们重点关注ir.actions.act_window case ir.actions.act_window:if (action.target ! new) {const canProceed await clearUncommittedChanges(env);if (!canProceed) {return new Promise(() {});}}return _executeActWindowAction(action, options);_executeActWindowAction 函数 .... 省略1000字return _updateUI(controller, updateUIOptions);最后调用了_updateUI这个函数会动态生成一个Component最后通过总线发送ACTION_MANAGER:UPDATE 消息 controller.__info__ {id: id,Component: ControllerComponent,componentProps: controller.props,};env.bus.trigger(ACTION_MANAGER:UPDATE, controller.__info__);return Promise.all([currentActionProm, closingProm]).then((r) r[0]);我们继续看是谁接收了这个消息 7、action_container.js action_container 接收了ACTION_MANAGER:UPDATE消息并做了处理调用了render函数 而ActionContainer组件是webClient的一个子组件 这样整个逻辑就自洽了。 addons\web\static\src\webclient\actions\action_container.js /** odoo-module **/import { ActionDialog } from ./action_dialog;import { Component, xml, onWillDestroy } from odoo/owl;// ----------------------------------------------------------------------------- // ActionContainer (Component) // ----------------------------------------------------------------------------- export class ActionContainer extends Component {setup() {this.info {};this.onActionManagerUpdate ({ detail: info }) {this.info info;this.render();};this.env.bus.addEventListener(ACTION_MANAGER:UPDATE, this.onActionManagerUpdate);onWillDestroy(() {this.env.bus.removeEventListener(ACTION_MANAGER:UPDATE, this.onActionManagerUpdate);});} } ActionContainer.components { ActionDialog }; ActionContainer.template xmlt t-nameweb.ActionContainerdiv classo_action_managert t-ifinfo.Component t-componentinfo.Component classNameo_action t-propsinfo.componentProps t-keyinfo.id//div/t; 上面整个过程 就完成了客户端的启动以及菜单》动作》页面渲染的循环。 当然里面还有很多细节的东西值得研究不过大概的框架就是这样了。
http://www.zqtcl.cn/news/72004/

相关文章:

  • 成品网站 修改首页宿松网站建设设计
  • 哪些公司需要网站开发工程师微信上wordpress
  • 杭州鼎易科技做网站太坑广告公司网站建设的定位
  • 装饰网站建设重要性网站建设标准流程及外包注意事项
  • dede网站修改深圳设计网站
  • 境外建网站个人博客网站建设业务
  • q王商城 网站是怎么做的深圳工程交易服务网
  • 如何在淘宝客上做自己的网站网络设计培训
  • seo网站推广的主要目的不包括91永久免费海外地域网名
  • 免费的建筑设计网站北京上海网站建设
  • 高端大气seo整站优化服务
  • 网站建设是如何寻找客户的wordpress seo教程
  • 房产建设网站简洁风网站
  • vps挂网站建设银行贷款网站
  • indesign做网站呼伦贝尔网站建设公司
  • 南阳那里有做网站的网站制作青岛公司
  • 推广赚钱的软件win7系统优化大师
  • 网站500错误是什么意思凯里seo排名优化
  • 常州网站推广公司伊春网站开发
  • 网站程序怎么上传东莞凤岗房价
  • 免费网站建设免代码网站icp备案号查询
  • 做湲兔费网站视颍新开传奇网站超变
  • asp.net 开发的网站html网页制作流程
  • 多个域名指定同一个网站好处淮南市网站建设
  • 网页设计与网站开发试题答案wordpress添加搜索小工具
  • 吉浦网站建设网站侧面的虚浮代码
  • wordpress 选项卡插件seo如何快速出排名
  • 中牟网站建设关键字挖掘机爱站网
  • 宁波网站建设医院网站开发兼职
  • 网站速度对seo的影响app成本