odoo14--odoo前端框架owl【odoo web library】


原文链接: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

 

 

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM