Layout

Trong chương này, bạn sẽ học cách:

  • Tạo một header tùy chỉnh.

  • Tạo một footer tùy chỉnh.

  • Chỉnh sửa một template tiêu chuẩn.

  • Thêm một phần bản quyền.

  • Cải thiện khả năng responsive của website.

Mặc định

Một trang Odoo kết hợp các phần tử chung cho toàn bộ trang và các phần tử riêng biệt. Các phần tử chung giống nhau trên mọi trang, trong khi các phần tử riêng biệt chỉ liên quan đến một trang cụ thể. Theo mặc định, một trang có hai phần tử chung là header và footer, cùng với một phần tử chính riêng biệt chứa nội dung cụ thể của trang đó.

<div id="wrapwrap">
   <header/>
      <main>
         <div id="wrap" class="oe_structure">
            <!-- Page Content -->
         </div>
      </main>
   <footer/>
</div>

Bất kỳ tệp XML nào của Odoo đều bắt đầu bằng khai báo encoding. Sau đó, bạn phải viết code của mình bên trong thẻ <odoo>.

<?xml version="1.0" encoding="utf-8" ?>
<odoo>
   ...
</odoo>

Ghi chú

Sử dụng tên template chính xác là rất quan trọng để tìm kiếm thông tin nhanh chóng qua tất cả các module. Tên template chỉ nên chứa các ký tự chữ và số viết thường cùng dấu gạch dưới.

Luôn thêm một dòng trống ở cuối tệp của bạn. Điều này có thể được thực hiện tự động bằng cách cấu hình IDE của bạn.

XPath

XPath (XML Path Language) là một ngôn ngữ biểu thức cho phép bạn dễ dàng điều hướng qua các phần tử và thuộc tính trong một tài liệu XML. XPath được sử dụng để mở rộng các template tiêu chuẩn của Odoo.

Một view được viết theo cách sau.

<template id="..." inherit_id="..." name="...">
   <!-- Content -->
</template>

Thuộc tính

Mô tả

id

ID của view đã được chỉnh sửa

inherited_id

ID của view tiêu chuẩn (theo mẫu sau: module.template)

name

Tên dễ đọc của view đã được chỉnh sửa

Đối với mỗi XPath, bạn chỉnh sửa hai thuộc tính: expression và position.

Example

/website_airproof/views/website_templates.xml
<template id="layout" inherit_id="website.layout" name="Welcome Message">
   <xpath expr="//header" position="before">
      <!-- Content -->
   </xpath>
</template>

XPath này thêm một thông báo chào mừng ngay trước nội dung trang.

Cảnh báo

Hãy cẩn thận khi thay thế các thuộc tính của phần tử mặc định. Vì theme của bạn mở rộng từ theme mặc định, các thay đổi của bạn sẽ được ưu tiên hơn bất kỳ bản cập nhật Odoo nào trong tương lai.

Ghi chú

  • Bạn nên cập nhật module của mình mỗi khi tạo một template hoặc bản ghi mới.

  • XML ID của các view kế thừa nên sử dụng cùng ID với bản ghi gốc. Điều này giúp dễ dàng tìm thấy tất cả các kế thừa chỉ trong nháy mắt. Vì XML ID cuối cùng được thêm tiền tố bởi module tạo ra chúng, nên sẽ không có sự trùng lặp.

Biểu thức

XPath sử dụng các biểu thức đường dẫn để chọn các node trong một tài liệu XML. Các selector được sử dụng bên trong biểu thức để nhắm đúng phần tử. Những selector hữu ích nhất được liệt kê bên dưới.

Selector con cháu

Mô tả

/

Chọn từ node gốc.

//

Chọn các node trong tài liệu từ node hiện tại khớp với lựa chọn, bất kể chúng nằm ở đâu.

Selector thuộc tính

Mô tả

*

Chọn bất kỳ thẻ XML nào. * có thể được thay thế bằng một thẻ cụ thể nếu cần lựa chọn chính xác hơn.

*[@id="id"]

Chọn một ID cụ thể.

*[hasclass("class")]

Chọn một class cụ thể.

*[@name="name"]

Chọn một thẻ có tên cụ thể.

*[@t-call="t-call"]

Chọn một t-call cụ thể.

Vị trí

Thuộc tính position xác định vị trí đặt code bên trong template. Các giá trị khả dụng được liệt kê bên dưới:

Vị trí

Mô tả

replace

Thay thế node mục tiêu bằng nội dung XPath.

inside

Thêm nội dung XPath vào bên trong node mục tiêu.

before

Thêm nội dung XPath trước node mục tiêu.

after

Thêm nội dung XPath sau node mục tiêu.

attributes

Thêm nội dung XPath vào bên trong một thuộc tính.

Example

XPath này xóa phần tử đầu tiên có class .breadcrumb.

<xpath expr="//*[hasclass('breadcrumb')]" position="replace"/>

XPath này thêm một phần tử <li> bổ sung sau phần tử con cuối cùng của phần tử <ul>.

<xpath expr="//ul" position="inside">
   <li>Last element of the list</li>
</xpath>

XPath này thêm một <div> trước <nav> là phần tử con trực tiếp của <header>.

<xpath expr="//header/nav" position="before">
   <div>Some content before the header</div>
</xpath>

XPath này xóa x_airproof_header trong thuộc tính class của header. Trong trường hợp này, bạn không cần sử dụng thuộc tính separator.

<xpath expr="//header" position="attributes">
   <attribute name="class" remove="x_airproof_header" />
</xpath>

XPath này thêm x_airproof_header vào thuộc tính class của header. Bạn cũng cần xác định thuộc tính separator để thêm một khoảng trắng trước class bạn đang thêm vào.

<xpath expr="//header" position="attributes">
   <attribute name="class" add="x_airproof_header" separator=" "/>
</xpath>
XPath này di chuyển phần tử có class .o_footer_scrolltop_wrapper đến trước phần tử có

thuộc tính ID footer.

<xpath expr="//div[@id='footer']" position="before">
   <xpath expr="//div[@id='o_footer_scrolltop_wrapper']" position="move" />
</xpath>

Mẹo

Sử dụng chỉ thị move bên trong một XPath khác buộc bạn chỉ được sử dụng loại chỉ thị này.

Example

Ví dụ đúng:
<xpath expr="//*[hasclass('o_wsale_products_main_row')]" position="before">
   <xpath expr="//t[@t-if='opt_wsale_categories_top']" position="move" />
</xpath>
<xpath expr="//*[hasclass('o_wsale_products_main_row')]" position="before">
   <div><!-- Content --></div>
</xpath>
Ví dụ sai:
<xpath expr="//*[hasclass('o_wsale_products_main_row')]" position="before">
   <xpath expr="//t[@t-if='opt_wsale_categories_top']" position="move" />
   <div><!-- Content --></div>
</xpath>

Xem thêm

Bạn có thể tìm thêm thông tin về XPath trong bảng tra cứu nhanh này.

QWeb

QWeb là engine templating chính được Odoo sử dụng. Đây là một engine templating XML chủ yếu được sử dụng để tạo ra các đoạn HTML và các trang.

Trường tùy chỉnh

Tùy theo nhu cầu, bạn có thể tạo các field tùy chỉnh để lưu dữ liệu trong database.

Khai báo

Trước tiên, hãy tạo một record để khai báo field. Field này phải được liên kết với một model đã tồn tại.

/website_airproof/data/fields.xml
<record id="x_post_category" model="ir.model.fields">
   <field name="name">x_post_category</field>
   <field name="field_description">...</field>
   <field name="ttype">html</field>
   <field name="state">manual</field>
   <field name="index">0</field>
   <field name="model_id" ref="website_blog.model_blog_post"/>
</record>

Ghi chú

Việc tạo field cũng có thể thực hiện (và được khuyến nghị) thông qua a model using Python.

Back-end

Thêm field vào view liên quan thông qua một XPath. Nhờ đó, người dùng có thể nhìn thấy field trong giao diện và điền vào sau đó.

/website_airproof/views/backend/website_blog_views.xml
<record id="view_blog_post_form_category" model="ir.ui.view">
   <field name="name">view_blog_post_form_category</field>
   <field name="model">blog.post</field>
   <field name="inherit_id" ref="website_blog.view_blog_post_form"/>
   <field name="arch" type="xml">
      <xpath expr="//field[@name='blog_id']" position="before">
         <field name="x_post_category" string="..." placeholder="..."/>
      </xpath>
   </field>
</record>

Front-end

Giá trị của field có thể được hiển thị ở đâu đó trên trang bằng cách gọi model_name.field_name như sau:

/website_airproof/views/website_blog_templates.xml
<h1 t-field="blog_post.x_post_category"/>

Nền

Bạn có thể xác định một màu sắc hoặc một hình ảnh làm nền cho website của mình.

Màu sắc

/website_airproof/static/src/scss/primary_variables.scss
$o-color-palettes: map-merge($o-color-palettes,
   (
      'airproof': (
         'o-cc1-bg':                     'o-color-5',
         'o-cc5-bg':                     'o-color-1',
      ),
    )
);

