uniapp常用tips,bug修复

2,897 阅读8分钟

1.解决uni-app打包H5后会自动请求shadow-grey.png

index.html页面设置样式

body::after { content: none; }

2.修改手机返回键弹出再按一次退出应用文案

// #ifdef APP-PLUS
let main = plus.android.runtimeMainActivity();
//为了防止快速点按返回键导致程序退出重写quit方法改为隐藏至后台
plus.runtime.quit = function(){
	main.moveTaskToBack(false);
};
//重写toast方法如果内容为 ‘再按一次退出应用’ 就隐藏应用,其他正常toast
plus.nativeUI.toast = (function(str){
if(str == '再按一次退出应用'){
	main.moveTaskToBack(false);
	return false;
}else{
	uni.showToast({
		title:str,
		icon:'none',
	})
}
});
// #endif

3.解决Vuex-在F5刷新页面后数据不见

store.js页面设置vuex相关

安装

npm install vuex-persistedstate --save

引⼊及配置 在store下的index.js

import createPersistedState from "vuex-persistedstate"
const store = new Vuex.Store({
 // ...
 plugins: [createPersistedState()]
})

默认存储到localStorage 想要存储到sessionStorage,配置如下

import createPersistedState from "vuex-persistedstate"
const store = new Vuex.Store({
 // ...
 plugins: [createPersistedState({
  storage: window.sessionStorage
 })]
})

想使⽤cookie同理 默认持久化所有state 指定需要持久化的state,配置如下

