继续前面话题,mpvue提供了vue的语法编译为小程序的能力,但语法上局限实在有点多。

当然,其根因还是小程序官方的限制,以致于我们vue中常用vuex、router都支持有限,截止发文时间,mpvue对vuex全局store的支持也有所提升,目前可以说基本满足需求,这里不再赘述。

使用上,vuex和以往类似,不同的是,小程序以多页形式渲染,故每个页面都需要创建vue实例并引入相应的store模块,入口配置大概如下:

import Vue from 'vue';
import Vuex from 'vuex';
import store from './store';
import App from './index';

Vue.use(Vuex);

const app = new Vue({
    ...App,
    store
});

app.$mount();

之后你就可以正常使用vuex的特性了,至于是否采用小程序的本地存储之类的,可以考虑使用vuex的钩子进行。

至于router,目前mpvue暂不支持,我在尝试后发现,插件注入什么的都没问题,唯独在组件内调用this.$router.push/replace时,得到的结果不很理想。

试想,axios可以写适配器,vue-router是不是也可以呢?当然,比如官方实现了hash、history和abstract三种模式,理论上我们可以加一种小程序的模式,但是官方似乎并没预留合适参数给我们用,不过导航守护的钩子,我们倒是可以稍加利用,增加beforeEach,发现每次调用push/replace,得到的结果是from为目标页面,to一直为“/”,这倒不影响我们使用,小程序端尝试编写钩子,调用wx.navigateTo({ url: from.path })或者……

等等,这里遗漏一个问题,导航守护并不知道是push或是replace,似乎达不到效果?既然这样,我们何不抛开庞大的vue-router,直接自己编写vue插件,分别注入$route、$router?

自己实现起来,总是那么得心应手!

import Vue from 'vue';
import App from './index';

Object.defineProperty(Vue.prototype, '$route', {
    get() {
        return {
            path: '...'
        }
    }
})

Object.defineProperty(Vue.prototype, '$router', {
    get() {
        return {
            push() {
            },
            replace() {
            },
            go() {
            },
            back() {
            }
        }
    }
})

const app = new Vue({
    ...App
});

app.$mount();

问题迎刃而解!

到这里有人可能会问,为什么不直接采用小程序的api做跳转呢?谁让我们是要做一份代码多端编译呢!

2018-04-04更新

经小伙伴进一步探索,发现前面所述问题

发现每次调用push/replace,得到的结果是from为目标页面,to一直为“/”

是我自己写demo时候漏写了next,且from、to参数顺序写错,既然这个问题不存在,那么,我们重新VueRouter原型方法的replace、back以及go,在调用前增加额外识别参数,比如:

const originReplace = VueRouter.prototype.replace;
const originPush = VueRouter.prototype.push;
const originGo = VueRouter.prototype.go;
const originBack = VueRouter.prototype.back;

VueRouter.prototype.replace = function replace(...args) {
    // TODO
    originReplace.apply(this, args)
}
VueRouter.prototype.push = function push(...args) {
    // TODO
    originPush.apply(this, args)
}
VueRouter.prototype.go = function go(...args) {
    // TODO
    originGo.apply(this, args)
}
VueRouter.prototype.back = function back(...args) {
    // TODO
    originBack.apply(this, args)
}