Hình ảnh/họa tiết

/website_airproof/static/src/scss/primary_variables.scss
$o-website-values-palettes: (
   (
      'body-image': '/website_airproof/static/src/img/background-lines.svg',
      'body-image-type': 'image' or 'pattern'
   )
);

Tiêu chuẩn

Odoo Website Builder phân biệt giữa các template desktop và template mobile nhằm tạo điều kiện thuận lợi cho việc điều chỉnh trải nghiệm người dùng theo từng thiết bị.

Template desktop

Kích hoạt một trong các template mặc định của header.

Quan trọng

Đừng quên rằng bạn có thể cần vô hiệu hóa template header đang hoạt động trước.

Example

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

Thiết lập rõ ràng template mong muốn trong file primary_variables.scss.

/website_airproof/static/src/scss/primary_variables.scss
$o-website-values-palettes: (
   (
      'header-template': 'Contact',
   ),
);
/website_airproof/data/presets.xml
<record id="website.template_header_contact" model="ir.ui.view">
   <field name="active" eval="True"/>
</record>

Template mobile

Mỗi template header đi kèm với template template_header_mobile nhằm đảm bảo trải nghiệm người dùng liền mạch trên mọi thiết bị.

Tùy chỉnh

Tạo template riêng của bạn và thêm nó vào danh sách.

Quan trọng

Đừng quên rằng bạn có thể cần vô hiệu hóa template header đang hoạt động trước khi kích hoạt template tùy chỉnh.

Tùy chọn

Sử dụng đoạn code sau để thêm một tùy chọn cho header tùy chỉnh mới của bạn trên Website Builder.

/website_airproof/views/website_templates.xml
<template id="template_header_opt" inherit_id="website.snippet_options" name="Header Template - Option">
   <xpath expr="//we-select[@data-variable='header-template']" position="inside">
      <we-button title="airproof"
         data-customize-website-views="website_airproof.header"
         data-customize-website-variable="'airproof'"  data-img="/website_airproof/static/src/img/wbuilder/template_header_opt.svg"/>
   </xpath>
</template>

Thuộc tính

Mô tả

data-customize-website-views

Template cần kích hoạt

data-customize-website-variable

Tên được đặt cho biến

data-img

Hình thu nhỏ của template tùy chỉnh được hiển thị trong phần lựa chọn template trên Website Builder

Bây giờ bạn cần xác định rõ ràng rằng bạn muốn sử dụng template tùy chỉnh của mình trong các biến SASS của Odoo.

/website_airproof/static/src/scss/primary_variables.scss
$o-website-values-palettes: (
   (
      'header-template': 'airproof',
   ),
);

Template

/website_airproof/views/website_templates.xml
<template id="header" inherit_id="website.layout" name="Airproof - Header" active="True">
   <xpath expr="//header//nav" position="replace">
      <!-- Static Content -->
      <!-- Components -->
      <!-- Editable areas -->
   </xpath>
</template>

Đừng quên điều chỉnh template_header_mobile cho phù hợp để giữ tính nhất quán giữa desktop và mobile:

website_airproof/views/website_templates.xml
<template id="template_header_mobile" inherit_id="website.template_header_mobile" name="Airproof - Template Header Mobile">
   <!-- Xpaths -->
</template>

Thành phần

Trong header tùy chỉnh của bạn, bạn có thể gọi nhiều template con bằng cách sử dụng directive t-call của QWeb:

Đăng nhập

<t t-call="portal.placeholder_user_sign_in">
   <t t-set="_item_class" t-valuef="nav-item"/>
   <t t-set="_link_class" t-valuef="nav-link"/>
</t>

Menu thả xuống của người dùng

<t t-call="portal.user_dropdown">
   <t t-set="_user_name" t-value="true"/>
   <t t-set="_icon" t-value="false"/>
   <t t-set="_avatar" t-value="false"/>
   <t t-set="_item_class" t-valuef="nav-item dropdown"/>
   <t t-set="_link_class" t-valuef="nav-link"/>
   <t t-set="_dropdown_menu_class" t-valuef="..."/>
</t>

Bộ chọn ngôn ngữ

<t t-call="website.placeholder_header_language_selector">
   <t t-set="_div_classes" t-valuef="..."/>
</t>

Kêu gọi hành động

<t t-call="website.placeholder_header_call_to_action">
   <t t-set="_div_classes" t-valuef="..."/>
</t>

Vùng thả

