习惯着 發表於 2019-9-15 23:29:00

odoo12学习之javascript

<h1 class="_1RuRku">本文来源:https://www.jianshu.com/p/1a47fac01077</h1>
<h1 class="_1RuRku">Odoo12 Javascript 参考指南</h1>
<div class="rEsl9f">
<div class="s-dsoj">&nbsp;</div>
</div>
<p>本文介绍了odoo javascript框架。从代码行的角度来看,这个框架不是一个大的应用程序,但它是非常通用的,因为它基本上是一个将声明性接口描述转换为活动应用程序的机器,能够与数据库中的每个模型和记录交互。甚至可以使用Web客户端修改Web客户端的接口。</p>
<h2>概览</h2>
<p>这个Javascript框架主要设计用于三个地方使用:</p>
<ul>
<li>web客户端:这是一个私有的web应用,可以在其中查看和编辑业务数据。这是一个单页应用程序(永远不会重新加载该页,只在需要时从服务器提取新数据)。</li>
<li>网站:这是Odoo的公共部分。它允许身份不明的用户作为客户端浏览某些内容、购物或执行许多操作。这是一个经典的网站:各种各样的带有控制器的路由和共同协作的Javascript代码。</li>
<li>POS:这是销售点的接口。它是一个特定的但也应用程序。</li>
</ul>
<p>&nbsp;</p>
<h2>Web客户端</h2>
<h4>单页应用</h4>
<p>简而言之,webclient实例是整个用户界面的根组件。它的职责是协调所有的子组件,并提供服务,如RPC、本地存储等等。</p>
<p>在运行时,Web客户端是单页应用程序。每次用户执行操作时,它不需要从服务器请求整页。相反,它只请求它所需要的,然后替换/更新视图。此外,它还管理URL:它与Web客户机状态保持同步。</p>
<p>这意味着,当用户在处理odoo时,Web客户机类(和动作管理器)实际上创建并销毁了许多子组件。状态是高度动态的,每个小部件都可以随时销毁。</p>
<h2>Web客户端JS代码概览</h2>
<p>这里,我们在web/static/src/js插件中快速概述了web客户机代码。注意,这是故意不详尽的,我们只涉及最重要的文件/文件夹。</p>
<ul>
<li>boot.js : 这是定义模块系统的文件,它需要首先加载。</li>
<li>core/ : 这是较低级别的构建基块的集合。值得注意的是,它包含类系统、小部件系统、并发实用程序和许多其他类/函数。</li>
<li>chorm/ :在这个文件夹中,我们有大多数大的小部件,它们构成了大部分用户界面。</li>
<li>chrome/abstract_web_client.js and chrome/web_client.js : 这些文件一起定义了WebClient小部件(widget),它是Web客户机的根小部件(wideget)。</li>
<li>chrome/action_manager.js : 这是将动作(action)转换为小部件(widget)(例如看板或表单视图)的代码。</li>
<li>chrome/search_X.js : 所有这些文件定义了搜索视图(它不是Web客户机视图中的视图,仅从服务器视)</li>
</ul>
<ul>
<li>fields : 这里定义了所有主要字段视图小部件(widget)</li>
<li>views : 这是视图所在的位置</li>
</ul>
<h2>资源管理</h2>
<p>在Odoo中管理资源并不像在其他应用程序中那样简单。其中一个原因是,在其中一些情况中我们有各种各样的状态,但不是所有的资源都是必需的。例如,Web客户端、销售点、网站甚至移动应用程序的需求是不同的。此外,有些资源可能很大,但很少需要。在这种情况下,我们有时希望它们被懒惰地加载。</p>
<p>主要思想是我们用XML定义一组包。捆绑包在这里定义为一组文件(javascript、css、scss)。在odoo中,最重要的包在addons/web/views/webclient_templates.xml文件中定义。看起来是这样的:</p>
<pre class="line-numberslanguage-xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;template <span class="token attr-name">id<span class="token attr-value"><span class="token punctuation">=<span class="token punctuation">"web.assets_common<span class="token punctuation">" <span class="token attr-name">name<span class="token attr-value"><span class="token punctuation">=<span class="token punctuation">"Common Assets (used in backend interface and website)<span class="token punctuation">"<span class="token punctuation">&gt;
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;link <span class="token attr-name">rel<span class="token attr-value"><span class="token punctuation">=<span class="token punctuation">"stylesheet<span class="token punctuation">" <span class="token attr-name">type<span class="token attr-value"><span class="token punctuation">=<span class="token punctuation">"text/css<span class="token punctuation">" <span class="token attr-name">href<span class="token attr-value"><span class="token punctuation">=<span class="token punctuation">"/web/static/lib/jquery.ui/jquery-ui.css<span class="token punctuation">"<span class="token punctuation">/&gt;
    ...
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;script <span class="token attr-name">type<span class="token attr-value"><span class="token punctuation">=<span class="token punctuation">"text/javascript<span class="token punctuation">" <span class="token attr-name">src<span class="token attr-value"><span class="token punctuation">=<span class="token punctuation">"/web/static/src/js/boot.js<span class="token punctuation">"<span class="token punctuation">&gt;<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/script<span class="token punctuation">&gt;
    ...
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/template<span class="token punctuation">&gt;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>然后,可以使用t-call-assets指令将捆绑包中的文件插入到模板中:</p>
<pre class="line-numberslanguage-xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;t <span class="token attr-name">t-call-assets<span class="token attr-value"><span class="token punctuation">=<span class="token punctuation">"web.assets_common<span class="token punctuation">" <span class="token attr-name">t-js<span class="token attr-value"><span class="token punctuation">=<span class="token punctuation">"false<span class="token punctuation">"<span class="token punctuation">/&gt;
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;t <span class="token attr-name">t-call-assets<span class="token attr-value"><span class="token punctuation">=<span class="token punctuation">"web.assets_common<span class="token punctuation">" <span class="token attr-name">t-css<span class="token attr-value"><span class="token punctuation">=<span class="token punctuation">"false<span class="token punctuation">"<span class="token punctuation">/&gt;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>下面是当服务器使用以下指令呈现模板时发生的情况:</p>
<ul>
<li>包中描述的所有SCSS文件都编译为CSS文件。名为file.scss的文件将编译在名为file.scss.css的文件中。</li>
<li><strong>如果我们在debug=assets模式</strong>:<br>   * t-js属性设置为false的t-call-assets指令将替换为指向css文件的样式表标记列表。<br>   * t-css属性设置为false的t-call-assets指令将替换为指向JS文件的脚本标记列表。</li>
<li><strong>如果我们不在debug=assets模式</strong><br>   * CSS文件将被连接并缩小,然后拆分为不超过4096个规则的文件(以绕过IE9的旧限制)。然后,我们根据需要生成尽可能多的样式表标签<br>   * JS文件被连接并缩小,然后生成一个脚本标记。</li>


