小程序从入门到实战系列(一)

3,638 阅读9分钟

前言

随着小程序日渐火热,扇贝在近一年投入了大量的精力来做小程序的相关业务,小程序相比于 APP 更容易传播,因为小程序是基于强大的社交平台微信的基础上的,这使其具有极强的传播能力,甚至可以在微信朋友圈产生病毒性传播,一夜爆红。

在看到头脑王者小程序几乎一夜爆红之后,其日活最好时期达到了百万级别,我们开始着手开发了单词大师,之前没有任何小程序的开发经验,几乎是零基础,然后就开始了小程序的采坑之路。在单词大师的功能迭代完成后,我们又开发了另一个小程序扇贝每日英语,接下来我会主要跟大家分享在这两个小程序的开发过程中遇到一些问题以及解决的办法。因为准备写一个小的系列文章,所以会从小程序的入门进行讲解,后面逐步深入,最后会有一个开源个人项目的实战讲解,敬请期待。

准备工作

在此,我们默认读者具有一定的前端开发经验,掌握 css、html、javascript、以及熟悉流行的 MVVM 框架,熟悉打包构建工具。

微信官方提供了小程序的开发文档,你可以点击这里前往查看小程序的官方文档,首先,你需要按照指引,创建一个微信小程序账号,然后登陆公众平台可以看到你的 appId,然后下载微信开发者工具,就可以预览一个微信官方提供的小 demo 了,然后需要用一个下午或者更多的时间去看一遍小程序文档中的框架、组件、API。

至此,你应该可以通过读文档完成以下任务:

  1. 可以读懂 demo 的代码了。
  2. 熟悉小程序的框架、配置、页面的生命周期事件、小程序数据绑定机制(逻辑层与视图层的交互、setDate)。
  3. 熟悉常用组件的使用:view、image、scroll-view、swiper、button、form、textarea、navigater、canvas 等等。
  4. 熟悉所有的 api,特别是界面方面的 api 要先比较熟悉。

如果你还没有读完一遍微信的官方文档,我建议你先别往下看了,找个时间熟悉了小程序的官方文档中的框架、组件、api 后,再继续往下浏览吧。

如果看完了文档,对于 demo 的代码还不是很懂,那我简单带你看一下 demo 的代码吧。

demo 源码分析

首先看代码的结构:

├── app.js
├── app.json
├── app.wxss
├── pages
│   ├── index
│   │   ├── index.js
│   │   ├── index.wxml
│   │   └── index.wxss
│   └── logs
│       ├── logs.js
│       ├── logs.json
│       ├── logs.wxml
│       └── logs.wxss
├── project.config.json
└── utils
    └── util.js

这个 demo 的代码结果很简单清晰,我们主要看三个部分:

项目配置文件 project.config.json

这个文件记录了你的小程序项目在在开发者工具上的一些配置信息,具体配置参考配置,比如:项目名称,小程序 appid,基础库版本,开发者工具的项目设置,如果你使用了小程序的云服务,就需要在这里面配置小程序的 miniprogramRoot 和 qcloudRoot,如果项目有一些自定义的编译条件,这边编译信息也会被记录到condition:miniprogram 下面。

小程序的全局 app

app 就是描述小程序整体的一个容器,它会先于页面被初始化,它主要由三个文件构成:app.js、app.json、app.wxss。demo 代码里面 app.js 使用到了 app 生命周期函数 onLaunch,和全局数据容器 globalData。小程序初始化的时候会触发 app 的 onLaunch 事件,这个方法也会先于 page 的 onLoad 事件被执行。因此,我们可以在 onLaunch 方法里面执行一些小程序初始化时需要完成的事情,比如 demo 里面做的事情:获取用户信息。

因为每个 page 有属于自己独立的 data,如果我们需要维护一些多个页面共享的数据,这时候就可以使用 globalData,当然你也可以使用一些数据管理的库,比如 redux,vuex.最新的小程序原生开发已经支持 npm 了。这使得引入依赖库变得很方便了。

