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: |
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. |
*[@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
<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>
<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.
Xem thêm
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'
)
);
Header¶
Theo mặc định, header chứa hai template riêng biệt (desktop và mobile) hiển thị thanh điều hướng chính, logo công ty và các thành phần tùy chọn khác (call-to-action, bộ chọn ngôn ngữ, v.v.). Tùy vào tình huống, bạn có thể chọn bật/tắt các thành phần có sẵn với một template tiêu chuẩn hoặc xây dựng một template tùy chỉnh hoàn toàn mới.
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:
Logo¶
<t t-call="website.placeholder_header_brand">
<t t-set="_link_class" t-valuef="..."/>
</t>
Quan trọng
Đừng quên create a record of the website logo cho logo trong database.
Đă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>
Bản quyền¶
Hiện tại chỉ có một template khả dụng cho thanh bản quyền.
Để thay thế nội dung hoặc chỉnh sửa cấu trúc của nó, bạn có thể thêm code riêng của mình vào XPath sau.
/website_airproof/views/website_templates.xml¶<template id="copyright" inherit_id="website.layout">
<xpath expr="//div[hasclass('o_footer_copyright')]" position="replace">
<div class="o_footer_copyright" data-name="Copyright">
<!-- Content -->
</div>
</xpath>
</template>
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:
Kích thước font được tính toán tự động tùy theo thiết bị
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)
Đ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_invisibleo_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_invisiblephả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.