概述
这里会通过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>
在这个页面中有两个核心知识点:
- 使用<input/> 组件来接受用户输入。
- <add-button>是一个自定义组件,我们可以将一些功能完整的代码封装为自定义组件,便于其他地方复用。
add-todo.js 页面逻辑代码:
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" }