自学微信小程序开发第六天- TODOS案例

  • 页面呈现
    • 界面结构
    • 添加界面样式
  • 界面交互
    • 抽象数据模型
    • 界面数据绑定
    • 界面交互的操作
      • 文本框输入数据,添加至列表
      • 切换任务完成状态
      • 剩余数量的实时改变
      • 删除任务
      • 切换全部
      • 清除完成项
      • 当没有待办项时隐藏列表和页脚
  • 数据保存
  • 日志
    • 记录日志信息
    • 日志页面
    • 日志的数据绑定
  • 整个项目代码

TODOS是一个待办事项的小程序,用这个来测试我们之前学到的内容。

页面呈现

准备达成的目标界面如图所示,按照这个图来设计页面。

界面结构

首先,最上方标题文字更改和最下方的 tagbar 在 app.json 里更改。

{"pages": ["pages/index/index","pages/logs/logs"],"window": {"backgroundTextStyle": "light","navigationBarBackgroundColor": "#fff","navigationBarTitleText": "TODOS","navigationBarTextStyle": "black"},"style": "v2","sitemapLocation": "sitemap.json","tabBar": {"list": [{"pagePath": "pages/index/index","text": "todos","iconPath": "images/todos.png","selectedIconPath": "images/todos-active.png"},{"pagePath": "pages/logs/logs","text": "日志","selectedIconPath": "images/logs-active.png","iconPath": "images/logs.png"}]}
}

再就是页面布局结构,这里很多应该是根据后台呈现的内容,先不管,把整体结构先规划出来,之后再进行更改。

<!--index.wxml-->
<view class="container"><!-- 增加项目 --><view class="add"><image src="../../images/plus.png"></image><input type="text" placeholder="准备做的事" /></view><!-- 需要做的事 --><view class="todos"><view class="item"><icon type="circle"></icon><text>做界面布局</text><icon type="clear"></icon></view><view class="item"><icon type="success"></icon><text>抽象业务数据</text><icon type="clear"></icon></view><view class="item"><icon type="circle"></icon><text>等等</text><icon type="clear"></icon></view></view><!-- 页脚 --><view class="footer"><text>切换全部</text><text>剩余2件事</text><text>清除完成项</text></view>
</view>

添加界面样式

界面样式主要是在 .wxss 里完成,不过页面中使用了 <icon> 标签,这个标签的大小使用标签的 size 来调整。其他的均使用样式表。

<icon type="clear" size="32rpx"></icon>
/**index.wxss**/
/* 页面容器 */
.container{border-top: 1rpx solid #e0e0e0;     /* 最上方的横线,以上边框的形式呈现 */
}
/* 增加项目栏 */
.add{border: 1rpx solid #e0e0e0;     /* 边框 */border-radius: 10rpx;       /* 边框圆角 */box-shadow: 0 0 10rpx #e0e0e0;   /* 阴影 */align-items: center;    /* 侧轴对齐 */display: flex;    /* 设置为flex盒子 */padding: 20rpx;     /* 内边距 */margin: 20rpx;      /* 外边距 */
}
/* 增加项目栏下的图片 */
.add image{width: 40rpx;       /* 宽 */height: 40rpx;      /* 高 */margin-right: 20rpx;        /* 右侧外边距 */
}
/* 需要做到事项区域 */
.todos{border: 1rpx solid #e0e0e0;     /* 边框 */border-radius: 10rpx;       /* 边框圆角 */box-shadow: 0 0 10rpx #e0e0e0;   /* 阴影 */align-items: center;    /* 子元素侧轴对齐 */margin: 20rpx;      /* 外边距 */
}
/* 任务项 */
.todos .item{padding: 20rpx;     /* 内边距 */border-bottom: 1rpx solid #e0e0e0;      /* 底部边框 */display: flex;      /* 设置为flex盒子 */align-items: center;    /* 子元素侧轴对齐 */
}
/* 最后一个任务项,不需要底部边框 */
.todos .item:last-child{padding: 20rpx;     /* 内边距 */display: flex;      /* 设置为flex盒子 */align-items: center;     /* 子元素侧轴对齐 */
}
/* 任务项里的文本 */
.todos .item text{flex: 1;        /* 获取全部剩余空间 */font-size: 30rpx;   /* 字体大小 */color: #444;        /* 字体颜色 */margin-left: 20rpx;     /* 左侧外边距 */
}
/* 页脚 */
.footer{font-size: 30rpx;       /* 字体大小 */margin: 20rpx;      /* 外边距 */display: flex;      /* 设置为flex盒子 */justify-content: space-between;     /* 子元素主轴对齐 */color: #333;    /* 字体颜色 */
}

