公众号打开小程序最佳解决方案(Vue)__Vue.js
粉丝福利 : 关注VUE中文社区公众号,回复视频领取粉丝福利
主题列表:juejin, github, smartblue, cyanosis, channing-cyan, fancy, hydrogen, condensed-night-purple, greenwillow, v-green, vue-pro, healer-readable, mk-cute, jzman, geek-black, awesome-green, qklhk-chocolate
贡献主题:https://github.com/xitu/juejin-markdown-themes
theme: juejin highlight:
场景
- 由于一些特殊的需求导致了项目的分离,当前的项目是在微信的公众号,部分需求要求用小程序来做,但是两者之间存在关联,需要通过公众号去跳转小程序。
技术方案
- 使用微信网页的 JSSDK
适用环境
- 微信版本要求为:
7.0.12
及以上 - 系统版本要求为:
iOS 10.3
及以上、Android 5.0
及以上
具体步骤
- 这部分是官方文档中的,我是挪过来方便大家看,也可以自己去官方文档看。 官方文档
-
绑定域名
- 先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”
-
引入
JS
文件- 在需要调用
JS
接口的页面引入如下JS
文件,(支持https
):http://res.wx.qq.com/open/js/jweixin-1.6.0.js
- 如需进一步提升服务稳定性,当上述资源不可访问时,可改访问:
http://res2.wx.qq.com/open/js/jweixin-1.6.0.js
(支持https
)。 - 注:支持使用
AMD/CMD
标准模块加载方法加载
- 在需要调用
-
通过
config
接口注入权限验证配置- 所有需要使用
JS-SDK
的页面必须先注入配置信息,否则将无法调用(同一个url
仅需调用一次,对于变化url
的SPA
的web app
可在每次url
变化时进行调用,目前Android
微信客户端不支持pushState
的H5
新特性,所以使用pushState
来实现web app
的页面会导致签名失败,此问题会在Android6.2
中修复)。
wx.config({ debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: '', // 必填,公众号的唯一标识 timestamp: , // 必填,生成签名的时间戳 nonceStr: '', // 必填,生成签名的随机串 signature: '', // 必填,签名 jsApiList: [], // 必填,需要使用的JS接口列表 openTagList: ['wx-open-launch-weapp'] // 微信开放标签 小程序跳转按钮:<wx-open-launch-weapp> });
- 所有需要使用
-
通过
ready
接口处理成功验证wx.ready(function(){ // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。 });
-
通过
error
接口处理失败验证wx.error(function(res){ // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。 });
-
通过请求后段接口拿到
config
需要的参数,去初始化后,在页面增加如下的标签
// 请求 config需要的参数
postUrl({url: curUrl}).then(res => {
if (res.code === 0) {
wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: res.data.appId, // 必填,公众号的唯一标识
timestamp: res.data.timeStamp, // 必填,生成签名的时间戳
nonceStr: res.data.nonceStr, // 必填,生成签名的随机串
signature: res.data.signature, // 必填,签名
jsApiList: ['onMenuShareAppMessage'],
openTagList: ['wx-open-launch-weapp'] // 可选,需要使用的开放标签列表,例如['wx-open-launch-app']
});
wx.ready(function(){})
wx.error(function(error){})
}
})
// html
<wx-open-launch-weapp
id="launch-weapp1"
username="gh_xxxxxx"
path="xxxxxx"
@launch="onLaunch"
@error="onError"
>
<script type="text/wxtag-template">
<div style="font-size: 14px;margin-top: 10px;text-align: center;">打开小程序</div>
</script>
</wx-open-launch-weapp>
(1)username
:要打开的小程序原始 id
以 gh_
开头的;
(2)path
:要打开的小程序页面(页面最后要加.html
,例如:'pages/index/index.html'
,否则 IOS
跳转时出现小程序页面未配置)
错误处理
- 标签报错
- 解决方法:在
main.js
中添加以下代码;
// main.js
Vue.config.ignoredElements = ['wx-open-launch-weapp'];
wx-open-launch-weapp
中的Dom
不显示
- 当前
wx-open-launch-weapp
标签中的Dom
只有在真机下才会显示,在电脑端的浏览器、微信开发者工具中都不会显示;这就导致了一个问题wx-open-launch-weapp
里面的内容控制、样式调试等很难,且渲染数据很麻烦。
wx-open-launch-weapp
中的Dom
显示,但真机点击无反应
- 如果所使用的标签允许提供插槽,由于插槽中模版的样式是和页面隔离的,因此需要注意在插槽中定义模版的样式。插槽模版及样式均需要通过
<template></template>
进行包裹。对于Vue
等视图框架,为了避免template
标签冲突的问题,可使用<script type="text/wxtag-template"><script>
进行代替,来包裹插槽模版和样式。
- 小程序无法打开
- 这种方式只能打开合法合规的小程序且小程序已正式发布(体验版不行)。
优化
- 当我们需要通过一个卡片或者有很多动态数据渲染一个大的
Dom
结构时,里面的样式写起来就十分的麻烦且动态设置里面的数据也很不方便,所以我们最好的方式就是不在wx-open-launch-weapp
中写任何内容。 - 经过我自己的尝试,我放弃了在
wx-open-launch-weapp
中写样式,因为那是在太麻烦了,一点改动就需要去部署,到真机上验证。
解决方案
- 我们在需要跳转的地方,去生成一个包裹层,并将这个包裹层覆盖到点击区域的上方,然后设置背景色为透明色。并动态生成
wx-open-launch-weapp
- 添加包裹层
<div class="weapp-cover"></div>
// weapp-cover的宽高应该根据点击区域动态设置
.weapp-cover {
z-index: 90;
position: absolute;
bottom: 16px;
right: 26px;
// background-color: red;
}
- 动态设置包裹层宽高
mounted() {
const weappDom = this.$el.querySelector('.weapp-cover');
const menuItemDom = this.$el.querySelector('.menu-item');// 点击区域对象
weappDom.style.width = menuItemDom.clientWidth + 'px';
weappDom.style.height = menuItemDom.clientHeight + 'px';
}
- 动态生成
wx-open-launch-weapp
/**
* [@description](/user/description): 生成wx-open-launch-weapp
* [@param](/user/param) {Object} info
*/
/*
* [@description](/user/description): info参数
let params={
width: "", 点击区域宽度
height: "", 点击区域高度
ele:"", // 元素ID
appid:"", // 小程序id号 gh_****
url:"", // 跳转小程序的页面路径地址 例: pages/home/home.html - (后面必须带上.html后缀 否则IOS跳转时出现小程序页面未配置)
content:"" // html字符串 例: "<button>点我</button>"
}
*/
export function wx_launch(info) {
const btn = info.ele.querySelector('.weapp-cover'); //获取元素
const script = document.createElement("script");// 创建script内容插槽 避免template标签冲突
script.type = "text/wxtag-template"; // 使用script插槽 必须定义这个type
script.text = info.content // 自定义的html字符串内容
const html = `<wx-open-launch-weapp
style="width:${info.width};
height:${info.height};
display:block;" username="${info.appid}"
path="${info.url}">${script.outerHTML}</wx-open-launch-weapp>`;
btn.innerHTML = html; // html字符串赋值
}
- 增加微信浏览器判断
// 判断是否微信环境
function is_weixn() {
let ua = navigator.userAgent.toLowerCase()
if (ua.match(/MicroMessenger/i) == 'micromessenger') {
return true
} else {
return false
};
};
- 增加微信版本判断
- 在测试中发现部分人员的微信一直提示 您的版本号不支持,通过查看各个微信版本发现,获取的微信版本字符串不一致,有的是三位、有的是四位;
const wxInfo = navigator.userAgent.match(/MicroMessenger\/([\d\.]+)/i); // 微信浏览器信息
// 微信版本号 wxInfo[1]
// 我们当前正常的版本
wxInfo[1] = "8.0.1840"
// 异常版本号
wxInfo[1] = "8.0.1.1840"
- 微信版本要求为:
7.0.12
及以上 - 通过上述问题,我们可以修改
is_version
方法,先判断大版本号及第一位大于7
时直接返回true
,当等于7
时,判断第二位是否大于0
,大于0
直接返回true
,等于0
时判断第三位是否大于等于12
。代码如下:
// 判断当前微信版本号是否支持
function is_version() {
const wxInfo = navigator.userAgent.match(/MicroMessenger\/([\d\.]+)/i); // 微信浏览器信息
// 微信正常版本号 wxInfo[1] = "8.0.1840" (示例)
// 微信异常版本号 wxInfo[1] = "8.0.1.1840" (示例)
//进行split转成数组进行判断 ['8','0','1','1840'] (示例)
const version = wxInfo[1].split(".");
// console.log('version', version);
// 判断版本在7.0.12及以上的版本
if (Number(version[0]) > 7) {
return true;
} else if (Number(version[0]) === 7) {
if (Number(version[1]) > 0) {
return true;
} else if (Number(version[1]) === 0) {
if (Number(version[2]) >= 12) return true;
}
}
return false;
}
- 注:字符串调用
split
方法后,数字在数组中为字符串。
- 修改动态生成
wx-open-launch-weapp
方法
export function wx_launch(info) {
+ if (!is_weixn()) {
+ return
+ }
+ if (is_version()) {
const btn = info.ele.querySelector('.weapp-cover'); //获取元素
...
+ } else {
+ alert("您的版本号不支持")
+ }
- 调用
wx_launch
mounted() {
const weappDom = this.$el.querySelector('.weapp-cover');
const menuItemDom = this.$el.querySelector('.menu-item');// 点击区域对象
weappDom.style.width = menuItemDom.clientWidth + 'px';
weappDom.style.height = menuItemDom.clientHeight + 'px';
// 动态生成小程序跳转遮罩层
+ wx_launch({
+ ele: this.$el,
+ width: menuItemDom.clientWidth + 'px',
+ height: menuItemDom.clientHeight + 'px',
+ appid: 'gh_xxxx',
+ url: this.miniProgramPath,
+ content:
+ `<style>
+ .res-cover {
+ width: ${menuItemDom.clientWidth}px;
+ height: ${menuItemDom.clientHeight}px;
+ }
+ </style>
+ <div class="res-cover"></div>`
+ })
}
总结
- 拿到需求后,首先是去是否有相关的技术方案能实现这样的功能;有技术方案时,通过分析需求看需要怎么样的实现以及可能遇到的问题;
- 自己遇到的坑:错误处理中的
4
个问题都遇到过、wx-open-launch-weapp
中的内容显示样式问题及卡片数据无法动态渲染问题、动态生成wx-open-launch-weapp
的Dom
找不到等很多小问题; - 在已实现功能后,我们可以通过一些奇技淫巧或间接方法去达到我们所想的预期,不要被需求局限了思维。
补充
- 后续问题在这里补充说明
URL
带参数跳转小程序,小程序接收不全,跳转URL
如下所示:小程序接收到的是
"Source=public&token={"
,原因是由于token
是一个对象通过JSON.stringify
生成的字符串,URL
通过模版字符串生成的插入token
生成的,导致小程序接收时对引号进行了截断,所以我们需要在生成的对象类型字符串使用encodeURI
进行URL
编码。
const pathStr = 'pages/detail/speakingDetail.html?Source=public'; let tokenParams = {}; const miniProgramUrl = `${pathStr}&token=${encodeURI(JSON.stringify(tokenParams))}`;
iOS
系统跳转URL
会有问题,原因是iOS
对encodeURI
编码方式不支持,替换为encodeURIComponent
即可。(注:这种方式编码后,小程序接收的地方需要解码)
参考
更多优质文章
- HXDM前端开发规范安排上
- 产品:我想要一个这样的日期时间选择界面!!!
- JS通信方式知多少?JS和多端应用通信
- ES6常用但被忽略的方法(第七弹async)
- ES6常用但被忽略的方法(第四弹Proxy和Reflect)
- ES6常用但被忽略的方法(第一弹解构赋值和数值)
- 进来看看ES6 Promise最全手写实现
「点赞、收藏和评论」
❤️关注+点赞+收藏+评论+转发❤️,原创不易,鼓励笔者创作更好的文章,谢谢🙏大家。
版权声明:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 作者: 小小小十七 原文链接:https://juejin.im/post/6925346648836112391