</ul>
<p>请注意,资源文件是缓存的,因此从理论上讲,浏览器应该只加载它们一次。</p>
<h2>主包</h2>
<p>当odoo服务器启动时,它检查包中每个文件的时间戳,如果需要,它将创建/重新创建相应的包。</p>
<p>以下是大多数开发人员需要知道的一些重要包:</p>
<ul>
<li>web.assets_common : 此包包含Web客户端、网站以及销售点(POS)所共有的大多数资源。这应该包含用于Odoo框架的较低级别的构建块。注意,它包含boot.js文件,它定义了odoo模块系统。</li>
<li>web.assets_backend :这个包包含特定于Web客户端的代码(特别是Web客户端/动作管理器/视图)</li>
<li>web.assets_frontend :这个包是关于所有特定于公共网站的:电子商务、论坛、博客、事件管理…</li>


</ul>
<h2>在一个资源包里添加文件</h2>
<p>将位于addons/web中的文件添加到bundle的正确方法很简单:只需将脚本或样式表标记添加到文件webclient_templates.xml中的bundle即可。但是当我们使用不同的插件(addon)时,我们需要从该插件添加一个文件。在这种情况下,应分三步进行:</p>
<ol>
<li>添加一个 assets.xml 文件到views/文件夹</li>
<li>添加字符'views/assets.xml' 到manifest文件的键'data'的值里</li>
<li>创建所需包的继承视图,并使用xpath表达式添加文件。例如:</li>


</ol>
<pre class="line-numberslanguage-xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;template <span class="token attr-name">id<span class="token attr-value"><span class="token punctuation">=<span class="token punctuation">"assets_backend<span class="token punctuation">" <span class="token attr-name">name<span class="token attr-value"><span class="token punctuation">=<span class="token punctuation">"helpdesk assets<span class="token punctuation">" <span class="token attr-name">inherit_id<span class="token attr-value"><span class="token punctuation">=<span class="token punctuation">"web.assets_backend<span class="token punctuation">"<span class="token punctuation">&gt;
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;xpath <span class="token attr-name">expr<span class="token attr-value"><span class="token punctuation">=<span class="token punctuation">"//script<span class="token punctuation">" <span class="token attr-name">position<span class="token attr-value"><span class="token punctuation">=<span class="token punctuation">"after<span class="token punctuation">"<span class="token punctuation">&gt;
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;link <span class="token attr-name">rel<span class="token attr-value"><span class="token punctuation">=<span class="token punctuation">"stylesheet<span class="token punctuation">" <span class="token attr-name">type<span class="token attr-value"><span class="token punctuation">=<span class="token punctuation">"text/scss<span class="token punctuation">" <span class="token attr-name">href<span class="token attr-value"><span class="token punctuation">=<span class="token punctuation">"/helpdesk/static/src/scss/helpdesk.scss<span class="token punctuation">"<span class="token punctuation">/&gt;
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;script <span class="token attr-name">type<span class="token attr-value"><span class="token punctuation">=<span class="token punctuation">"text/javascript<span class="token punctuation">" <span class="token attr-name">src<span class="token attr-value"><span class="token punctuation">=<span class="token punctuation">"/helpdesk/static/src/js/helpdesk_dashboard.js<span class="token punctuation">"<span class="token punctuation">&gt;<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/script<span class="token punctuation">&gt;
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/xpath<span class="token punctuation">&gt;
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/template<span class="token punctuation">&gt;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<blockquote>
<p>请注意,当用户加载odoo web客户端时,包中的所有文件都会立即加载。这意味着每次通过网络传输文件(浏览器缓存处于活动状态时除外)。在某些情况下,最好使用Lazyload的一些资产。例如,如果一个小部件需要一个大的库,而这个小部件不是体验的核心部分,那么在实际创建小部件时,最好只加载库。widget类实际上已经为这个用例内置了支持。(查阅QWeb模板引擎部分)</p>
</blockquote>
<h2>如果文件没有加载/更新应该怎么办</h2>
<p>文件可能无法正确加载有许多不同的原因。您可以尝试以下几点来解决此问题:</p>
<ul>
<li>一旦服务器启动,它就不知道资源文件是否已被修改。因此,您可以简单地重新启动服务器来重新生成资源。</li>
<li>检查控制台(在开发工具中,通常用F12打开),确保没有明显的错误</li>
<li>尝试在文件的开头添加console.log(在任何模块定义之前),这样您就可以查看文件是否已加载。</li>
<li>在用户界面中,在调试模式下(在此处插入链接到调试模式),有一个选项可以强制服务器更新其资源文件。</li>
<li>使用debug=assets模式。这实际上会绕过资源包(请注意,它实际上并不能解决问题,服务器仍然使用过时的包)</li>
<li>最后,对于开发人员来说,最方便的方法是使用--dev=all选项启动服务器。这将激活文件监视程序选项,必要时将自动使资源无效。请注意,如果操作系统是Windows,它就不能很好地工作。</li>
<li>记住刷新页面!</li>
<li>或者保存代码文件…</li>
</ul>
<p>&nbsp;</p>
<h2>Javascript模块系统</h2>
<p>一旦我们能够将我们的javascript文件加载到浏览器中,我们就需要确保以正确的顺序加载它们。为了实现这一点,odoo定义了一个小模块系统(位于addons/web/static/src/js/boot.js文件中,需要首先加载该文件)。</p>
<p>在AMD的启发下,odoo模块系统通过在全局odoo对象上定义函数define来工作。然后我们通过调用该函数来定义每个javascript模块。在odoo框架中,模块是一段将尽快执行的代码。它有一个名称,可能还有一些依赖项。当它的依赖项被加载时,模块也将被加载。模块的值就是定义模块的函数的返回值。</p>
<p>一个例子,看起来像这样:</p>
<pre class="line-numberslanguage-jsx"><code class="language-jsx"><span class="token comment">// in file a.js
odoo<span class="token punctuation">.<span class="token function">define<span class="token punctuation">(<span class="token string">'module.A'<span class="token punctuation">, <span class="token keyword">function <span class="token punctuation">(<span class="token parameter">require<span class="token punctuation">) <span class="token punctuation">{
    <span class="token string">"use strict"<span class="token punctuation">;

    <span class="token keyword">var <span class="token constant">A <span class="token operator">= <span class="token operator">...<span class="token punctuation">;

    <span class="token keyword">return <span class="token constant">A<span class="token punctuation">;
<span class="token punctuation">}<span class="token punctuation">)<span class="token punctuation">;

<span class="token comment">// in file b.js
odoo<span class="token punctuation">.<span class="token function">define<span class="token punctuation">(<span class="token string">'module.B'<span class="token punctuation">, <span class="token keyword">function <span class="token punctuation">(<span class="token parameter">require<span class="token punctuation">) <span class="token punctuation">{
    <span class="token string">"use strict"<span class="token punctuation">;

    <span class="token keyword">var <span class="token constant">A <span class="token operator">= <span class="token function">require<span class="token punctuation">(<span class="token string">'module.A'<span class="token punctuation">)<span class="token punctuation">;

    <span class="token keyword">var <span class="token constant">B <span class="token operator">= <span class="token operator">...<span class="token punctuation">; <span class="token comment">// something that involves A

    <span class="token keyword">return <span class="token constant">B<span class="token punctuation">;
<span class="token punctuation">}<span class="token punctuation">)<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>定义模块的另一种方法是在第二个参数中明确地给出依赖项列表。</p>
<pre class="line-numberslanguage-jsx"><code class="language-jsx">odoo<span class="token punctuation">.<span class="token function">define<span class="token punctuation">(<span class="token string">'module.Something'<span class="token punctuation">, <span class="token punctuation">[<span class="token string">'module.A'<span class="token punctuation">, <span class="token string">'module.B'<span class="token punctuation">]<span class="token punctuation">, <span class="token keyword">function <span class="token punctuation">(<span class="token parameter">require<span class="token punctuation">) <span class="token punctuation">{
    <span class="token string">"use strict"<span class="token punctuation">;

    <span class="token keyword">var <span class="token constant">A <span class="token operator">= <span class="token function">require<span class="token punctuation">(<span class="token string">'module.A'<span class="token punctuation">)<span class="token punctuation">;
    <span class="token keyword">var <span class="token constant">B <span class="token operator">= <span class="token function">require<span class="token punctuation">(<span class="token string">'module.B'<span class="token punctuation">)<span class="token punctuation">;

    <span class="token comment">// some code
<span class="token punctuation">}<span class="token punctuation">)<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>如果某些依赖项丢失/未就绪,那么模块将不会被加载。几秒钟后控制台中将出现警告。</p>
<p>请注意,不支持循环依赖项。这是有道理的,但这意味着需要谨慎。</p>
<h2>定义一个模块</h2>
<p>odoo.define 方法给了三个参数:</p>
<ul>
<li>moduleName: javascript模块的名称。它应该是一个唯一的字符串。惯例是在odoo插件(addon)的名字后面加上一个具体的描述。例如,“web.widget”描述在web插件中定义的模块,该模块导出一个widget类(因为第一个字母大写)。<br>如果名称不唯一,将引发异常并显示在控制台中</li>
<li>dependencies : 第二个参数是可选的。如果给定,它应该是一个字符串列表,每个字符串对应一个JavaScript模块。这描述了在执行模块之前需要加载的依赖项。如果这里没有明确地给出依赖项,那么模块系统将通过调用ToString从函数中提取它们,然后使用regexp查找所有Require语句。</li>
<li>最后一个参数是定义模块的函数。它的返回值是模块的值,可以传递给其他需要它的模块。注意,异步模块有一个小的异常,请参见下一节。<br>如果发生错误,将在控制台中记录(在调试模式下):</li>
<li>Missing dependencies: 这些模块不会出现在页面中。可能是javascript文件不在页面中或模块名称错误</li>
<li>Failed Modules : 一个Javascript错误被检测到</li>
<li>Rejected modules :块返回拒绝的延迟。它(及其相关模块)未加载。</li>
<li>Rejected linked modules: 依赖被拒绝模块的模块</li>
<li>Non loaded modules : 模块依赖了一个缺失/失败的模块</li>


</ul>
<h2>异步模块</h2>
<p>模块可能需要在准备就绪之前执行一些工作。例如,它可以做一个RPC来加载一些数据。在这种情况下,模块只需返回一个deferred(promise)。在这种情况下,模块系统只需等待deferred完成,然后注册模块。</p>
<pre class="line-numberslanguage-jsx"><code class="language-jsx">odoo<span class="token punctuation">.<span class="token function">define<span class="token punctuation">(<span class="token string">'module.Something'<span class="token punctuation">, <span class="token punctuation">[<span class="token string">'web.ajax'<span class="token punctuation">]<span class="token punctuation">, <span class="token keyword">function <span class="token punctuation">(<span class="token parameter">require<span class="token punctuation">) <span class="token punctuation">{
    <span class="token string">"use strict"<span class="token punctuation">;

    <span class="token keyword">var ajax <span class="token operator">= <span class="token function">require<span class="token punctuation">(<span class="token string">'web.ajax'<span class="token punctuation">)<span class="token punctuation">;

    <span class="token keyword">return ajax<span class="token punctuation">.<span class="token function">rpc<span class="token punctuation">(<span class="token operator">...<span class="token punctuation">)<span class="token punctuation">.<span class="token function">then<span class="token punctuation">(<span class="token keyword">function <span class="token punctuation">(<span class="token parameter">result<span class="token punctuation">) <span class="token punctuation">{
      <span class="token comment">// some code here
      <span class="token keyword">return something<span class="token punctuation">;
    <span class="token punctuation">}<span class="token punctuation">)<span class="token punctuation">;
<span class="token punctuation">}<span class="token punctuation">)<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<h2>最好的练习</h2>
<ul>
<li>记住模块名的约定:插件名加上模块名后缀</li>
<li>在模块顶部声明所有依赖项。此外,它们应该按模块名称的字母顺序排序。这样更容易理解您的模块。</li>
<li>在末尾声明所有导出的值</li>
<li>尽量避免从一个模块导出过多的内容。通常最好在一个(小/更小)模块中简单地导出一件事情。</li>
<li>异步模块可以用来简化一些用例。例如,web.dom_ready模块返回一个deferred ,当dom实际就绪时,这个deferred 将被解决。因此,另一个需要dom的模块可以在某个地方简单地有一个require(“web.dom_ready”)语句,并且只有当dom准备好时才会执行代码。</li>
<li>尽量避免在一个文件中定义多个模块。这在短期内可能很方便,但实际上很难维护。</li>
</ul>
<p>&nbsp;</p>
<p>例子1</p>
<div class="cnblogs_code">
<pre>odoo.define('my_field_widget',<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(require){
    </span>"user strict"<br><br><span style="color: rgba(128, 128, 128, 1)">// 此方法:三个参数:1、A自定义:唯一的。2、是一个列表:可以不写。3、function(require)固定写法<br><span style="color: rgba(152, 118, 170, 1)"> //odoo.<span style="color: rgba(255, 198, 109, 1)">define(<span style="color: rgba(106, 135, 89, 1)">"A"<span style="color: rgba(204, 120, 50, 1)">,[]<span style="color: rgba(204, 120, 50, 1)">,<span style="color: rgba(204, 120, 50, 1); font-weight: bold">function (require) {<br> //       <span style="color: rgba(106, 135, 89, 1)">"user strict"<span style="color: rgba(106, 135, 89, 1)"><br>//})<span style="color: rgba(204, 120, 50, 1)">;</span></span></span></span></span></span></span></span></span></span><br><br>
<span style="color: rgba(0, 0, 255, 1)">var</span> AbstractField = require('web.AbstractField'<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">var</span> fieldRegistry = require('web.field_registry'<span style="color: rgba(0, 0, 0, 1)">);


</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 通过扩展AbstractField来扩展widget</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> colorField =<span style="color: rgba(0, 0, 0, 1)"> AbstractField.extend({
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 设置css类,根元素标记和支持的字段类型</span>
    className:'o_int_colorpicker'<span style="color: rgba(0, 0, 0, 1)">,
    tagName:</span>'span'<span style="color: rgba(0, 0, 0, 1)">,
    supportedFieldTypes: [</span>'integer'<span style="color: rgba(0, 0, 0, 1)">],

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> #获取js事件</span>
<span style="color: rgba(0, 0, 0, 1)">    events:{
      </span>'click.o_color_pill':'clickPill'<span style="color: rgba(0, 0, 0, 1)">,
    },

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 继承init,进行一些初始化</span>
    init:<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.totalColors=10<span style="color: rgba(0, 0, 0, 1)">;
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>._super.apply(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">,arguments);
    },


    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 继承_renderEdit、_renderReadonly以设置Dom元素</span>
    <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> #编辑状态下操作</span>
    _renderEdit:<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
      </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.$el.empty();
      </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> i=0; i&lt;<span style="color: rgba(0, 0, 255, 1)">this</span>.totalColors;i++<span style="color: rgba(0, 0, 0, 1)">){
          </span><span style="color: rgba(0, 0, 255, 1)">var</span> className = "o_color_pill o_color_" +<span style="color: rgba(0, 0, 0, 1)"> i;
          </span><span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">this</span>.value===<span style="color: rgba(0, 0, 0, 1)">i){
            className </span>+= 'active'<span style="color: rgba(0, 0, 0, 1)">
          }
          </span><span style="color: rgba(0, 0, 255, 1)">this</span>.$el.append($('&lt;span&gt;'<span style="color: rgba(0, 0, 0, 1)">,{
             </span>'class'<span style="color: rgba(0, 0, 0, 1)">: className,
            </span>'data-val'<span style="color: rgba(0, 0, 0, 1)">: i,
          }));
      }
    },

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 只读</span>
    _renderReadonly:<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
      </span><span style="color: rgba(0, 0, 255, 1)">var</span> className = "o_color_pill active readonly o_color_"+ <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.value;
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.$el.append($('&lt;span&gt;'<span style="color: rgba(0, 0, 0, 1)">,{
          </span>'class'<span style="color: rgba(0, 0, 0, 1)">:className,
      }));
    },
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 处理程序</span>
    clickPill:<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(ev){
      </span><span style="color: rgba(0, 0, 255, 1)">var</span> $target =<span style="color: rgba(0, 0, 0, 1)"> $(ev.currentTarget);
      </span><span style="color: rgba(0, 0, 255, 1)">var</span> data =<span style="color: rgba(0, 0, 0, 1)"> $target.data();
      </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">._setValue(data.val.toString());
    }
});


