MENU

小程序如何实现AOP

August 30, 2019 • 微信小程序

今天咱们来聊聊小程序如何实现AOP

  相信大家在日常开发小程序项目的时候需要用到授权登录,比如商城类型、论坛圈子类小程序,这类小程序往往在开发中有些特定的页面功能需要获取用户的信息,如头像、手机号码、位置等等信息。比如用户点击购物车、个人中心这种页面往往需要获取信息,一般的几种方法相信大家都用过。以下三种种是我以前常用的。

1.多页面内写逻辑代码

  在app.js的onLaunch中写入判断代码,这种是最省事的方法,现在不能用了呢?
给你们看个东西:

image
查看详情

惊不惊喜?意不意外?马哥对开发者就是这么“友好”。

2.多页面内写逻辑代码

  在需要获取用户信息的页面编写判断语句,判断用户是否授权过,如果没有授权,则跳转到首页页面或者显示Modal框,然后用户授权后将授权信息存入缓存或者提交到服务器。
  但是这种太过于繁琐,需要在每个用到的页面都要写相应的代码,而且每次跳转授权页面也会闪一下,及其难受。

1.封装request,请求时判断

  这种方法是针对有些api接口调用时需要附带用户信息,比如用户注册这种接口就需要用到用户的头像等等信息,将判断代码写到封装的request函数中,以微信小程序举例:

/**
 * request封装
 */
module.exports = (o) => {
    var url = o.url, //请求url
        data = o.data || undefined, //请求参数
        success = o.success || function(){}, //回调函数
        complete = o.complete || function(){}, //回调函数
        method = o.method || 'GET', //请求方式
        header = o.header || 'application/json', //请求头
        getUserInfo = o.getUserInfo || 0 //是否获取用户数据 1为获取
    //判断是否要求获取用户数据并且判断是否已经存储过用户信息
    //如果getUserInfo=1并且没有存储过用户信息 则跳转到授权页面
    if (getUserInfo && !wx.getStorageInfoSync('userInfo')) {
        console.log('未授权,跳转授权页面');
        wx.navigateTo({
            url: '/pages/user/getUserInfo'//跳转到授权页面
        })

    }
    //请求数据
    wx.request({
        url,
        method,
        data,
        header,
        success,
        fail(e) {
            console.log('数据请求失败');
            // Code
        },
        complete
    })
}
//调用方法
import request from "../../utils/request.js"//引入request

onLoad: function() {
    request({
        url: 'https://www.baidu.com',
        getUserInfo: 1,
        success(r) {
            console.log(r);
        }
    })
}

  这种解决了方法二的多个页面反复写判断的问题,但是新的问题就是如果检测到未授权跳转授权页面授权完成之后,用户还需要重新点击,重新触发事件提交请求

扯这些跟小程序实现AOP有什么关系???

没有太大关系,咳咳 回归正题....

image

先来了解下什么是AOP

  AOP又叫面向切面编程,其中“通知”是切面的具体实现,分为before(前置通知)、after(后置通知)、around(环绕通知),用过spring的同学肯定对它非常熟悉,而在js中,AOP是一个被严重忽视的技术点。但是利用aop可以有效的改善js代码逻辑,比如前端框架dojo和yui3中AOP则被提升至自定义事件的一种内在机制,在源码中随处可见。得益于这种抽象使得dojo的自定义事件异常强大和灵活。dojo中aop的实现在dojo/aspect模块中,主要有三个方法:before、after、around,先来说说before这个“切面”函数. 顾名思义,就是让一个函数在另一个函数之前或者之后执行,巧妙的是,before或者after都可以和当前的函数公用this和arguments, 这样一来供我们发挥的地方就多着了。想深入了解的请自行Google或百度

image

小程序使用AOP有什么用呢?

本人知道的有以下几点:

  • 劫持页面(想不到其他形容词了)
  • 分离表单请求和校验
  • 给request请求动态添加参数

今天主要说说 如何在onLoad之前动态设置data数据

先创建一个page.js 用来存放AOP的代码,我的page.js放在utils/pages.js

var that //当前页面this
function before(e, n, o) {
    var t = e[n];//得到要操作的函数 
    e[n] = function() {
        that = getCurrentPages()[0]
        //apply方法能劫持另外一个对象的方法,继承另外一个对象的属性.
        o(arguments[0]), t.apply(that, arguments);
    }
    //返回对象
    return e;
}

function after(e, n, o) {
    var t = e[n];
    e[n] = function() {
        t.apply(that, arguments), o(arguments[0]);
    }
    return e;
}

module.exports = function(e) {
    // 检查传入的Object中的onLoad、onShow、onReady是否为函数(也可以不检查,因为只要是你写的就一定是函数 哈哈)
    "function" != typeof e.onLoad && (e.onLoad = function(e) {})
    "function" != typeof e.onShow && (e.onShow = function(e) {})
    "function" != typeof e.onReady && (e.onReady = function(e) {})
    //在当前页面渲染之前劫持onLoad,进行数据获取写入
    e = before(e, "onLoad", (e)=>{
        
    })
    
    //执行页面渲染
    Page(e)
};

在需要劫持的页面写法(必须这样写)

//当前页面路径/pages/index
import page from "../../utils/page.js"

page({
    data: { },//同微信小程序Page中的data
    onLoad: function() { },//同微信小程序Page中的onLoad
})

在页面渲染之前在data中加入数据

var that //当前页面this
function before(e, n, o) {
    var t = e[n];//得到要操作的函数 
    e[n] = function() {
        that = getCurrentPages()[0]
        //apply方法能劫持另外一个对象的方法,继承另外一个对象的属性.
        o(arguments[0]), t.apply(that, arguments);
    }
    //返回对象
    return e;
}

function after(e, n, o) {
    var t = e[n];
    e[n] = function() {
        t.apply(that, arguments), o(arguments[0]);
    }
    return e;
}

module.exports = function(e) {
    // 检查传入的Object中的onLoad、onShow、onReady是否为函数(也可以不检查,因为只要是你写的就一定是函数 哈哈)
    "function" != typeof e.onLoad && (e.onLoad = function(e) {})
    "function" != typeof e.onShow && (e.onShow = function(e) {})
    "function" != typeof e.onReady && (e.onReady = function(e) {})
    //在当前页面渲染之前劫持onLoad,进行数据获取写入
    e = before(e, "onLoad", (e)=>{
        that.setData({//直接通过setData来设置当前data
            name:'张三'
        })
    })
    //直接赋值也可以
    e.data.age = 23;
    //执行页面渲染
    Page(e)
};

image

image

我知道你在想那样,也知道你在那样想,是不是发现了新大陆了,别急看下如何给页面加入函数。比如小程序模板消息通知需要获取fromID,那就得写一个方法来存储fromID并且提交给服务器,那这样不就得每个页面写一遍?用这种方法就就可以很简单搞定了(虽说与AOP没什么关系)

var that //当前页面this
function before(e, n, o) {
    var t = e[n];//得到要操作的函数 
    e[n] = function() {
        that = getCurrentPages()[0]
        //apply方法能劫持另外一个对象的方法,继承另外一个对象的属性.
        o(arguments[0]), t.apply(that, arguments);
    }
    //返回对象
    return e;
}

function after(e, n, o) {
    var t = e[n];
    e[n] = function() {
        t.apply(that, arguments), o(arguments[0]);
    }
    return e;
}

module.exports = function(e) {
    // 检查传入的Object中的onLoad、onShow、onReady是否为函数(也可以不检查,因为只要是你写的就一定是函数 哈哈)
    "function" != typeof e.onLoad && (e.onLoad = function(e) {})
    "function" != typeof e.onShow && (e.onShow = function(e) {})
    "function" != typeof e.onReady && (e.onReady = function(e) {})
    //在当前页面渲染之前劫持onLoad,进行数据获取写入
    e = before(e, "onLoad", (e)=>{
        
    })
    e.submit = (e)=>{
        console.log('获取到:',e.detail.formId);
    }
    //也可以将方法写到公共js文件中 这样也可以
    e.submit = submitFromId
    //执行页面渲染
    Page(e)
};

image

关于AOP在页面函数之前跟之后执行代码这个就不说了。我也是个小白,很多东西是靠自己理解的,可能说的有些地方是错的,大家还请包含,请在评论区指出来,谢谢!

下一篇我们来说说如何通过今天学习到的知识实现动态设置从服务器获取的底部tabbar

个人博客  LoveEmpathy