界面交互

抽象数据模型

页面设计好了,就要抽象数据模型了。抽象数据模型就是根据页面情况,确定添加哪些数据成员。即,确定哪个数据在程序使用过程中会改变,将其设计成变量。

// index.js
Page({data: {// 文本框数据add: '',// 任务列表todos: [{ name: '', completed: false }],// 剩余数量leftCount: 0}
})

界面数据绑定

数据模型建立好了,则要和相应的元素进行绑定。这里有个需注意的地方:需要做的事中具体项目的图标类型和文本样式会改变,使用三元表达式进行判断,然后随之进行改变。

<!--index.wxml-->
<view class="container"><!-- 增加项目 --><view class="add"><image src="../../images/plus.png"></image><input type="text" placeholder="准备做的事" value="{{add}}" /></view><!-- 需要做的事 --><view class="todos"><view class="item{{item.completed ? ' completed' : ''}}" wx:for="{{todos}}" ><icon type="{{item.completed ? 'success' : 'circle'}}"></icon><text>{{item.name}}</text><icon type="clear" size="32rpx"></icon></view></view><!-- 页脚 --><view class="footer"><text>切换全部</text><text>剩余{{leftCount}}件事</text><text>清除完成项</text></view>
</view>

新增样式,已完成任务的文本样式,改变字体颜色,增加删除线。

/* 任务项里已完成任务的文本 */
.todos .item.completed text{flex: 1;        /* 获取全部剩余空间 */font-size: 30rpx;   /* 字体大小 */color: #888;        /* 字体颜色 */margin-left: 20rpx;     /* 左侧外边距 */text-decoration: line-through;  /* 中划线 */
}

界面交互的操作

文本框输入数据,添加至列表

因为小程序的数据流是单向的,所以要绑定事件,来获取文本框输入的内容。点击 “+” 也要绑定事件,来向列表数组添加数据。

    <!-- 增加项目 --><view class="add"><image src="../../images/plus.png" bindtap="addTodo"></image><input type="text" placeholder="准备做的事" value="{{add}}" bindinput="textChange" bindconfirm="addTodo" focus /></view>
    // 将文本框的数据添加至任务列表数组addTodo: function () {if (!this.data.add) return      // 如果文本框是空的,则终止执行var todos = this.data.todostodos.push({name: this.data.add,completed: false})this.setData({ todos: todos, add: '' })},// 文本有改变,改变相应数据成员textChange: function (e) {this.setData({ add: e.detail.value })}

切换任务完成状态

切换任务状态需要给每个 item 项绑定个点击事件,且绑定个 data 数据,以便获取点击的项的索引号进行操作。

    <!-- 需要做的事 --><view class="todos"><view class="item{{item.completed ? ' completed' : ''}}" wx:for="{{todos}}" bindtap="toggleState" data-index="{{index}}"><icon type="{{item.completed ? 'success' : 'circle'}}"></icon><text>{{item.name}}</text><icon type="clear" size="32rpx"></icon></view></view>
    // 切换单项任务状态toggleState: function (e) {var item = this.data.todos[e.currentTarget.dataset.index] // 获取当前点击元素的索引号,确定具体 item 项item.completed = !item.completed // 单项的完成情况取非this.setData({ todos: this.data.todos })    //刷新数据绑定}

剩余数量的实时改变

剩余数量绑定了数据成员 leftCount ,即需要在新增项、删除、切换等操作时维护此数据成员。已经完成了新增、切换的操作,所以先在这两个操作中进行维护。另在呈现的时候,如果 leftCount 为 0 ,则剩余的文本不显示,可以使用三元表达式进行判断。

    <!-- 页脚 --><view class="footer"><text>切换全部</text><text hidden="{{leftCount == 0 ? true : false}}">剩余{{leftCount}}件事</text><text>清除完成项</text></view>
    // 将文本框的数据添加至任务列表数组addTodo: function () {if (!this.data.add) returnvar todos = this.data.todostodos.push({name: this.data.add,completed: false})this.setData({todos: todos,add: '',leftCount: this.data.leftCount + 1})},// 切换单项任务状态toggleState: function (e) {// 根据参数获得的索引号,确定具体项目var item = this.data.todos[e.currentTarget.dataset.index]item.completed = !item.completed// 根据当前任务状态决定增加还是减少var leftCount = this.data.leftCount + (item.completed ? -1 : 1)this.setData({ todos: this.data.todos, leftCount: leftCount })}

删除任务

删除任务是点任务列表里单项文本后面的叉号进行删除,除了需要绑定事件,还需要操作数组,维护数据成员。另,叉号的事件必须阻止冒泡。

    <!-- 需要做的事 --><view class="todos"><view class="item{{item.completed ? ' completed' : ''}}" wx:for="{{todos}}" wx:key="name" bindtap="toggleState" data-index="{{index}}"><icon type="{{item.completed ? 'success' : 'circle'}}"></icon><text>{{item.name}}</text><icon type="clear" size="32rpx" catchtap="deleteItem" data-index="{{index}}"></icon></view></view>
    // 删除单项任务deleteItem: function (e) {var todos = this.data.todos// 根据索引号查找是否完成,决定leftCount是否改变var item = this.data.todos[e.currentTarget.dataset.index]var leftCount = this.data.leftCount + (item.completed ? 0 : -1)// 根据索引号删除数组中的元素todos.splice(e.currentTarget.dataset.index, 1)this.setData({ todos: todos, leftCount: leftCount })}

切换全部

点击后是切换成完成还是未完成,需要设置个标记变量来判断。

    <!-- 页脚 --><view class="footer"><text bindtap="toggleAll">切换全部</text><text hidden="{{leftCount == 0 ? true : false}}"> 剩余{{leftCount}}件事 </text><text>清除完成项</text></view>
    data: {// 文本框数据add: '',// 任务列表todos: [],// 剩余数量leftCount: 0,allCompleted: false},// 切换全部任务状态toggleAll: function () {// 切换全部任务的状态为this.data.allCompleted = !this.data.allCompletedvar todos = this.data.todos// this在函数内部使用出错,不是指page对象var that = this// 历遍todos更改completed状态todos.forEach(function (item) {item.completed = that.data.allCompleted})// 更改剩余数量var leftCount = (this.data.allCompleted ? 0 : todos.length)// 刷新值this.setData({ todos: todos, leftCount: leftCount })}

另外切换状态也涉及了 allCompleted ,所以也需要增加判断。

    // 切换单项任务状态toggleState: function (e) {// 根据参数获得的索引号,确定具体项目var item = this.data.todos[e.currentTarget.dataset.index]// 切换状态item.completed = !item.completed// 根据当前任务状态决定剩余数增加还是减少var leftCount = this.data.leftCount + (item.completed ? -1 : 1)// 判断是否全部完成var todos = this.data.todosvar completed = item.completed// 如果切换后状态为true,则历遍todos,发现false则completed赋值falseif (completed) {for (var i = 0; i < todos.length; i++) {if (!todos[i].completed) {completed = falsebreak}}}this.data.allCompleted = completed// 刷新值this.setData({ todos: this.data.todos, leftCount: leftCount })}

清除完成项

清除完成项的思路很简单,历遍数组,将所有 completed 的值为 true 的项删掉。或者新建个空数组,将所有 completed 为 false 的项添加至新数组。因为前一种方法在历遍时还需要考虑到删除时索引号的改变,所以使用后一种方法较为简单明了。

    <!-- 页脚 --><view class="footer"><text bindtap="toggleAll">切换全部</text><text hidden="{{leftCount == 0 ? true : false}}">剩余{{leftCount}}件事</text><text bindtap="clearCompleted">清除完成项</text></view>

即使1种思路,实现方法也有多个,这里写2个。

    //清除完成项clearCompleted: function () {// 创建新列表,将所有老列表completed为false的项添加到新列表// 方法1:使用forEach历遍// var todos=[]// this.data.todos.forEach(function(item){//     if(!item.completed){//         todos.push(item)//     }// })// 方法2:使用filter过滤,根据条件(函数)过滤,返回值为true则添加到新数组var todos = this.data.todos.filter(function (item) {return !item.completed})// 刷新值this.setData({ todos: todos })}

再就是考虑到,没有完成项的时候,就不显示清除完成项了。思路是比对todos.length 和 leftCount 。

    <!-- 页脚 --><view class="footer"><text bindtap="toggleAll">切换全部</text><text hidden="{{leftCount == 0 ? true : false}}">剩余{{leftCount}}件事</text><text bindtap="clearCompleted" hidden="{{todos.length == leftCount ? true : false}}" >清除完成项</text></view>

当没有待办项时隐藏列表和页脚

主要思路就是判断 todos.length ,当值为 0 时不显示,或显示其他提示。

    <!-- 判断是否需要显示列表和页脚 --><block wx:if="{{todos.length}}"><!-- 需要做的事 --><view class="todos"></view><!-- 页脚 --><view class="footer"></view></block><!-- 不显示列表和页脚 --><block wx:else><view class="empty"><text class="title">恭喜你</text><text class="content">没有剩余的工作了</text></view></block>
/* 列表空 */
.empty {display: flex;/* 设置为flex盒子 */flex-direction: column;/* 主轴设置为纵轴 */align-items: center;/* 子元素侧轴对齐方式 */justify-content: center;/* 子元素主轴对齐方式 */
}
/* 列表空时显示的标题 */
.empty .title {font-size: 120rpx;margin: 200rpx 50rpx 50rpx;color: #444;
}
/* 列表空时显示的内容 */
.empty .content {font-size: 40rpx;color: #666;text-align: center;
}

数据保存

到这里结构、界面就都完成了,作为一个应用程序,还有一道工具就是数据处理,即后台工作。对于 todos 这个程序来说,大部分的后台工作其实就是界面交互的控制,剩余的后台工作就只剩下数据保存了。

我们的小程序测试时发现目前无法保存数据,每次重新加载时数据是重置的,所以就需要进行数据保存。

在小程序中,我们可以使用API函数 wx.setStorageSync 以键值对的形式保存数据到缓存中,使用 wx.getStorageSync 函数来进行读取。在 onLoad 事件中进行读取,在数据有变动时进行保存,即达到了存储数据的目的。

    // 保存数据save: function () {wx.setStorageSync('todo_list', this.data.todos)},// 读取数据load: function () {var todos = wx.getStorageSync('todo_list')// 判断是否获得数据,并根据获得数据重新计算剩余数量if (todos) {var leftCount = todos.filter(function (item) {return !item.completed}).lengthif (leftCount == 0) this.data.allCompleted = true// 刷新值this.setData({ todos: todos, leftCount: leftCount })}},// 页面加载事件onLoad: function () {this.load()}

最后就是每个设计数据变动的函数最后都增加 this.save()

日志

记录日志信息

在希望达成目标的界面中,还有个日志页面。这就需要在每次数据有改动时记录日志,日志内容初步设计为记录操作行为(增加、删除、改变状态、全部改变状态、删除已完成)、操作时间及操作项目。同时需要保存日志到缓存中。(这里只写相关代码)

//读取数据时
var logs = wx.getStorageSync('todo_logs')    // 读取日志
if (logs) this.setData({ logs: logs })      // 如果读取到日志,刷新值
// 保存数据
save: function () {wx.setStorageSync('todo_list', this.data.todos)wx.setStorageSync('todo_logs', this.data.logs)
},
//清除完成项
var logs = this.data.logs  // 写日志
logs.push({timestamp: new Date(), action: '清除', item: '所有完成项'
})
// 切换全部任务状态
var logs = this.data.logs  // 写日志
logs.push({timestamp: new Date(), action: this.data.allCompleted ? '完成' : '重启', item: '所有列表项'
})
// 删除单项任务
var logs = this.data.logs  // 写日志
logs.push({timestamp: new Date(), action: '删除', item: item.name
})
// 切换单项任务状态
var logs = this.data.logs  // 写日志
logs.push({timestamp: new Date(), action: item.completed ? '完成' : '重启', item: item.name
})
// 新增列表项
var logs = this.data.logs      // 写日志
logs.push({timestamp: new Date(), action: '新增', item: this.data.add
})

日志页面

日志页面比较简单,就是一个列表框,显示所有列表项。日志列表只有3个元素:内容、行为、时间。

<!--pages/logs/logs.wxml-->
<!-- 页面容器 -->
<view class="container" ><!-- 日志列表 --><view class="logs" wx:if="{{logs}}"><!-- 列表项目 --><view class="item" wx:for="{{logs}}" wx:key="{{index}}"><text class="content">{{item.item}}</text><text class="action">{{item.action}}</text><text class="timestamp">{{item.timestamp}}</text></view></view>
</view>
/* pages/logs/logs.wxss */
/* 日志列表 */
.logs{border: 1rpx solid #e0e0e0;border-radius: 10rpx;box-shadow: 0 0 10rpx #e0e0e0;
}
.logs .item{border-bottom: 1rpx solid #e0e0e0;padding: 30rpx;font-size: 30rpx;
}
.logs .item .content{width: 70%;color: #aa0;display: inline-block;
}
.logs .item .action{display: inline-block;text-align: right;color: #f40;width: 30%;
}
.logs .item .timestamp{display: block;color: #888;margin-top: 20rpx;
}

日志的数据绑定

日志页面只是呈现日志列表,不需要复杂的交互。只是需注意的是,加载缓存需要在页面呈现事件中,而不能在页面加载事件中。

// pages/logs/logs.js
Page({/*** 页面的初始数据*/data: {logs: []},/*** 生命周期函数--监听页面显示*/onShow() {this.load()},load: function () {// 读取日志var logs = wx.getStorageSync('todo_logs')// 如果读取到日志,刷新值(因为数组是按时间最早的在最下方,所以呈现时候需逆序)if (logs) this.setData({ logs: logs.reverse() })}
})

整个项目代码

/**app.wxss**/
/* 页面容器 */
.container {border-top: 1rpx solid #e0e0e0;/* 最上方的横线,以上边框的形式呈现 */padding: 20rpx;
}

app.json

{"pages": ["pages/index/index","pages/logs/logs"],"window": {"backgroundTextStyle": "light","navigationBarBackgroundColor": "#fff","navigationBarTitleText": "TODOS","navigationBarTextStyle": "black"},"style": "v2","sitemapLocation": "sitemap.json","tabBar": {"list": [{"pagePath": "pages/index/index","text": "todos","iconPath": "images/todos.png","selectedIconPath": "images/todos-active.png"},{"pagePath": "pages/logs/logs","text": "日志","selectedIconPath": "images/logs-active.png","iconPath": "images/logs.png"}]}
}
// app.js
App({})
// index.js
Page({data: {// 文本框数据add: '',// 任务列表todos: [],// 剩余数量leftCount: 0,// 是否全部完成allCompleted: false,// 日志logs: []},// 新增列表项addTodo: function () {// 如果文本框为空if (!this.data.add) return// 增加到数组最后var todos = this.data.todostodos.push({name: this.data.add,completed: false})// 写日志var logs = this.data.logslogs.push({timestamp: new Date(), action: '新增', item: this.data.add})// 刷新值this.setData({todos: todos,add: '',leftCount: this.data.leftCount + 1,logs: logs})this.save()},// 文本有改变,改变相应数据成员textChange: function (e) {this.setData({ add: e.detail.value })},// 切换单项任务状态toggleState: function (e) {// 根据参数获得的索引号,确定具体项目var item = this.data.todos[e.currentTarget.dataset.index]// 切换状态item.completed = !item.completed// 根据当前任务状态决定剩余数增加还是减少var leftCount = this.data.leftCount + (item.completed ? -1 : 1)// 判断是否全部完成if (leftCount == 0) this.data.allCompleted = true// 写日志var logs = this.data.logslogs.push({timestamp: new Date(), action: item.completed ? '完成' : '重启', item: item.name})// 刷新值this.setData({ todos: this.data.todos, leftCount: leftCount, logs: logs })this.save()},// 删除单项任务deleteItem: function (e) {var todos = this.data.todos// 根据索引号删除数组中的元素,返回值为删除的元素数组var item = todos.splice(e.currentTarget.dataset.index, 1)[0]// 根据删除元素的完成状态,决定leftCount是否改变var leftCount = this.data.leftCount + (item.completed ? 0 : -1)// 判断是否全部完成if (leftCount == 0) this.data.allCompleted = true// 写日志var logs = this.data.logslogs.push({timestamp: new Date(), action: '删除', item: item.name})// 刷新值this.setData({ todos: todos, leftCount: leftCount, logs: logs })this.save()},// 切换全部任务状态toggleAll: function () {// 切换全部任务的状态为this.data.allCompleted = !this.data.allCompletedvar todos = this.data.todos// this在函数内部使用出错,不是指page对象var that = this// 历遍todos更改completed状态todos.forEach(function (item) {item.completed = that.data.allCompleted})// 更改剩余数量var leftCount = this.data.allCompleted ? 0 : todos.length// 写日志var logs = this.data.logslogs.push({timestamp: new Date(), action: this.data.allCompleted ? '完成' : '重启', item: '所有列表项'})// 刷新值this.setData({ todos: todos, leftCount: leftCount, logs: logs })this.save()},//清除完成项clearCompleted: function () {// 创建新列表,历遍老列表,将completed为false项添加到新列表// 使用forEach历遍// var todos=[]// this.data.todos.forEach(function(item){//     if(!item.completed){//         todos.push(item)//     }// })// 使用filter过滤,根据条件(函数)过滤,返回值为true则添加到新数组var todos = this.data.todos.filter(function (item) {return !item.completed})// 写日志var logs = this.data.logslogs.push({timestamp: new Date(), action: '清除', item: '所有完成项'})// 刷新值this.setData({ todos: todos, logs: logs })this.save()},// 保存数据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}).lengthif (leftCount == 0) this.data.allCompleted = true// 刷新值this.setData({ todos: todos, leftCount: leftCount })}// 读取日志var logs = wx.getStorageSync('todo_logs')// 如果读取到日志,刷新值if (logs) this.setData({ logs: logs })},// 页面加载事件onLoad: function () {this.load()}
})
<!--index.wxml-->
<view class="container"><!-- 增加项目 --><view class="add"><image src="../../images/plus.png" bindtap="addTodo"></image><input type="text" placeholder="准备做的事" value="{{add}}" bindinput="textChange" bindconfirm="addTodo" /></view><!-- 判断是否需要显示列表和页脚 --><block wx:if="{{todos.length}}"><!-- 需要做的事 --><view class="todos"><view class="item{{item.completed ? ' completed' : ''}}" wx:for="{{todos}}" wx:key="name" bindtap="toggleState" data-index="{{index}}"><icon type="{{item.completed ? 'success' : 'circle'}}"></icon><text>{{item.name}}</text><icon type="clear" size="32rpx" catchtap="deleteItem" data-index="{{index}}"></icon></view></view><!-- 页脚 --><view class="footer"><text bindtap="toggleAll">切换全部</text><text hidden="{{leftCount == 0 ? true : false}}">剩余{{leftCount}}件事</text><text bindtap="clearCompleted" hidden="{{todos.length == leftCount ? true : false}}">清除完成项</text></view></block><!-- 不显示列表和页脚 --><block wx:else><view class="empty"><text class="title">恭喜你</text><text class="content">没有剩余的工作了</text></view></block>
</view>
/**index.wxss**/
/* 增加项目栏 */
.add {border: 1rpx solid #e0e0e0;/* 边框 */border-radius: 10rpx;/* 边框圆角 */box-shadow: 0 0 10rpx #e0e0e0;/* 阴影 */align-items: center;/* 侧轴对齐 */display: flex;/* 设置为flex盒子 */padding: 20rpx;/* 内边距 */
}/* 增加项目栏下的图片 */
.add image {width: 40rpx;/* 宽 */height: 40rpx;/* 高 */margin-right: 20rpx;/* 右侧外边距 */
}/* 需要做到事项区域 */
.todos {border: 1rpx solid #e0e0e0;/* 边框 */border-radius: 10rpx;/* 边框圆角 */box-shadow: 0 0 10rpx #e0e0e0;/* 阴影 */align-items: center;/* 子元素侧轴对齐 */
}/* 任务项 */
.todos .item {padding: 20rpx;/* 内边距 */border-bottom: 1rpx solid #e0e0e0;/* 底部边框 */display: flex;/* 设置为flex盒子 */align-items: center;/* 子元素侧轴对齐 */
}/* 最后一个任务项,不需要底部边框 */
.todos .item:last-child {padding: 20rpx;/* 内边距 */display: flex;/* 设置为flex盒子 */align-items: center;/* 子元素侧轴对齐 */
}/* 任务项里的文本 */
.todos .item text {flex: 1;/* 获取全部剩余空间 */font-size: 30rpx;/* 字体大小 */color: #444;/* 字体颜色 */margin-left: 20rpx;/* 左侧外边距 */
}/* 任务项里已完成任务的文本 */
.todos .item.completed text {flex: 1;/* 获取全部剩余空间 */font-size: 30rpx;/* 字体大小 */color: #888;/* 字体颜色 */margin-left: 20rpx;/* 左侧外边距 */text-decoration: line-through;/* 中划线 */
}
/* 页脚 */
.footer {font-size: 30rpx;/* 字体大小 */margin: 10rpx;/* 外边距 */display: flex;/* 设置为flex盒子 */justify-content: space-between;/* 子元素主轴对齐 */color: #333;/* 字体颜色 */
}
/* 列表空 */
.empty {display: flex;/* 设置为flex盒子 */flex-direction: column;/* 主轴设置为纵轴 */align-items: center;/* 子元素侧轴对齐方式 */justify-content: center;/* 子元素主轴对齐方式 */
}
/* 列表空时显示的标题 */
.empty .title {font-size: 120rpx;margin: 200rpx 50rpx 50rpx;color: #444;
}
/* 列表空时显示的内容 */
.empty .content {font-size: 40rpx;color: #666;text-align: center;
}
// pages/logs/logs.js
Page({/*** 页面的初始数据*/data: {logs: []},/*** 生命周期函数--监听页面显示*/onShow() {this.load()},load: function () {// 读取日志var logs = wx.getStorageSync('todo_logs')// 如果读取到日志,刷新值(因为数组是按时间最早的在最下方,所以呈现时候需逆序)if (logs) this.setData({ logs: logs.reverse() })}
})
<!--pages/logs/logs.wxml-->
<!-- 页面容器 -->
<view class="container" ><!-- 日志列表 --><view class="logs" wx:if="{{logs}}"><!-- 列表项目 --><view class="item" wx:for="{{logs}}" wx:key="{{index}}"><text class="content">{{item.item}}</text><text class="action">{{item.action}}</text><text class="timestamp">{{item.timestamp}}</text></view></view>
</view>
/* pages/logs/logs.wxss */
/* 日志列表 */
.logs{border: 1rpx solid #e0e0e0;border-radius: 10rpx;box-shadow: 0 0 10rpx #e0e0e0;
}
.logs .item{border-bottom: 1rpx solid #e0e0e0;padding: 30rpx;font-size: 30rpx;
}
.logs .item .content{width: 70%;color: #aa0;display: inline-block;
}
.logs .item .action{display: inline-block;text-align: right;color: #f40;width: 30%;
}
.logs .item .timestamp{display: block;color: #888;margin-top: 20rpx;
}

重要参考:

B站上找到的开发教程视频,Up主不知道叫啥……

自学微信小程序开发第六天- TODOS案例相关推荐

  1. 自学微信小程序开发第二天-事件处理、数据流

    自学微信小程序开发第二天-事件处理.数据流 事件处理 绑定冒泡事件 阻止冒泡事件 互斥事件 事件传参 事件对象的属性 数据流 实例:登录页面案例 之前学习了微信小程序开发的相关环境,测试了小程序开发工 ...

  2. 自学微信小程序开发第四天-研究弹性盒子(FlexBox)的伸缩布局,微信小程序的CSS使用实例

    @TOC 组件都了解的差不多了,下面就是页面整体布局设计了.在HTML中,使用的是DIV + CSS的布局方式,也可以用在小程序里.不过因为移动端的分辨率不统一,使得布局的自适应十分重要.所以研究一下 ...

  3. 自学微信小程序开发第五天- 页面切换相关

    自学微信小程序开发第五天- 页面切换相关 创建多个页面 页面间跳转 页面间传值 另一个页面跳转的方式(重定向) 点击跳转元素时的样式 导航API 研究过页面样式设计后,就是多页面的呈现了,这就需要研究 ...

  4. 学习(微信小程序 开发入门及案例详解 --李骏,边思编著)

    第一章 初识小程序 1.小程序不仅在商业上具备很大潜力,同时在技术上解决了一套代码多端运行和动态发版的两大痛点,用户在微信中扫一扫或搜一下即可打开具备原生体验的应用,这给开发者带来了很大的想象空间 2 ...

  5. 微信小程序开发 | API应用案例(上)

    API应用案例(上) 5.1[案例1]用户登录 5.1.1 案例分析 5.1.2 前导知识 5.1.3 搭建开发者服务器 5.1.4 实现用户登录 5.1.5 检查用户是否已经登录 5.1.6 获取用 ...

  6. 微信小程序开发 | API应用案例(下)

    API应用案例(下) 6.1[案例5]模拟时钟 6.1.1 案例分析 6.1.2 前导知识 6.1.3 钟表页面布局 6.1.4 钟表页面绘制 6.2[案例6]罗盘动画 6.2.1 案例分析 6.2. ...

  7. 视频教程-微信小程序开发【初级篇 / 附案例】-微信开发

    微信小程序开发[初级篇 / 附案例] 北风网讲师!瓢城Web俱乐部创始人,教学总监! 李炎恢 ¥129.00 立即订阅 扫码下载「CSDN程序员学院APP」,1000+技术好课免费看 APP订阅课程, ...

  8. 微信小程序开发 自学

    微信小程序开发 自学方向 小程序基础知识 一.小程序的结构目录 1.小程序文件结构与传统web对比 2.基本项目目录 3.全局配置 app,json 3.1.pages 添加页面文件 3.2.wind ...

  9. 微信小程序开发学习6(基础加强之使用npm包和全局数据共享及分包【Tab底栏案例改进】)

    微信小程序开发学习6(基础加强之使用npm包和全局数据共享及分包) 1.使用npm包 小程序对npm包的支持 目前,小程序中已经支持使用p安装第三方包,从而来提高小程序的开发效率.但是,在小程序中使用 ...

  10. 微信小程序wxml如何判断字符串中汉语某字符_微信小程序开发经典案例解析“嗨兔儿”...

    嗨兔儿是微信公众号嗨日语歌(hitaici)助手,主要为用户提供,关键词检索,帮助手册等,为外语学习者提供一个便捷的操作方式,能够开心工作,开心生活. 开发过程及注意事项分享视频. 1. 微信小程序开 ...

最新文章

  1. 【Socket研究】~。~ Scoket开发蛋疼笔记 Silverlight
  2. 7个实战案例、24个学习视频、12G干货资料...今天带你免费入门Python数据分析!...
  3. Java-编程规范与代码风格
  4. 3.SpringBoot 常用配置
  5. Python零基础入门(零)——Anaconda安装(python安装)和使用
  6. 【学习笔记3】hook、冒烟测试、Procexp的使用
  7. 2018百战程序员大数据全套教程
  8. JS简单的时间控件分享
  9. cs服务器(cs索沛服务器)
  10. python3 tk_python3.5 安装python3-tk
  11. 论文写作技巧----公式
  12. 费率与利率的差别_费率是什么(利率和费率有啥区别?)
  13. Scratch-简易时钟制作
  14. IOS仿支付宝首页滑动效果
  15. 算法与程序设计相关知识
  16. mmse评估量表_简易精神状态评价量表(MMSE)
  17. Totam animi repellendus consequuntur ad.Deserunt temporibMous nulla soluta distinctio voluptas esse.
  18. 接口限流算法及解决方案
  19. edge浏览器什么相当于ie的中低_杀死IE!Edge浏览器是Windows历代最好
  20. mPaaS跳转到继承于H5WebViewController的离线包容器出现蓝色导航条的问题

热门文章

  1. 如何在edge浏览器上安装flash插件运行需要flash的游戏
  2. uniapp iOS打包
  3. Latex 图注设置(图1:改为图1-1)
  4. 使用 IDEA Maven 整合 SSM 框架(Spring+SpringMVC+Mybatis)
  5. 计算机蓝屏了 怎么维修,电脑蓝屏怎么办?电脑出现蓝屏快速解决教程
  6. Au:突发性噪音降噪方法
  7. PPT中如何插入页码和母版修改
  8. 【Elasticsearch源码】 更新性能分析
  9. 无人机原理图、pcb图下载地址
  10. 程序人生 -- 我的成长之路和进阶经验分享