详细了解 Todo App Demo
概述
这里会通过Todo App Demo更加细致的了解小程序的实现原理。
全局配置
app.js 是小程序公共的逻辑脚本文件,在这个文件中可以监听小程序的生命周期,声明全局变量,调用框架提供的丰富 API,如以下所示的存储以及获取用户信息 API,更多 API 参见 API 文档.
// 调用存储 api 获取已经存在的数据
const todos = my.getStorageSync({key:'todos'}).data || [
{ text: 'Learning Javascript', completed: true },
{ text: 'Learning ES2016', completed: true },
{ text: 'Learning 支付宝小程序', completed: false },
];
App({
// 声明全局数据
todos,
userInfo: null,
// 声明全局方法
setTodos(todos) {
this.todos = todos;
// 调用存储 api 存储数据
my.setStorageSync({key:'todos', data:todos});
},
getUserInfo() {
return new Promise((resolve, reject) => {
if (this.userInfo) resolve(this.userInfo);
// 调用用户授权 api 获取用户信息
my.getAuthCode({
success: (authcode) => {
console.info(authcode);
my.getAuthUserInfo({
scopes: ['auth_user'],
success: (res) => {
this.userInfo = res;
resolve(this.userInfo);
},
fail: () => {
reject({});
},
});
},
fail: () => {
reject({});
},
});
});
},
});
app.json 是属于小程序的全局配置,在这个 json 文件中可以记配置小程序的页面集合,通用的的状态栏、导航条、标题、窗口背景色等。更多配置参见 文档配置。
{
"pages": [
"pages/todos/todos",
"pages/add-todo/add-todo"
],
"window": {
"defaultTitle": "Todo App"
}
}
app.acss 是小程序的公共样式,可以在页面的 axml 中直接使用 app.acss 定义的选择器,影响所有页面的样式。
page {
flex: 1;
display: flex;
}
上例中的 page 为框架支持的特殊选择器,会匹配框架提供的页面根节点容器。
小程序页面
在这个示例中,我们有两个页面,Todo List 页面和 Add Todo 页面,他们都在 pages 目录下。小程序的所有页面路径必须写在 app.json 中,路径从项目根目录开始且不能包括后缀名,pages 的第一个页面就是小程序的首页。
每一个 小程序页面 是由同路径下的四种类型文件组成,即.js 后缀的逻辑脚本文件,.json 后缀的配置文件, .acss 后缀的样式文件, .axml 后缀的模版文件。
Todo List 页面
todos.axml 为页面结构模版文件:
<view class="page-todos">
<view class="user">
<image class="avatar" src="{{user.avatar}}" background-size="cover"></image>
<view class="nickname">{{user.nickName}}'s Todo List</view>
</view>
<view class="todo-items">
<checkbox-group class="todo-items-group" onChange="onTodoChanged">
<label class="todo-item" a:for="{{todos}}">
<checkbox value="{{item.text}}" checked="{{item.completed}}" />
<text class="{{item.completed ? 'checked' : ''}}">{{item.text}}</text>
</label>
</checkbox-group>
<view class="todo-item">
<button onTap="addTodo">Add Todo</button>
</view>
</view>
</view>
使用 <view/>
,<image/>
,<text/>
,<button/>
,<label/>
,<checkbox/>
,来搭建页面结构以及 a:for 绑定 todos 数据,并将 todos 数据循环展开节点。绑定数据可以查阅视图层文档,绑定事件可以查阅事件处理文档.
todos.js 是页面的逻辑脚本文件:
// 获取全局 app 实例
const app = getApp();
Page({
data: {},
onLoad() {
// 获取用户信息并渲染
app.getUserInfo().then(
user => this.setData({
user,
}),
);
},
// 监听生命周期
onShow() {
// 渲染全局数据到当前页面
this.setData({ todos: app.todos });
},
// 事件处理函数
onTodoChanged(e) {
// 修改全局数据并重新渲染
const checkedTodos = e.detail.value;
app.setTodos(app.todos.map(todo => ({
...todo,
completed: checkedTodos.indexOf(todo.text) > -1,
})));
this.setData({ todos: app.todos });
},
addTodo() {
// 调用页面跳转 API 实现页面跳转
my.navigateTo({ url: '../add-todo/add-todo' });
},
});
在这个文件中可以:
- 监听并处理页面的生命周期函数 (onHide, onShow, onLoad, onUnload, onReady)。
- 获取小程序实例以及其他页面实例 (getApp, getCurrentPages)。
- 声明并处理数据 (data)。
- 响应页面交互事件,调用 API 等。
- 这里需要注意的是app.todos是来自app.js中全局的变量定义
todos.acss 是页面的样式文件:
.page-todos {
flex: 1;
display: flex;
flex-direction: column;
}
.user {
display: flex;
padding: 30px 30px 0 30px;
}
.avatar {
width: 128rpx;
height: 128rpx;
margin-right: 40rpx;
border-radius: 50%;
}
.nickname {
display: flex;
flex-direction: column;
justify-content: center;
font-size: 40rpx;
}
.todo-items {
padding: 80rpx;
}
.todo-items-group {
display: flex;
flex-direction: column;
}
.checked {
color: #d9d9d9;
text-decoration: line-through;
}
.todo-item {
margin-bottom: 15px;
}
acss 文件不是必须的。语法可以查阅 样式 文档。当有页面样式表时,页面的样式表中的样式规则会层叠覆盖 app.acss 中的样式规则。如果不指定页面的样式表,也可以在页面的结构文件中直接使用 app.acss 中指定的样式规则。
todos.json 是页面的配置文件,这里是一个空文件。
配置文件不是必须的。当有页面的配置文件时,配置项在该页面会覆盖 app.json 的 window 中相同的配置项。如果没有指定的页面配置文件,则在该页面直接使用 app.json 中的默认配置。因此 index 页面的标题为 app.json 中指定的 Todo App
。
Add Todo 页面
add-todo.axml 为页面结构模版文件:
<view class="page-add-todo">
<view class="add-todo">
<input
class="add-todo-input"
placeholder="What needs to be done?"
onBlur="onBlur"
value="{{inputValue}}"
/>
</view>
<view class="todo-footer">
<add-button text="Add Todo" onClickMe="add" ></add-button>
</view>
</view>
在这个页面中有两个核心知识点:
const app = getApp();
Page({
data: {
inputValue: '',
},
onBlur(e) {
this.setData({
inputValue: e.detail.value,
});
},
add() {
app.todos = app.todos.concat([
{
text: this.data.inputValue,
compeleted: false,
},
]);
my.navigateBack();
},
});
add-todo.acss 同 todo list 页面用法基本一致。
add-todo.json 由于引用了自定义组件,所以需要在json中进行声明,否则会报错:
"usingComponents": {
"add-button": "/components/add-button/add-button"
}
接下来我们看看如何将小程序发布上线。