主题设计

在您的开发环境完全设置好之后,您可以开始构建主题模块的框架。在本章中,您将了解如何:

  • 启用或禁用网站构建器的标准选项和模板。

  • 定义设计中使用的颜色和字体。

  • 充分利用 Bootstrap 变量。

  • 添加自定义样式和 JavaScript。

主题模块

Odoo 提供了一个默认主题,它提供了一个最小化的结构和布局。当您创建一个新主题时,您是在扩展默认主题。

在开发环境中运行 Odoo 时,请记住将包含您的模块的目录添加到命令行参数 addons-path 中。

技术命名

第一步是创建一个新目录。

website_airproof

注解

为其添加 website_ 前缀,并仅使用小写的 ASCII 字母、数字和下划线。

在本文档中,我们将以 Airproof (一个虚构项目)为例。

文件结构

主题像任何 Odoo 模块一样被打包。即使您正在设计一个基础网站,也需要像模块一样打包其主题。

website_airproof
├── data
├── i18n
├── static
│   ├── description
│   ├── fonts
│   ├── lib
│   ├── image_shapes // Shapes for images
│   ├── shapes // Shapes for background
│   └── src
│       ├── img
│       │   ├── content // For those used in the pages of your website
│       │   └── wbuilder // For those used in the builder
│       ├── js
│       ├── scss // Theme specific styles
│       ├── snippets // Custom snippets
│       └── website_builder // Options for the Website Builder
├── views
├── __init__.py
└── __manifest__.py

文件夹

描述

数据

预设、菜单、页面、图像、形状等( *.xml )

国际化

翻译(*.po、*.pot)

库

外部库( *.js )

静态文件

自定义资源(*.jpg、*.gif、*.png、*.svg、*.pdf、*.scss、*.js)

视图

自定义视图和模板( *.xml )

初始化

Odoo 模块也是一个 Python 包,包含一个 __init__.py 文件,该文件包含模块中各种 Python 文件的导入指令。此文件目前可以保持为空。

声明

Odoo 模块通过其清单文件进行声明。该文件将 Python 包声明为 Odoo 模块,并指定模块的元数据。它至少必须包含始终必需的 name 字段,通常还包含更多信息。

/website_airproof/__manifest__.py
{
   'name': 'Airproof Theme',
   'description': '...',
   'category': 'Website/Theme',
   'version': '20.0.0',
   'author': '...',
   'license': '...',
   'depends': ['website'],
   'data': [
      # ...
   ],
   'assets': {
      # ...
   },
}

字段

描述

名称

模块的可读名称(必填)

描述

模块的扩展描述,使用 reStructuredText 格式

类别

Odoo 中的分类类别

版本

此模块针对的 Odoo 版本

作者

模块作者的名称

许可证

默认情况下,我们使用 LGPL-3 许可证。更多信息请参阅 模块清单 页面。

依赖

必须在此模块之前加载这些 Odoo 模块,因为此模块使用它们创建的功能或更改它们定义的资源

数据

XML 文件列表

资源

SCSS 和 JS 文件列表

注解

  • 上面的文件结构只是一个建议。我们可以根据需要在项目中添加其他文件夹,例如 /controllers 用于包含控制器或 /views/backend 用于后端视图等。

  • 要创建一个网站主题,您只需安装 Website 应用。如果您需要其他应用(如博客、活动、电子商务等),也可以添加它们。

  • Odoo 版本号及主版本号是必填的,但补丁号可选。若需指定运行本模块所要求的 Odoo 版本,应使用五段式结构,其中前两段表示当前的 Odoo 版本(* = 20.0)。

模块版本控制

示例:20.0.1.0.0,格式为 odoo_major.odoo_minor.module_major.module_minor.module_patch

警告

在 Odoo SaaS 数据库中,使用通配符表示法(例如: /myfolder/*.scss )的自动文件包含不起作用。在这种情况下,请在清单中手动包含每个文件。

默认选项

首先,尝试使用 Odoo 的默认选项构建您的主题。这确保了两点:

  1. 您不会重新发明已经存在的功能。例如,由于 Odoo 提供了在页脚添加边框的选项,您不应自己重新编写代码。相反,首先启用默认选项,然后在需要时扩展它。

  2. 用户仍然可以使用您的主题中的所有 Odoo 功能。例如,如果您重新编写页脚边框的代码,可能会破坏默认选项或使其无用,从而给用户带来糟糕的体验。此外,您的重写可能不如默认选项好,因为其他 Odoo 功能可能依赖于它。

小技巧

  • 每个缩进级别使用四个空格。

  • 不要使用制表符。

  • 切勿混用空格和制表符。

另请参阅

Odoo 编码指南

Odoo 变量

Odoo 定义了许多 CSS 规则,大多数可以通过覆盖相关的 SCSS 变量完全自定义。为此,请创建一个 primary_variables.scss 文件并将其添加到 _assets_primary_variables 包中。

声明

/website_airproof/__manifest__.py
'assets': {
   'web._assets_primary_variables': [
      'website_airproof/static/src/scss/primary_variables.scss',
   ],
},

通过阅读源代码,与选项相关的变量很容易被注意到。

<BuilderSelectItem
   id="'...'"
   title.translate="..."
   actionParam="[
      {
         action: 'websiteConfig',
         actionParam: {
             views: [...],
             vars: { 'header-template': 'sidebar' },
             checkVars: false,
         }
      }
   ]">
   <Img src="'/website_airproof/static/src/img/wbuilder/template-header-opt.svg'" class="'mw-100'" />
</BuilderSelectItem>

例如,这些变量可以通过 $o-website-value-palettes 映射覆盖。

全局

声明

/website_airproof/static/src/scss/primary_variables.scss
$o-website-values-palettes: (
   (
      // Templates
      // Colors
      // Fonts
      // Buttons
      // ...
   ),
);

小技巧

该文件只能包含 SCSS 变量和混合的定义和覆盖。

另请参阅

主要变量 SCSS

字体

您可以嵌入任何字体到您的网站中。Website Builder 会自动将它们显示在字体选择器中。

声明

/website_airproof/static/src/scss/primary_variables.scss
$o-theme-font-configs: (
   <font-name>: (
      'family': <CSS font family list>,
      'url' (optional): <related part of Google fonts URL>,
      'properties' (optional): (
         <font-alias>: (
            <website-value-key>: <value>,
            ...,
         ),
      ...,
   )
)

用法

/website_airproof/static/src/scss/primary_variables.scss
$o-website-values-palettes: (
   (
      'font':                             '<font-name>',
      'headings-font':                    '<font-name>',
      'navbar-font':                      '<font-name>',
      'buttons-font':                     '<font-name>',
   ),
);
Google 字体
/website_airproof/static/src/scss/primary_variables.scss
$o-theme-font-configs: (
   'Poppins': (
      'family':                         ('Poppins', sans-serif),
      'url':                            'Poppins:400,500',
      'properties' : (
         'base': (
            'font-size-base':           1rem,
         ),
      ),
   ),
);
自定义字体

首先,创建一个特定的 SCSS 文件来声明您的自定义字体。

/website_airproof/__manifest__.py
'assets': {
   'web.assets_frontend': [
      'website_airproof/static/src/scss/fonts.scss',
   ],
},

然后,使用 @font-face 规则允许您的自定义字体加载到网站上。

/website_airproof/static/src/scss/fonts.scss
@font-face {
   font-family: "My Custom Font", Helvetica, Helvetica Neue, Arial, sans-serif;
   font-weight: 400;
   font-style: normal;
   src: url('/fonts/my-custom-font.woff') format('woff'),
        url('/fonts/my-custom-font.woff2') format('woff2');
}
/website_airproof/static/src/scss/primary_variables.scss
$o-theme-font-configs: (
   'Proxima Nova': (
      'family':                         ('Proxima Nova', sans-serif),
      'properties' : (
         'base': (
            'font-size-base':           1rem,
         ),
      ),
   ),
);

小技巧

建议为您的字体使用 .woff 和/或 .woff2 格式。

颜色

Website Builder 依赖于由五种命名颜色组成的调色板。在主题中定义这些颜色可以确保一致性。

颜色

描述

o-color-1

主色

o-color-2

次色

o-color-3

额外(浅色)

o-color-4

偏白色

o-color-5

偏黑色

主题颜色

声明

/website_airproof/static/src/scss/primary_variables.scss
$o-color-palettes: map-merge($o-color-palettes,
   (
      'airproof': (
         'o-color-1':                    #bedb39,
         'o-color-2':                    #2c3e50,
         'o-color-3':                    #f2f2f2,
         'o-color-4':                    #ffffff,
         'o-color-5':                    #000000,
      ),
   )
);

将创建的调色板添加到 Website Builder 提供的调色板列表中。

$o-selected-color-palettes-names: append($o-selected-color-palettes-names, 'airproof');

用法

/website_airproof/static/src/scss/primary_variables.scss
$o-website-values-palettes: (
   (
      'color-palettes-name':              'airproof',
   ),
);
主题颜色 Airproof

颜色组合

基于之前定义的五种颜色调色板,Website Builder 会自动生成五种颜色组合,每种组合分别为背景、文本、标题、链接、主按钮和次按钮定义颜色。用户稍后可以自定义这些颜色。

主题颜色

颜色组合中使用的颜色可以通过 $o-color-palettes 访问并覆盖,使用特定前缀( o-cc 表示颜色组合)。

/website_airproof/static/src/scss/primary_variables.scss
$o-color-palettes: map-merge($o-color-palettes,
   (
      'airproof': (

         'o-cc*-bg':                     'o-color-*',
         'o-cc*-text':                   'o-color-*',
         'o-cc*-headings':               'o-color-*',
         'o-cc*-h2':                     'o-color-*',
         'o-cc*-h3':                     'o-color-*',
         'o-cc*-h4':                     'o-color-*',
         'o-cc*-h5':                     'o-color-*',
         'o-cc*-h6':                     'o-color-*',
         'o-cc*-link':                   'o-color-*',
         'o-cc*-btn-primary':            'o-color-*',
         'o-cc*-btn-primary-border':     'o-color-*',
         'o-cc*-btn-secondary':          'o-color-*',
         'o-cc*-btn-secondary-border':   'o-color-*',

      ),
   )
);

注解

对于每个 o-cc* ,将 * 替换为对应所需颜色组合的数字(1 - 5)。

默认文本颜色为 o-color-5 。如果背景太暗,它将自动更改为 o-color-4 颜色。

另请参阅

颜色组合 SCSS

演示页面

Website Builder 会自动生成一个页面以查看主题调色板的颜色组合:http://localhost:8069/website/demo/color-combinations

渐变

您还可以直接在 primary_variables.scss 文件中为菜单、页眉、页脚和版权栏定义渐变。

声明

/website_airproof/static/src/scss/primary_variables.scss
$o-website-values-palettes: (
   (
      'menu-gradient': linear-gradient(135deg, rgb(203, 94, 238) 0%, rgb(75, 225, 236) 100%),
      'header-boxed-gradient': [your-gradient],
      'footer-gradient': [your-gradient],
      'copyright-gradient': [your-gradient],
   ),
);

Bootstrap 变量

Odoo 默认包含 Bootstrap。您可以使用框架中的所有变量和混合(mixins)。

如果 Odoo 没有提供您需要的变量,可能会有一个 Bootstrap 变量可以满足需求。事实上,所有 Odoo 布局都遵循 Bootstrap 结构并使用 Bootstrap 组件或其扩展。如果您自定义一个 Bootstrap 变量,则会为整个用户网站添加通用样式。

使用添加到 _assets_frontend_helpers 包的专用文件来覆盖 Bootstrap 值,而不是使用 primary_variables.scss 文件。

声明

/website_airproof/__manifest__.py
'assets': {
   'web._assets_frontend_helpers': [
      ('prepend', 'website_airproof/static/src/scss/bootstrap_overridden.scss'),
   ],
},

用法

/website_airproof/static/src/scss/bootstrap_overridden.scss
// Typography
$h1-font-size:                 4rem !default;

// Navbar
$navbar-nav-link-padding-x:    1rem!default;

// Buttons + Forms
$input-placeholder-color:      o-color('o-color-1') !default;

// Cards
$card-border-width:            0 !default;

小技巧

该文件只能包含 SCSS 变量和混合的定义和覆盖。

警告

不要覆盖依赖于 Odoo 变量的 Bootstrap 变量。否则,可能会破坏用户使用 Website Builder 自定义它们的能力。

当某个选项由 primary_variables.scss 中的变量和 Bootstrap 变量定义时,您应始终通过主变量进行覆盖。只有在主变量中不存在任何内容时,才通过 bootstrap_overridden.scss 进行覆盖。

另请参阅

Bootstrap 覆盖 SCSS

字体大小

Odoo 提供了 CSS 字体大小类,以将样式(字体大小)与语义(标签和一般样式)分开。这两种逻辑可以结合使用以实现更大的灵活性。

文本样式

Odoo 的 Website Builder 允许为您的文本选择样式。有些仅与标签相关,例如没有额外 CSS 类的 Header 。其他则是将标签和样式直接结合应用的,例如 Header 1 Display 。

标题样式
<!-- h1 with display heading sizes -->
<h1 class="display-1">Heading 1 with Display Heading 1 size</h1>
<h1 class="display-2">Heading 1 with Display Heading 2 size</h1>
<h1 class="display-3">Heading 1 with Display Heading 3 size</h1>
<h1 class="display-4">Heading 1 with Display Heading 4 size</h1>

<!-- Lead text - named "Light" in the dropdown -->
<p class="lead">A text typically used as an introduction.</p>

<!-- Small text -->
<p class="o_small">Body text with a smaller size.</p>
尺寸类

尺寸类被添加到目标元素内部新创建的 span 标签上(参见下面的示例)。

尺寸类
标题和正文文本

假设这些类可以应用于任何文本元素,以下以 h2 为例:

<!-- h2 sized like an h1 -->
<h2><span class="h1-fs">Heading</span></h2>

<!-- h2 sized with other heading sizes -->
<h2><span class="h2-fs">Heading</span></h2>
<h2><span class="h3-fs">Heading</span></h2>
<h2><span class="h4-fs">Heading</span></h2>
<h2><span class="h5-fs">Heading</span></h2>
<h2><span class="h6-fs">Heading</span></h2>

<!-- h2 sized like a normal paragraph (base size, 16px by default) -->
<h2><span class="base-fs">Heading</span></h2>

<!-- h2 sized like a small text (14px by default) -->
<h2><span class="o_small-fs">Heading</span></h2>
显示标题

如果需要更大的标题,Odoo 使用 Bootstrap 的 Display Headings 类,从 display-1 到 6 。

<h2><span class="display-1-fs">Heading</span></h2>
<h2><span class="display-2-fs">Heading</span></h2>
<h2><span class="display-3-fs">Heading</span></h2>
<h2><span class="display-4-fs">Heading</span></h2>

注解

Website Builder 仅允许用户配置 Display 1 到 Display 4 的尺寸。您可以设置其他尺寸( 5 和 6 )以在代码中使用,但用户无法直接在 Website Builder 界面中修改它们。

网站设置

与网站相关的全局选项可以通过以下结构中的网站记录进行设置。

声明

/website_airproof/data/website.xml
<?xml version="1.0" encoding="utf-8"?>
<odoo noupdate="1">
   <record id="base.default_website" model="website">
      <field name="name">Airproof</field>
      <field name="logo" type="bytes" file="website_airproof/static/src/img/content/logo_airproof.png"/>
      <field name="favicon" type="bytes" file="website_airproof/static/description/favicon.png" />
      <field name="shop_ppg">18</field>
      <field name="shop_ppr">3</field>
      <field name="shop_gap">16px</field>
      <field name="shop_opt_products_design_classes">
            o_wsale_products_opt_layout_catalog
            o_wsale_products_opt_design_cards
            o_wsale_products_opt_name_color_regular
            o_wsale_products_opt_thumb_cover
            o_wsale_products_opt_img_hover_zoom_out_light
            o_wsale_products_opt_has_cta
            o_wsale_products_opt_actions_onhover
            o_wsale_products_opt_wishlist_fixed
            o_wsale_products_opt_cc
            o_wsale_products_opt_cc1
            o_wsale_products_opt_rounded_2
            o_wsale_products_opt_actions_promote
            o_wsale_products_opt_actions_subtle
            o_wsale_products_opt_name_weight_bold
      </field>
      <field name="cookies_bar" eval="True" />
      <field name="contact_us_link_url">/contact-us</field>
      <field name="social_facebook">https://www.facebook.com/Airproof</field>
      <field name="social_instagram">https://www.instagram.com/airproof</field>
      <field name="social_linkedin">https://www.linkedin.com/company/airproof</field>
      <field name="social_youtube">https://www.youtube.com/c/airproof</field>
   </record>
</odoo>

另请参阅

来自电商(eCommerce)应用的 网站模型:

  • 以 shop_ 为前缀的字段与 /shop 页面配置相关;

  • 以 product_page_ 为前缀的字段与产品页面配置相关;

  • 卡片设计” 类在 /shop 页面与动态产品片段之间共用。

字段

描述

名称

网站名称(在浏览器中显示)

标志

标志的路径(之前已创建为记录)

网站图标

网站图标的路径(之前已创建为记录)

每页显示的产品数量

电子商务中每页显示的产品数量

每行显示的产品数量

电子商务中每行显示的产品数量(在页面中)

shop_gap

用于分隔产品网格项目的间距值

shop_opt_products_design_classes

与产品设计方案相关的 CSS 类列表。

Cookie 横幅

启用/禁用 Cookie 横幅

contact_us_link_url

联系我们 页面的 URL(例如,在标准页眉模板中使用)。

Facebook 社交链接

Facebook 个人资料的 URL

Instagram 社交链接

Instagram 个人资料的 URL

LinkedIn 社交链接

LinkedIn 公司资料的 URL

YouTube 社交链接

YouTube 频道的 URL

注解

base.default_website 是仅处理单个网站时的默认引用。若数据库中拥有多个网站,该记录将指向默认站点(即第一个站点)。

视图

对于某些选项,除了 Website Builder 变量之外,您还需要激活特定的视图。

通过阅读源代码,与选项相关的模板很容易找到。

<BuilderContext action="'websiteConfig'">
   <BuilderRow label.translate="...">
      <BuilderCheckbox actionParam="{views: ['website.show_website_info']}" />
   </BuilderRow>
</BuilderContext>
<template id="..." inherit_id="..." name="..." active="True"/>
<template id="..." inherit_id="..." name="..." active="False"/>

另请参阅

在这样的情形下,在 XML 中定义该记录时,应优先使用 <template id="..."> 语法,而非 <record id="..." model="ir.ui.view"> 语法。

参见 template,特别是关于 active 取值的部分。

预设

为了将视图作为预设激活或停用,您应该将其包含在 presets.xml 文件中。

用法

/website_airproof/data/presets.xml
<record id="module.view" model="ir.ui.view">
   <field name="active" eval="False"/>
</record>

Example

更改菜单项的水平对齐方式

/website_airproof/data/presets.xml
<record id="website.template_header_default_align_center" model="ir.ui.view">
   <field name="active" eval="True"/>
</record>

同样的逻辑也可以应用于其他 Odoo 应用。

电子商务 - 显示产品分类

/website_airproof/data/presets.xml
 <record id="website_sale.products_categories" model="ir.ui.view">
    <field name="active" eval="False"/>
 </record>

门户 - 禁用语言选择器

/website_airproof/data/presets.xml
<record id="portal.footer_language_selector" model="ir.ui.view">
   <field name="active" eval="False"/>
</record>

资源

本节我们参考 web 模块中的 assets_frontend 资产包(asset bundle)。该资产包列出了加载到网站前端(公开页面)的资源清单,目标是将你的 SCSS 与 JS 文件加入该资产包。网站生成器(Website Builder)使用它自己的资产包(例如:website.website_builder_assets 与 website.assets_wysiwyg)。

以下是一个网站常用包的非详尽列表:

包

描述

web._assets_primary_variables

定义主层级的 SCSS 主要变量(颜色、字体、间距等),在所有资产包之间充当主题层。主要用于 primary_variables.scss 文件。

web._assets_secondary_variables

定义依赖于并扩展主要变量的次级 SCSS 变量。主要用于 secondary_variables.scss 文件。

web._assets_frontend_helpers

提供前端专属的 Bootstrap 覆盖,需在任何前端 SCSS 编译之前引入。主要用于 bootstrap_overridden.scss 文件。

web.assets_frontend

提供渲染并与 Odoo 前端交互所需的基础资源。你可以在此添加所有自定义的 SCSS、JS 或客户端 QWeb 模板。

website.website_builder_assets

提供加载到网站生成器(Website Builder)上下文的资源,包括编辑模式样式、自定义构建块的自定义方法等)。

web._assets_bootstrap

例如,如果您需要通过 Bootstrap Utilities API 扩展 Bootstrap

样式

Website Builder 与 Bootstrap 结合使用非常适合定义网站的基本样式。但要设计出独特的内容,您需要更进一步。为此,您可以轻松地将任何 SCSS 文件添加到主题中。

声明

/website_airproof/__manifest__.py
'assets': {
   'web.assets_frontend': [
      'website_airproof/static/src/scss/theme.scss',
   ],
},

请随意在您的 theme.scss 文件中重用来自 Bootstrap 文件和 Odoo 使用的变量。

Example

/website_airproof/static/src/scss/theme.scss
 blockquote {
   border-radius: $rounded-pill;
   color: o-color('o-color-3');
   font-family: o-website-value('headings-font');
 }

交互性

Odoo 支持三种不同类型的 JavaScript 文件:

大多数新的 Odoo JavaScript 代码应使用原生 JavaScript 模块系统。它更简单,并且通过更好的 IDE 集成带来更好的开发体验。

声明

/website_airproof/__manifest__.py
'assets': {
   'web.assets_frontend': [
      'website_airproof/static/src/js/theme.js',
   ],
},

注解

如果要包含来自外部库的文件,可以将它们添加到模块的 /lib 文件夹中。

小技巧

  • 使用 linter(ESLint 等)。

  • 始终添加已压缩(minified)的 JavaScript 库

  • 对使用 JavaScript 操作的元素,使用以 js_ 为前缀的 CSS 类。

  • 变量和函数应使用 驼峰命名法 ( myVariable ),而不是 蛇形命名法 ( my_variable )。

  • JavaScript 类使用 大驼峰(PascalCase) 命名(如 MyClass)。

  • 不要将变量命名为 event ,而是使用 ev 。这是为了避免在非 Chrome 浏览器上出现错误,因为 Chrome 会自动分配一个全局的 event 变量(因此,如果您在未声明的情况下使用 event 变量,在 Chrome 上可以正常工作,但在其他浏览器上会导致崩溃)。

  • 使用严格比较( === 而不是 == )。

  • 所有字符串使用双引号(如 "Hello"、".x_nav_item")。

  • 如果你在使用原生标准 JS 函数(start()、willStart()、cleanForSave() 等),请务必调用父类的实现(例如 super.start(...arguments);请检查标准代码中是否需要这样做)。