app.json 文件用来对微信小程序进行全局配置,决定页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 等,具体查看配置

小程序页面 page

小程序的每个页面最多由四个文件构成:page.js、page.wxml、page.json、page.wxss。

js 文件用来写页面逻辑,wxml 文件类似 html,是小程序的模板文件,json 文件是页面的配置文件,wxss 是页面的样式文件,类似 css 文件。

//index.js
//获取应用实例
const app = getApp();

Page({
    data: {
        motto: 'Hello World',
        userInfo: {},
        hasUserInfo: false,
        canIUse: wx.canIUse('button.open-type.getUserInfo'),
    },
    //事件处理函数
    bindViewTap: function() {
        wx.navigateTo({
            url: '../logs/logs',
        });
    },
    onLoad: function() {
        if (app.globalData.userInfo) {
            this.setData({
                userInfo: app.globalData.userInfo,
                hasUserInfo: true,
            });
        } else if (this.data.canIUse) {
            // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
            // 所以此处加入 callback 以防止这种情况
            app.userInfoReadyCallback = res => {
                this.setData({
                    userInfo: res.userInfo,
                    hasUserInfo: true,
                });
            };
        } else {
            // 在没有 open-type=getUserInfo 版本的兼容处理
            wx.getUserInfo({
                success: res => {
                    app.globalData.userInfo = res.userInfo;
                    this.setData({
                        userInfo: res.userInfo,
                        hasUserInfo: true,
                    });
                },
            });
        }
    },
    getUserInfo: function(e) {
        console.log(e);
        app.globalData.userInfo = e.detail.userInfo;
        this.setData({
            userInfo: e.detail.userInfo,
            hasUserInfo: true,
        });
    },
});

我们分析一下 index.js 的代码,通过 getAPP(),获取全局 app 对象,从而可以调用 app 里面的方法,使用 globalData 里的全局数据。data 里放着页面的内部数据,通过 setData()去改变数据,从而改变视图。这与 MVVM 框架的设计是一致的。与视图无关的页面数据不要放在 data 里面,因为逻辑层和渲染层传输数据(经 JSON.stringify 序列化为字符串)的是比较占用进程资源的。onLoad 是页面的初始化生命周期函数,我们在这个函数里初始化页面数据。另外 page 里剩下的是页面的点击事件和自定义函数。

再来看看 index.js 中使用到的 api,首先wx.canIUse用来判断小程序的 API,回调,参数,组件等是否在当前版本可用。因为小程序的基础库随着微信客户端版本升级,如果有些用户没有升级微信客户端,那么一些新的 api、组件特性就无法使用,这时候我们可以使用 canIUse 做兼容处理。wx.getUserInfo,这个接口用户获取用户的信息,如果用户未授权过,调用该接口将直接进入 fail 回调,更详细的入参、返回值、使用场景请查看文档。wx.navigateTo保留当前页面,跳转到应用内的某个页面,使用 wx.navigateBack 可以返回到原页面。这儿涉及到小程序的页面路由,小程序的页面间有哪几种路由跳转方式,此时的页面栈是什么样的,以及分别触发了两个页面的那些生命周期,具体参加路由文档

demo 中 index 页面并没有配置 index.json 文件,页面的配置只能设置 app.json 中部分 window 配置项的内容,页面中配置项会覆盖 app.json 的 window 中相同的配置项。具体参见配置

小程序框架选择

由于小程序的原生开发存在太多的不方便:不支持 npm(现已经支持),蹩脚的模板语法、文件过于分散、request 并发问题、api 非 promise、缺少配套的状态管理库。 我们最先接触的是wepy 框架,这个框架解决了大部分原生开发存在的问题,采用类 Vue.js 的语法,减小开发小程序的语法学习成本,支持组件化,支持 npm,支持 promise,支持一些通用的 css、js 编译器和图片压缩插件。所以,我们的单词大师小程序就使用了 wepy 框架。

