h5 打开小程序 wx-open-launch-weapp 踩坑
towry opened this issue · comments
关键词:"wx-open-launch-weapp 安卓不显示"
对于一些问题,请直接看最下面的问题汇总。
首先,官方文档在这里,之前一直就没看到过。https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_Open_Tag.html
目前我测试的情况是:
- 支持 js 动态插入
wx-open-launch-weapp
标签。 - 自定义样式还是可以的,我的解决方案是将这个自定义标签用一个 div 包着,然后 absolute 定位在某个元素上面透明显示。
封装的 vue 基础组件,这个组件会以 position: absolute
的形式,悬浮在其他元素上面,透明看不到,但是可以点击到。在侦测设备不支持的时候,可以设置 disabled=false,这样该组件就会不显示。:
/**
* @description 展示一个透明的打开微信小程序的按钮,悬浮在其他元素上面。
*
* @see https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_Open_Tag.html
*
* @example
* ```html
* <open-weapp-plast :disabled="false" appid="123456" path="your_path" />
* ```
*/
import uniqueId from "lodash/uniqueId";
import { Component, Prop, Vue, Watch } from "vue-property-decorator";
import { convertToUnit } from "../../vue/utils/helper";
/**
* @emits warn - 警告,组件未准备好。
* @emits click - 用户点击了打开小程序的按钮。
* @emits ready - 组件OK,用户可以准备点击了。
* @emits error - 错误发生了。
*/
@Component
export default class OpenWeappPlast extends Vue {
/**
* 是否被禁用。
*/
@Prop(Boolean) disabled!: boolean;
/**
* 小程序原始账号 ID(gh_ 开头的)
*/
@Prop(String) appid!: string;
/**
* 要跳转到的页面路径
*/
@Prop(String) path!: string;
/**
* 是否要阻止事件的默认行为。
*/
@Prop(Boolean) preventDefault!: boolean;
/**
* 因兼容性问题无法使用标签的。
*/
disabledLazy = false;
isReady = false;
uniqueid = uniqueId("wxopen_");
get isDisabled() {
return this.disabled || this.disabledLazy;
}
@Watch("isDisabled")
onDisabledChange(newVal: boolean) {
if (!newVal) {
this.$nextTick(() => {
this.onUpdate();
});
}
}
created() {
document.addEventListener("WeixinOpenTagsError", (e: any) => {
let errMsg = e.detail || "";
errMsg = e.detail.errMsg
? e.detail.errMsg
: typeof e.detail === "string"
? e.detail
: "Unknown";
this.$emit("error", new Error(errMsg));
this.disabledLazy = true;
});
}
mounted() {
this.onUpdate();
}
private getSelfSize() {
const el = this.$el;
if (!el) {
return {
width: 0,
height: 0,
};
}
const box = el.getBoundingClientRect();
return {
width: box.width,
height: box.height,
};
}
private onUpdate() {
this.inject();
this.addEvent_();
}
/**
* 监听元素显示.
*/
private addVisibleObserver() {
if (!window.IntersectionObserver || !this.$el) {
return;
}
const observer = new IntersectionObserver(
(entries, ob) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
if (entry.intersectionRatio >= 0.75) {
ob.disconnect();
this.onUpdate();
}
}
});
},
{
root: null,
rootMargin: "0px",
threshold: [0.0, 0.75],
}
);
observer.observe(this.$el);
}
private addEvent_() {
if (this.isDisabled) {
return;
}
const el = document.getElementById(this.uniqueid);
if (!el) {
return;
}
el.addEventListener("error", (e: any) => {
e = e || {};
const eDetail = e.detail || {};
let errMsg = e.detail || "";
errMsg = eDetail.errMsg
? eDetail.errMsg
: typeof e.detail === "string"
? e.detail
: "Unknown";
console.error(errMsg);
this.$emit("error", new Error(errMsg));
this.disabledLazy = true;
});
el.addEventListener("launch", (event: any) => {
console.log(`${this.uniqueid} is launched`);
this.$emit("click", event);
});
el.addEventListener("ready", () => {
console.log(`${this.uniqueid} is ready`);
this.$emit("ready");
this.isReady = true;
});
}
/**
* 能否渲染成功,和微信 jssdk 有关系。
* 注意!如果元素刚开始是 hide 的,因为无法拿到容器的宽高,导致微信的开放按钮的宽高为0的话,
* 会出现点击没反应。
*/
private inject() {
if (this.isDisabled) {
return;
}
const mainText = `<button class="invisible-weapp-button">...</button>`;
const boxSize = this.getSelfSize();
const swidth = convertToUnit(boxSize.width || "100%");
const sheight = convertToUnit(boxSize.height || "100%");
if (!boxSize.width && !boxSize.height && window.IntersectionObserver) {
this.addVisibleObserver();
return;
}
let styleText = `.invisible-weapp-button {
display: block; outline: none; border: none; background-color: transparent; color: transparent; width: ${swidth}; height: ${sheight};
}
`;
const script = this.$refs.weapp as HTMLDivElement;
const style = `<style>${styleText.replace(/\\n/g, "")}</style>`;
if (!script) {
return;
}
const content = style + mainText;
const all =
`
<wx-open-launch-weapp id="${
this.uniqueid
}" style="display: block; width: 100%;height: 100%;" username="${
this.appid
}" ${this.path ? 'path="' + this.path + '"' : ""}>` +
'<script type="text/wxtag-template">' +
content +
"</sc" +
"ript></wx-open-launch-weapp>";
script.innerHTML = all;
}
render() {
const h = this.$createElement;
if (this.isDisabled) {
return null;
}
return h(
"div",
{
staticClass: "OpenWeappPlast",
style: {
width: "100%",
height: "100%",
overflow: "hidden",
position: "absolute",
top: 0,
bottom: 0,
right: 0,
left: 0,
zIndex: 1,
},
on: {
click: (e: MouseEvent) => {
if (e?.stopPropagation) {
e.stopPropagation();
}
if (this.preventDefault && e?.preventDefault) {
e.preventDefault();
}
if (!this.isReady) {
this.$emit("warn");
}
},
},
},
[
h("div", {
style: {
width: "100%",
height: "100%",
},
ref: "weapp",
}),
]
);
}
}
问题汇总
jssdk config 里记得加上 openTagList: ["wx-open-launch-weapp"]
如果点击没反应,检查微信开放按钮样式的宽高是否有被设置,如果宽高为0是不会显示的,因此点击也会没反应的。
CSP
https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_Open_Tag.html
对于有CSP要求的页面,需要添加白名单
frame-src https://*.qq.com webcompt:
,才能在页面中正常使用开放标签。
检查你页面的 response 里,是否有一个字段:"Content-Security-Policy",如果有,说明你的页面要求了 CSP,则修改此字段的值,添加上面说的白名单。
这个问题会导致 ios 下按钮正常显示,但是安卓下不显示,且无事件无报错。
jsApiList 里不能为空。
在微信的社区很多类似答案里贴了这个页面的链接,希望其他人能少踩坑。
另外请注意检查是否复制了官方文档中的代码:
openTagList: [] // 可选,需要使用的开放标签列表,例如['wx-open-launch-app']
上面官方文档中关于 wx-open-launch-weapp
的拼写是错的,排查了半天才发现,就离谱 🙃
最后这个很关键
检查你页面的 response 里,是否有一个字段:"Content-Security-Policy",如果有,说明你的页面要求了 CSP,则修改此字段的值,添加上面说的白名单。这个问题会导致 ios 下按钮正常显示,但是安卓下不显示,且无事件无报错。
调了两天没搞出来 情况一模一样 ios能显示 正常 微信开发者工具调试也正常 安卓不显示 最后是nginx配置了这个加白名单就解决了