uni-app项目踩坑经历

3,162 阅读3分钟

uni-app微信公众号H5分享踩坑

最近项目中使用uni-app写了一款H5的微信公众号开发,其中有一个活动详情的分享功能的踩坑经历,解决起来也是遇到了一些坑,话不多说,上代码。

本人有前端交流群:群里妹子多多,大佬多多,有兴趣的可以私聊我进群

第一块是分享,第二部分是微信公众号跳转网页授权流程

我们先来看一波微信官方文档

一:我们第一步是需要绑定域名,这个在微信公众开发平台可以绑定

二: 引入js文件,我是在项目中直接引入的文件

var jweixin = require('jweixin-module')

三:config的权限注入验证,这里直接调取后台接口获取到对应的参数写进去就行

compomentDidmount() {
    let url = `${location.origin}${location.pathname}${location.search}`;
    
    return this.$http.request({
        url: `/h5/mobile/WXShare`,
        method: 'post',
        data: {
            url: url
        }
    }).then(res => {
        if (res.code === 200) {
            jweixin.config({
                debug: false,
                appId: res.data.appId,
                timestamp: res.data.timestamp,
                nonceStr: res.data.nonceStr,
                signature: res.data.signature,
                jsApiList: res.data.jsApiList
            });
        }
    })

},
这里的url传给后台一般只需要location.href就能满足需要,但是后来遇到一些问题,这个等下再说,继续看流程。

四:通过ready处理成功的验证,我这里是后台直接返回的我需要配置的jsApiList,所以就不需要在手动填写。

let url =
    `${location.origin}${location.pathname}#/pages/look_activity/look_activity?activity_id=${this.activity_id}&invite_id=${invite_id}&spreader_id=${spreader_id}`;
let data = {
    title: '', // 分享标题
    desc: '', // 分享描述
    link: url, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
    imgUrl: '', // 分享图标
    success: function () {
        // 用户点击了分享后执行的回调函数
    }
};
jweixin.updateAppMessageShareData(data)
// 分享到朋友圈
jweixin.updateTimelineShareData(data)
注意:这里的路径必须要和公众号配置的一样,当然我这里是路径分享出去以后要带参数,所以路径后面 ? 可以不用一致,此处只贴出来关键代码。

这里有一个问题就是

${location.origin}${location.pathname}#/
// 如果我直接在上方url写成 let url = ${location.href}
// 这时候我的分享出去的标题等等都会失效
// 然后找了一下问题,就在原代码的路径前加入 ${location.origin}${location.pathname}?#/
// 这个时候我的分享就能正常运行

就在昨天用户从首页直接访问进来分享的时候就出现了之前的问题,当时我拿手机测试的都是正常的,还以为是客户苹果手机的问题,然后就开始找问题,终于在我同事大佬的帮助下找到了问题所在。

签名生成规则如下:参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分) 

这里官方给的解释是 当前网页的URL,不包含#及其后面部分

// 这就是我为什么必须要在路径后面加 ? 号才能正常访问的问题,所以我就干脆直接点在进入程序的时候就改变url后面的规则,从而在任何一个地方分享都能正常分享

刚开始想的是在APP.vue里面进来就改变url地址
if (location.href.indexOf('?') == -1) {
	location.href = '?' + location.hash
	return
}
这个方法,如果在编辑器运行都是正常的,换成真机就会失败,所以在进入到分享的页面的时候,就直接改变 let url = `${location.origin}${location.pathname}${location.search}`;

到这里就能正常的使用了,还有分享的时候微信会有自带的参数,需要解析。本人项目中没用到这一需求所以就没有进行处理,不过还是给方法给你们贴出来好了。

encodeURLComponent(window.location.href) 搞定!

微信公众号网页授权登录流程

当时在写这一部分的时候,应为是初次写不太熟所以走了很多弯路,现在把代码给发出来,就当是回顾一下代码好了。

话不多说,先上文档哈哈哈哈 微信网页授权文档

文档上面写的很清楚,直接按照文档一步一步来就行
1 第一步:用户同意授权,获取code

2 第二步:通过code换取网页授权access_token

3 第三步:刷新access_token(如果需要)

4 第四步:拉取用户信息(需scope为 snsapi_userinfo)

5 附:检验授权凭证(access_token)是否有效

话不多说上代码!!!


Store->user.js Vuex

state: {
    // 用户code值
    code: '',
        // 用户信息
        userInfo: { },
    // 返回跳转链接
    backUrl: '',
},

mutations:{
    // 获取code
    getCode(state) {
        state.code = ''
        
        //要跳转的url
        let url = `${location.origin}${location.pathname}?#/pages/login/login`;
        //在这里根据官方文档进行 解析
        let local = encodeURIComponent(url)
        //这部分就是文档要求的了
        let params = '&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect';
        let loginUrl = `${baseConfig.baseUrl}?appid=${baseConfig.APPID}&redirect_uri=${local}${params}`;
    
        uni.setStorageSync('backUrl', location.hash);
        window.location.href = loginUrl; // 跳转即可!!
    }
},
actions: {
    // 判断用户token是否有效
    checkToken(context) {
        // 获取用户信息
        api.getUserInfo().then(res => {
            if (res.code == 200) {
                this.userInfo = res.data;
                uni.setStorageSync('userInfo', res.data);
            } else {
                context.commit('getCode');
            }
        });
    },
    // 判断用户是否登录
    checkAuth(context, path) {
        let token = uni.getStorageSync('userToken');
        if (!token && path !== 'pages/login/login') {
            // token 不存在肯定没有登录
            context.commit('getCode');
        } else {
            if (path !== 'pages/login/login') {
                // token 存在验证token有效性
                context.dispatch('checkToken');
            }
        }
    }
},

到这里就是vuex需要做的操作了,那么下边,我们是做了一个login的过度页去过度一下,话不多说,程序员用代码交流

login.vue

<template>
	<view class="wrap">
		<image class="loading" src="http://pjserver.huasukeji.net/uploads/loading.gif"></image>
		<text>正在登录请稍后...</text>
		<view>如果长时间没有跳转,<text class="doLogin" @click="goIndex">请点击这里</text></view>
	</view>
</template>

methods:{
    //这里就对code进行处理
    getParam(path, name) {
        var reg = new RegExp("(^|\\?|&)" + name + "=([^&]*)(\\s|&|$)", "i");
        if (reg.test(path))
        return unescape(RegExp.$2.replace(/\+/g, " "));
        return "";
    },
    
    init() {
        let code = this.getParam(location.href, 'code') //获取授权成功返回的code
        if (code) {
        //这里就不做解释了,想必大家都能看的懂
            this.doLogin(code);
        }
    },
    
    doLogin(code) {
        let params = {
            code: code
        }
        this.$api.login(params).then(res => {
            if (res.code && res.code === 200) {
                uni.setStorageSync('userToken', res.data.token);
                history.replaceState({}, null, `${location.origin}${location.pathname}`);
                let backUrl = uni.getStorageSync('backUrl');
                if (backUrl) {
                    backUrl = backUrl.replace('#', '')
                } else {
                    backUrl = '/';
                }
                this.$api.getUserInfo().then(res => {
                    if (res.code == 200) {
                        this.userInfo = res.data
                        uni.setStorageSync('userInfo', res.data)
    
                        uni.reLaunch({
                            url: backUrl
                        })
                    } else {
                        uni.showToast({
                            icon: 'none',
                            title: res.msg
                        })
                    }
                })
    
            } else {
                uni.showToast({
                    icon: 'none',
                    title: '登录失败'
                })
            }
        })
    },
    //这里是担心用户在本login页面时间过长,所以做了路由跳转的处理
    goIndex() {
        history.replaceState({}, null, `${location.origin}${location.pathname}`);
        uni.reLaunch({
            url: '/pages/index/index'
        });
    },
    
    // 截取code
    getUrlCode() {
        var url = location.search
        this.winUrl = url
        var theRequest = new Object()
        if (url.indexOf("?") != -1) {
            var str = url.substr(1)
            var strs = str.split("&")
            for (var i = 0; i < strs.length; i++) {
                theRequest[strs[i].split("=")[0]] = (strs[i].split("=")[1])
            }
        }
        return theRequest
    },
    // 可以直接拿来用
}

这里对history.replaceState做一下解释 基于replaceState() 是修改了当前的历史记录项而不是新建一个,所以无论用户在当前页面多少次的点开不同的子页面,当点击返回时,都会回到https://固定页面。

应为考虑到分享出去时候 肯定不能让用户登录成功以后在跳转到首页,所以做的需求就是用户进来的时候直接判断有没有登录,没有登录的话点击登录还是在本页面保持不变!!

最后在APP.vue调用方法

onLaunch: function(e) {
    this.$store.dispatch('checkAuth', e.path);
},

到这里就搞定了!

@手动艾特我的两位后台同事,在项目中给予我很大的帮助

本人只是分享在项目中从陌生到踩坑的一些经历,帮助没有做过此需求的大佬们一个参考,如果可以请帮忙点个赞,写文章很累,白天加班,晚上分享。

@有什么不明白或者不足之处,请留言告诉我,谢谢!