但是很快美团的mpvue 框架横空出世,它给我们带来了什么呢?

  • 彻底的组件化开发能力:提高代码复用性
  • 完整的 Vue.js 开发体验
  • 方便的 Vuex 数据管理方案:方便构建复杂应用
  • 快捷的 webpack 构建机制:自定义构建策略、开发阶段 hotReload
  • 支持使用 npm 外部依赖
  • 使用 Vue.js 命令行工具 vue-cli 快速初始化项目
  • H5 代码转换编译成小程序目标代码的能力

是不是很惊喜,是不是很震撼?这完全就是 Vue 开发 web 应用的那一套啊,对于熟悉 Vue 的开发者来说基本就是零学习成本开发微信小程序。mpvue 相比于 wepy 的优势立马显现出来,首先,mpvue 拥有完整的 vue 语法规范(虽然小部分语法不能用),配套的数据管理 Vuex,集成 webpack 打包构建工具(wepy 使用自己的一个打包构建工具,显然没有 webpack 强大),还有方便 h5 和小程序复用项目代码。

最后在对比一下两个框架:

mpvue wepy
语法 vuejs 类 vuejs
标签 html+小程序 小程序
组件化 Vue 规范 自定义组件规范
自动构建 webpack 框架内置
学习成本 vue+小程序 vue+wepy+小程序
数据管理 vuex redux

wepy 项目创建和使用

安装最新的 wepy-cli,并使用标准的模板初始化项目:

npm install -g wepy-cli
wepy init standard myproject

初始化项目会需要你在终端输入项目名称,小程序 appid,描述,是否启用 redux,是否使用 eslint.

使用wepy list可以列出可以选择的其他初始化项目模板。

切换至项目目录

cd myproject

安装依赖

npm install

开启实时编译

npm run dev

wepy 项目的目录结构

.
├── package.json
├── project.config.json
├── src
│   ├── app.wpy
│   ├── components
│   │   ├── counter.wpy
│   │   ├── group.wpy
│   │   ├── groupitem.wpy
│   │   ├── list.wpy
│   │   ├── panel.wpy
│   │   └── wepy-list.wpy
│   ├── index.template.html
│   ├── mixins
│   │   └── test.js
│   ├── pages
│   │   └── index.wpy
│   └── store
│       ├── actions
│       │   ├── counter.js
│       │   └── index.js
│       ├── index.js
│       ├── reducers
│       │   ├── counter.js
│       │   └── index.js
│       └── types
│           ├── counter.js
│           └── index.js
└── wepy.config.js

为了方便我们开发,我们还要在模板的基础上改造一下。因为产品开发至少会有一个开发环境,一个生产环境,所以,我们可以新建一个 config 目录,添加两个环境的配置文件。

首先 package.json 中指定 NODE_ENV 环境变量值:

 "scripts": {
        "start": "cross-env NODE_ENV=local npm run dev",
        "preview": "cross-env NODE_ENV=preview wepy build --no-cache",
        "dev": "wepy build --watch",
        "build": "cross-env NODE_ENV=production wepy build --no-cache",
        "clean": "find ./dist -maxdepth 1 -not -name 'project.config.json' -not -name 'dist' | xargs rm -rf",
        "test": "echo \"Error: no test specified\" && exit 1"
    },

然后在 wepy.config.js 中配置 resolve:alias:

const env = process.env.NODE_ENV || 'production';
//
module.exports = {
 resolve: {
        alias: {
            ... //other alias
            '@config': path.join(__dirname, `src/config/config.${env}.js`),
        },
        modules: ['node_modules'],
    },
}

这样你 import * from '@config',就会根据当前的环境加载不同的 config 了。

详细指引参考wepy 官方文档;

mpvue 框架使用

直接查看官方文档吧。

小结

框架选择好了以后,我们就开始准备开发自己的小程序吧。

下篇我们一起学习如何利用腾讯云+mpvue 开发一个自己的小程序---拼词乐斗。线上预览: