小程序系列——缠
这一篇文章将是小程序系列的第三篇文章,我们会更加的篇实践。上一篇文章最后介绍的知识点是模板,这个知识点很重要,因为它对于功能模块的封装,进行模块化开发,启着关键的作用。所以,这一篇文章第一个知识点还是模板使用,我们使用模板,实践封装一个小程序 toast。
模板实践开发
我们要利用模板,开发一个小程序的 toast。因为,原生 api 提供的 toast 对于类型、字数等方面都有很大的局限性。所以,我们要开发一个自己的。开发预期:1. 可以较灵活的配置(显示内容与延时设置)2. 封装合理,调用灵活,尽可能的不要污染其它业务逻辑
我们先来开一下实现效果是什么样的(上图):
很简洁的一个具有动画效果的 toast 实现。我们来看看代码目录:
核心文件就是 templates/toast/
目录下的三个文件。我们看看应用页面应用这个 toast 是如何做到的呢?
// app.js 文件
import { WeToast } from './templates/toast/toast.js';
App({
WeToast
})
在 app.js
文件中全局加载 WeToast,我们自定 toast 的 js 文件。
// app.wxss 文件
@import './templates/toast/toast.wxss'
在 app.wxss
文件中引入 toast 的样式文件。ok,最后一步,在首页中应用:
// index.wxml 文件
<import src="../../templates/toast/toast.wxml" />
<button bindtap="showToast">show me</button>
<template is="toast" data="{{...wetoast}}"/>
在要使用的页面引入 toast 的模板文件,看 index.js
中的调用:
const app = getApp();
Page({
onLoad() {
// 初始化 toast
new app.WeToast();
},
showToast() {
this.wetoast.toast({
content: '嘻嘻哈哈,我是toast',
duration: 1500
})
}
});
在 onLoad()
函数中初始化 WeToast 实例,然后就可以在想调用的地方通过 this (即 Page 对象)调用 wetoast 上的 toast()
函数了。这样,就可以调起我们的 toast 的了。可以看到,整个 toast
的逻辑封装比较合理,没有散落很多逻辑在业务中。我们只需要在用到的页面调用模板并注册实例就可以了,使用很方便。下面我们主要看一下 toast.js
的实现:
/**
* @file 小程序 toast 增强版
* @author tang
*/
function WeToast () {
let pages = getCurrentPages();
let curPage = pages[pages.length - 1];
WeToast.cPage = curPage;
WeToast.cTimeout = null;
curPage.wetoast = WeToast;
return this;
}
WeToast.toast = function (data) {
if (!data) {
this.hide();
} else {
this.show(data);
}
};
WeToast.show = function (data) {
let page = this.cPage;
clearTimeout(this.cTimeout);
page.setData({
'wetoast.show': true
});
let animation = wx.createAnimation();
animation.opacity(1).step();
data.toastAnimationData = animation.export();
page.setData({
wetoast: data
});
page.setData({
wetoast: data
});
this.cTimeout = setTimeout(() => {
this.toast();
}, (data.duration || 800));
};
WeToast.hide = function () {
let page = this.cPage;
clearTimeout(this.cTimeout);
let animation = wx.createAnimation();
animation.opacity(0).step();
page.setData({
'wetoast.toastAnimationData': animation.export()
}, function () {
page.setData({
'wetoast.show': false
});
page.setData({
wetoast: {}
});
});
};
module.exports = {
WeToast
}
可以把函数 WeToast()
看作是构造函数,执行它,它会在当前的页面对象上绑定一个 wetoast 对象,该对象的引用其实就是 WeToast()
函数本身。然后在 WeToast()
函数上继续添加 toast 所需的逻辑函数,完成整个功能。这里需要注意一个地方,继续添加的逻辑函数,例如:toast、show、hide 没有必要绑在在 WeToast 上的 prototype 对象上。因为在小程序的环境(目前的环境:IDE 版本号1.02.1801081)中,prototype 其实也是对象的一个普通属性,环境不会根据原型链的规则自动到 prototype 属性上查找引用函数,不知道是版本问题还是小程序环境设计就是如此。OK,详细的 DEMO 我放在了 github 上。项目地址是:https://github.com/tangxiaolang101/WeCharMiniDemo欢迎 star 加下载。
授权问题
小程序的部分接口调用前需要用户授权。例如, wx.getUserInfo()
获取用户信息的接口。所以,在调用该接口之前,我们可以利用 wx.authroize()
接口向用户发起授权请求。
提前向用户发起授权请求。调用后会立刻弹窗询问用户是否同意授权小程序使用某项功能或获取用户的某些数据,但不会实际调用对应接口。如果用户之前已经同意授权,则不会出现弹窗,直接返回成功。
示例:
// 可以通过 wx.getSetting 先查询一下用户是否授权了 "scope.userInfo" 这个 scope
wx.getSetting({
success(res) {
if (!res.authSetting['scope.userInfo']) {
wx.authorize({
scope: 'scope.userInfo',
success() {
....
}
})
}
}
})
调用用户授权后,就是两种情况,一种同意,一种拒绝。同意就是正常流程,但是如果是拒绝的话,一般都要拒绝用户继续使用小程序了。所以,我们需要调用 wx.openSetting
api 引导如何到授权设置页面,同意授权。这段逻辑一般都会涉及几个异步的情况,所以,我们最好的做法就是将这几个流程封装为 promise 的模式,以后进行调用。采用链式的方式实现这个调用逻辑,这样代码结构会很清晰。封装 promise 有多种,例如我们可以这样:
wxOpenSetting () {
return new Promise(resolve, reject) {
wx.openSetting({
success: res => resolve(res),
fail: res => reject(res)
});
}
}
这只是一个简单的例子,实际开发中,我们可能会进一步设计,利用工厂设计模式,通过不同的 api name 产生不同的 promise 化的函数。
结束语——摘抄一段话
小程序带来的不是流量红利,是心智红利。如同张小龙所言,我们要理解小程序,就要先理解 PC 时代的官网。官网对于 PC 时代的企业而言,没有不行。因为客户一般会去搜索你的官网,看你是不是一家靠谱的企业,但是一般官网不会是你全部收入的来源。在我看来,小程序带来的不是流量红利,是心智红利。你能不能在用户心目中,实现让我们微信一下这样的产品即类品?我大胆的预测一下,未来用户在需要某类服务的时候,会不会在微信上第一时间搜你的小程序很重要,因为,这可能是你拉开与对手差距的关键。