逻辑代码
save方法是把TODO列表及操作日志存放到本地缓存
lode文件是小程序加载时默认调用,先调取本地缓存中的数据,然后筛选出还在进行中的列表及数量
inputChangeHandle获取用户输入的内容
addTodoHandle添加事件
toggleTodoHandle更改事件状态
removeTodoHandle删除事件
toggleAllHandle全先及全不选事件
clearCompletedHandle消除已完成事件
Page({
data: {
input: '',
todos: [],
leftCount: 0,
allCompleted: false,
logs: []
},
save: function () {
wx.setStorageSync('todo_list', this.data.todos)
wx.setStorageSync('todo_logs', this.data.logs)
},
load: function () {
var todos = wx.getStorageSync('todo_list')
if (todos) {
var leftCount = todos.filter(function (item) {
return !item.completed
}).length
this.setData({ todos: todos, leftCount: leftCount })
}
var logs = wx.getStorageSync('todo_logs')
if (logs) {
this.setData({ logs: logs })
}
},
onLoad: function () {
this.load()
},
inputChangeHandle: function (e) {
this.setData({ input: e.detail.value })
},
addTodoHandle: function (e) {
if (!this.data.input || !this.data.input.trim()) return
var todos = this.data.todos
todos.push({ name: this.data.input, completed: false })
var logs = this.data.logs
logs.push({ timestamp: new Date(), action: 'Add', name: this.data.input })
this.setData({
input: '',
todos: todos,
leftCount: this.data.leftCount + 1,
logs: logs
})
this.save()
},
toggleTodoHandle: function (e) {
var index = e.currentTarget.dataset.index
var todos = this.data.todos
todos[index].completed = !todos[index].completed
var logs = this.data.logs
logs.push({
timestamp: new Date(),
action: todos[index].completed ? 'Finish' : 'Restart',
name: todos[index].name
})
this.setData({
todos: todos,
leftCount: this.data.leftCount + (todos[index].completed ? -1 : 1),
logs: logs
})
this.save()
},
removeTodoHandle: function (e) {
var index = e.currentTarget.dataset.index
var todos = this.data.todos
var remove = todos.splice(index, 1)[0]
var logs = this.data.logs
logs.push({ timestamp: new Date(), action: 'Remove', name: remove.name })
this.setData({
todos: todos,
leftCount: this.data.leftCount - (remove.completed ? 0 : 1),
logs: logs
})
this.save()
},
toggleAllHandle: function (e) {
this.data.allCompleted = !this.data.allCompleted
var todos = this.data.todos
for (var i = todos.length - 1; i >= 0; i--) {
todos[i].completed = this.data.allCompleted
}
var logs = this.data.logs
logs.push({
timestamp: new Date(),
action: this.data.allCompleted ? 'Finish' : 'Restart',
name: 'All todos'
})
this.setData({
todos: todos,
leftCount: this.data.allCompleted ? 0 : todos.length,
logs: logs
})
this.save()
},
clearCompletedHandle: function (e) {
var todos = this.data.todos
var remains = []
for (var i = 0; i < todos.length; i++) {
todos[i].completed || remains.push(todos[i])
}
var logs = this.data.logs
logs.push({
timestamp: new Date(),
action: 'Clear',
name: 'Completed todo'
})
this.setData({ todos: remains, logs: logs })
this.save()
}
})
页面布局
<view class="container">
<view class="header">
<image class="plus" src="../../assets/plus.png"/>
<input class="new-todo" value="{
{ input }}" placeholder="Anything here..." auto-focus bindinput="inputChangeHandle" bindconfirm="addTodoHandle"/>
</view>
<block wx:if="{
{ todos.length }}">
<view class="todos">
<!-- List items should get the class `completed` when marked as completed -->
<view class="item{
{ item.completed ? ' completed' : '' }}" wx:for="{
{ todos }}" wx:key="{
{ index }}" bindtap="toggleTodoHandle" data-index="{
{ index }}">
<!-- completed: success, todo: circle -->
<icon class="checkbox" type="{
{ item.completed ? 'success' : 'circle' }}"/>
<text class="name">{
{ item.name }}</text>
<icon class="remove" type="clear" size="16" catchtap="removeTodoHandle" data-index="{
{ index }}"/>
</view>
</view>
<view class="footer">
<text class="btn" bindtap="toggleAllHandle">Toggle all</text>
<text wx:if="{
{ leftCount }}">{
{ leftCount }} {
{ leftCount === 1 ? 'item' : 'items' }} left</text>
<text class="btn" wx:if="{
{ todos.length > leftCount }}" bindtap="clearCompletedHandle">Clear completed</text>
</view>
</block>
<block wx:else>
<view class="empty">
<text class="title">Congratulations!</text>
<text class="content">There's no more work left.</text>
</view>
</block>
</view>
页面样式
.header {
display: flex;
align-items: center;
border: 1rpx solid #e0e0e0;
border-radius: 10rpx;
box-shadow: 0 0 5rpx #e0e0e0;
margin-bottom: 30rpx;
padding: 20rpx;
}
.header .plus {
width: 41rpx;
height: 41rpx;
margin-right: 20rpx;
}
.header .new-todo {
flex: 1;
font-size: 28rpx;
}
.todos {
border: 1rpx solid #e0e0e0;
border-radius: 10rpx;
box-shadow: 0 0 5rpx #e0e0e0;
}
.todos .item {
display: flex;
align-items: center;
padding: 25rpx;
border-bottom: 1rpx solid #e0e0e0;
}
.todos .item:last-child {
border-bottom: 0;
}
.todos .item .checkbox {
margin-right: 20rpx;
}
.todos .item .name {
flex: 1;
font-size: 30rpx;
color: #444;
}
.todos .item.completed .name {
text-decoration: line-through;
color: #888;
}
/*
.todos .item .remove {
cursor: pointer;
}
*/
.footer {
display: flex;
justify-content: space-between;
margin: 30rpx 0;
padding: 0 10rpx;
font-size: 26rpx;
color: #777;
}
/*
.footer .btn {
cursor: pointer;
}
*/
.empty {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.empty .title {
font-size: 60rpx;
margin: 200rpx 50rpx 50rpx;
color: #444;
}
.empty .content {
color: #666;
text-align: center;
}