Thay vì xác định toàn bộ layout của một trang, bạn có thể tạo các khối xây dựng (snippet) và để người dùng chọn nơi kéo thả chúng, tự tạo ra layout trang theo ý mình. Chúng ta gọi đây là thiết kế module hóa.

Bạn có thể xác định một vùng trống mà người dùng có thể lấp đầy bằng các snippet.

<div id="oe_structure_layout_01" class="oe_structure"/>

Class

Mô tả

oe_structure

Xác định một vùng kéo thả cho người dùng.

oe_structure_solo

Chỉ có một snippet có thể được thả vào vùng này.

oe_structure_not_nearest

Nếu một khối xây dựng được thả bên ngoài vùng thả có class này, khối đó sẽ được chuyển vào vùng thả gần nhất.

Bạn cũng có thể lấp đầy một vùng thả đã có sẵn bằng nội dung của mình.

<template id="oe_structure_layout_01" inherit_id="..." name="...">
   <xpath expr="//*[@id='oe_structure_layout_01']" position="replace">
      <div id="oe_structure_layout_01" class="oe_structure oe_structure_solo">
         <!-- Content -->
      </div>
   </xpath>
</template>

Đáp ứng (responsive)

Nhìn chung, Odoo dựa vào framework Bootstrap giúp việc đáp ứng của website bạn dễ dàng hơn trên desktop và mobile. Bạn chủ yếu có thể tác động vào 3 khía cạnh:

  1. Kích thước font được tính toán tự động tùy theo thiết bị

  2. Kích thước cột trên desktop (các cột tự động xếp chồng lên nhau trên mobile)

  3. Điều kiện hiển thị (Hiện/Ẩn một thành phần nào đó trên desktop/mobile)

Kích thước font

Trong Bootstrap 5, kích thước font đáp ứng được bật theo mặc định, cho phép văn bản co giãn tự nhiên hơn theo thiết bị và kích thước viewport (dựa vào biến $enable-rfs).

Kích thước cột

Bootstrap sử dụng một lưới gồm các hàng và cột để dàn trang. Nhờ cấu trúc này, các cột có thể có kích thước khác nhau trên mobile và desktop. Trong phiên bản này, Website Builder cho phép đặt kích thước cho mobile (ví dụ col-12) và cho desktop (ví dụ col-lg-4) nhưng không cho các breakpoint trung bình (ví dụ col-md-4).

Cảnh báo

Các kích thước trung bình có thể được thiết lập nhưng người dùng cuối không thể chỉnh sửa chúng bên trong Website Builder.

Điều kiện hiển thị

Trong Odoo Website Builder, toàn bộ các phần hoặc các cột cụ thể có thể được ẩn trên mobile hoặc desktop.

Chức năng này tận dụng Bootstrap cùng với các class riêng của Odoo:

  • o_snippet_mobile_invisible

  • o_snippet_desktop_invisible

Ẩn một phần trên desktop:

<section class="s_text_block o_cc o_cc1 o_colored_level pt16 pb16 d-lg-none o_snippet_desktop_invisible" data-snippet="s_text_block" name="Text">
    <!-- Content -->
</section>

Ẩn một cột trên mobile:

<section class="s_text_block o_cc o_cc1 o_colored_level pt16 pb16" data-snippet="s_text_block" name="Text">
   <div class="container s_allow_columns">
      <div class="row">
         <div class="col-12 col-lg-6 d-none d-lg-block o_snippet_mobile_invisible">
            Column 1
         </div>
         <div class="col-12 col-lg-6">
            Column 2
         </div>
      </div>
   </div>
</section>

Class

Mô tả

o_snippet_mobile_invisible

Nó báo cho Website Builder biết rằng thành phần này đang bị ẩn và đang sử dụng tùy chọn điều kiện hiển thị.

o_snippet_desktop_invisible

Nó báo cho Website Builder biết rằng thành phần này đang bị ẩn trên desktop và đang sử dụng tùy chọn điều kiện hiển thị.

d-none

Ẩn thành phần trong mọi trường hợp.

d-lg-block

Hiển thị thành phần từ breakpoint "large" (trên desktop).

Quan trọng

Các class o_snippet_mobile_invisible / o_snippet_desktop_invisible phải được chỉ định để giữ

cho tùy chọn điều kiện hiển thị hoạt động. Ngay cả khi một thành phần bị ẩn trên desktop, Website Builder vẫn hiển thị danh sách các thành phần này, cho phép người dùng cuối buộc hiển thị thành phần đó và chỉnh sửa nó mà không cần chuyển đổi giữa chế độ mobile và desktop.

Buộc hiển thị một thành phần bị ẩn trên thiết bị hiện tại.