H5
-
下载文件
h5下载文件使用uni.downloadFile()有跨域问题,导致无法下载文件
可以使用window.location.href=url
方式解决 -
token失效拦截并登录
根据token是否存在进行判断,是否跳转登录页面。
uni.request({
...defaultOpts,
success(response) {
if (response.data.code === -1) { // token失效 跳转登录
// 避免一次请求多个接口,多次跳转登录页面
if (uni.getStorageSync('token')) {
uni.removeStorageSync('token');
uni.$emit('logout');
uni.navigateTo({
url: '../login/index',
});
}
reject(response.data);
} else if (response.data.code === 1) {
resolve(response.data);
} else {
if (!options.hasErrorTip) {
uni.showToast({
icon: 'none',
title: response.data.msg,
});
}
reject(response.data);
}
},
fail(err) {
console.log(err);
uni.showToast({
icon: 'none',
title: '服务响应失败',
});
reject(err);
},
complete() {
uni.hideLoading();
},
});
注意:
- 谨慎使用
uni.redirectTo(OBJECT)
,首页请求接口时,登录页会将首页替换掉,无法进入游客模式,因为返回按钮不会显示。 - 使用
uni.navigateTo(OBJECT)
,要注意重复跳转登录页的问题,可以通过uni.getStorageSync('token')
是否存在来判断,不存在就不需要再跳转登录。 - 在H5上,浏览器可以
刷新页面
;刷新后,路由中只存在当前页面一个路由。首页或者其他页面均不存在,这种情况要考虑登陆成功回到首页的使用uni.navigateBack()
,还是使用uni.switchTab(OBJECT)
。
// #ifndef APP-PLUS
// 非APP平台
const pages = getCurrentPages();
if (pages.length === 1) {
uni.switchTab({
url: '../home/index',
});
return;
}
// #endif
uni.navigateBack();
-
loading加载框表现丑陋
uni.showLoading(OBJECT)
显示加载弹窗,在App上样式表现正常,在h5上很丑陋,无法满足需求。
需要使用自定义弹窗。 -
事件监听注册问题
在首页,特别是有TabBar的首页,每个tab页面都需要注册和取消注册事件
,否则其他tab页无法收到消息。
例如:更新用户信息- 在App上只需要在一个tab页注册监听,获取用户信息即可更新UI。
- 在h5上,A、B、C三个都是tab页,只在A页面注册了user监听。当用户在B或者C页面时,同时刷新了页面,导致当前路由中没有A,在登录成功后,发送user消息获取用户信息,A无法收到消息,B、C都未注册user消息,也就无法获取用户信息。所以,需要每个tab页都需要注册监听才能正常收到消息。
onLoad() {
uni.$on('logout', this.loginEvent);
// #ifndef APP-PLUS
uni.$on('user', this.getUserInfo);
// #endif
},
onUnload() {
uni.off('logout', this.loginEvent);
// #ifndef APP-PLUS
uni.$off('user', this.getUserInfo);
// #endif
},
-
检测手机端、PC端
使用ismobilejs
库,根据navigator.userAgent
来检测当前是否是手机端。如果不是手机端,在PC端访问h5 ,直接跳转到PC端的站点。
检测位置在App.vue
中的onShow
函数
// 导入插件
import isMobile from 'ismobilejs';
onShow: function () {
// #ifdef H5
if (!isMobile(navigator.userAgent).phone) {
// 重定向到另一个站点
window.location.replace('https://www.xxx.com');
}
// #endif
console.log('App Show');
},
-
h5上,API uni.navigateBack() 的问题
刷新一个二级页面,使用uniapp默认导航栏,右上角的按钮可以关闭页面同时回到首页。使用APIuni.navigateBack();
来关闭页面,无法回到首页,始终会跳转到当前页面。
可以使用switchTab来回到首页,App也支持该API。 -
浏览器自动填充账号和密码问题
在页面中第一个密码框前面增加两个input组件,用于欺骗浏览器。这两个组件宽高设置为0,设置对应的type。
第一个input组件用于填充账号,第二个组件用于填充密码。
<!-- H5浏览器记住密码自动填充密码 -->
<!-- #ifdef H5 -->
<input class="w-0 h-0" type="text" />
<input class="w-0 h-0" type="password" />
<!-- #endif -->
scroll-view滑动问题
在带有TabBar的页面中使用scroll-view组件下拉刷新,出现上下滑动异常
- 在page.json文件中将该页面设置为禁止滑动
disableScroll: true
- 指定scroll-view的高度
scroll-view高度计算
- 页面template的根view设定高度
100%
- 计算高度。记住:使用
100%
去计算
// 第一步
.container {
height: 100%;
}
// 第二步
.scroll-box {
height: calc(100% - 258rpx);
}
uni-app中vh的理解
- APP 和小程序的导航栏和 tabbar 均是
原生控件
,元素区域坐标是不包含原生导航栏和 tabbar
的;而H5 里导航栏和 tabbar 是 div 模拟实现
的,所以元素坐标会包含导航栏和tabbar的高度
。 - 为了优雅的解决多端高度定位问题,uni-app 新增了2个css变量:
--window-top
和--window-bottom
,这代表了页面的内容区域距离顶部和底部的距离
。 - 举个实例,如果你想在原生tabbar 上方悬浮一个菜单,之前写 bottom:0。这样的写法编译到 h5 后,这个菜单会和 tabbar
重叠
,位于屏幕底部。而改为使用 bottom:var(--window-bottom),则不管在 app 下还是在h5下,这个菜单都是悬浮在 tabbar 上浮的。这就避免了写条件编译代码。当然仍然也可以使用 H5 的条件编译处理界面的不同。 - CSS 內使用 vh 单位的时候注意
100vh 包含导航栏
,使用时需要减去导航栏和 tabBar 高度
,部分浏览器还包含浏览器操作栏高度
,使用时请注意。
CSS 变量
--status-bar-height
:系统状态栏高度
--window-top
:内容区域距离顶部的距离,NavigationBar 的高度
--window-bottom
:内容区域距离底部的距离,TabBar 的高度
App的包名
mainifest文件中配置AppId是__UNI__9204D49,App的实际包名则是uni.UNI920D49
页面滚动到目标view位置
- 给目标view设置id
<view id="test" class="bg-bgColor">
- 给按钮添加事件
@click="elementScroll('#test')"
- 根据id找到组件设置滚动距离
elementScroll(selector) {
const query = uni.createSelectorQuery();
query
.select(selector)
.boundingClientRect((data) => {
let pageScrollTop = Math.round(data.top) + uni.upx2px(50);
uni.pageScrollTo({
scrollTop: pageScrollTop, //滚动的距离
duration: 100, //过渡时间
});
})
.exec();
},
- 回到顶部
uni.pageScrollTo({
scrollTop: 0,
duration: 100,
});
process.env对象
uni-app中的process.env对象属性如下
{
"NODE_ENV": "development",
"VUE_APP_DARK_MODE": "false",
"VUE_APP_NAME": "测试",
"VUE_APP_PLATFORM": "h5",
"VUE_APP_INDEX_CSS_HASH": "97465e7b",
"VUE_APP_INDEX_DARK_CSS_HASH": "e6047db7",
"VUE_APP_BASE_URL": "http://api.test.com",
"BASE_URL": "/"
}
时间排序iOS兼容性问题
this.aar.sort((a, b) => {
return new Date(b.createTime.replace(/-/g, '/')) - new Date(a.createTime.replace(/-/g, '/'));
});
媒体适配
template中使用了class样式img-box
、img-top
、code-view
<view class="flex justify-center img-box">
<image class="img-top" src="@/static/imgs/img_ggyzm_ybd.png"></image>
</view>
<view class="text-44 text-white flex justify-center code-view">确定</view>
<view class="text-32 text-898FA8 text-center mt-40 mx-40 pb-50">
温馨提示: {{tips}}
</view>
使用media声明,注意screen
是媒体的特性
@media screen and (max-width: 375px) {
.img-box {
padding-top: 60rpx;
}
.img-top {
height: 330rpx;
width: 300rpx;
}
.code-view {
margin-top: 50rpx;
}
}
@media screen and (min-width: 375px) {
.img-box {
padding-top: 180rpx;
}
.img-top {
height: 420rpx;
width: 380rpx;
}
.code-view {
margin-top: 100rpx;
}
}
自定义弹窗组件无法遮挡Tabbar的事件
方案:在Tabbar上层添加一层遮罩,禁止点击Tabbar。
let maskView = null;
export default {
showMask() {
if (!maskView) {
maskView = new plus.nativeObj.View('maskTabarCar', {
bottom: '0px',
left: '0', // 控制遮罩层起点
height: '50px',
width: '100%' // 设置遮罩层宽度
})
maskView.drawRect({
color: 'rgba(255, 255, 255, 0)'
})
maskView.addEventListener('click', () => {
// 遮罩层出发click事件
}, false);
//遮罩层显示
maskView.show()
} else {
maskView.show()
}
},
hideMask() {
if (maskView) {
//遮罩层关闭
maskView.hide()
}
},
}
App多环境多域名打包
方案:采用离线打包来实现。
- 使用脚本生成本地App打包资源,脚本配置多个环境的打包命令
"scripts": {
"dev:h5": "cross-env NODE_ENV=development TAILWIND_MODE=watch UNI_PLATFORM=h5 vue-cli-service uni-serve --mode dev",
"build:dev:h5": "cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build --mode dev",
"build:test:h5": "cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build --mode test",
"build:pre:h5": "cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build --mode pre",
"build:release:h5": "cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build --mode release",
"build:dev:app-plus": "cross-env NODE_ENV=production UNI_PLATFORM=app-plus vue-cli-service uni-build --mode dev",
"build:test:app-plus": "cross-env NODE_ENV=production UNI_PLATFORM=app-plus vue-cli-service uni-build --mode test",
"build:pre:app-plus": "cross-env NODE_ENV=production UNI_PLATFORM=app-plus vue-cli-service uni-build --mode pre",
"build:release:app-plus": "cross-env NODE_ENV=production UNI_PLATFORM=app-plus vue-cli-service uni-build --mode release"
},
-
将打包出来的本地包资源拷贝到Android项目中,使用Android studio来打包。
image.png
启动页取消转圈
"app-plus" : {
"usingComponents" : true,
//设置 启动界面
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : false,
"autoclose" : true, //自动关闭启动页
"delay" : 0
},
alwaysShowBeforeRender
:是否等待首页渲染完毕后再关闭启动界面
autoclose
:是否自动关闭启动界面,仅当alwaysShowBeforeRender设置为false时生效,如果需要手动关闭启动界面,需将 alwaysShowBeforeRender 及 autoclose 均设置为 false。
waiting
:是否在启动界面显示等待雪花
底部安全距离
在适配手机兼容问题上,有时需要处理底部安全距离。
当使用scroll-view时,往往需要设置高度。此时,需要考虑安全距离问题。
- 模板view:在scroll-view后面,增加<u-safe-bottom></u-safe-bottom>
- css:指定scroll-view高度,height: calc(100vh - 120rpx - env(safe-area-inset-bottom));
rich-text解析特殊符号‘<
’出错
在使用<rich-text>
组件展示HTML文本内容时,遇到内容中有小于等于(<=
)的具有特殊含义的符号时,解析会出错,导致无法显示内容。
解决方案:查找全局的小于等于符号,进行替换。
err.msg.replace(/<=/g, '<=')
当内容中有小于符号时,则无法进行替换,否则会将破坏其他HTML标签结构。
uQrcode 添加Logo
<uqrcode
ref="uqrcode"
canvas-id="uqrcode"
:value="qrCode"
@complete="qrcodeGenerFinished"
:options="{
foregroundImageSrc: '/static/imgs/tab_order_sel.png', //logo
foregroundImageWidth: size / 3, //logo宽
foregroundImageHeight: size / 3, //logo高
foregroundImageBorderRadius: 35, //logo圆角
margin: 15, //二维码外边距
backgroundPadding: 10, //二维码内边距
areaColor: 'rgba(100, 100, 100, 0.5)', //二维码绘制区域颜色、底部背景色
foregroundColor: 'rgba(25, 147, 227, 0.5)',//二维码前景色
backgroundImageSrc :'/static/mycenter/tab_order_sel.png',//背景图片
}"
:size="size">
</uqrcode>
scroll-view滑动报错
image.png解决方案:在<scroll-view @touchmove.stop>标签上添加@touchmove.stop
可避免。
scroll-view水平滚动,子元素不能水平排列
1 查看文档:
- 使用竖向滚动时,需要给 <scroll-view> 一个固定高度,通过 css 设置 height
- 使用
横向滚动
时,需要给<scroll-view>添加white-space: nowrap;
样式。
2 子元素样式添加属性:display: inline-block;
;或者使用<block></block>
包裹子元素
网友评论