Learn HarmonyOS Component & JS Interaction by Building a Todo List
This tutorial walks through creating a full-featured Todo List app in HarmonyOS, covering page navigation, HML layout, data binding with for-loops, switch components, computed properties, event handling in JavaScript, and the accompanying CSS styling.
The article demonstrates how to implement page navigation and a complete Todo List feature in a HarmonyOS application.
First, the HML layout is defined, using a <div class="container"> that contains a title, a back button, a repeatable <div class="item" for="{{todoList}}"> block, an info section, and an input area for adding new tasks. The for attribute iterates over todoList, displaying each item's {{$item.info}} and a <switch> whose checked state is bound to {{$item.status}}. The switch’s @change event calls checkStatus($idx), and a delete button calls remove($idx). The remaining‑task count is shown via the computed property needTodoNum, and new tasks are added through an input change event ( getNewTodo) and a button click ( addTodo).
<div class="container">
<text class="title">待办事项</text>
<button @click="goback">返回</button>
<div class="item" for="{{todoList}}">
<text class="todo">{{$item.info}}</text>
<switch showtext="true" checked="{{$item.status}}"
texton="完成" textoff="待办" class="switch"
@change="checkStatus($idx)"></switch>
<button class="remove" onclick="remove($idx)">删除</button>
</div>
<div class="info">
<text class="info-text">您还有</text>
<text class="info-num">{{needTodoNum}}</text>
<text class="info-text">件事情待办,加油!</text>
</div>
<div class="add-todo">
<input class="plan-input" type="text" onchange="getNewTodo"></input>
<button class="plan-btn" onclick="addTodo">添加待办</button>
</div>
</div>The accompanying CSS styles the container, title, list items, switch, delete button, info bar, and the fixed bottom input area, using flex layout, colors, spacing, and sizing to create a clean UI.
.container { flex-direction: column; justify-content: flex-start; align-items: center; padding-bottom: 100px; }
.title { font-size: 28px; margin: 20px 0; color: #000000; opacity: 0.9; }
.item { width: 325px; padding: 10px 0; flex-direction: row; align-items: center; justify-content: space-around; border-bottom: 1px solid #eee; }
.todo { color: #000; width: 180px; font-size: 18px; }
.switch { font-size: 12px; texton-color: green; textoff-color: red; text-padding: 5px; width: 100px; height: 24px; allow-scale: false; }
.remove { font-size: 12px; margin-left: 10px; width: 50px; height: 22px; color: #fff; background-color: red; }
.info { width: 100%; margin-top: 10px; justify-content: center; }
.info-text { font-size: 18px; color: #AD7A1B; }
.info-num { color: orangered; margin: 0 10px; }
.add-todo { position: fixed; left: 0; bottom: 0; width: 100%; height: 60px; flex-direction: row; justify-content: space-around; align-items: center; background-color: #ddd; }
.plan-input { width: 240px; height: 40px; background-color: #fff; }
.plan-btn { width: 90px; height: 35px; font-size: 15px; }In the JavaScript section, the data source todoList is imported from a common module. The component’s data includes the list and a placeholder inputTodo. A computed property needTodoNum iterates over todoList to count items whose status is false.
import todoList from "../../common/datas/todoList.js"
import router from '@system.router'
export default {
data: {
todoList,
inputTodo: "IDE无法调用输入"
},
computed: {
needTodoNum() {
let num = 0;
this.todoList.forEach(item => {
if (!item.status) {
num++;
}
});
return num;
}
},
remove(index) {
console.log(index)
this.todoList.splice(index, 1)
},
addTodo() {
this.todoList.push({
info: this.inputTodo,
status: false
})
},
checkStatus(index) {
console.log(index);
this.todoList[index].status = !this.todoList[index].status;
},
getNewTodo(e) {
this.inputTodo = e.value;
},
goback() {
router.back();
}
}The methods perform the following actions: remove deletes an item by index; addTodo pushes a new object with the current inputTodo value; checkStatus toggles the status boolean; getNewTodo updates inputTodo from the input event; and goback navigates back using the system router.
The data module todoList.js exports an array of objects, each with info (task description) and status (boolean). Sample entries include "关注公众号" (true) and "霸道的程序猿" (false).
export default [
{ info: '关注公众号', status: true },
{ info: '霸道的程序猿', status: false },
{ info: '学习编程知识', status: true },
{ info: '接受编程推送', status: false },
{ info: '努力学习', status: false }
]Two images illustrate the UI: one static screenshot of the layout and a GIF showing the interactive behavior. A note mentions that the on‑screen keyboard does not appear in preview mode, so the app should be run on a simulator or device.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
The Dominant Programmer
Resources and tutorials for programmers' advanced learning journey. Advanced tracks in Java, Python, and C#. Blog: https://blog.csdn.net/badao_liumang_qizhi
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