</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 注册你的widget</span>
fieldRegistry.add('int_color'<span style="color: rgba(0, 0, 0, 1)">,colorField);

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 使其可以用于其他附加</span>
<span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> {
    colorField:colorField,
};


});<br></span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(128, 0, 0, 1)">.o_int_colorpicker </span>{<span style="color: rgba(255, 0, 0, 1)">
    .o_color_pill {
      display</span>:<span style="color: rgba(0, 0, 255, 1)"> inline-block</span>;<span style="color: rgba(255, 0, 0, 1)">
      height</span>:<span style="color: rgba(0, 0, 255, 1)"> 25px</span>;<span style="color: rgba(255, 0, 0, 1)">
      width</span>:<span style="color: rgba(0, 0, 255, 1)"> 25px</span>;<span style="color: rgba(255, 0, 0, 1)">
      margin</span>:<span style="color: rgba(0, 0, 255, 1)"> 4px</span>;<span style="color: rgba(255, 0, 0, 1)">
      border-radius</span>:<span style="color: rgba(0, 0, 255, 1)"> 25px</span>;<span style="color: rgba(255, 0, 0, 1)">
      position</span>:<span style="color: rgba(0, 0, 255, 1)"> relative</span>;<span style="color: rgba(255, 0, 0, 1)">
      @for $size from 1 through length($o-colors) {
            &amp;.o_color_#{$size - 1</span>} {<span style="color: rgba(255, 0, 0, 1)">
                background-color</span>:<span style="color: rgba(0, 0, 255, 1)"> nth($o-colors, $size)</span>;<span style="color: rgba(255, 0, 0, 1)">
                &amp;</span>:<span style="color: rgba(0, 0, 255, 1)">not(.readonly):hover {
                  transform: scale(1.2)</span>;<span style="color: rgba(255, 0, 0, 1)">
                  transition</span>:<span style="color: rgba(0, 0, 255, 1)"> 0.3s</span>;<span style="color: rgba(255, 0, 0, 1)">
                  cursor</span>:<span style="color: rgba(0, 0, 255, 1)"> pointer</span>;
                }<span style="color: rgba(128, 0, 0, 1)">
                &amp;.active:after</span>{<span style="color: rgba(255, 0, 0, 1)">
                  content</span>:<span style="color: rgba(0, 0, 255, 1)"> "\f00c"</span>;<span style="color: rgba(255, 0, 0, 1)">
                  display</span>:<span style="color: rgba(0, 0, 255, 1)"> inline-block</span>;<span style="color: rgba(255, 0, 0, 1)">
                  font</span>:<span style="color: rgba(0, 0, 255, 1)"> normal normal normal 14px/1 FontAwesome</span>;<span style="color: rgba(255, 0, 0, 1)">
                  font-size</span>:<span style="color: rgba(0, 0, 255, 1)"> inherit</span>;<span style="color: rgba(255, 0, 0, 1)">
                  color</span>:<span style="color: rgba(0, 0, 255, 1)"> #fff</span>;<span style="color: rgba(255, 0, 0, 1)">
                  position</span>:<span style="color: rgba(0, 0, 255, 1)"> absolute</span>;<span style="color: rgba(255, 0, 0, 1)">
                  padding</span>:<span style="color: rgba(0, 0, 255, 1)"> 4px</span>;<span style="color: rgba(255, 0, 0, 1)">
                  font-size</span>:<span style="color: rgba(0, 0, 255, 1)"> 16px</span>;
                }<span style="color: rgba(128, 0, 0, 1)">
            }
      }
    }
}</span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">&lt;?</span><span style="color: rgba(255, 0, 255, 1)">xml version="1.0" encoding="UTF-8"</span><span style="color: rgba(0, 0, 255, 1)">?&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">odoo</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">template </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="assets_end"</span><span style="color: rgba(255, 0, 0, 1)"> inherit_id</span><span style="color: rgba(0, 0, 255, 1)">="web.assets_backend"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">xpath </span><span style="color: rgba(255, 0, 0, 1)">expr</span><span style="color: rgba(0, 0, 255, 1)">="."</span><span style="color: rgba(255, 0, 0, 1)"> position</span><span style="color: rgba(0, 0, 255, 1)">="inside"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">src</span><span style="color: rgba(0, 0, 255, 1)">="/xxx/static/src/js/field_widget.js"</span><span style="color: rgba(255, 0, 0, 1)"> type</span><span style="color: rgba(0, 0, 255, 1)">="text/javascript"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">link </span><span style="color: rgba(255, 0, 0, 1)">href</span><span style="color: rgba(0, 0, 255, 1)">="/xxx/static/src/scss/field_widget.scss"</span><span style="color: rgba(255, 0, 0, 1)"> rel</span><span style="color: rgba(0, 0, 255, 1)">="stylesheet"</span><span style="color: rgba(255, 0, 0, 1)"> type</span><span style="color: rgba(0, 0, 255, 1)">="text/scss"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">xpath</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">odoo</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span></pre>
</div>
<div class="cnblogs_code">
<pre><strong>   <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">field </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="color"</span><span style="color: rgba(255, 0, 0, 1)"> widget</span><span style="color: rgba(0, 0, 255, 1)">="int_color"</span><span style="color: rgba(0, 0, 255, 1)">/&gt;</span></strong></pre>
</div>
<p>&nbsp;</p>
<h2>小部件(Widget)</h2>
<p>widget类实际上是用户界面的一个重要构建块。几乎用户界面中的所有内容都在小部件(widget)的控制之下。widget类在widget.js中的module web.widget中定义。<br>简而言之,widget类提供的特性包括:</p>
<ul>
<li>小部件之间的父/子关系(PropertiesMixin)</li>
<li>**具有安全功能的广泛生命周期管理 **(e.g. 在销毁父级期间自动销毁子窗口小部件)</li>
<li>自动渲染qweb模板</li>
<li>帮助与外部环境交互的各种实用功能。<br>一个计数的小部件例子:</li>


