菜鸡前端的混合开发之旅
最近做的项目是混合开发的项目,遇到了很多坑,都填起来后分享一下
1.ios图片设置了固定宽高无法显示
解决方法:给图片外层套一层div,给div设置宽高,然后图片设置宽高100% 或者引入svg(小图标,网上很多方法)
<div style="width:10px;height:10px;">
<img src="xxx" style="width:100%;height:100%;">
</div>
2.ios时间显示NaN
原因大概是ios时间中间如果不是/,放入new data会变NAN
解决办法: (因为我们数据库存的都是-的格式,所以只能我自己改) utils:
export function format(date, pattern) {
if (!date) {
return '';
}
if (typeof (date) === 'string') {
let s = '';
if (/\./.test(date)) {
let arr = date.split(' ');
s = [arr[0], arr[1].split('.')[0]].join(' ');
} else {
s = date;
}
s = s.replace(/-|\./g, '/');
date = new Date(s);
} else if (typeof (date) === 'number') {
date = new Date(date);
}
pattern = pattern || DEFAULT_PATTERN
return pattern.replace(SIGN_REGEXP, function ($0) {
switch ($0.charAt(0)) {
case 'y':
return padding(date.getFullYear(), $0.length)
case 'M':
return padding(date.getMonth() + 1, $0.length)
case 'd':
return padding(date.getDate(), $0.length)
case 'w':
return date.getDay() + 1
case 'h':
return padding(date.getHours(), $0.length)
case 'm':
return padding(date.getMinutes(), $0.length)
case 's':
return padding(date.getSeconds(), $0.length)
}
})
}
然后在需要用到地方引入, 使用方法:
format(时间, 'yyyy-MM-dd hh:mm:ss')
ps:第二个参数是想要的格式
3.调用原生的方法
混合app肯定会涉及各种互相调用 解决办法:
export function x(id) { //自己用的方法名,参数
let u = navigator.userAgent
let isAndroid = u.indexOf('Android') > -1 || u.indexOf('Linux') > -1; //android终端
//非app内没有方法就不会调用,不然一直报错很烦
if (isAndroid && window.AndroidJs) {
//特别注意安卓必须得JSON.stringify才能才能传
window.AndroidJs.xxxxx(JSON.stringify({//xxxxx调原生的方法名
Id: id
}))
} else {
if (window.webkit) {
window.webkit.xx.xxxxx.postMessage({
Id: id
})
}
}
}
4.ios安卓调用h5方法
因为vue所有方法都是在组件内部调用,所以要暴露在window上才能给原生调用到
methods: {
内部的方法(){
xxxxx
}
}
mounted () {
window['暴露的方法名'] = () => {
this.内部的方法()
}
}
5.计算精度问题
这个可能不止混合开发会遇到,最近解除的和数字有关的东西多了,还要自己计算, 然后就遇到了很多精度问题 解决方法: utils:
// 加法: accAdd(0.1, 0.2) // 得到结果:0.3
export function accAdd(num1, num2) {
num1 = Number(num1);
num2 = Number(num2);
var dec1, dec2, times;
try {
dec1 = countDecimals(num1) + 1;
} catch (e) {
dec1 = 0;
}
try {
dec2 = countDecimals(num2) + 1;
} catch (e) {
dec2 = 0;
}
times = Math.pow(10, Math.max(dec1, dec2));
// var result = (num1 * times + num2 * times) / times;
var result = (accMul(num1, times) + accMul(num2, times)) / times;
return getCorrectResult("add", num1, num2, result);
// return result;
}
// 减法: accSub(1, 0.9) // 得到结果:0.1
export function accSub(num1, num2) {
num1 = Number(num1);
num2 = Number(num2);
var dec1, dec2, times;
try {
dec1 = countDecimals(num1) + 1;
} catch (e) {
dec1 = 0;
}
try {
dec2 = countDecimals(num2) + 1;
} catch (e) {
dec2 = 0;
}
times = Math.pow(10, Math.max(dec1, dec2));
// var result = Number(((num1 * times - num2 * times) / times);
var result = Number((accMul(num1, times) - accMul(num2, times)) / times);
return getCorrectResult("sub", num1, num2, result);
// return result;
}
// 除法: accDiv(2.2, 100) // 得到结果:0.022
export function accDiv(num1, num2) {
num1 = Number(num1);
num2 = Number(num2);
var t1 = 0,
t2 = 0,
dec1, dec2;
try {
t1 = countDecimals(num1);
} catch (e) {}
try {
t2 = countDecimals(num2);
} catch (e) {}
dec1 = convertToInt(num1);
dec2 = convertToInt(num2);
var result = accMul((dec1 / dec2), Math.pow(10, t2 - t1));
return getCorrectResult("div", num1, num2, result);
// return result;
}
// 乘法: accMul(7, 0.8) // 得到结果:5.6
export function accMul(num1, num2) {
num1 = Number(num1);
num2 = Number(num2);
var times = 0,
s1 = num1.toString(),
s2 = num2.toString();
try {
times += countDecimals(s1);
} catch (e) {}
try {
times += countDecimals(s2);
} catch (e) {}
var result = convertToInt(s1) * convertToInt(s2) / Math.pow(10, times);
return getCorrectResult("mul", num1, num2, result);
// return result;
}
6.全局loading多次请求会多次loading闪烁
菜鸡前端的loading,用的全局,虽然应该有更好的办法, 勉强解决部分:
(没考虑请求.then后再调用一个请求的情况)
Axiossetting里
let loadingall=0; //loading总数
然后每次请求loadingall++,
请求结束的时候loadingall--,
If(loadingall<0){ //防止异常情况
loadingall=0
},
然后设置一个0秒的定时器, 当loadingall===0时关闭loading菊花
考虑一部分的话定时器设置一个300毫秒,但是用户体验会差很多,这部分还没有特别完美的解决方法
7.百度地图定位问题
解决办法:
var geolocation = new BMap.Geolocation();
let that=this //function会改变this指向
geolocation.getCurrentPosition(function (r) {
// console.log(this.getStatus())
if(this.getStatus() == BMAP_STATUS_SUCCESS){
// alert(JSON.stringify(r))
// getCurrentPosition 但是用户拒绝或者允许获取地理位置,this.getStatus()都是0;
//解决办法:当用户拒绝该网站使用浏览器位置时,此时其精度则为null,通过此值判断用户是否拒绝网站获取浏览器位置信息
if(r.accuracy==null){
// 精度失败xxxxx
}else{
// 成功xxxxxx
}
}
else {
//定位失败xxxxx
}
})
但是安卓部分机型一直无法获取准确精度(不管开不开启定位),
所以我们安卓是用的原生的定位方法,然后数据传给我
8.清除app的h5缓存的刷新页面,但是安卓部分机型无效
解决办法:
window.location.href = '地址?time=' + ((new Date()).getTime());
9.用户手机手动调整字体大小,h5和app样式均出错
解决办法: text-size-adjust无效,要原生端控制禁止
10.安卓键盘不会自动顶起input
我试了下网上的resize也没用(大概安卓是全屏的webview的关系?)。。没办法只能自己边找边写写了一个,大概是没问题的(自己用没问题) 解决办法: 根据input在页面的大概位子让页面的top改变,最底下上移1/2,在屏幕上半部分的input点击页面不上移,应该还有一些优化空间
utils:
export function inputup(rootelement, rootelement2) {
let u = navigator.userAgent
let isAndroid = u.indexOf('Android') > -1 || u.indexOf('Linux') > -1; //android终端
if (isAndroid) { // android统一处理,不影响ios的自身处理
let body = document.getElementsByTagName('body')[0] // 兼容获取body
let regDom = document.querySelector(rootelement) // 获取页面内层元素
let regDom2 = document.querySelector(rootelement2) // 获取页面外层根元素
let clientHeight = body.clientHeight + 41 //可见高
let fixHeight3 = clientHeight / 8 // 定位高,弹出键盘时input距浏览器上部的距离,自己定义合适的
// 符合需弹出键盘的元素query
let queryStr = 'input[type=text],input[type=tel],input[type=number],input[type=password], textarea'
let inputs = document.querySelectorAll(queryStr)
for (let i = 0; i < inputs.length; i++) {
let item = inputs[i]
item.addEventListener('focus', () => {
// 改变top上移页面
let offsetTopArr = Array.prototype.map.call(inputs, item => {
return getElementOffsetTop(item) // offsetTop只能获取到顶部距它的offsetParent的距离,需此方法获取到元素距顶部的距离
})
if ((offsetTopArr[i] - regDom2.scrollTop) > (7 * fixHeight3)) { //元素距离页面顶部的距离-浏览器的滚动条距离页面顶部距离>屏幕的一半
// regDom.style.top = '-' + (offsetTopArr[i] - fixHeight) + 'px'
regDom.style.top = '-' + 4 * fixHeight3 + 'px'
} else if ((offsetTopArr[i] - regDom2.scrollTop) > (6 * fixHeight3)) {
regDom.style.top = '-' + 3 * fixHeight3 + 'px'
} else if ((offsetTopArr[i] - regDom2.scrollTop) > (5 * fixHeight3)) {
regDom.style.top = '-' + 2 * fixHeight3 + 'px'
} else if ((offsetTopArr[i] - regDom2.scrollTop) > (4 * fixHeight3)) {
regDom.style.top = '-' + fixHeight3 + 'px'
} else if ((offsetTopArr[i] - regDom2.scrollTop) > (3 * fixHeight3)) {
regDom.style.top = '-' + fixHeight3 / 2 + 'px'
}
})
item.addEventListener('blur', () => {
// 恢复top
if (regDom.style.top !== 0) {
regDom.style.top = 0
}
})
}
//这里是安卓写给我的一个方法,因为我监听不到用户点击键盘的下,这是用户点击键盘的下时安卓端调我的方法
window.inputdown = function inputdown() {
if (regDom.style.top !== 0) {
regDom.style.top = 0
}
for (let i = 0; i < inputs.length; i++) {
let item = inputs[i]
item.blur()
}
}
} else {
let queryStr = 'input[type=text],input[type=tel],input[type=number],input[type=password], textarea'
let inputs = document.querySelectorAll(queryStr)
inputs.forEach((item) => { //循环给input添加监听
item.addEventListener('blur', () => {
setTimeout(function () {
var scrollHeight = document.documentElement.scrollTop || document.body.scrollTop || 0;
window.scrollTo(0, Math.max(scrollHeight - 1, 0));
}, 100)
})
})
}
}
function getElementOffsetTop(el) {
let top = el.offsetTop
let cur = el.offsetParent
while (cur != null) {
top += cur.offsetTop
cur = cur.offsetParent
}
return top
}
页面结构大概是这样的:
复制一份移除监听的,2个方法都引入
<template>
<div class="rootelement" style="position:absolute">//很重要
<div class="rootelement2">//input所在的里面
xxxxx
</div>
</div>
</template>
mounted()
inputup('.rootelement2','.rootelement')
},
beforeDestroy(){ //不要忘了复制一份移除监听
inputup2('.rootelement2','.rootelement')
},