uniapp 微信小程序webview 和 h5数据通信
项目是uniapp编写,因为是先开发了h5和app,小程序是突然要用的,做兼容开发已经来不及,由于微信小程序webview载入h5 因为通信必须要特殊限制(网页向小程序 postMessage 时,会在以下特定时机触发并收到消息:小程序后退、组件销毁、分享、复制链接(2.31.1)。e.detail = { data },data是多次 postMessage 的参数组成的数组。),不能满足使用,所以搞了一套特别low的通信机制,缺点是通信时候会有一个loading的过渡页面
业务逻辑大致为:
1、微信小程序webview访问h5带参数的url,获取初始的参数,可以携带页面参数或者登录token等,通过reciver接受h5返回的参数。
2、h5通过一个中间html页面存储小程序的通信逻辑,然后在h5页面通过定时器一直获取缓存本地的数据,根据数据信息执行不同的业务逻辑
1、微信小程序项目
(1)微信小程序项目
index.vue
<template><web-view v-if="src" :src="src" bindload="bindload" binderror="binderror"></web-view>
</template><script lang="ts">
import { cfg } from '@/cfg'
import Base64 from '@/utils/Base64'export default {data() {return {src: '',}},onLoad(e: any) {let loginA = parseInt(e.loginA)console.log(e.loginA)if (loginA) {let self = thiswx.login({success(res: any) {// 自动登录成功self.msg(Base64.encode64('loginA,' + JSON.stringify([loginA, cfg.mpApp, res.code])))},fail(res: any) {// 自动登录失败self.msg(Base64.encode64('loginAFail,' + JSON.stringify([loginA, res.errMsg])))},})return}this.msg(e.msg)},methods: {msg(msg: any) {if (msg) {this.src = cfg.mpUrl + 'static/mpMsg.html?uid=' + cfg.mpid + '&msg=' + msg// this.src = 'http://www.baidu.com/#/'console.log(this.src)// 超时自动关闭// @ts-ignorethis['$timer'] = setTimeout(() => {this.navBack()}, 3000)return}this.navBack()},bindload() {console.log('bindload')this.navBack()},binderror() {console.log('binderror')this.navBack()},navBack() {let pages = getCurrentPages()if (pages[pages.length - 1].$vm == this) {uni.navigateBack()}// @ts-ignorelet timer = this['$timer']if (timer) {// @ts-ignoredelete this['$timer']clearTimeout(timer)}},},
}
</script><style></style>
(2)reciver.vue
<template><view id="preloader"></view>
</template><script lang="ts">
import { App } from '@/store/app'
import Base64 from '@/utils/Base64'export default {data() {return {src: '',}},onLoad(e: any) {try {let msg = e.msgif (msg) {msg = Base64.decode64(msg)let i = msg.indexOf(',')let key = msglet val = ''if (i > 0) {key = msg.substring(0, i)val = msg.substring(i + 1)}// 如果是pc小程序bridge支付,则直接跳转到支付页面// const info = uni.getSystemInfoSync()// if ((info?.deviceType == 'pc' || info?.deviceType == 'PC') && key == 'pay') {// uni.redirectTo({// url: `/pages/index/pay?pay=${Base64.encode64(val)}`,// })// } else {// uni.navigateBack({// complete() {// // setTimeout(() => {// App.mpRecieverMsg(key, val)// // }, 100)// },// })// }uni.navigateBack({complete() {// setTimeout(() => {App.mpRecieverMsg(key, val)// }, 100)},})return}} catch (e) {console.error(e)}uni.navigateBack()},methods: {},
}
</script><style scoped>
#preloader {position: absolute;width: 30px;height: 30px;background: rgba(253, 87, 17, 1);border-radius: 50px;left: 0;right: 0;top: 0;bottom: 0;margin: auto;-webkit-animation: preloader_1 1.5s infinite linear;-moz-animation: preloader_1 1.5s infinite linear;-ms-animation: preloader_1 1.5s infinite linear;animation: preloader_1 1.5s infinite linear;
}
#preloader:after {position: absolute;width: 50px;height: 50px;border-top: 10px solid rgba(255, 139, 9, 1);border-bottom: 10px solid rgba(255, 139, 9, 1);border-left: 10px solid transparent;border-right: 10px solid transparent;border-radius: 50px;content: '';top: -20px;left: -20px;-webkit-animation: preloader_1_after 1.5s infinite linear;-moz-animation: preloader_1_after 1.5s infinite linear;-ms-animation: preloader_1_after 1.5s infinite linear;animation: preloader_1_after 1.5s infinite linear;
}@-webkit-keyframes preloader_1 {0% {-webkit-transform: rotate(0deg);}50% {-webkit-transform: rotate(180deg);background: #ff4f11;}100% {-webkit-transform: rotate(360deg);}
}
@-webkit-keyframes preloader_1_after {0% {border-top: 10px solid rgba(253, 87, 17, 1);border-bottom: 10px solid rgba(255, 139, 9, 1);}50% {border-top: 10px solid rgba(253, 87, 17, 1);border-bottom: 10px solid rgba(253, 87, 17, 1);}100% {border-top: 10px solid rgba(255, 139, 9, 1);border-bottom: 10px solid rgba(255, 139, 9, 1);}
}@-moz-keyframes preloader_1 {0% {-moz-transform: rotate(0deg);}50% {-moz-transform: rotate(180deg);background: #ff4f11;}100% {-moz-transform: rotate(360deg);}
}
@-moz-keyframes preloader_1_after {0% {border-top: 10px solid rgba(255, 139, 9, 1);border-bottom: 10px solid rgba(255, 139, 9, 1);}50% {border-top: 10px solid rgba(253, 87, 17, 1);border-bottom: 10px solid rgba(253, 87, 17, 1);}100% {border-top: 10px solid rgba(255, 139, 9, 1);border-bottom: 10px solid rgba(255, 139, 9, 1);}
}@-ms-keyframes preloader_1 {0% {-ms-transform: rotate(0deg);}50% {-ms-transform: rotate(180deg);background: #ff4f11;}100% {-ms-transform: rotate(360deg);}
}
@-ms-keyframes preloader_1_after {0% {border-top: 10px solid rgba(255, 139, 9, 1);border-bottom: 10px solid rgba(255, 139, 9, 1);}50% {border-top: 10px solid rgba(253, 87, 17, 1);border-bottom: 10px solid rgba(253, 87, 17, 1);}100% {border-top: 10px solid rgba(255, 139, 9, 1);border-bottom: 10px solid rgba(255, 139, 9, 1);}
}@keyframes preloader_1 {0% {transform: rotate(0deg);}50% {transform: rotate(180deg);background: #ff4f11;}100% {transform: rotate(360deg);}
}
@keyframes preloader_1_after {0% {border-top: 10px solid rgba(255, 139, 9, 1);border-bottom: 10px solid rgba(255, 139, 9, 1);}50% {border-top: 10px solid rgba(253, 87, 17, 1);border-bottom: 10px solid rgba(253, 87, 17, 1);}100% {border-top: 10px solid rgba(255, 139, 9, 1);border-bottom: 10px solid rgba(255, 139, 9, 1);}
}
</style>
(3)app.ts
import cfg from '@/cfg'
import Base64 from '@/utils/Base64'export const App = {shareData: {},mpPostMsg(key: string, val?: string, redirect: boolean = true) {const msg = val ? key + ',' + val : keyif (redirect) {uni.redirectTo({ url: '/pages/msg/post?msg=' + Base64.encode64(msg) })} else {uni.navigateTo({ url: '/pages/msg/post?msg=' + Base64.encode64(msg) })}},mpRecievers: {userStorageCert(cert: string) {console.log('userCert', cert)if (cert) {uni.setStorageSync(cfg.mpApp + 'userStorageCert', cert)}},shareAppMessage(v: string) {let sharetry {share = JSON.parse(v)if (share.path) {// 使用正则表达式匹配 _i= 后面的字符串const match1 = share.path.match(/_i=([^&]+)/)// 如果匹配成功,获取匹配到的字符串if (match1) {const extractedString = match1[1]share.path = '/pages/index/index?i=' + extractedStringconsole.log(' share.path', share.path)}}} catch (error) {}try {if (share.imageUrl) {share.imageUrl = share.imageUrl.replace(/(w_\d+)|(h_\d+)/g, (match: string) => {if (match.startsWith('w_')) {return 'w_300'} else if (match.startsWith('h_')) {return 'h_300'}})}} catch (error) {}if (share) {App.shareData = share}},pay(v: string) {const pay = JSON.parse(v)pay.success = function () {// 需要通知App.mpPostMsg('pay,1', undefined, false)}// pay.complete = function () {// // 需要通知// App.mpPostMsg('pay,1', undefined, false)// }pay.fail = function (e: any) {console.log('pay fail ' + JSON.stringify(e))uni.showToast({title: '支付失败',icon: 'none',duration: 2000,})}// 支付参数console.log(JSON.stringify(pay))const info = uni.getSystemInfoSync()// 如果是pc小程序bridge支付,则延迟掉起,防止不显示支付弹窗if (info?.deviceType == 'pc' || info?.deviceType == 'PC') {uni.showLoading()setTimeout(() => {uni.hideLoading()wx.requestPayment(pay)}, 1000)} else {wx.requestPayment(pay)}},bindWx() {wx.login({success: function (res: any) {let data = ''if (res) {let appid = ''if (cfg.mpApp) {appid = cfg.mpApp}data = JSON.stringify([appid, res.code])}App.mpPostMsg('bindWx', data, false)},fail: function (err: any) {console.log('bindWx fail', err)App.mpPostMsg('bindWx', '', false)},})},openLocation(adress: string) {const data = JSON.parse(adress)wx.openLocation({latitude: Number(data.latitude),longitude: Number(data.longitude),name: data.name,scale: 18,complete: e => {console.log('openLocation complete', e)},})console.log('openLocation data', data)},downloadAndSave(res: string) {const data = JSON.parse(res)const $delay = data['$delay']if ($delay > 0) {setTimeout(() => {wx.downloadFile({url: data.url,success: function (res) {wx.openDocument({filePath: res.tempFilePath,fileType: 'pdf',showMenu: true,})},})}, $delay)} else {wx.downloadFile({url: data.url,success: function (res) {wx.openDocument({filePath: res.tempFilePath,fileType: 'pdf',showMenu: true,})},})}},callFun(res: string) {const data = JSON.parse(res)// @ts-ignoreconst fun = wx[data['$fun']]if (fun) {delete data['$fun']const $delay = data['$delay']if ($delay > 0) {delete data['$delay']setTimeout(() => {fun.call(wx, data)}, $delay)} else {fun.call(wx, data)}}},},mpRecieverMsg(key: string, val?: string) {// @ts-ignoreconst fun = App.mpRecievers[key]if (fun) {fun(val)return}},
}
(3)Base64.ts
// private property
let _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";// private method for UTF-8 encoding
let _utf8_encode = function (str: string) {str = str.replace(/\r\n/g, "\n");let utftext = "";for (let n = 0; n < str.length; n++) {let c = str.charCodeAt(n);if (c < 128) {utftext += String.fromCharCode(c);} else if ((c > 127) && (c < 2048)) {utftext += String.fromCharCode((c >> 6) | 192);utftext += String.fromCharCode((c & 63) | 128);} else {utftext += String.fromCharCode((c >> 12) | 224);utftext += String.fromCharCode(((c >> 6) & 63) | 128);utftext += String.fromCharCode((c & 63) | 128);}}return utftext;
}// private method for UTF-8 decoding
let _utf8_decode = function (utftext: string) {let string = "";let i = 0;let c, c1, c2, c3c = c1 = c2 = 0;while (i < utftext.length) {c = utftext.charCodeAt(i);if (c < 128) {string += String.fromCharCode(c);i++;} else if ((c > 191) && (c < 224)) {c2 = utftext.charCodeAt(i + 1);string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));i += 2;} else {c2 = utftext.charCodeAt(i + 1);c3 = utftext.charCodeAt(i + 2);string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));i += 3;}}return string;
}const Base64 = {// public method for encodingencode(input: string) {let output = "";let chr1, chr2, chr3, enc1, enc2, enc3, enc4;let i = 0;input = _utf8_encode(input);while (i < input.length) {chr1 = input.charCodeAt(i++);chr2 = input.charCodeAt(i++);chr3 = input.charCodeAt(i++);enc1 = chr1 >> 2;enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);enc4 = chr3 & 63;if (isNaN(chr2)) {enc3 = enc4 = 64;} else if (isNaN(chr3)) {enc4 = 64;}output = output +_keyStr.charAt(enc1) + _keyStr.charAt(enc2) +_keyStr.charAt(enc3) + _keyStr.charAt(enc4);}return output;},// public method for decodingdecode(input: string) {let output = "";let chr1, chr2, chr3;let enc1, enc2, enc3, enc4;let i = 0;input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");while (i < input.length) {enc1 = _keyStr.indexOf(input.charAt(i++));enc2 = _keyStr.indexOf(input.charAt(i++));enc3 = _keyStr.indexOf(input.charAt(i++));enc4 = _keyStr.indexOf(input.charAt(i++));chr1 = (enc1 << 2) | (enc2 >> 4);chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);chr3 = ((enc3 & 3) << 6) | enc4;output = output + String.fromCharCode(chr1);if (enc3 != 64) {output = output + String.fromCharCode(chr2);}if (enc4 != 64) {output = output + String.fromCharCode(chr3);}}output = _utf8_decode(output);return output;},// 编码encode64(str: string, uri: boolean = true) {str = Base64.encode(str);if (uri) {str = str.replace(/[+|=|/]/g, function (word) {switch (word) {case "+":return "-";case "=":return "_";case "/":return ".";}return word;});}return str;},// 解码decode64(str: string, uri: boolean = true) {if (uri) {str = str.replace(/[-|_|.]/g, function (word) {switch (word) {case "-":return "+";case "_":return "=";case ".":return "/";}return word;});}str = Base64.decode(str);return str;},
}export default Base64
index.vue
<template><web-view :src="src" @message="receiveMessage"> </web-view>
</template><script lang="ts">
import { cfg } from '@/cfg'
import { App } from '@/store/app'
import Base64 from '@/utils/Base64'
export default {data() {return {src: '',srcP: '',shareData: {imageUrl:'https://yjy.yiyiny.com//static/images/20240122/' +cfg.mpApp +'.png?x-oss-process=image/auto-orient,1/resize,m_fixed,w_100,h_100',},shareI: '',}},onLoad(e: any) {// e.scene 生成小程序码必须是这个keythis.setSrc(cfg.entryUrl, e.i || e.scene)wx.showShareMenu({withShareTicket: true,menus: ['shareAppMessage'],success(res) {console.log('mixin share success', res ? JSON.stringify(res) : res)},fail(err) {console.log('mixin share fail', err ? JSON.stringify(err) : err)},})},onShow() {cfg.mpSrcP = this.srcPApp.shareData = {}},onShareAppMessage(res: any) {console.log(res)if (res.from === 'button') {return this.shareData}if (res.from === 'menu') {return this.shareData || {}}},onShareTimeline() {let data = {title: '一乙艺术山庄',query: 'id=1',// imageUrl: '',}return data// return axCc.vueSelf.shareData || {};},onHide() {},methods: {setSrc(src: string, shareI?: string) {let cert = uni.getStorageSync(cfg.mpApp + 'userStorageCert')console.log('setSrc src', src)console.log('setSrc shareI', shareI)let i = src.indexOf('#')let j = src.indexOf('?')let srcP = i > 0 && i < j ? src.substring(0, i) : j > 0 ? src.substring(0, j) : srcif (srcP && srcP[srcP.length - 1] != '/') {srcP = srcP + '/'}if (i > 0) {cfg.mpUrl = src.substring(0, i)} else {cfg.mpUrl = cfg.entryUrl}console.log('[ cfg.mpUrl ] >', cfg.mpUrl)this.srcP = srcPcfg.mpSrcP = this.srcPsrc = j > 0 ? src + '&_mpid_=' + cfg.mpid : src + '?_mpid_=' + cfg.mpidif (shareI) {src = src + '&_i=' + shareI// 分享地址拼接const startIndex = src.indexOf('#')const endIndex = src.indexOf('?')if (startIndex !== -1 && endIndex !== -1) {src = src.substring(0, startIndex) + src.substring(endIndex)console.log(src)}this.shareI = shareI}src = src + '&ver=' + cfg.versionif (cert) {src = src + '&_cert_=' + encodeURIComponent(cert)}this.src = srcconsole.log('setSrc this.src', this.src)},// 监听h5 消息// { merber 用户信息 imageUrl 默认分享图 path 分享地址 title:分享标题 desc }receiveMessage(e: any) {console.log('receiveMessage333', e)let arr = e?.detail?.datalet data = arr && arr.length > 0 ? arr[arr.length - 1] : nulllet urlif (data && data?.merber?.id) {url = data?.path? data.path: cfg.mpName == 'mp_wdysj'? 'pages/artisthome/artisthome': '/pagesShop/shop/wHome'let parms = this.gen(url, false, { mmId: data?.merber.id }, 13050, data?.merber?.id)console.log('data222', data)this.shareData = {path: '/pages/index/index?i=' + parms + '&fk=1',imageUrl: data?.imageUrl? data.imageUrl: 'https://yjy.yiyiny.com//static/images/20240122/' +cfg.mpApp +'.png?x-oss-process=image/auto-orient,1/resize,m_fixed,w_100,h_100',title: data?.title ? data.title : cfg.mpName,desc: data?.desc ? data.desc : '',query: parms,}} else {wx.hideShareMenu()}},// 地址加密gen(uri: string, bind: boolean, reg: any, eid?: number, memberId?: number): string {// 标准编码let ps = [memberId, '', false, uri || '', reg || '', eid]for (let i = ps.length - 1; i >= 0; i--) {if (ps[i]) {let del = ps.length - i - 1if (del > 0) {ps.splice(i + 1, del)}break}}let _ps: any = ps_ps[0] = _ps[0] || ''if (bind) {_ps[2] = uri_ps[3] = ''} else {_ps[2] = ''}return Base64.encode64(JSON.stringify(ps))},},
}
</script><style></style>
cfg.ts
export const cfg = {mpApp: 'mp_wdysj', //一乙艺术商城mpName: '一乙艺术商城',mpUrl: 'https://p.yiyiny.com/xxx/',mpid: '',mpSrcP: '',version: '1.0.8',entryUrl: 'https://p.yiyiny.com/xxx/#/pagesShop/shop/wHome',
}const info = uni.getSystemInfoSync()
if (!cfg.mpid) {const host = info.host// @ts-ignoreif (host && host.appid) {// @ts-ignorecfg.mpid = host.appid}if (!cfg.mpid) {cfg.mpid = cfg.mpApp}
}
export default cfg
2、h5端
(1)项目初始化时候h5载入微信sdk
Ainit.ts
// #ifdef H5let _mpid_;try {let search = <any>((launcher.h5Search || ab_.route(false, false, false).search));_mpid_ = search['_mpid_'];let _cert_ = search['_cert_'];// 获取小程序传递的证书if (_cert_) {_cert_ = decodeURIComponent(_cert_)User.status.storage.cert = _cert_}let app = axConfig.webType || 'web'if (Weixin.isWeiXin()) {axCc.Loader().wait("weixinLogin");ab_.reqJs(axCc.https? "https://res.wx.qq.com/open/js/jweixin-1.6.0.js": "http://res.wx.qq.com/open/js/jweixin-1.6.0.js",null,function () {function wxH5() {if (search["code"]) {let parms: Array<string> = [axConfig.webType, search["code"]];User.loginProvBack("wx",function (logined) {console.log("微信登陆成功", logined);try {if (logined) {axCc.saveStorage("wxLogined", {token: App.client.plt.headers["atoken"],authPar: User.status.authPar,authParas: User.status.authParas,});} else {axCc.saveStorage("wxLogined", {});}} finally {axCc.Loader().done("weixinLogin");// 微信jsConfigWeixin.wxConfig();}},parms,true,true,true);} else {try {// 关闭自动登录// User.autoLogin = false;let wxLogined = axCc.getStorage("wxLogined");if (wxLogined && wxLogined.token && wxLogined.authParas && wxLogined.authParas[0] === app) {User.loginToken(wxLogined.token, (logined) => {if (logined) {User.status.authPar = wxLogined.authPar;User.status.authParas = wxLogined.authParas;axCc.Loader().done("weixinLogin");} else {//微信浏览器 吊起微信支付必须要获取openidconsole.log("掉起微信支付必须要获取openid");Weixin.snsapi_base();}});} else {//微信浏览器 吊起微信支付必须要获取openidconsole.log("掉起微信支付必须要获取openid");Weixin.snsapi_base();}} finally {// 微信jsConfigWeixin.wxConfig();}}}// @ts-ignoreif (window.wx) {User.autoLogin = false;try {// @ts-ignoreif (typeof WeixinJSBridge == "object" && typeof WeixinJSBridge.invoke == "function") {handleFontSize();} else {if (document.addEventListener) {document.addEventListener("WeixinJSBridgeReady", handleFontSize, false);// @ts-ignore} else if (document.attachEvent) {// @ts-ignoredocument.attachEvent("WeixinJSBridgeReady", handleFontSize);// @ts-ignoredocument.attachEvent("onWeixinJSBridgeReady", handleFontSize);}}function handleFontSize() {// 设置网页字体为默认大小// @ts-ignoreWeixinJSBridge.invoke('setFontSizeCallback', { 'fontSize': 0 });// 重写设置网页字体大小的事件// @ts-ignoreWeixinJSBridge.on('menu:setfont', function () {// @ts-ignoreWeixinJSBridge.invoke('setFontSizeCallback', { 'fontSize': 0 });});}// @ts-ignoreif (wx.miniProgram) {// @ts-ignorewx.miniProgram.getEnv((res) => {if (res.miniprogram) {User.status.info.cert = trueUser.autoLogin = true;// && search['_mpid_'] == "mp_wdysj_shop"if (_mpid_) {if ((_mpid_ == "mp_wdysj_shop" || _mpid_ == "mp_wdysj_yiyi_shop")) {axConfig.pltName = "商城"axConfig.home = "/pagesShop/shop/wHome"App.shopScoreName = '商城'App.client.storeHttp.head('platform', 'mp')axConfig.appProv = _mpid_axConfig.appEid = 13061}axConfig.pltApp = _mpid_User.status.info.app = _mpid_}// 小程序Weixin.initWxMpH5(_mpid_, search['ver'])axCc.Loader().done("weixinLogin");} else {wxH5()}})return}} catch (e) {console.error(e)}wxH5()} else {axCc.Loader().done("weixinLogin");}},undefined);} else {}} catch (e) {console.error(e);}// #endif
2、Weixin.ts
import ab_ from 'axj-ab_'; //npm install axj-ab_
import Base64 from '../util/Base64';interface ShareInfo {title: string,desc?: string,link: string,imageUrl?: string,logo?: string,//兼容老项目imgUrl?: string,//兼容老项目scene?: string
}let weixin = false;
let readyReg = false;
let wxConfigState = -1;
let wxMpH5 = false;
let wxMpApp = '';
// let wxMpToken = '';const Weixin = {initStepsArray: [1000, 2000, 4000, 8000, 16000, 32000, 64000],initI: 0,erred: false,readyed: false,shareInfo: <undefined | ShareInfo>undefined,// 如果wx授权失败,则定时再次获取授权wxConfigRe(e?: any) {console.log('wxConfig error ' + e)// alert('wxConfig error ' + JSON.stringify(e))Weixin.erred = true// @ts-ignoresetTimeout(Weixin.wxConfig, Weixin.initI < Weixin.initStepsArray.length ? Weixin.initStepsArray[Weixin.initI++] : Weixin.initStepsArray[Weixin.initStepsArray.length - 1])},// 通过config接口注入权限验证配置wxConfig() {let authUrl = location.hrefwxConfigState++switch (wxConfigState) {case 1:authUrl = Ainit.h5Hrefbreak// case 2:// authUrl = location.protocol + '//' + location.host + location.pathname + location.search + location.hash// breakdefault:wxConfigState = 0break}//调接口授权的方法可以自己写App.client.plt.reqA(-1, 'C/wxConfig', [axConfig.webType, authUrl], function (err, rep) {console.log('pltClient C/wxConfig err,data:', err, rep)if (rep && rep.appId) {// rep.debug = truerep.jsApiList = ['updateAppMessageShareData','updateTimelineShareData','onMenuShareAppMessage','onMenuShareTimeline',"getLocation","scanQRCode",// 'wx-open-launch-weapp',// 'chooseWXPay']// rep.debug = trueconsole.log('wxready wx.config')Weixin.erred = false// @ts-ignorewx.config(rep)// @ts-ignorewx.error(Weixin.wxConfigRe)let readyFun = function () {if (Weixin.erred) {return}Weixin.readyed = true}if (readyReg) {setTimeout(readyFun, 1000);} else {readyReg = true// @ts-ignorewx.ready(readyFun)}return;}Weixin.wxConfigRe()})},wxShare(v: ShareInfo) {console.log('h5 wxShare alert', v);if (weixin) {// @ts-ignorev = typeof (v) === 'object' ? v : JSON.parse(v)if (!Weixin.readyed) {Weixin.shareInfo = vreturn}delete Weixin.shareInfovar share = {title: v.title || 'xx', // 分享标题desc: v.desc || '', // 分享描述link: v.link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致imgUrl: v.imageUrl || v.logo || v.imgUrl, // 分享图标success: (e) => {console.log('wxShare success ', e)// 显示微信分享// @ts-ignore// if (window.WeixinJSBridge) {// // @ts-ignore// window.WeixinJSBridge.call('showOptionMenu')// }if (window.wx && window.wx.showMenuItems) {// @ts-ignorewindow.wx.showMenuItems({menuList: ['menuItem:share:appMessage','menuItem:share:timeline','menuItem:favorite','menuItem:share:qq','menuItem:share:QZone',]})}},fail: function (e) {console.log('wxShare fail', e)}}console.log('updateWx', share)// @ts-ignorewx.updateAppMessageShareData(share)// @ts-ignorewx.updateTimelineShareData(share)// WeixinJSBridge.call("showOptionMenu");}},// 静默授权snsapi_base() {var backUri = Ainit.h5Href || location.hrefconsole.log(backUri)var redirectUri = axConfig.pltH5 + 'static/wx.html?u=' + Base64.encode64(backUri, true)redirectUri ='https://open.weixin.qq.com/connect/oauth2/authorize?appid=' + (axConfig.webType == 'wdysjh5' ? 'wxab385cf8a7ec96d8' : 'wx59a0fb7a9bd076e5') + '&redirect_uri=' +encodeURIComponent(redirectUri) +'&response_type=code&scope=snsapi_userinfo&state=1'console.log(redirectUri)location.replace(redirectUri)// setTimeout(() => {// location.replace(redirectUri)// }, 3000);},isWeiXin() {return weixin;},isWxMpH5() {return wxMpH5},getWxMpApp() {return wxMpApp},initWxMpH5(mpid: string, ver?: string) {console.log('initWxMpH5 ' + mpid)weixin = falsewxMpH5 = trueif (mpid) {wxMpApp = mpid} else {console.log('initWxMpH5 no mpid' + location.href)console.log(launcher.h5Href)console.log(launcher.h5Search)}Artist.getReviewVersion(`mp-${ver}`)// 消息通道setInterval(function () {let msg = localStorage.getItem('_mpmsg_')if (msg) {try {msg = JSON.parse(msg)if (!mpid || msg[0] === mpid) {// 是发给我的消息msg = msg[1]msg = Base64.decode64(msg)let i = msg.indexOf(',')if (i > 0) {Weixin.onWxMpMsg(msg.substring(0, i), msg.substring(i + 1))} else {Weixin.onWxMpMsg(msg, '')}localStorage.removeItem('_mpmsg_')}} catch (e) {console.error(e)localStorage.removeItem('_mpmsg_')}}}, 100)},onWxMpMsg(key: string, val?: string) {console.log('onWxMpMsg,' + key + ',' + val)if (key == 'pay') {console.log('updatePay,更新支付状态' + key)uni.$emit('updatePay', { msg: '更新支付状态' })}// @ts-ignorewx.miniProgram.navigateBack()let fun = Weixin.onWxMpCenter[key]if (fun) {fun(val)}},forWxMpToken(back: (err?: any) => void) {if (User.status.authPar) {back && back()return}// @ts-ignorelet nextT = ab_.nextT()// @ts-ignoreWeixin['forWxMpTokenBacks'] = [nextT, back]// @ts-ignorewx.miniProgram.navigateTo({ url: '/pages/msg/post?loginA=' + nextT })},onWxMpCenter: {loginA(val: string) {let paras = JSON.parse(val)let nextT = 0let back: anylet loginA = falseif (typeof (paras[0]) === 'number') {loginA = truenextT = paras[0]paras = ab_.args(paras, 1, paras.length)let backs = Weixin['forWxMpTokenBacks']if (backs) {delete Weixin['forWxMpTokenBacks']if (backs[0] === nextT) {back = backs[1]}}}let noRep = nextT && User.state.loginedUser.loginProvBack('wx', (succ, rep) => {console.log('loginA ', succ, rep)if (succ) {Page.loginSuccBack()if (loginA) {// @ts-ignorewx.miniProgram.navigateBack()}} else if (!User.state.authing && !nextT) {console.log('toLogin--------')Weixin.postWxMpMsg('toLogin')}// 回调back && back(User.status.authToken ? undefined : rep)}, paras, false, 2, false, noRep)},loginAFail(val: string) {let paras = JSON.parse(val)let nextT = paras[0]let backs = Weixin['forWxMpTokenBacks']if (backs) {delete Weixin['forWxMpTokenBacks']if (backs[0] === nextT) {backs[1] && backs[1](paras[1])}}},loginInfo(val: string) {//let loginInfo = JSON.parse(val)let paras = JSON.parse(val)if (User.status.authToken) {paras[1] = User.status.authToken}User.loginProvBack('wx', (succ) => {if (succ) {Page.loginSuccBack()} else if (!User.state.authing) {User.status.authToken = ''}}, paras, true, 2)},bindWx(val: string) {uni.$emit('updateBindWx', { msg: val })}},postWxMpMsg(key: string, val?: string) {console.log('postWxMpMsg,' + key + ',' + val)if (key === 'toLogin') {// ios 微信新用户第一次登录 会导致不执行此逻辑setTimeout(() => {// @ts-ignorewx.miniProgram.navigateTo({ url: '/pages/index/login?t=' + User.status.authToken })}, 400);return}// if (key === 'toLoginA') {// // @ts-ignore// wx.miniProgram.navigateTo({ url: '/pages/index/login' })// return// }if (key === 'share') {// @ts-ignorewx.miniProgram.navigateTo({ url: '/pages/msg/share?s=' + val })return}let msg = val ? (key + ',' + val) : keysetTimeout(() => {// @ts-ignorewx.miniProgram.navigateTo({ url: '/pages/msg/reciver?msg=' + Base64.encode64(msg) })}, 400);console.log('postWxMpMsg.navigateTo');},
}// #ifdef H5
try {// 微信环境判断let userAgent: any = window.navigator.userAgent.toLowerCase();weixin =userAgent.match(/MicroMessenger/i) == "micromessenger" &&!(window.parent && window.parent !== window);//兼容 微信支付路径if (weixin) {let h5Uri = location.href;if (h5Uri.indexOf('/#/') < 0) {// axCc.Loader().wait("weixinHref");try {h5Uri = location.origin + location.pathname + "#/" + location.searchlocation.href = h5UrisetTimeout(() => {location.reload()}, 1000);axCc.Loader().wait("weixinHref");} catch (error) {}}}} catch (e) {console.error(e);
}
// #endifexport default Weixin;
3、公共h5跳转页
<html><head><meta charset="utf-8" /><metaname="viewport"content="width=device-width,initial-scale=1.0,maximum-scale=1,viewport-fit=cover"/><title>···</title><style>#loadingBg {width: 100vw;height: 100vh;position: fixed;z-index: 10000;top: 0;}body {margin: 0px;font-size: 12px;}#preloader {position: absolute;width: 30px;height: 30px;background: rgba(253, 87, 17, 1);border-radius: 50px;left: 0;right: 0;top: 0;bottom: 0;margin: auto;-webkit-animation: preloader_1 1.5s infinite linear;-moz-animation: preloader_1 1.5s infinite linear;-ms-animation: preloader_1 1.5s infinite linear;animation: preloader_1 1.5s infinite linear;}#preloader:after {position: absolute;width: 50px;height: 50px;border-top: 10px solid rgba(255, 139, 9, 1);border-bottom: 10px solid rgba(255, 139, 9, 1);border-left: 10px solid transparent;border-right: 10px solid transparent;border-radius: 50px;content: "";top: -20px;left: -20px;-webkit-animation: preloader_1_after 1.5s infinite linear;-moz-animation: preloader_1_after 1.5s infinite linear;-ms-animation: preloader_1_after 1.5s infinite linear;animation: preloader_1_after 1.5s infinite linear;}@-webkit-keyframes preloader_1 {0% {-webkit-transform: rotate(0deg);}50% {-webkit-transform: rotate(180deg);background: #ff4f11;}100% {-webkit-transform: rotate(360deg);}}@-webkit-keyframes preloader_1_after {0% {border-top: 10px solid rgba(253, 87, 17, 1);border-bottom: 10px solid rgba(255, 139, 9, 1);}50% {border-top: 10px solid rgba(253, 87, 17, 1);border-bottom: 10px solid rgba(253, 87, 17, 1);}100% {border-top: 10px solid rgba(255, 139, 9, 1);border-bottom: 10px solid rgba(255, 139, 9, 1);}}@-moz-keyframes preloader_1 {0% {-moz-transform: rotate(0deg);}50% {-moz-transform: rotate(180deg);background: #ff4f11;}100% {-moz-transform: rotate(360deg);}}@-moz-keyframes preloader_1_after {0% {border-top: 10px solid rgba(255, 139, 9, 1);border-bottom: 10px solid rgba(255, 139, 9, 1);}50% {border-top: 10px solid rgba(253, 87, 17, 1);border-bottom: 10px solid rgba(253, 87, 17, 1);}100% {border-top: 10px solid rgba(255, 139, 9, 1);border-bottom: 10px solid rgba(255, 139, 9, 1);}}@-ms-keyframes preloader_1 {0% {-ms-transform: rotate(0deg);}50% {-ms-transform: rotate(180deg);background: #ff4f11;}100% {-ms-transform: rotate(360deg);}}@-ms-keyframes preloader_1_after {0% {border-top: 10px solid rgba(255, 139, 9, 1);border-bottom: 10px solid rgba(255, 139, 9, 1);}50% {border-top: 10px solid rgba(253, 87, 17, 1);border-bottom: 10px solid rgba(253, 87, 17, 1);}100% {border-top: 10px solid rgba(255, 139, 9, 1);border-bottom: 10px solid rgba(255, 139, 9, 1);}}@keyframes preloader_1 {0% {transform: rotate(0deg);}50% {transform: rotate(180deg);background: #ff4f11;}100% {transform: rotate(360deg);}}@keyframes preloader_1_after {0% {border-top: 10px solid rgba(255, 139, 9, 1);border-bottom: 10px solid rgba(255, 139, 9, 1);}50% {border-top: 10px solid rgba(253, 87, 17, 1);border-bottom: 10px solid rgba(253, 87, 17, 1);}100% {border-top: 10px solid rgba(255, 139, 9, 1);border-bottom: 10px solid rgba(255, 139, 9, 1);}}</style></head><script>function getPara(name) {var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");var r = window.location.search.substr(1).match(reg);if (r != null) {return unescape(r[2]);}return null;}let uid = getPara("uid");let msg = getPara("msg");if (msg) {localStorage.setItem("_mpmsg_", JSON.stringify([uid, msg]));}</script><body><div id="loadingBg"><div id="preloader"></div><!-- <div>加载中</div> --></div></body>
</html>相关文章:
uniapp 微信小程序webview 和 h5数据通信
项目是uniapp编写,因为是先开发了h5和app,小程序是突然要用的,做兼容开发已经来不及,由于微信小程序webview载入h5 因为通信必须要特殊限制(网页向小程序 postMessage 时,会在以下特定时机触发并收到消息&a…...
SSM01-MyBatis框架(一文学会MyBatis)
Mybatis框架 一、Mybatis框架简介 1.1 传统JDBC的缺陷 (1)数据库连接创建、释放频繁会造成系统资源浪费 【MyBatis通过在核心配置文件中配置数据路连接池解决此问题】 (2) SQL语句在代码中硬编码(PreparedStatement向占位符传…...
【PlantUML系列】状态图(六)
一、状态图的组成部分 状态:对象在其生命周期内可能处于的条件或情形,使用 state "State Name" as Statename 表示。初始状态:表示对象生命周期的开始,使用 [*] 表示。最终状态:表示对象生命周期的结束&…...
JS中重排和重绘的区别是什么?
在JavaScript中,当DOM(文档对象模型)发生变化时,浏览器需要重新计算和更新渲染树,这个过程通常涉及到重排(reflow)和重绘(repaint)。了解这两者之间的区别对于优化页面性…...
工业—使用Flink处理Kafka中的数据_ProduceRecord2
使用 Flink 消费 Kafka 中 ProduceRecord 主题的数据,统计在已经检验的产品中,各设备每 5 分钟 生产产品总数,将结果存入HBase 中的 gyflinkresult:Produce5minAgg 表, rowkey“...
C 库中的断言与 FreeRTOS 中的 trace 宏
在 C 编程领域,断言和 FreeRTOS 中的 trace 宏都有着独特而重要的作用。 一、断言(assert) 断言在一般的 C 库中是一个非常有用的工具,它以函数的形式存在。其核心作用在于对程序中的逻辑条件进行检查,确保特定的表达…...
JAVAWeb中的Servlet学习
一 Servlet简介 1.1动态资源和静态资源 静态资源 无需在程序运行时通过代码运行生成的资源,在程序运行之前就写好的资源.例如:html css js img ,音频文件和视频文件 动态资源 需要在程序运行时通过代码运行生成的资源,在程序运行之前无法确定的数据,运行时动态生成,例如Servle…...
docker安装ddns-go(外网连接局域网)
docker先下载镜像,目前最新版是v6.7.6 也可以csdn资源下载 再导入dockers https://download.csdn.net/download/u014756339/90096748 docker load -i ddns-go.tar 启动 docker run -d --name ddns-go --restartalways --nethost -v /opt/ddns-go:/root jeessy/…...
时间复杂度度详解
时间复杂度是衡量算法性能的重要指标,用来描述算法随着输入规模 n 增大,运行时间的增长趋势。以下是时间复杂度的核心概念与常见分类的详细讲解。 1. 时间复杂度的定义 时间复杂度反映了算法执行的 基本操作数量 与输入规模 n 的关系。它通常使用大 O表示法来表示,即: 其中…...
如何处理和优化大文件上传和下载
如何处理和优化大文件上传和下载 简单来说 文件过大会导致内存溢出,上传和下载过慢会影响用户体验,不合理的设计可能引发安全问题,还有网络问题,数据完整性,服务器压力等 文件过大,内存溢出,…...
QT 线程锁
在 Qt 中,线程锁是用来同步多线程访问共享资源的机制,防止数据竞争和线程安全问题。Qt 提供了几种线程锁和同步工具,主要包括以下几种: 1. QMutex 功能:QMutex 是 Qt 中最常用的互斥锁(mutex)…...
光猫开DMZ教程
本教程以移动光猫未例,具体操作以实际光猫为准 1、登录移动光猫管理后台 打开浏览器,在浏览器地址栏输入移动光猫登录管理地址192.168.1.1或者tplogin.cn 按“回车键”打开登录页面,然后输入路由器管理密码登录。 移动光猫登录页面 超级密…...
分区之间的一种度量方法-覆盖度量(Covering Metric)
分区之间的一种度量方法——覆盖度量(Covering Metric),用于量化一个分区如何被另一个分区覆盖或近似。以下是逐步详细解释: 1. 背景与符号说明 分区的概念: 分区是将一个集合(这里是 { 1 , … , n } \{…...
cocos creator接入字节跳动抖音小游戏JSAPI敏感词检测(进行文字输入,但输入敏感词后没有替换为*号)
今天更新了某个抖音小游戏的版本,增加了部分剧情,半天过后一条短信审核未通过,emmm…抖音总是能给开发者惊喜…打开电脑看看这次又整什么幺蛾子… 首先是一脸懵逼,后端早已接入了官方的内容安全检测能力了(https://de…...
13.Java IO 流(文件流、字符流、字符处理流、字节处理流、对象处理流、标准流、转换流、打印流、Properties 配置文件、其他流)
一、文件引入 1、文件的概念 文件是保存数据的地方(例如,文档,图片,音视频等) 2、文件流 流:数据在数据源(文件)和程序(内存)之间经历的路径 输入流&…...
掌握 DOM 操作:让你的网页动起来
文章目录 前言一、什么是 DOM?二、DOM 树的结构三、使用 JavaScript 操作 DOM总结前言 在现代 Web 开发中,动态交互几乎是每个网站的标配。而这种交互的实现,离不开 DOM(Document Object Model) 的操作。本次课程深入讲解了 DOM 的基础知识以及如何使用 JavaScript 操作 …...
JVM整理部分面试题
1.如何主动触发垃圾回收? 在Java中,垃圾回收是自动进行的,由Java虚拟机(JVM)负责管理。但是,有时候我们可能希望手动触发垃圾回收以释放一些无用的对象。这可以通过调用System.gc()方法来实现 手动触发垃…...
ubuntu20 使用 pyspacemouse获取 spacemouse wireless 输入
1. 设置设备权限 (1) 默认情况下,普通用户可能没有权限访问 HID 设备,可以通过设置 udev 规则解决: cd /etc/udev/rules.d sudo touch 99-spacemouse.rules sudo gedit 99-spacemouse.rules在新建的99-spacemouse.rules中添加以下内容 SUB…...
windows下Qt5自动编译配置QtMqtt环境(11)
文章目录 [toc]1、概述2、准备1.1 下载源码1.2 配置环境1.3 解释原理 3、编译4、验证5、参考6、视频 更多精彩内容👉内容导航 👈👉Qt网络编程 👈 1、概述 Qt默认是不包含mqtt库的,如果需要使用到mqtt库就只能自己编译配…...
速盾:高防cdn有哪些冷知识?
高防CDN(Content Delivery Network)是一种用于提供高可靠性、高性能的互联网服务的技术。它通过将内容分发到离用户最近的服务器上,并优化网络流量,以提升网站的响应速度和承载能力。除了这些基本的了解,下面是一些高防…...
7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
DingDing机器人群消息推送
文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人,点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置,详见说明文档 成功后,记录Webhook 2 API文档说明 点击设置说明 查看自…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...
[特殊字符] 手撸 Redis 互斥锁那些坑
📖 手撸 Redis 互斥锁那些坑 最近搞业务遇到高并发下同一个 key 的互斥操作,想实现分布式环境下的互斥锁。于是私下顺手手撸了个基于 Redis 的简单互斥锁,也顺便跟 Redisson 的 RLock 机制对比了下,记录一波,别踩我踩过…...
解决MybatisPlus使用Druid1.2.11连接池查询PG数据库报Merge sql error的一种办法
目录 前言 一、问题重现 1、环境说明 2、重现步骤 3、错误信息 二、关于LATERAL 1、Lateral作用场景 2、在四至场景中使用 三、问题解决之道 1、源码追踪 2、关闭sql合并 3、改写处理SQL 四、总结 前言 在博客:【写在创作纪念日】基于SpringBoot和PostG…...