</ul>
<pre class="line-numberslanguage-jsx"><code class="language-jsx"><span class="token keyword"><br>var Widget <span class="token operator">= <span class="token function">require<span class="token punctuation">(<span class="token string">'web.Widget'<span class="token punctuation">)<span class="token punctuation">;

<span class="token keyword">var Counter <span class="token operator">= Widget<span class="token punctuation">.<span class="token function">extend<span class="token punctuation">(<span class="token punctuation">{
    template<span class="token punctuation">: <span class="token string">'some.template'<span class="token punctuation">,
    events<span class="token punctuation">: <span class="token punctuation">{
      <span class="token string">'click button'<span class="token punctuation">: <span class="token string">'_onClick'<span class="token punctuation">,
    <span class="token punctuation">}<span class="token punctuation">,
    <span class="token function-variable function">init<span class="token punctuation">: <span class="token keyword">function <span class="token punctuation">(<span class="token parameter">parent<span class="token punctuation">, value<span class="token punctuation">) <span class="token punctuation">{
      <span class="token keyword">this<span class="token punctuation">.<span class="token function">_super<span class="token punctuation">(parent<span class="token punctuation">)<span class="token punctuation">;
      <span class="token keyword">this<span class="token punctuation">.count <span class="token operator">= value<span class="token punctuation">;
    <span class="token punctuation">}<span class="token punctuation">,
    <span class="token function-variable function">_onClick<span class="token punctuation">: <span class="token keyword">function <span class="token punctuation">(<span class="token punctuation">) <span class="token punctuation">{
      <span class="token keyword">this<span class="token punctuation">.count<span class="token operator">++<span class="token punctuation">;
      <span class="token keyword">this<span class="token punctuation">.<span class="token function">$<span class="token punctuation">(<span class="token string">'.val'<span class="token punctuation">)<span class="token punctuation">.<span class="token function">text<span class="token punctuation">(<span class="token keyword">this<span class="token punctuation">.count<span class="token punctuation">)<span class="token punctuation">;
    <span class="token punctuation">}<span class="token punctuation">,
<span class="token punctuation">}<span class="token punctuation">)<span class="token punctuation">;<br><br></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>对于本例,假设模板some.template(并且正确加载:模板位于一个文件中,该文件在模块清单中的qweb键中正确定义)如下:</p>
<pre class="line-numberslanguage-xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;div <span class="token attr-name">t-name<span class="token attr-value"><span class="token punctuation">=<span class="token punctuation">"some.template<span class="token punctuation">"<span class="token punctuation">&gt;
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;span <span class="token attr-name">class<span class="token attr-value"><span class="token punctuation">=<span class="token punctuation">"val<span class="token punctuation">"<span class="token punctuation">&gt;<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;t <span class="token attr-name">t-esc<span class="token attr-value"><span class="token punctuation">=<span class="token punctuation">"widget.count<span class="token punctuation">"<span class="token punctuation">/&gt;<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/span<span class="token punctuation">&gt;
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;button<span class="token punctuation">&gt;Increment<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/button<span class="token punctuation">&gt;
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/div<span class="token punctuation">&gt;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>这个例子说明了小部件类的一些特性,包括事件系统、模板系统、带有初始父参数的构造函数。</p>
<h2>小部件的生命周期</h2>
<p>与许多组件系统一样,widget类有一个定义良好的生命周期。通常的生命周期如下:调用init,然后willStart,然后rendering,然后start,最后destroy。</p>
<p><code>Widget.init(parent)</code><br>这是构造函数。init方法应该初始化小部件的基本状态。它是同步的,可以被重写以从小部件的创建者/父对象获取更多参数。</p>
<blockquote>
<p>Arguments : parent(<code>Widget()</code>)–新的widget的父级,用于处理自动销毁和事件传播。对于没有父级的小部件,可以为<code>null</code>。</p>


</blockquote>
<p><code>Widget.willStart()</code><br>当一个小部件被创建并被附加到DOM的过程中,框架将调用这个方法一次。willstart方法是一个钩子,它应该返回一个deferred。JS框架将等待这个deferred完成,然后再继续渲染步骤。注意,此时小部件没有dom根元素。willstart钩子主要用于执行一些异步工作,例如从服务器获取数据。</p>
<p><code>()</code><br>此步骤由框架自动完成。框架会检查小部件上是否定义了template键。如果定义了,那么它将在呈现上下文中使用绑定到小部件的widget键呈现该模板(请参见上面的示例:我们在QWeb模板中使用widget.count来读取小部件的值)。如果没有定义模板,则读取 tagName 键并创建相应的DOM元素。渲染完成后,我们将结果设置为小部件的$el属性。在此之后,我们将自动绑定events和custom_events键中的所有事件。</p>
<p><code>Widget.start()</code><br>渲染完成后,框架将自动调用Start方法。这对于执行一些特殊的后期渲染工作很有用。例如,设置库。<br>必须返回deferred以指示其工作何时完成。</p>
<blockquote>
<p>Returns: deferred 对象</p>


</blockquote>
<p><code>Widget.destroy()</code><br>这始终是小部件生命周期中的最后一步。当小部件被销毁时,我们基本上执行所有必要的清理操作:从组件树中删除小部件,取消绑定所有事件,…<br>当小部件的父级被销毁时自动调用,如果小部件没有父级,或者如果它被删除但父级仍然存在,则必须显式调用。</p>
<p>请注意,不必调用willstart和start方法。可以创建一个小部件(将调用init方法),然后销毁(destroy方法),而不需要附加到DOM。如果是这种情况,将不会调用will start和start。</p>
<pre class="line-numberslanguage-jsx"><code class="language-jsx"><span class="token keyword"><span class="token operator"><span class="token function"><span class="token punctuation"><span class="token string"><span class="token punctuation"><span class="token punctuation"><span class="token keyword"><span class="token operator"><span class="token punctuation"><span class="token function"><span class="token punctuation"><span class="token punctuation"><span class="token punctuation"><span class="token string"><span class="token punctuation"><span class="token punctuation"><span class="token punctuation"><span class="token string"><span class="token punctuation"><span class="token string"><span class="token punctuation"><span class="token punctuation"><span class="token punctuation"><span class="token function-variable function"><span class="token punctuation"><span class="token keyword"><span class="token punctuation"><span class="token parameter"><span class="token punctuation"><span class="token punctuation"><span class="token punctuation"><span class="token keyword"><span class="token punctuation"><span class="token function"><span class="token punctuation"><span class="token punctuation"><span class="token punctuation"><span class="token keyword"><span class="token punctuation"><span class="token operator"><span class="token punctuation"><span class="token punctuation"><span class="token punctuation"><span class="token function-variable function"><span class="token punctuation"><span class="token keyword"><span class="token punctuation"><span class="token punctuation"><span class="token punctuation"><span class="token keyword"><span class="token punctuation"><span class="token operator"><span class="token punctuation"><span class="token keyword"><span class="token punctuation"><span class="token function"><span class="token punctuation"><span class="token string"><span class="token punctuation"><span class="token punctuation"><span class="token function"><span class="token punctuation"><span class="token keyword"><span class="token punctuation"><span class="token punctuation"><span class="token punctuation"><span class="token punctuation"><span class="token punctuation"><span class="token punctuation"><span class="token punctuation"><span class="token punctuation">&nbsp;</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<h2>Widget API</h2>
<p><code>Widget.tagName</code><br>如果小部件没有定义模板,则使用。默认为DIV,将用作标记名来创建要设置为小部件的dom根的dom元素。可以使用以下属性进一步自定义生成的dom根目录:</p>
<p><code>Widget.id</code><br>用于在生成的dom根上生成id属性。请注意,这是很少需要的,如果一个小部件可以多次使用,这可能不是一个好主意。</p>
<p><code>Widget.className</code><br>用于在生成的dom根上生成class属性。请注意,它实际上可以包含多个css类:“some-class other-class”</p>
<p><code>Widget.attributes</code><br>属性名到属性值的映射(对象文本)。这些k:v对中的每一个都将被设置为生成的dom根上的dom属性。</p>
<p><code>Widget.el</code><br>将原始dom元素设置为小部件的根(仅在start lifecyle方法之后可用)</p>
<p><code>Widget.$el</code><br>jquery封装的el,(仅在Start Lifecyle方法之后可用)</p>
<p><code>Widget.template</code><br>应设置为QWeb模板的名称。如果设置了,模板将在小部件初始化之后但在其启动之前呈现。模板生成的根元素将被设置为小部件的dom根。</p>
<p><code>Widget.xmlDependencies</code><br>呈现小部件之前需要加载的XML文件的路径列表。这不会导致加载已加载的任何内容。如果您想延迟加载模板,或者想要在网站和Web客户机界面之间共享一个小部件,这很有用。</p>
<pre class="line-numberslanguage-csharp"><code class="language-csharp"><span class="token keyword">var EditorMenuBar <span class="token operator">= Widget<span class="token punctuation">.<span class="token function">extend<span class="token punctuation">(<span class="token punctuation">{
    xmlDependencies<span class="token punctuation">: <span class="token punctuation">[<span class="token string">'/web_editor/static/src/xml/editor.xml'<span class="token punctuation">]<span class="token punctuation">,
    <span class="token punctuation">.<span class="token punctuation">.<span class="token punctuation">.
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p><code>Widget.events</code><br>事件是事件选择器(由空格分隔的事件名称和可选CSS选择器)到回调的映射。回调可以是小部件方法或函数对象的名称。在这两种情况下,这都将设置为小部件:</p>
<pre class="line-numberslanguage-events"><code class="events: :language-events">    'click p.oe_some_class a': 'some_method',
    'change input': function (e) {
      e.stopPropagation();
    }
},
</code></pre>
<p>选择器用于jquery的事件委托,回调只对与选择器匹配的dom根的后代触发。如果选择器被省略(只指定了一个事件名),那么事件将直接设置在小部件的dom根上。<br>注意:不鼓励使用内联函数,将来可能会删除它。</p>
<p><code>Widget.custom_events</code></p>
<blockquote>
<p>returns: true 如果小部件正在或者已经被销毁,否则false</p>


</blockquote>
<p><code>Widget.$(selector)</code><br>将指定为参数的CSS选择器应用于小部件的dom根:<br><code>this.$(selector);</code><br>功能上与以下相同:<br><code>this.$el.find(selector);</code></p>
<blockquote>
<p>arguments: selector(string)-CSS选择器<br>return:jQuery 对象</p>


</blockquote>
<blockquote>
<p>这个助手方法类似于<code>Backbone.View.$</code></p>


</blockquote>
<p><code>Widget.setElement(element)</code><br>将小部件的dom根重新设置为提供的元素,还处理重新设置dom根的各种别名以及取消设置和重新设置委托事件。</p>
<blockquote>
<p>arguments: element(Element) -一个DOM元素或者jQuery对象设置为小部件的根DOM</p>


</blockquote>
<h2>在DOM中插入一个小部件</h2>
<p><code>Widget.appendTo(element)</code><br>渲染小部件并将它作为子元素插入到目标元素后面,使用<code>.appentTo()</code></p>
<p><code>Widget.prependTo(element)</code><br>渲染小部件并将它作为子元素插入到目标元素前面,使用<code>.prependTo()</code></p>
<p><code>Widget.insertAfter(element)</code><br>渲染小部件并将它作为目标元素的前一个同级插入,使用<code>.insertAfter()</code></p>
<p><code>Widget.insertBefore(element)</code><br>渲染小部件并将其作为目标的后一个同级插入,使用<code>.insertBefore()</code></p>
<p>所有这些方法都接受相应jquery方法接受的任何内容(css选择器、dom节点或jquery对象)。他们都会返回一个 deferred,并承担三个任务:</p>
<ul>
<ul>
<li><strong>通过以下方式呈现小部件的根元素:</strong><br><code>renderElement()</code></li>
<li><strong>使用jquery在DOM中插入小部件的根元素</strong><br>匹配的方法</li>
<li>启动小部件并返回启动结果
<div>&nbsp;</div>

</li>


</ul>

</ul>

</div>
<div id="MySignature" role="contentinfo">
    心有猛虎,细嗅蔷薇<br><br>
来源:https://www.cnblogs.com/1314520xh/p/11525103.html
頁: [1]
查看完整版本: odoo12学习之javascript