图片禁用长按保存属性 pointer-events: none;
可以采用第一种 给img全局设置属性,然后那些在img上绑定事件处理的可以在外面包一层div把handle 提到父级,然后那些需要分享的只需要加个class即可
// 分享页可保存
.able-save {
pointer-events: auto;
}
// 长按图片禁止保存
img {
pointer-events: none;
}
复制代码
// 长按图片禁止保存
.disable-save {
pointer-events: none;
}
复制代码
css实现宇宙同心圆动态
// 宇宙背景动画
.round1 {
height: 10rem;
width:10rem;
border:1px solid rgba(255,255,255,0.13);
border-radius:50%;
position:absolute;
top: 10%;
left:-50%;
animation:rotate1 16s linear infinite;
}
// keyframes值为animation值的第一项
@keyframes rotate1 {
0% {transform : rotate(0deg);}
100% {transform : rotate(360deg);}
}
.round1-child {
height:10px;
width:10px;
position:absolute;
background-color:#999999;
border-radius:50%;
top:3.9rem;
}
<div className="round1">
<div className="round1-child" />
</div>
复制代码
query带有特殊字符的参数
一定要先encodeURIComponent 再# decodeURIComponent 否则会造成参数丢失拿不到 比如+这样的字符
ios手机左上角返回按钮触发后H5页面没有重新加载问题
解决办法:在上一页useEffect中添加
window.addEventListener('pageshow', event => {
if (event.persisted) {
location.reload()
}
})
复制代码
即可实现页面刷新
Jsbridge
/* eslint-disable no-unused-ex
// eslint-disable-next-line import/no-mutable-exports
const isAndroid = /android/.test(navigator.userAgent.toLowerCase())
const isiOS = /ios|iphone|ipad|ipod/.test(navigator.userAgent.toLowerCase())
const successCode = 1
/**
* initJSBridge 初始化
* @param {*} callback
* @returns
*/
export function initJSBridge(callback) {
if (isAndroid) {
if (window.WebViewJavascriptBridge) {
callback(window.WebViewJavascriptBridge)
} else {
document.addEventListener(
'WebViewJavascriptBridgeReady',
() => {
callback(window.WebViewJavascriptBridge)
},
false,
)
}
} else if (isiOS) {
if (window.WebViewJavascriptBridge) {
return callback(window.WebViewJavascriptBridge)
}
if (window.WVJBCallbacks) {
return window.WVJBCallbacks.push(callback)
}
window.WVJBCallbacks = [callback]
const WVJBIframe = document.createElement('iframe')
WVJBIframe.style.display = 'none'
WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__'
document.documentElement.appendChild(WVJBIframe)
setTimeout(() => {
document.documentElement.removeChild(WVJBIframe)
}, 0)
}
}
/**
* 仅供安卓初始化
* @param {*} bridge
*/
export function androidInit(bridge) {
window.JSBridge = bridge
if (isAndroid) {
window.JSBridge.init((message, responseCallback) => {
const data = { 'Javascript Responds': message }
if (responseCallback) {
responseCallback(data)
}
})
}
}
/**
* 注册方法
* @param {*} typeArr 多种注册类型
* @param {*} fn 回调使用
* @param {*} openShare 仅供安卓使用
* openShare:{
* title
* shareImg
* shareUrl
* shareDes
* shareType
* }
*/
export function registerHandler(typeArr, fn, openShare) {
window.JSBridge.registerHandler('nativeToJs', message => {
if (message) {
// 直接获取newMsg, 如贴片
const newMsg = JSON.parse(message)
if (!typeArr) {
fn(newMsg)
return
}
// 安卓注册初始化、设置头部、右上角分享、头部事件配置、页面前后台切换等
if (Array.isArray(typeArr)) {
typeArr.forEach(item => {
if (newMsg.optionType === 'onInit' && isAndroid && openShare) {
// 安卓使用jsbridge,必须重新接收右上角...分享功能
window.JSBridge.call('setHeadMenu', {
rightOption: [{
optionType: 'h5HandleShare',
}],
}, () => { })
} else if (newMsg.optionType === item) {
if (openShare && isAndroid) {
// 安卓使用jsbridge,必须重新接收右上角...分享功能
const newShareConfig = {}
newShareConfig.title = openShare.title
newShareConfig.imgUrl = openShare.shareImg
newShareConfig.shareUrl = openShare.shareUrl
newShareConfig.description = openShare.shareDes
newShareConfig.shareType = openShare.shareType || 0
window.JSBridge.call('openShare', newShareConfig, () => { })
} else {
fn(item)
}
}
})
}
}
})
}
/**
* 保存图片至相册
* @param {*} imgUrl
* @param {*} Toast
* @param {*} toastConfig
* @returns
*/
export async function JSBSaveImage(imgUrl, Toast, toastConfig) {
if (!imgUrl) {
Toast.fail(toastConfig ? toastConfig.fail : '保存失败')
return
}
Toast.loading(`${toastConfig ? toastConfig.loading : '保存中...'}`, 0)
if (window.BluedJSBridge) {
window.BluedJSBridge.call('saveImage', {
imgUrl,
}, res => {
if (res) {
Toast.hide()
const newData = JSON.parse(res)
if (newData.code === successCode) {
Toast.success(toastConfig ? toastConfig.success : '保存成功')
} else {
Toast.fail(toastConfig ? toastConfig.fail : '保存失败')
}
} else {
console.log('\n[🍒JSBLOG] ——> 🌻🙏🌻 JSBSaveImage error 👉', res)
}
})
}
}
import { initJSBridge, androidInit, registerHandler } from '@utils/jsbridge'
const { env, shareConfig } = window.CONFIG
useEffect(() => {
// ================= 引用jsbridge开始 ===================
if (env === 'native') {
initJSBridge(bridge => {
androidInit(bridge)
// 需要setHeadMenu头部 可以在此位置写,不需要可不写。
// 比如 BluedJSBridge.call('setHeadMenu', {}) 具体用法参看下面step2
const typeArr = ['onInit', 'h5HandleShare'] //registerHandler使用
registerHandler(typeArr, (res) => {
// tips: 此处也可以setHeadMenu头部,只是只有iOS生效,安卓不生效
// do something 自定义逻辑
}, shareConfig) // shareConfig,安卓重新配置右上角...分享使用,不使用可不传
})
}
}, [])
网页分享微信配置经验记录
一、问题介绍
- 从端内App分享H5网页到微信,再从微信进行二次分享,出现如下图非理想状态的卡片:
- 从微信进行二次分享,应出现如下图理想状态的卡片:
二、原因分析 因迁移至腾讯云,导致H5链接的出口IP,未配置到公众号管理后台IP白名单,导致获取微信分享access_token失败,影响到微信的二次分享。
三、解决方案
- 配置IP白名单: 登录您授权的公众号管理后台(mp.weixin.qq.com),在左侧导航下拉到最底找到【开发-基本配置】,点击IP白名单【配置】。
- 在IP白名单配置框里,输入如下两个IP地址,点击确认修改即可。(注:多个IP地址需用回车隔开)
upload组件视频上传显示为音频解决方案
问题描述 upload上传MP4视频,页面展示为音频播放器,并且仅能播放声音,没有画面显示,如图
问题原因
MP4有三种编码方式,分别为:mpg4(xdiv),mpg4(xvid),avc(h264/h265) H5 标签仅提供了一种解码器:h.264 解码
其他平台需要查看依赖包提供的解码器种类
问题定位 - 需要获取问题视频的 原视频 ,获取原视频时 不要 使用微信,飞书等聊天工具直接传输,建议压缩包传输(直接传输,部分聊天工具为了可以正常播放,会进行有损转码) - 查看原视频文件后缀是否为 .mp4 - 查看原视频是否可以在本机播放器中正常播放
以上情况均符合的情况下,大概率是视频编码问题,查看视频编码方式如下
mac: 右键视频文件 -> 显示简介
Linux & windows 目前没有直接显示方案,只能借助 vlc 播放器 或 ffmpeg 进行查看
#ffmpeg 查看命令
ffmpeg -i [videoPath]/[videoName]
#例如
ffmpeg -i C:\Users\Admin\Desktop\video.mp4
如 Stream 或 encoder 字段显示的不是 h264 编码,例如
则可以确定是视频编码问题,通知业务方或自行转码。转码方式可以使用格式工厂,或直接使用 ffmpeg
#ffmpeg 视频转码命令
ffmpeg -i [videoPath] -vcodec h264 -preset fast -b:v 2000k [outputPath]
#例如
ffmpeg -i Downloads/video.mp4 -vcodec h264 -preset fast -b:v 2000k Downloads/output.mp4
# -preset: 清晰度参数,从左到右清晰度依次增加,转码速度依次降低
# ultrafast、superfast、veryfast、faster、fast、medium、slow、slower、veryslow
目前 js 层面不支持视频/音频文件解码器类型判断,也不支持音视频转码操作,如有音视频编解码方式判断需求,需要使用 nodejs 调用 ffmpeg 库进行操作,不建议在当前业务场景中使用
使用html2canvas的躲坑经验
-
图片跨域问题 useCORS:true,allowTaint:false
若同时设置为 allowTaint: true ,会认为画布已被污染而不可用。在IphoneSE手机上会走不进去html2canvas的then方法。
-
图片显示半截或者图片无法显示问题
-
截取部分尽量少用或者不用absolute定位。
-
图片全部加载完成后,再调用生成图片方法。
-
适当加延迟再调用html2canvas。
-
UI给的图要求不能过大.我的活动400多k就会有问题。
后续: html2canvas大家使用过程中遇到奇怪的问题,也可以从issue里面翻翻解决办法~附上地址:github.com/niklasvh/ht…