原文链接: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`
<button t-on-click="state.value++">
Click Me! [<t t-esc="state.value"/>]
</button>`; state = useState({ value: 0 });
} class App extends Component {
static template = xml`
<div>
<span>Hello Owl</span>
<Counter />
</div>`; 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;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>OWL Todo App</title>
<link rel="stylesheet" href="app.css" />
<script src="owl.js"></script>
<script src="app.js"></script>
</head>
<body></body>
</html>

owl.js  在   https://github.com/odoo/owl

 

odoo14--odoo前端框架owl【odoo web library】的更多相关文章

  1. 前端框架对于未来web移动端的影响

    现在前端框架市场比较乱,各种各样的框架参差不齐,这给我带来了很多困惑,同样是很多朋友的困惑吧!因为前端框架有很多种,对于程序员来说选择学习是非常困难的,不可能有几十上百种都要学习吧,不过最好的办法就是 ...

  2. 前端框架framework和库library的一点区别和记录

    本篇纯文字,无关代码,只是一点概念的记录 关于所谓前端 首先学的是HTML5.CSS3.JavaScript这三个 之后接触了一下UI框架,如layui和bootstrap 目前是打算去学VUE和an ...

  3. Web前端框架汇总

    在做web开发的时候难免遇到一个问题,那就是,选择什么样的框架.下面把前端的框架简单的列一下. 1.flex Apache基金会今天发布了Flex 4.8版本,这是Adobe将Flex捐献给Apach ...

  4. 国内5款优秀的WEB前端框架

    1. JX(腾讯) 官网地址:http://alloyteam.github.io/JX/#home JX 是一个类似 Google Closure Library 的 Web 前端开发框架,服务于 ...

  5. Web前端,HTML5开发,前端资源,前端网址,前端博客,前端框架整理 - 转改

    Web前端/H5开发,前端资源,前端网址,前端博客,前端框架整理 综合类 前端知识体系 前端知识结构 Web前端开发大系概览 Web前端开发大系概览-中文版 Web Front-end Stack v ...

  6. python开发学习-day15(前端部分知识、web框架、Django创建项目)

    s12-20160430-day15 *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: ...

  7. odoo前端

    bootstrap: http://www.runoob.com/bootstrap/bootstrap-tutorial.html javascript: http://www.runoob.com ...

  8. Web前端框架与类库的思考

    说起前端框架,我也是醉了.现在去面试或者和同行聊天,动不动就这个框架碉堡了,那个框架好犀利. 当然不是贬低框架,只是有一种杀鸡焉用牛刀的感觉.网站技术是为业务而存在的,除此毫无意义,框架也是一样.在技 ...

  9. React 还是 Vue: 你应该选择哪一个Web前端框架?

    学还是要学的,用的多了,也就有更多的认识了,开发中遇到选择的时候也就简单起来了. 本文作者也做了总结: 如果你喜欢用(或希望能够用)模板搭建应用,请使用Vue    如果你喜欢简单和“能用就行”的东西 ...

随机推荐

  1. 基于Android平台的图书管理系统的制作(1)

    在学习了郭神的第一行代码前半段之后,想通过一次实践来完成对已学知识的巩固.于是码下了这个图书管理系统客户端. IDE Android studio,语言 JAVA.XML: 在刚开始设计的时候对于这个 ...

  2. 【SQLite】教程01-SQLite简介与安装

    为什么要用 SQLite? 不需要一个单独的服务器进程或操作的系统(无服务器的). SQLite 不需要配置,这意味着不需要安装或管理. 一个完整的 SQLite 数据库是存储在一个单一的跨平台的磁盘 ...

  3. c#根据名称反射对应的枚举类型

    今天遇到了要配置串口的停止位,这个时候直接反射枚举比较方便. 第一反射所有的枚举值 FieldInfo[] fieldInfoes= typeof(StopBits).GetFields(Bindin ...

  4. 如果给IIS添加防火墙入站配置,支持外部或者局域网访问

    背景简介 也许你试着在本机IIS运行了一些网站,但是奇怪的是,同网络的终端却无法访问你,这时候极有可能被防火墙拦截了,所以我们要找到正确的姿势来开启魔法了. 找到入站规则设置 不管你是Win7还是Wi ...

  5. 非静态的字段、方法或属性“System.Web.UI.Page.ClientScript.get”要求对象引用

    解决Response.Write("<script>alert('修改失败,请稍后再试!');</script>");布局错误的问题 在后台CS代码(不是C ...

  6. Mysql索引降维 优化查询 提高效率

    在前一篇文章中,我们已经介绍了索引.索引的优化规则等等 原文链接:Siam博客 mysql索引优化 在其中我们有引申出组合索引,多个单字段索引冲突两个知识点. 本文章主要是与后者有关联. 在原文中,我 ...

  7. 关于mysql binlog二进制

    binlog 在mysql中,当发生数据变更时,都会将变更数据的语句,通过二进制形式,存储到binlog日志文件中. 通过binlog文件,你可以查看mysql一段时间内,对数据库的所有改动. 也可以 ...

  8. 输出 time 命令的结果到文件中

    译至:http://unicus.jp/skmk/archives/338 由于输出 time 命令的结果到文件时使用的错误的方式,所以将其记录下来. 环境是bash. 目标 将运行的a.out程序的 ...

  9. 『心善渊』Selenium3.0基础 — 23、Selenium元素等待

    目录 1.什么是元素等待 2.为什么要设置元素等待 3.Selenium中常用的等待方式 4.强制等待 5.隐式等待 (1)隐式等待介绍 (2)示例 6.显式等待 (1)显式等待介绍 (2)语法 (3 ...

  10. Leetcode No.35 Search Insert Position(c++实现)

    1. 题目 1.1 英文题目 Given a sorted array of distinct integers and a target value, return the index if the ...