原文链接:https://www.alanhou.org/odoo-14-owl-todolist/
1、组件树
Root
/ \
A B
/ \
C D
2、状态(state):各组件可管理其自身的本地状态。这是一个简单的ES6类,没有特殊规则:
const { Component, useState } = owl;
const { xml } = owl.tags;
class Counter extends Component {
static template = xml`
`;
state = useState({ value: 0 });
}
class App extends Component {
static template = xml`
static components = { Counter };
}
const app = new App();
app.mount(document.body);
owl_todoapp
(function () {
const {Component, Store} = owl; // const {xml} = owl.tags; //用来插入xml代码片段的
const {whenReady} = owl.utils; //工具类
const {useRef, useDispatch, useState, useStore} = owl.hooks; //钩子
// -------------------------------------------------------------------------
// Store
// -------------------------------------------------------------------------
const actions = {
addTask({state}, title) {
title = title.trim();
if (title) {
const task = {
id: state.nextId++,
title: title,
isCompleted: false,
};
state.tasks.push(task);
}
},
toggleTask({state}, id) {
const task = state.tasks.find((t) => t.id === id);
task.isCompleted = !task.isCompleted;
},
deleteTask({state}, id) {
const index = state.tasks.findIndex((t) => t.id === id);
state.tasks.splice(index, 1);
},
};
const initialState = {
nextId: 1,
tasks: \[\],
};
// -------------------------------------------------------------------------
// Task Component 可点击任务标题来切换复选框状态:
// -------------------------------------------------------------------------
const TASK\_TEMPLATE = xml/\* xml \*/\`
<div class="task" t-att-class="props.task.isCompleted ? 'done' : ''">
<input type="checkbox" t-att-checked="props.task.isCompleted"
t-att-id="props.task.id"
t-on-click="dispatch('toggleTask', props.task.id)"/>
<label t-att-for="props.task.id"><t t-esc="props.task.title"/></label>
<span class="delete" t-on-click="dispatch('deleteTask', props.task.id)"></span>
</div>\`;
class Task extends Component {
static template = TASK\_TEMPLATE;
static props = \["task"\];
dispatch = useDispatch();
}
// -------------------------------------------------------------------------
// App Component
// -------------------------------------------------------------------------
const APP\_TEMPLATE = xml/\* xml \*/\`
<div class="todo-app">
<input placeholder="Enter a new task" t-on-keyup="addTask" t-ref="add-input"/>
<div class="task-list">
<Task t-foreach="displayedTasks" t-as="task" t-key="task.id" task="task"/>
</div>
<div class="task-panel" t-if="tasks.length">
<div class="task-counter">
<t t-esc="displayedTasks.length"/>
<t t-if="displayedTasks.length lt tasks.length">
/ <t t-esc="tasks.length"/>
</t>
task(s)
</div>
<div>
<span t-foreach="\['all', 'active', 'completed'\]"
t-as="f" t-key="f"
t-att-class="{active: filter.value===f}"
t-on-click="setFilter(f)"
t-esc="f"/>
</div>
</div>
</div>\`;
class App extends Component {
static template = APP\_TEMPLATE;
static components = {Task};
inputRef = useRef("add-input");
tasks = useStore((state) => state.tasks);
filter = useState({value: "all"});
dispatch = useDispatch();
mounted() {
this.inputRef.el.focus();
}
addTask(ev) {
// 13 is keycode for ENTER
if (ev.keyCode === 13) {
this.dispatch("addTask", ev.target.value);
ev.target.value = "";
}
}
get displayedTasks() {
switch (this.filter.value) {
case "active":
return this.tasks.filter((t) => !t.isCompleted);
case "completed":
return this.tasks.filter((t) => t.isCompleted);
case "all":
return this.tasks;
}
}
setFilter(filter) {
this.filter.value = filter;
}
}
// -------------------------------------------------------------------------
// Setup code
// -------------------------------------------------------------------------
function makeStore() {
const localState = window.localStorage.getItem("todoapp");
const state = localState ? JSON.parse(localState) : initialState;
const store = new Store({state, actions});
store.on("update", null, () => {
localStorage.setItem("todoapp", JSON.stringify(store.state));
});
return store;
}
function setup() {
owl.config.mode = "dev";
App.env.store = makeStore();
const app = new App();
app.mount(document.body);
}
whenReady(setup);
})();
.todo-app {
width: 300px;
margin: 50px auto;
background: aliceblue;
padding: 10px;
}
.todo-app > input {
display: block;
margin: auto;
}
.task-list {
margin-top: 8px;
}
.task {
font-size: 18px;
color: #111111;
display: grid;
grid-template-columns: 30px auto 30px;
}
//在用户鼠标悬浮到任务上方时添加视觉反馈:
.task:hover {
background-color: #def0ff;
}
.task > input {
margin: auto;
}
.delete {
opacity: 0;
cursor: pointer;
text-align: center;
}
.task:hover .delete {
opacity: 1;
}
.task.done {
opacity: 0.7;
}
//对已完成任务的标题添加中划线
.task.done label {
text-decoration: line-through;
}
.task-panel {
color: #0088ff;
margin-top: 8px;
font-size: 14px;
display: flex;
}
.task-panel .task-counter {
flex-grow: 1;
}
.task-panel span {
padding: 5px;
cursor: pointer;
}
.task-panel span.active {
font-weight: bold;
}
owl.js 在 https://github.com/odoo/owl
手机扫一扫
移动阅读更方便
你可能感兴趣的文章