mport createPersistedState from "vuex-persistedstate"
const store = new Vuex.Store({
 // ...
 plugins: [createPersistedState({
  storage: window.sessionStorage,
  reducer(val) {
    return {
        // 只储存state中的assessmentData
        assessmentData: val.assessmentData
   }
 }
})

4.局部样式

一般都是使用 scoped 方案:

<style lang="scss" scoped>
  ...
</style>

5.场景:uniapp webview src参数重新赋值时H5会重定向,多次点击才能返回上一页。

解决方案:src赋值前先对src进行src=>null处理

6. 项目中H5环境 blur和click事件冲突

click事件改成mousedown事件,mousedown事件优于blur事件

@click => @mousedown.native

7.input number如何禁止输入e和小数点等数学符号

onKeypress="return (/[\d]/.test(String.fromCharCode(event.keyCode)))"

demo:

<input type="number" onKeypress="return (/[\d]/.test(String.fromCharCode(event.keyCode)))">

8. Uniapp开发h5页面输入框软键盘被顶起

问题:当使用uniapp的input时,真机上软键盘将页面顶起的解决方案:
第一步:给input添加class=“uni-input” cursor-spacing=“10”(uniapp文档也有说明)
第二步:pages配置文件对应的页面模块添加**“softinputMode”: “adjustResize”**(uniapp文档也有说明)

"style": {
    "app-plus": {
        //"titleNView": false,
        "softinputMode": "adjustResize"
    }
}

9. 关闭安卓打包提示弹框基座不对应

manifest.json文件添加compatible属性:

"app-plus" : {
    "compatible" : {
        "ignoreVersion" : true
    }
}

10. uniapp中数字串不换行问题

white-space: normal; // 规定段落中的文本不进行换行

//让数字串换行问题 word-break: break-all; // 允许单词中换行,在容器的最右边进行断开不会浪费控件

word-wrap: break-word; // 防止长单词溢出,单词内部短句

自动换行 word-break:break-all和word-wrap:break-word

word-break:break-all和word-wrap:break-word都是能使其容器如DIV的内容自动换行。 1,word-break:break-all 例如div宽200px,它的内容就会到200px自动换行,如果该行末端有个英文单词很长(congratulation等),它会把单词截断,变成该行末端为conra(congratulation的前端部分),下一行为tulation(conguatulation)的后端部分了。 2,word-wrap:break-word 例子与上面一样,但区别就是它会把congratulation整个单词看成一个整体,如果该行末端宽度不够显示整个单词,它会自动把整个单词放到下一行,而不会把单词截断掉的。

11.app设置webview位置 this.scope.scope.getAppWebview()延迟性解决

1、onReady调用this.scope.scope.getAppWebview()

onReady() {
    // #ifdef APP-PLUS
    var currentWebview = this.$scope.$getAppWebview() || this.$parent.$scope.$getAppWebview() //此对象相当于html5plus里的plus.webview.currentWebview()。在uni-app里vue页面直接使用plus.webview.currentWebview()无效,非v3编译模式使用this.$mp.page.$getAppWebview()
    // 处理currentWebview获取延时问题
    this.getWebview(currentWebview);
    // #endif
},

2、methods里面利用递归函数直至获取到currentWebview.children()[0]

methods:{
    getWebview(currentWebview){
            let that = this;
            // console.log("currentWebview.children()[0]",currentWebview.children()[0])
            if(currentWebview&&currentWebview.children()[0]){
                    wv = currentWebview.children()[0]
                    wv.setStyle({top:155,bottom:80})
            }else{
                    setTimeout(function() {
                            // 递归函数直到获取到currentWebview.children()[0]
                            that.getWebview(currentWebview)
                    }, 200);
            }
    },
}

11 uni-app 限制输入两位小数点

<template>
	<view>
		<input v-model="money" type="number" @input="check" placeholder="金额(元)" />
	</view>
</template>
 
<script>
	export default {
		data() {
			return {
				money:''
			}
		},
		methods: {
			check: function(e) {
				//正则表达试
				e.target.value = (e.target.value.match(/^\d*(\.?\d{0,2})/g)[0]) || null
				//重新赋值给input
				this.$nextTick(() => {
					this.money= e.target.value
				})
			},
		},
	}
</script>
 
<style>
</style>

12、 base64转图片

  1. 创建一个base.js文件
const fsm = wx.getFileSystemManager();
const FILE_BASE_NAME = 'tmp_base64src'; //自定义文件名

function base64src(base64data, cb) {
  const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64data) || [];
  if (!format) {
    return (new Error('ERROR_BASE64SRC_PARSE'));
  }
  const filePath = `${wx.env.USER_DATA_PATH}/${FILE_BASE_NAME}.${format}`;
  const buffer = wx.base64ToArrayBuffer(bodyData);
  fsm.writeFile({
    filePath,
    data: buffer,
    encoding: 'binary',
    success() {
      cb(filePath);
    },
    fail() {
      return (new Error('ERROR_BASE64SRC_WRITE'));
    },
  });
};
module.exports = base64src;
  1. 在要用的页面引入
 var base64src = require('../../js/base64.js')
 								var shareQrImg=`data:image/jpg;base64,iVBORw0KGgoAAAANSUhEUgAAAQwAAAErCAYAAAArJb0dAAAgAElEQVR4nNS92Y9l2XXm9zvjPXceY.....`; 		//   base64编码省略号代替,太长了
 	注意:data:image/jpg,jpg也可以是其他图片格式,例如:png,看后端给你返回什么
								console.log(shareQrImg)
								 base64src(shareQrImg, resCurrent => {
								      console.log(resCurrent)    // 返回图片地址,直接赋值到image标签即可(此图片只是本地图片)
 })


//  网络图片转base64编码(此方法没试,留在这里备用)

    let base64 = wx.arrayBufferToBase64(网图地址);
    let userImageBase64 = 'data:image/jpg;base64,' + base64;
    console.log(userImageBase64); // 打印base64格式图片

13、 uni-app弹窗列表滚动, 蒙层下面也跟随滚动解决方案

1.弹窗组件代码,需要在最外层的view中加入@touchmove.stop.prevent="moveHandle",且弹窗中需要滚动的列表要使用scroll-view标签包裹起来,且scroll-y 属性不能忘记加。

<view class="uni-mask" @touchmove.stop.prevent="moveHandle" v-if="showModelLine" @click="hideModelLine">
	<scroll-view :scroll-y="true" class="txt">
                
        </scroll-view>		
</view>
methods: {
    moveHandle() {
            return;
    },
},

14、uni-app打包H5出现“网络不给力,点击屏幕重试”

uni-app默认在弱网或者断网的情况下反馈出来的。可以在manifest.json中延长时间来解决问题。

可参考官方文档:uniapp.dcloud.io/collocation…

 "h5": {
        "title": "演示", //页面标题,默认使用 manifest.json 的 name
        "template": "index.html", //index.html模板路径,相对于应用根目录,可定制生成的 html 代码
        "router": {
            "mode": "history", //路由跳转模式,支持 hash|history ,默认 hash
            "base": "/hello/" //应用基础路径,例如,如果整个单页应用服务在 /app/ 下,然后 base 就应该设为 "/app/"
        },
        "async": { //页面js异步加载配置
            "loading": "AsyncLoading", //页面js加载时使用的组件(需注册为全局组件)
            "error": "AsyncError", //页面js加载失败时使用的组件(需注册为全局组件)
            "delay": 200, //展示 loading 加载组件的延时时间(页面 js 若在 delay 时间内加载完成,则不会显示 loading 组件)
            "timeout": 3000 //页面js加载超时时间(超时后展示 error 对应的组件)
        }
},
"networkTimeout": {
	"request": 6000     //uni.request的settimeout
}

15、 uniapp设置强制竖屏wgt包强制竖屏uniapp锁定屏幕竖直方向

分为三步

  1. 第一步

    uniapp 根目录下pages.json 文件中追加下面四项

"globalStyle": {
    "pageOrientation": "portrait", //横屏配置,全局屏幕旋转设置(仅 APP/微信/QQ小程序),支持 auto / portrait / landscape
    "rpxCalcMaxDeviceWidth": 960,
    "rpxCalcBaseDeviceWidth": 375,
    "rpxCalcIncludeWidth": 750
}
  1. 第二步

    uniapp 根目录下mainfest.json文件中追加如下配置

distribute" : {
"orientation" : ["portrait-primary" ] //重力感应、横竖屏配置
}
  1. 第三步

    在你想强制横竖屏的页面的vue文件中的 onLoad 或者onShow的生命周期里面 加上如下代码即可

//#ifdef APP-PLUS
plus.screen.lockOrientation('portrait-primary');
//#endif

16、 uni-app H5解决IOS音频不能自动播放的问题

先看uniapp的uni.createInnerAudioContext() 接口示例

const innerAudioContext = uni.createInnerAudioContext();
innerAudioContext.autoplay = true;
innerAudioContext.src = 'https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-hello-uniapp/2cc220e0-c27a-11ea-9dfb-6da8e309e0d8.mp3';
innerAudioContext.onPlay(() => {
  console.log('开始播放');
});
innerAudioContext.onError((res) => {
  console.log(res.errMsg);
  console.log(res.errCode);
});

示例在pc和安卓微信客户端是可以自动播放的,IOS就不行了。

所以得通过集成微信JS-SDK验证来解决

通过npm安装方式

npm install jweixin-module --save

然后再引用jweixin-module,可以在main.js上定义或者在单独页面上,首页引用:

<script>
	var jweixin = require('jweixin-module');
	export default {
		components: {},
		data() {
			return {}
		},
		onLoad: function (option) { 
			// this.creatAudio();
		},
		created(){
 
		},
		mounted() {
			this.creatAudio();
		},
		methods: {
			creatAudio(){
				const innerAudioContext = uni.createInnerAudioContext();
                innerAudioContext.autoplay = true;
                innerAudioContext.src = 'https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-hello-uniapp/2cc220e0-c27a-11ea-9dfb-6da8e309e0d8.mp3';
                innerAudioContext.onPlay(() => {
                  console.log('开始播放');
                });
                innerAudioContext.onError((res) => {
                  console.log(res);
                });
				
				jweixin.config({});// 不做任何签名验证都可以
				jweixin.ready(function(){
					WeixinJSBridge.invoke('getNetworkType', {}, function(e){  
						innerAudioContext.play();
					})
				})
			},
	
		}
	}
</script>

17、uniapp 播放音频

//../../static/image/login_bg.png
console.log("=====testClick=====");
let src = '../../static/voice/test.mp3';
//实例化声音  
const Audio = uni.createInnerAudioContext();
Audio.autoplay = true;
Audio.src = src; //音频地址  
Audio.play(); //执行播放  
Audio.onError((res) => {
        console.log(res.errMsg);
        console.log(res.errCode);
});
Audio.onPause(function() {
        console.log('end');
        Audio.destroy();
});

18、 uniapp APP端使用指纹

使用插件指纹模板:

ext.dcloud.net.cn/plugin?id=3…

Fingerprint模块管理指纹识别

要使用指纹识别功能需要具备条件:

  • 确认当前设备环境是否支持指纹识别,
  • 当前设备是否设置密码锁屏,
  • 当前设备是否已经录入指纹。

(Android平台6.0及以上系统支持,只识别标准Android的指纹API,仅适配Google官方指纹识别的标准接口的设备)

以上条件都要满足才可以使用识别功能,识别功能,指的是与手机中已录入的指纹进行比对检测,也就是说,只要与手机中录入任意指纹比对成功,便可进入成功回调。

首先需要获取得到权限:

在 manifest.json文件中配置(指纹识别)

image.png

image.png

目前市场上还是有很多设备不支持指纹,所以要先使用 plus.fingerprint.isSupport()  方法判断(以下三个方法均返回值为Boolean类型)

// #ifdef APP-PLUS
if (!plus.fingerprint.isSupport()) {
   plus.nativeUI.toast('此设备不支持指纹识别');
   console.log('此设备不支持指纹识别')
}
// #endif

再使用   ****plus.fingerprint.isKeyguardSecure()  判断是否开启密码锁屏

// #ifdef APP-PLUS
if (!plus.fingerprint.isKeyguardSecure()) {
   plus.nativeUI.toast('此设备未设置密码锁屏');
   console.log('此设备未设置密码锁屏')
}
// #endif

再然后使用   plus.fingerprint.isEnrolledFingerprints()  判断是否录入指纹

// #ifdef APP-PLUS
if (!plus.fingerprint.isEnrolledFingerprints()) {
   plus.nativeUI.toast('此设备未录入指纹');
   console.log('此设备未录入指纹')
}
// #endif

总结:指纹识别封装为一个方法

fingerprint: function() {
    // #ifdef APP-PLUS
    plus.fingerprint.authenticate(function() {
        console.log('匹配成功');
    }, function(e) {
        switch (e.code) {
            case e.AUTHENTICATE_MISMATCH:
                plus.nativeUI.toast('指纹匹配失败,请重新输入');
                break;
            case e.AUTHENTICATE_OVERLIMIT:
                plus.nativeUI.closeWaiting(); //兼容Android平台关闭等待框
                plus.nativeUI.toast('指纹识别失败次数超出限制,请使用其它方式进行认证');
                break;
            case e.CANCEL:
                plus.nativeUI.toast('已取消识别');
                break;
            default:
                plus.nativeUI.closeWaiting(); //兼容Android平台关闭等待框
                plus.nativeUI.toast('指纹识别失败,请重试');
                break;
        }
    });
    // #endif
},

指纹识别demo:

<template>
	<view>
		<button  class="button_fin" @tap="fingerprint()" :disabled="disabled">按下开始识别指纹</button>
		 
	</view>
</template>
 
<script>
	export default {
		data() {
			return {
				disabled: true
			}
		},
		onLoad() {
			
			// #ifdef APP-PLUS
			if (!plus.fingerprint.isSupport()) {
				uni.showToast({
					title: '此设备不支持指纹识别',
					icon: 'none',
					duration: 2000
				});
		 
				// alert("此设备不支持指纹识别")
				this.disabled = true;
			} else if (!plus.fingerprint.isKeyguardSecure()) {
				uni.showToast({
					title: '此设备未设置密码锁屏,无法使用指纹识别',
					icon: 'none',
					duration: 2000
				});
			 
				this.disabled = true;
			} else if (!plus.fingerprint.isEnrolledFingerprints()) {
				uni.showToast({
					title: '此设备未录入指纹,请到设置中开启',
					icon: 'none',
					duration: 2000
				});
				 
				this.disabled = true;
			} else {
			 
				// this.disabled=true
				this.disabled = false;
			}
			// #endif
			
			// #ifdef MP-WEIXIN
			this.disabled = false;
			 
			uni.showToast({
				title: '请在微信真机中使用,模拟器不支持',
				icon: 'none',
				duration: 2000
			});
			// #endif
			// #ifndef APP-PLUS || MP-WEIXIN
			 
 
			uni.showToast({
				title: '此平台不支持指纹识别',
				icon: 'none',
				duration: 2000
			});
 
			// #endif
			// 初次调用指纹
			// this.fingerprint()
		},
		methods: {			
			fingerprint: function() {
				// #ifdef APP-PLUS
				plus.fingerprint.authenticate(function() {
					plus.nativeUI.closeWaiting(); //兼容Android平台关闭等待框
					// plus.nativeUI.alert('指纹识别成功');
					// plus.nativeUI.alert("指纹识别成功", function(){
					// 		console.log("指纹识别成功");
					// 	}, "指纹验证", "确定");
					  
					uni.showToast({
						title: '指纹识别成功',
						// icon: 'none',
						mask:true,
						image:"/static/FingerprintBlue.png",
						duration: 2000
					});
					// uni.showModal({
					// 	title: '友情提示',
					// 	content: '指纹识别成功',
					// 	success: function(res) {
					// 		if (res.confirm) {
					// 			console.log('用户点击确定');
					// 		} else if (res.cancel) {
					// 			console.log('用户点击取消');
					// 		}
					// 	}
					// });
				}, function(e) {
					switch (e.code) {
						case e.AUTHENTICATE_MISMATCH:
							plus.nativeUI.toast('指纹匹配失败,请重新输入');
							break;
						case e.AUTHENTICATE_OVERLIMIT:
							plus.nativeUI.closeWaiting(); //兼容Android平台关闭等待框
							plus.nativeUI.alert('指纹识别失败次数超出限制,请使用其它方式进行认证');
							break;
						case e.CANCEL:
							plus.nativeUI.toast('已取消识别');
							break;
						default:
							plus.nativeUI.closeWaiting(); //兼容Android平台关闭等待框
							plus.nativeUI.alert('指纹识别失败,请重试');
							break;
					}
				});
				// Android平台手动弹出等待提示框 
				if ('Android' == plus.os.name) {
					// var opt = '{"width":"150px","height":"150px","style": "white",  "color": "#1d8079"}';
					// plus.nativeUI.showWaiting('指纹识别中...', JSON.parse(opt)).onclose = function() {
					// 	plus.fingerprint.cancel();
					// }
					var wt=plus.nativeUI.showWaiting("请验证指纹",{
						width:"200px",
						height:"200px",
						color: "#1d8079",
						mask:true,
						background:"#ffffff",
						loading:{
							icon:"/static/Fingerprint.png"
						}
					});
					wt.onclose=function(){
						plus.fingerprint.cancel();
					}
					 
				 
				}
				// #endif
 
				// #ifdef MP-WEIXIN
				wx.startSoterAuthentication({
					requestAuthModes: ['fingerPrint'],
					challenge: '123456',
					authContent: '请用指纹解锁',
					success(res) {
						uni.showToast({
							title: '识别成功',
							mask: false,
							duration: 1500
						});
					}
				})
				// #endif
			}
		}
	}
</script>
 
<style>
.button_fin{
	background-color: #00BBB1;
	border-radius: 5px ;
	width: 80%;
	color: #D1E9E9;
}
</style>

19、 通过HbuilderX 新建项目创建的uniapp项目如何关闭sockjs-node/info

HBuilderX安装目录下
\plugins\uniapp-cli\node_modules\sockjs-client\dist\sockjs.js
找到代码的 1605行

try {  
  //  self.xhr.send(payload); 把这里注掉  
  } catch (e) {  
    self.emit('finish', 0, '');  
    self._cleanup(false);  
  }

20、uniapp_vue_更改数据后_页面组件的值未刷新

可能原因:可能是对象层数太深了

通用解决办法:控制未刷新组件,先不显示,再显示

1、组件添加v-if控制显示

<view v-for="(item,index) in dataArr" :key="index">     
    <hx-number-box v-if="showNumberBox" v-mode="item.name"></hx-number-box>
</view>

2、刷新方法

// 修改组件双向绑定的数据 
this.dataArr[i].name = 3;
 
//刷新显示
let that = this;
that.showNumberBox = false;
that.$nextTick(()=>{
    that.showNumberBox = true;
})

nextTick会等待下一个时间片执行,即等上面的数据修改完成后。

解决方法2:组件的数据绑定对象,换成一个浅一点的对象

ask.dcloud.net.cn/article/378…

21、 uniapp 输入框防抖节流_函数的节流(throttle)与防抖(debounce)

一、函数节流(throttle)

  1. 理解:

在函数需要频繁触发时: 函数执行一次后,只有大于设定的执行周期后才会执行第二次 适合多次事件按时间做平均分配触发

  1. 场景:

窗口调整(resize) 页面滚动(scroll) DOM 元素的拖拽功能实现(mousemove) - 抢购疯狂点击(click) 抢购疯狂点击(click)

二、函数防抖(debounce)

  1. 理解:

在函数需要频繁触发时: 在规定时间内,只让最后一次生效,前面的不生效。 适合多次事件一次响应的情况 2. 场景:

输入框实时搜索联想(keyup/input)

三、封装

  1. 函数节流-封装
 /* 
    用来返回节流函数的工具函数
*/
function throttle(callback, delay) {
  let pre = 0 // 默认值不要是Date.now() ==> 第1次事件立即调用
  return function (event) { // 节流函数/真正的事件回调函数   this是发生事件的标签
    const current = Date.now()
    if (current - pre > delay) { // 只有离上一次调用callback的时间差大于delay
      // 调用真正处理事件的函数, this是事件源, 参数是event
      callback.call(this, event)
      // 记录此次调用的时间
      pre = current
    }
  }
}
// 使用封装的节流函数
document.addEventListener('scroll',throttle(function() {
  console.log('这是带有大量计算的函数')
},2000))

2. 函数防抖-封装

  /* 
    用来返回防抖函数的工具函数
*/
function debounce(callback, delay) {
  return function (event) {
    // 如果上次事件还没有真正处理, 取消它
    // if (callback.timeoutId) { // 会查找原型链
    if (callback.hasOwnProperty('timeId')) { // 不会查找原型链
      // 清除
      clearTimeout(callback.timeId)
    }

    // 发事件发生指定事件后才调用处理事件的回调函数
    // 启动定时器, 只是准备真正处理
    callback.timeId = setTimeout(() => {
      // 正在处理事件
      callback.call(this, event)
      // 删除准备处理的标记
      delete callback.timeId
    }, delay)
  }
}

// 使用封装的防抖函数
document.querySelector('.input').addEventListener('input',debounce((e)=>{
  console.log(e.target.value)
},1000))

四、直接使用

1. 函数节流-直接使用

// 定义一个记录时间的变量
let flagTime = Date.now()
// 直接使用函数节流
document.addEventListener('scroll',function(e) {
  let current = Date.now()
  // 表示1000毫秒执行一次
  if(current-flagTime<1000) return
  // 执行代码
  console.log('我是带有大量计算的函数')
  // 最后修改原来的时间
  flagTime = current
})

2.函数防抖-直接使用

document.querySelector('.input').addEventListener('input',function(e) {
  // 判断this.timeId是否有值
  if(this.timeId) {
    // 有就清除定时器
    clearInterval(this.timeId)
  }
  // 为 this.timeId赋值,定时器表示1000毫秒内触发了input事件就不执行,只有超过了1000毫秒才执行
  this.timeId = setTimeout(()=>{
    console.log(e.target.value)
  },1000)
})

22、Android webview隐藏后跳转新页面input输入卡顿与白屏渲染慢的问题

Android System WebView 内核的bug:当webview页面中存在持续渲染(如跑马灯效果。banner轮播等)。页面被隐藏后会导致JS阻塞影响页面渲染效率。从66.0.3359.126版本到最新都存在此问题。
注意:

  • 此问题必须是页面隐藏hide后,并且当前页面包含持续渲染(如跑马灯效果。banner轮播等)时才会触发此问题。如果你的页面不会隐藏、没有持续渲染逻辑可忽略此问题。
  • 一般新窗体进入盖住老窗体,不会调用webview的hide方法,不会引发此问题。此问题常见于tabbar的切换,不同tab的webview页面只有一个是显示的,其他是hide的。或者开发者手动调用了plus.webview对象的hide方法。

解决方案:

方案1:  我们推荐开发者在页面被hide后,主动停用持续操作ui的js或css。
在隐藏的页面持续操作视图本身也不合理,影响性能。
在uni-app中,基础组件swiper和扩展uni ui的跑马灯,组件内部会判断,如果当前页面已经不再前台显示,会停止轮播。所以正常使用这些组件也不会遇到问题。
如果开发者引用了未做判断的三方组件,或者自己编写了持续操作视图的代码,则应该注意编写判断代码,在页面hide时,停止这些js或css。然后在恢复显示时,重新启用它们。

在uniapp中实现方案1的代码

//组件内监听webview隐藏停止动画(即将新增组件所在页面的生命周期,可以监听页面隐藏来停止动画)  
mounted() {  
  // #ifdef APP-PLUS  
  const pages = getCurrentPages();  
  let currentWebview = pages[pages.length - 1].$getAppWebview();  
  currentWebview.addEventListener('hide', () => {  
    // webview隐藏,停止动画  
  })  
  currentWebview.addEventListener('show', () => {  
    // webview显示,开启动画  
  })  
  // #endif  
},
//页面内监听页面隐藏停止动画  
onShow() {  
  // 页面显示,开启动画  
},  
onHide() {  
  // 页面隐藏,停止动画  
}

方案2:  当页面被隐藏时主动调用webview的pause方法,暂停这个webview里的所有js和css动画的运行
首先需要升级HBuilderX 2.3.8或更高版本。(如发现版本没更新请等待更新后再操作)
5+提供了新的API ,WebviewObject对象添加pause、resume方法。

  • void pause() 暂停Webview对象,停止js执行、DOM渲染
  • void resume() 恢复Webview对象,恢复js执行、DOM渲染
  • boolean isPause() 是否暂停,暂停则返回ture,否则返回false

uniapp用户(推荐):

nvue页面无此问题。忽略即可。

vue页面:

在页面存在持续渲染(如跑马灯效果。banner轮播等)的情况下。可在页面周期onShow、onHide分别调用webview的resume、pause方法即可

onShow() {  
    const w = this.$mp.page.$getAppWebview();  
    if(w.isPause()){  
        w.resume();  
    }  
},  
onHide() {  
    const w = this.$mp.page.$getAppWebview();  
    w.pause();  
},

5+用户:

可以通过WebviewObject对象控制管理方式规避问题。当调用WebviewObject的show、hide方法时主动调用相关页面的pause、resume方法。

//创建页面 此页面包含持续渲染(如跑马灯效果。banner轮播等)的逻辑存在。  
var a = plus.webview.open('list.html','list');  
//当a页面要隐藏时可调用如下代码  
var a = plus.webview.getWebviewById('list');  
a.hide('none');  
a.pause();  

//当a页面显示时调用如下代码  
var a = plus.webview.getWebviewById('list');  
if(a.isPause()) {  
   a.resume();  
}

23、uniapp与webview之间的相互传值

1.uni-app 如何发送数据到 H5? 其实很接单、在 web-view 中只需要通过 URL 就可以向 H5 进行传参 例如在 uni-app 中:

<template>
    <view class="advertisement" style="width: 100%;">
        <web-view :src="url" @message="message"></web-view>
    </view>
</template>

<script>
export default {
    data() {
        return {
            url:'/hybrid/html/local.html?data='
        };
    },
    onLoad(data) {
     //这里对要传入到webview中的参数进行encodeURIComponent编码否则中文乱码
        this.url+=encodeURIComponent(data.data)
    },
    mounted() {},
    methods: {
        message(event){
            console.log(event.detail.data);
        },
    }
    
};
</script>

<style scoped="scoped" lang="scss">
@import './advertisement.scss';
</style>

在 H5 中是接收值

console.log(getQuery('data'));  //获取 uni-app 传来的值
                   
//取url中的参数值
function getQuery(name) {
    // 正则:[找寻'&' + 'url参数名字' = '值' + '&']('&'可以不存在)
    let reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
    let r = window.location.search.substr(1).match(reg);
    console.log(r);
    if(r != null) {
        // 对参数值进行解码
        return decodeURIComponent(r[2]);
    }
    return null;
}

2.webview向uniapp传值

<script>
    document.addEventListener('UniAppJSBridgeReady', function() {
        //向uniapp传值
        uni.postMessage({
            data: {
                action: 'message'
            }
        });
        uni.getEnv(function(res) {
            console.log('当前环境:' + JSON.stringify(res));
        });
    });
</script>  

uniapp接受返回值

//message接受方法
<template>
    <view class="advertisement" style="width: 100%;">
        <web-view :src="url" @message="message"></web-view>
    </view>
</template>

24、uniapp H5刷新页面问题解决

//#ifndef H5
let pages = getCurrentPages();

for(let i = 0; i < pages.length; i ++){
        let tmppg = pages[i];
        if(tmppg.route == "pages/user/user"){
                tmppg.onLoad();
        }
        // console.log('tmppg:' + tmppg)
        // console.log('tmppg.route:' + tmppg.route)
}
//#endif
//#ifdef H5
window.location.reload();
//#endif

25、在uniapp或者vue中,单行文字或者数字无法换行导致后面内容无法展示问题的解决方案

view {
    white-space: normal;  // 规定段落中的文本不进行换行
    // 数字换行字符串截断换行
    word-break: break-all;  // 允许单词中换行,在容器的最右边进行断开不会浪费控件
    // 数字换行字符串不截断换行
    word-wrap: break-word;  // 防止长单词溢出,单词内部短句
}

26、uni-app h5端双标题解决方法

H5端双标题栏

由于APP端和小程序端都有原生的标题栏可以使用,H5端页面没提供一个可以隐藏标题的方法,在移动端访问的时候会出现双标题,一个是微信浏览器的标题,加上运行到H5项目模拟的标题栏,如图:

image.png

解决思路:

在发布到H5端时不渲染这个标题栏。然后观察到最后这个标题栏在发布时会渲染成一个<uni-page-head>元素,在全局的css中如下设置

uni-page-head {
  display: none;
}

标题栏去掉之后的效果:

image.png

但是去掉标题栏后会导致页面主体部分,H5中渲染为<uni-page-wrapper>的标签高度计算错误,可以加上下面的代码重新计算高度(好像高度不对并不会影响显示效果,哈哈哈)

uni-page-wrapper {
  height: calc(100% - 50px - env(safe-area-inset-bottom)) !important;
}
//50px为底部导航栏的高度

H5端标题自动修改

解决了标题栏的显示问题,还有个令人头疼的问题就是pages.json中给每个页面设置的标题,在页面切换的时候其实改得是模拟的标题栏,我们把模拟的标题栏隐藏以后,标题就不会变化了,所以我们用到document.title来修改页面的标题。

已知两种修改标题的情况,一种是固定标题,还有一种是动态标题,比如***商品详情。 封装了一个修改标题的方法,在项目的main.js中对Vuemixin中添加一个onShow

Vue.mixin({
  onShow() {
    let { title } = this  //在固定标题的页面data中设置title
    if (this.$mp.query) { //整个app的onShow也会触发,这时$mp中没有query属性
      let setTitle = this.$mp.query.title || title //在进入页面的query中没有title属性时会取data中的title
      if (setTitle) {
        uni.setNavigationBarTitle({ //uni-app 的修改title接口
          title: setTitle
        })
        //以下为H5平台差异写法
        // #ifdef H5
        document.title = setTitle
        // #endif
      }
    }
  }
})

这样每个页面在onShow的时候就会自动修改页面的标题了。

27、uni-app框架的switch组件的checked属性值动态绑定不生效

1.原因分析:可能是变量层级太深的原因:

this.$set(this.checkoutInfo.goods_list[0].goods[index2], "integralSelf", false)

2.解决方案:

在switch组件外层添加一个变量isShowEle做if判断,先隐藏组件后显示,这样switch组件就会重新渲染数据了,唯一的缺点是按钮会有闪烁,这个闪烁时间可自行调节(我在代码设置了默认100毫秒),建议还是要做个定时器,毕竟页面加载需要耗时可能会导致switch按钮还是没生效。

<view class="value" v-if="!goodsItem.isShowEle">
    <switch :checked="goodsItem.integralSelf" @change="integralSelfHandle" />
</view>
this.$set(this.checkoutInfo.goods_list[0].goods[index2], "isShowEle", true) //先隐藏switch组件
this.$set(this.checkoutInfo.goods_list[0].goods[index2], "integralSelf", false) //修改checked绑定的变量值
this.$nextTick(()=>{
    setTimeout(()=>{
            this.$set(this.checkoutInfo.goods_list[0].goods[index2], "isShowEle", false) //显示switch组件
            this.$forceUpdate() //强制更新
    },100)
})

28、uniapp小程序禁止遮罩弹窗下的页面滚动

<template>
	<view class="container" :style="showMsk ? 'height: 100vh' : ''">
		<!-- 滚动列表 -->
		<scroll-view scroll-y="true">
		</scroll-view>
		<!-- 自定义弹窗 -->
		<view v-if="showMsk" class="msk"
                    @touchmove.stop.prevent="moveHandle">
		</view>
	</view>
<template>
<script>
...
data() {
	return {
		showMsk: false,
	};
},
methods: {
	moveHandle: {
		return;
	}
}
...
</script

29、mui的APP和uni-app的程序对于提示安卓9不兼容、无响应等问题的解决方法

1、开启相关权限:

"ssl": {  
    "untrustedca": "accept"  //安卓9屏蔽了非https的访问,在这里设置允许非https的请求
},

image.png

与 "orientation"同级,写入后保存即可

image.png

2、设置API等级高于24,建议使用26

"targetSdkVersion" : 26, //API等级设置

30、uni-app打包H5跟小程序后会自动请求shadow-grey.png的问题

问题分析:

这个图片是导航栏底边阴影效果预加载加速显示用的。

2.解决方案:

如果不需要参考下面的配置:

H5 平台:在起始页 html 文件中添加下面代码,参考 manifest H5 index.html 模板配置

body::after { content: none; }

有需要的可以进行下面的替换。\

使用方法

background-image:url(https://cdn.dcloud.net.cn/img/shadow-blue.png);

替换为:

background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAGBAMAAADwPukCAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAASUExURb7T9ezy/MbY9t/p tHg Pf6/gmQWsMAAAAUSURBVAjXY2BgUGBwYDBgEGAIAAAEXADx8btKYQAAAABJRU5ErkJggg==)

下面是各个颜色的Base64编码,需要对css文件逐个替换 cdn.dcloud.net.cn/img/shadow-…

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAGBAMAAADwPukCAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAASUExURb7T9ezy/MbY9t/p+tHg+Pf6/gmQWsMAAAAUSURBVAjXY2BgUGBwYDBgEGAIAAAEXADx8btKYQAAAABJRU5ErkJggg==

cdn.dcloud.net.cn/img/shadow-…

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAGBAMAAADwPukCAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAASUExURb71vuz87Mb2xt/639H40ff+98iMtmEAAAAUSURBVAjXY2BgUGBwYDBgEGAIAAAEXADx8btKYQAAAABJRU5ErkJggg==

cdn.dcloud.net.cn/img/shadow-…

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAGBAMAAADwPukCAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAASUExURdnZ2fT09N7e3uzs7OTk5Pr6+vVa4lkAAAAUSURBVAjXY2BgUGBwYDBgEGAIAAAEXADx8btKYQAAAABJRU5ErkJggg==

cdn.dcloud.net.cn/img/shadow-…

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAGBAMAAADwPukCAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAASUExURfXTvvzy7PbYxvrp3/jg0f7692in75UAAAAUSURBVAjXY2BgUGBwYDBgEGAIAAAEXADx8btKYQAAAABJRU5ErkJggg==

cdn.dcloud.net.cn/img/shadow-…

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAGBAMAAADwPukCAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAASUExURfW+yvzs7/bG0Prf5PjR2v73+TToEXgAAAAUSURBVAjXY2BgUGBwYDBgEGAIAAAEXADx8btKYQAAAABJRU5ErkJggg==

cdn.dcloud.net.cn/img/shadow-…

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAGBAMAAADwPukCAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAASUExURfXvvvz67Pbxxvr33/j00f7997nVB7sAAAAUSURBVAjXY2BgUGBwYDBgEGAIAAAEXADx8btKYQAAAABJRU5ErkJggg==

31、uniapp图片加载不出来的解决方案

分为两种

1.第一种

<image :src="require('../../static/picture')">   //使用v-bind + require

2.第二种

第一种可以解决99%的问题,若有1%的没解决,可以使用background-image属性

background-image:url(../../static/picture.png);

总结:使用图片的最好是,本地图片使用背景图,万无一失,网络图片使用image src。