Learn More About Todo App Demo

Overview

We will introduce the development of a Mini Program in detail through the Todo App Demo.

Global Configuration

The app.js is the entry point to a Mini Program, you can configure the lifecycle of a Mini Program, declare global variables, and perform app initialization in this file. The following code snippet shows an example of calling APIs for storage and getting user information. For more APIs, see API document.

copy
// Call the storage API to get the stored data
const todos = my.getStorageSync({key:'todos'}).data || [
    { text: 'Learning Javascript', completed: true },
    { text: 'Learning ES2016', completed: true },
    { text: 'Learning Mini Program ', completed: false },
  ];

App({
  // Declare global data
  todos,

  userInfo: null,

  // Declare global method
  setTodos(todos) {
    this.todos = todos;
    // Call storage API to store data
    my.setStorageSync({key:'todos', data:todos});
  },

  getUserInfo() {
    return new Promise((resolve, reject) => {
      if (this.userInfo) resolve(this.userInfo);
      // Call user authorization API to get user info
      my.getAuthCode({
        success: (authcode) => {
          console.info(authcode);

          my.getAuthUserInfo({
            scopes: ['auth_user'],
            success: (res) => {
              this.userInfo = res;
              resolve(this.userInfo);
            },
            fail: () => { 
              reject({});
            },
          });
        },
        fail: () => { 
          reject({});
        },
      });
    });
  },
});

The app.json is the global configuration file of the Mini Program, where it is possible to configure the general navigation bar title, window background color and other configurations of the Mini Program. For more configurations, see global configuration documentation.

copy
{
  "pages": [
    "pages/todos/todos",    
    "pages/add-todo/add-todo"
  ],
  "window": {
    "defaultTitle": "Todo App"
  }
}

The app.acss is the global style of a Mini Program. The selectors defined in the app.acss can be applied to all pages in the Mini Program project.

copy
page {
  flex: 1;
  display: flex;
}

The page selector is a special selector supported by the framework, which works with the page root node container available in the framework.

Mini Program Page

We have two pages in this demo project: Todo List page and Add Todo page, both reside in the pages directory. All page paths of the Mini Program must be declared in the app.json, and a page path starts from the project root directory and should omit the filename extension. The very first path declared app.json is the home page of a Mini Program.

Each Mini Program page consists of four types of files under the same directory:

  • JS logic script file with the .js extension
  • Configuration file with the .json extension
  • Style file with the .acss extension
  • UI Layout file with the .axml extension.

Todo List Page

The todos.axml is the structure template file of the page:

copy
<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>

This UI layout have built-in UI components such as <view/>,<image/>,<text/>,<button/>,<label/> and <checkbox/> to build up the page structure, and we use a:for attribute to perform list rendering which iterates the todos list and render a label for each todo data respectively.

For binding data, see Data binding document. For binding event, see event handling document.

The todos.js is the logic script file of the page:

copy
// Get global app instance
const app = getApp();

Page({
  data: {},
  onLoad() {
    // Get user information and render
    app.getUserInfo().then(
      user => this.setData({
        user,
      }),
    );
  },
  // Listen to lifecycle
  onShow() {
    // Render global data to current page
    this.setData({ todos: app.todos });
  },
  // Event handler
  onTodoChanged(e) {
    // Modify global data and re-render
    const checkedTodos = e.detail.value;
    app.setTodos(app.todos.map(todo => ({
      ...todo,
      completed: checkedTodos.indexOf(todo.text) > -1,
    })));
    this.setData({ todos: app.todos });
  },
  addTodo() {
    // Call page jump API for page jump
    my.navigateTo({ url: '../add-todo/add-todo' });
  },
});

In this file, we have:

  • Listen to and process the lifecycle function of the page (onHide, onShow, onLoad, onUnload, onReady).
  • Get Mini Program app instance and other page instances (getApp, getCurrentPages).
  • Declare and process data
  • Respond to page interaction events, call APIs, etc.
  • Attention here: the app.todos object is the global variable defined in app.js.

The todos.acss is the style file of the page:

copy
.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;
}

The acss styling file is not mandatory. See Style document for acss file syntax. When a page has the style sheet, the style rule in the page style sheet overrides the style rules in the app.acss. if the style sheet is not specified for the page, it is also possible to directly use the style rules specified in app.acss.

The todos.json is the configuration file of the page. Here it is an empty file.

The configuration file is not mandatory. When a page has the configuration file, the configuration item overwrites the same configuration items in the window of app.json. If no page configuration file is specified, the page directly uses the default configuration in app.json. Therefore, the index page title is the Todo App specified for app.json.

Add Todo Page

The add-todo.axml is the structure template file of the page:

copy
<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>

There are two core functions in the page:

  1. Use the <input/> component to accept user input.
  1. The <add-button> is a custom component. We can wrap the whole codes of some function into a custom component for easy reuse elsewhere.

add-todo.js page logic code:

copy
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 is consistent with todos.acss usage and will not be described again.

Since the add-todo.json refers to a custom component, it should be declared in json, otherwise error will be reported:

copy
"usingComponents": {
    "add-button": "/components/add-button/add-button"
}

We will learn how to publish a Mini Program in the next tutorial.