笔者最近一直在开发京东app嵌入的h5项目和微信小程序商城项目,在此期间遇到不少坑。这篇文章主要是针对 h5| Hybrid | 微信小程序 三个方向来说述我遇到的坑,以及详细讲解我是如何解决问题的。css
一直以来,移动端适配就是一个使人头疼的问题。若是想要吃透移动端,还须要很多的实践经验,有的时候在pc
端调试没有问题,可是在m端就会出现问题。如下这16个问题是我在实际工做中遇到的,亲自奉上给你们。但愿你们收藏一波,以备不时之需。html
喜欢笔者的能够「点赞 + 收藏 」 一波,持续更新前端硬核文章。前端
如下是京东嵌入h5,h5落地页,遇到的问题。我用一个思惟导图表示出来。vue
在开发京东app,Hybrid h5
业务页面的时候,遇到一个很是棘手的问题,由于这个页面相似京东app商品详情页面的动画效果。 动画效果以下所示。安卓手机正常,可是ios手机出现,滑块抖动问题,图片会出现闪动的效果。这个问题困扰了好久,网上搜索了大量的解决方案,都没有实际解决问题,本身也尝试了几种方法,也没有成功,当时很奔溃😭😭😭,最后仍是灵光一现,想到了一个巧妙的解决方案😂。react
整个流程就是,当视图容器向上滑动的时候,商品卡片容器须要缓慢移动,首先须要将商品卡片须要脱离标准流,设置定位position:fixed
固定定位。而后控制top
值来控制滑块的缓慢移动。可是在容器向上滑动的过程当中,滑块会出现抖动
,闪动
的效果。android
🤔分析这个缘由,应该是ios
对position
表现不友好的缘由,这种相似的缘由在小程序里也很常见。ios
① 给顶级元素设置height:100%
( 并无奏效 ) 。web
② 增长 transform: translate(0)
属性 ( 并无奏效 )算法
③ 改变布局由fixed
定位,改为absolute
定位,滚动条基于自身。( 可以从根本上解决偶尔跳屏的问题,可是随之而来的就是ios
滚动条问题,基于document
才能有效触发,遂放弃此方案)canvas
④ 不改变布局的状况下,由fixed
定位,改为absolute
定位,滚动条基于document
,定位值彻底取决于数据驱动。(可以从根本上解决偶尔跳屏的问题,可是随之而来的就是要不断改变自身的top值 ,致使更新会慢的状况 ,用户体验很差,流畅度欠佳,遂放弃此方案 )
⑤ -webkit-overflow-scroll:touch
解决滑动无惯性( 并无奏效 )
⑥ background-attachment:fixed
( 并无奏效 )
试了很久,终于想到了一个解决方法。继续使用 fixed
定位,由于咱们这里须要经过定位,抖动不是单纯fixed
定位的缘由。和频繁改变top
值也有很大关系。放弃改变top
值 ,运用transform: translateY
来使视图上下移动。
<view class="scroll_box" style={{ transform:`translateY(${ top }px)` }} >
<!-- 不少东西 -->
</view>
复制代码
.scroll_box{
position:fixed;
}
复制代码
当咱们指望用 border-radius:50%;
来绘制圆点的时候。若是圆比较大可能不是很明显,可是若是圆比较小的时候,会出现明显的不圆,圆被拉伸的状况。
大体效果以下所示。
🤔分析缘由, 在移动端一般会适配不一样的手机,因此使用rem
布局,,rem
在换算为px
时,会是一个带小数点的值,安卓对小于1px
的作了处理(不一样浏览器对小于1px
的处理方式不一样,有的采用四舍五入,有的大于某个值展现1px
不然就舍去),从而致使圆角不圆;在ios
下就没有这个问题。
咱们先把已知视图宽高变成2倍 ,而后用 transform: scale(.5)
让视图缩小50% ,就能够在 android
获得很圆的效果。亲测这个方法很是奏效,造成的圆很是的圆。
咱们举个例子🌰:
<div class="round" ></div>
复制代码
没有作兼容以前的样式,
.round{
border-radius:50%;
width:10px;
heigth:10px;
}
复制代码
改为
.round{
border-radius:50%;
width:20px;
heigth:20px;
transform: scale(.5);
}
复制代码
这里用的taro-h5
, px
会被自动转化成rem
。
有的时候咱们在给元素设置高度很是小的时候也会出现这个问题。
<view class='box' />
复制代码
.box{
width:100px;
height:1px;
}
复制代码
由于咱们高度设置为height:1px
,当taro
给转换成rem
的时候,也会出现四舍五入的状况,结果将1px
弄没了,变成了0px
,因而乎就形成了1px
元素没法显示的bug
,解决方案和上述的原理同样。将高度变成原来的2倍,再经过transform: scaleY(.5);
y方向变为原来的二分之一。
.box{
width:100px;
height:2px;
transform: scaleY(.5);
}
复制代码
这个问题在ios
环境下,仍是很容易发生的。当视图容器的最后一个元素设置 margin-bottom
,指望距离整个容器视图有一个距离的时候,发如今安卓手机正常,可是在ios
下,会出现margin-bottom
无效的状况。
这个的解决方案也很是很是的简单,将margin-bottom
改为padding-bottom
就能根本的解决问题。
例子🌰:
<div class="box" ></div>
复制代码
.box{
margin-bottom: 148px;
}
复制代码
改为
.box{
padding-bottom: 148px;
}
复制代码
手指按住屏幕下拉,屏幕顶部会多出一块空白区域。手指按住屏幕上拉,底部多出一块空白区域。空白区域的颜色,在不一样app
平台打开,颜色会有差异,嵌入京东app h5中的空白背景色为白色,可是在微信中为灰色。
🤔分析缘由: 在 iOS
中,手指按住屏幕上下拖动,会触发 touchmove
事件。这个事件触发的对象是整个 webview
容器,容器天然会被拖动,剩下的部分会成空白。
效果以下:
好比对于京东app这种白色背景,若是咱们background
也是白色的,彻底能够用整个顶端容器,定位填充整个容器来解决这个问题。这样视图不会跟随上拉下滑而移动。若是空白颜色和背景颜色一致,视觉上就会抵消滑动效果。根本上解决出现空白的问题。
一言不合上代码😜。
<div id="root" >
<!-- 此处省略不少内容 -->
</div>
复制代码
#root{
position: fixed;
left:0;
top:0;
bottom: 0;
right: 0;
}
复制代码
这种方法比较靠谱,俗话说解铃还须系铃人
,这个问题根本缘由是 touchmove
引发的,那么从根本上解决问题,仍是要从touchmove
这个事件入手。咱们须要监听移动端document
的 touchmove
而后经过 preventDefault
方法,阻止同一触点上全部默认行为,好比滚动事件。这里要注意的是何时,不让滑动,何时让滑动。
<div ref="root" ></div>
复制代码
const box = this.$refs.root
box.addEventListener('touchmove',function(e){
/* 让视图容器正常滚动 */
e._isScroller = true
})
/* 禁止上滑,下滑 */
document.body.addEventListener('touchmove', function (e) {
if (e._isScroller) return
/* 阻止默认事件 */
e.preventDefault()
}, {
passive: false
})
复制代码
在开发移动端的时候,会遇到 input
的 placeholder
垂直方向不居中的状况。
input
的placeholder
会出现文本位置偏上的状况:PC端设置line-height
等于height
可以对齐,而移动端仍然是偏上,解决方案时是设置css line-height:normal
;
html:
<input class="input" />
复制代码
样式:
.input{
line-height:normal;
}
复制代码
在ios
页面向上向下滑动的过程当中,会出现卡顿,不流畅的现象,具体问题以下:
1 在safari
上,使用了-webkit-overflow-scrolling:touch
以后,页面偶尔会卡住不动。(中招) 2 在safari
上,点击其余区域,再在滚动区域滑动,滚动条没法滚动的(中招)。
在解决这个问题以前,咱们先理解-webkit-overflow-scrolling
的两个属性
1 auto
: 使用普通滚动, 当手指从触摸屏上移开,滚动会当即中止。 2 touch
: 使用具备回弹效果的滚动,当手指从触摸屏上移开,内容会继续保持一段时间的滚动效果。继续滚动的速度和持续的时间和滚动手势的强烈程度成正比。同时也会建立一个新的堆栈上下文。
<div id="app" style="-webkit-overflow-scrolling: touch; ">
<div style="min-height:101%"></div>
</div>
复制代码
或
<div id="app" style="-webkit-overflow-scrolling: touch; ">
<div style="height:calc(100%+1px)"></div>
</div>
复制代码
方法就是在webkit-overflow-scrolling:touch
属性的下一层子元素上, 将height
加1%或1px。从而主动触发scrollbar
。
若是没有使用taro
等跨平台框架构建的h5,当在M端展现h5的时候,双击或者双指张开手指页面元素,页面会放大或缩小。
针对这个状况,实际不算一个bug
,由于html
自己就支持缩放。在pc
端的时候,咱们能够控制鼠标滚轮控制页面缩放,可是在移动端这个行为也存在。可是对于嵌入的 M端 h5页面,咱们不须要这个功能。
咱们能够经过 meta
元标签标准中有个 中 viewport
属性,用来控制页面的缩放,通常用于移动端。
咱们先看看taro-h5
是怎么适配的.
<meta content="width=device-width,initial-scale=1,user-scalable=no" name="viewport">
复制代码
核心user-scalable=no
,没错,就是经过这个属性来阻止缩放行为的。
在用taro-vue
构建 h5
应用的时候,对于banner
轮播图部分,出现一个诡异的问题,就是水平方向轮播的时候,指望图片是正常的轮播效果,可是初始化的时候,图片垂直方向平铺。
大体效果以下图所示:
指望结果
实际结果
大体代码以下:
<swiper class="swiper-wrap" >
<swiper-item v-for="(v,idx) in renderList" :key="idx" class="swiper-item" >
<view class="swiper-wrap-item">
<image mode="widthFix" :src="v.path" class="swiper-image" />
</view>
</swiper-item>
</swiper>
复制代码
这个棘手的问题在于不是每次都复现,因为这个页面是商品详情页,问题会根据某一个商品出现。由于 renderList
是经过后台获取的图片列表,因此判断问题是由渲染swiper
-> 请求数据赋值renderList
-> 再到swiper-item
渲染图片列表的过程当中,某一个环节出了问题。遂改变了渲染方案, 因此采用 获取数据 -> 渲染swiper ->渲染swiperItem的方案。
改进后的代码以下:
<swiper class="swiper-wrap" v-if="renderList.length > 0" >
<swiper-item v-for="(v,idx) in renderList" :key="idx" class="swiper-item" >
<view class="swiper-wrap-item">
<image mode="widthFix" :src="v.path" class="swiper-image" />
</view>
</swiper-item>
</swiper>
复制代码
当 renderList
获取到数据以后,在依次渲染swiper
,swiper-item
。根本解决了这个问题。
如下在开发小程序的过程当中遇到的兼容问题。
在微信小程序里开发webview h5
的时候,在配置了合法域名,域名备案的状况下,出现了 ios
上正常打开,可是在 android
手机上出现了被拦截的状况。并且这些状况都是由于打开webview
的 url
中存在汉字的状况。
效果图片
实际缘由很简单,安卓手机对于 http / https
url若是存在汉字,须要用encodeURI
对汉字进行编码处理就能够了。
<web-view :src="webViewUrl" @message="handerMessage" />
复制代码
this.webViewUrl = commonUrl + '/pages/goods/index?name=' + encodeURI('外星人')
复制代码
若是是接口请求,就这么写
wx.request({
url: commonUrl + '/pages/goods/index?name=' + encodeURI('外星人'),
method: "GET",
})
复制代码
完美解决了问题。
关于微信小程序中webview
被拦截。我总结了一个详细的方案,供你们参考,也是开发中踩坑实录。
若是在微信小程序开发webview
中 , 被微信拦截,你须要这样逐一排查。
首先检查域名是否备案,若是域名没有备案,是没法正常打开webview
的,若是当前域名是二级域名
,那就看主域名有没有备案,二级域名无需独立备案。
配置业务域名流程很简单,首先登录小程序后台 -> 开发,开发管理 - > 开发设置。
而后选择业务域名 -> 点击修改 -> 添加业务域名。
注意上边这部分,须要按这上面的操做添加。添加成功后,会自动添加到,合法域名列表中。
若是走完上边的两步,仍然被拦截。在2020年以前的域名,通常不会被拦截,可是微信对新申请的域名比较严格,须要先点击申诉试试,若是申诉还不行的话,须要联系微信团队相关人员解决问题,由于咱们公司有与微信团队联系的部门,因此无须咱们联系。
若是只有安卓手机被拦截的状况,请按照上面的方法,编码带汉字的url
。
微信小程序在iphone低版本手机(iphone6 ,6p),若是多个视图容器排列(水平和竖直方向都会存在),可能会出现个别边框显示不全的问题。
效果以下图所示:
<view class="father" >
<view class="item" >商品1</view>
<view class="item" >商品2</view>
<view class="item" >商品3</view>
<view class="item" >商品4</view>
</view>
复制代码
.father{
width: 696rpx;
height: 60rpx;
font-size: 28rpx;
color: #01b5b5;
margin: 0 auto;
}
.item{
height: 60rpx;
line-height: 60rpx;
border: 1rpx solid #01b5b5;
float: left;
border-radius: 10rpx;
padding: 0 20rpx;
margin-right: 16rpx;
margin-bottom: 16rpx;
}
复制代码
通过测试得来一组数据 ,注意步骤1中加粗的文本.label-con类中width:696rpx,将标签的父容器宽度设置为下面的值都会出现这个692 693 696 697 700 701 704 705 708 709。咱们把这组数字除以2。
692/2=346
,693/2=346.5
,696/2=348
,697/2=348.5
,700/2=350
,701/2=350.5
,704/2=352
,705/2=352.5
,708/2=354
,709/2=354.5
**分析结果:**当标签的父容器宽度(单位rpx)÷2的值为偶数或偶数.5的时候会出现该bug,那么咱们能够推到出用200.52=401,3022=604等等都会重现这个bug。那么解决方案油然而生。
第一种方式是设置标签父容器的宽度到无bug值,即(奇数或奇数.5)2,例如2812rpx,281.5*2rpx能够解决;
<view class="father" >
<view class="hold" />
<view class="item" >商品1</view>
<view class="item" >商品2</view>
<view class="item" >商品3</view>
<view class="item" >商品4</view>
</view>
复制代码
.hold{
width: 1rpx;
height: 100%;
float: left;
}
复制代码
效果以下,完美的解决了这个问题。
相信不少同窗在开发微信小程序的时候都会遇到scroll-view
不滑动的状况,形成scroll-view
不滑动的缘由有会多,横向和竖向不滑动的缘由也不一样,接下来我会分别从横向和竖向分别介绍形成滑动的缘由。
横向:
竖向:
对于竖直方向的滑动,形成缘由以下:
① scroll-view
的 scroll-y
是否为 true
<scroll-view :scroll-y="true" >
<!-- 此处省略不少东西 -->
</scroll-view>
复制代码
② scroll-view
必须设置具体的高度,若是没有设置高度,或者直接继承父元素高度100%
,那么 scroll-view
竖直方向将无效。咱们必须动态获取scroll-height
由于在不一样型号手机,都要达到完美的效果
如何正确获取scroll-view
高度
状况一 scroll-view
在中间的状况:
const scrollHeight = windowHeight - scrollTop - scrollBottom
复制代码
状况二 scroll-view
靠底部的状况 :
const scrollHeight = windowHeight - scrollTop
复制代码
③ 检查 scroll-view 是否设置了 overflow-y: auto;
等滑动属性。
<scroll-view :scroll-y="true" class="scroll_box" >
<!-- 此处省略不少东西 -->
</scroll-view>
复制代码
.scroll_box{
height:500px;
overflow-y: auto;
}
复制代码
对于水平方向的滑动,形成缘由以下:
① scroll-view
的 scroll-x
是否为 true
<scroll-view :scroll-x="true" >
<!-- 此处省略不少东西 -->
</scroll-view>
复制代码
② 不要设置 display:flex;
等状况 ,让子元素设置 display:inline-block
<scroll-view :scroll-x="true" class="scroll_box" >
<view class="item" > <!-- 此处省略不少东西 --> </view>
<view class="item" > <!-- 此处省略不少东西 --> </view>
<view class="item" > <!-- 此处省略不少东西 --> </view>
<!-- .... -->
</scroll-view>
复制代码
.scroll_box{
/* display:flex; 不要这么作 */
white-space: nowrap;
}
.item{
display:inline-block; /* 这么作 */
}
复制代码
③ scroll-view
设置样式 white-space: nowrap;
<scroll-view :scroll-x="true" style="white-space: nowrap;" ></scroll-view>
复制代码
这个是好久以前作的一个相似地图的项目,在地图组件上,有一个view
,在高版本手机上,正常显示,可是在低版本安卓手机上,会出现view
只有文字能看见,背景彻底被原生组件覆盖,设置层级也没有效果。
后来差了微信文档,才明白原生组件和原生组件的限制。
小程序中的部分组件是由客户端建立的原生组件,这些组件有:
camera canvas input(仅在focus时表现为原生组件) live-player live-pusher map textarea video
因为原生组件脱离在 WebView 渲染流程外,所以在使用时有如下限制:
①原生组件的层级是最高的,因此页面中的其余组件不管设置 z-index 为多少,都没法盖在原生组件上。后插入的原生组件能够覆盖以前的原生组件。
②原生组件还没法在 picker-view 中使用。基础库 2.4.4 如下版本,原生组件不支持在 scroll-view、swiper、movable-view 中使用。
③部分CSS样式没法应用于原生组件,例如:没法对原生组件设置 CSS 动画,没法定义原生组件为 position: fixed,不能在父级节点使用 overflow: hidden 来裁剪原生组件的显示区域。
④原生组件的事件监听不能使用 bind:eventname 的写法,只支持 bindeventname。原生组件也不支持 catch 和 capture 的事件绑定方式。原生组件会遮挡 vConsole 弹出的调试面板。 在工具上,原生组件是用web组件模拟的,所以不少状况并不能很好的还原真机的表现,建议开发者在使用到原生组件时尽可能在真机上进行调试。*
cover-view
与 cover-image
为了解决原生组件层级最高的限制。小程序专门提供了 cover-view
和 cover-image
组件,能够覆盖在部分原生组件上面。这两个组件也是原生组件,可是使用限制与其余原生组件有所不一样。
ios
环境下,scroll-view
标签里面若是有,position:absolute
的元素。当scroll-view
滑动的过程当中,定位的元素会出现抖动的状况。
🤔分析缘由,仍是 scroll-view
和 ios
兼容性的缘由形成的。
针对这个抖动问题,解决方案也是很简单,咱们把定位的元素从scroll-view
拿出来。就能根本解决这个问题。
<view class="box" >
<scroll-view class="scroll_box" :scroll-y="true" >
<view class="current" >我是定位元素</view>
</scroll-view>
</view>
复制代码
.box{
}
.scroll_box{
height:500px;
overflow-y: auto;
position:relative;
}
.current{
position:absolute;
left:0;
top:0;
}
复制代码
改为
<view class="box" >
<scroll-view class="scroll_box" :scroll-y="true" >
</scroll-view>
<view class="current" >我是定位元素</view>
</view>
复制代码
.box{
position:relative;
}
.scroll_box{
height:500px;
overflow-y: auto;
}
.current{
position:absolute;
left:0;
top:0;
}
复制代码
在开发小程序的时候,有一个小程序跳转另一个小程序的场景,第一次的时候没有任何问题,可是当从跳转的目标小程序,返回到当前小程序以后,第二次跳转的时候,发现跳转功能失效了,没法再次跳转。咱们的跳转逻辑是写在一个小程序过渡页面的生命周期中的。具体流程图以下所示:
先看看跳转小程序方法
wx.navigateToMiniProgram({
appId:'appId',
path:'路径',
extraData:'须要传递给小程序的数据',
success(){}, // 成功回调
fail(){}, //失败回调
complete(){} //不管成功/失败,都会执行完成方法。
})
复制代码
🤔这究竟是为何呢,这个问题困扰我好久,查阅了相关资料,微信文档都没找到相关的解决方案。可是微信文档有这么一句话,须要用户触发跳转,从 2.3.0 版本开始,若用户未点击小程序页面任意位置,则开发者将没法调用此接口自动跳转至其余小程序 最后发现是第二次跳转的过程当中,因为不是用户主动行为(点击事件等人为主动的行为),而是又过渡页面的生命周期执行的跳转小程序,因此微信被断定无效的跳转,就会直接走跳转失败的逻辑,webview
里面的点击跳转事件不算是用户的主动行为😂😂。
因此咱们在过渡页进行一判断,若是是第二次跳转,先弹出弹窗,让用户主动点击,触发用户主动行为。而后再跳转小程序。
在用taro-vue
搭建小程序的时候,在scroll-view
向下滑动的时候,会出现一个诡异状况,就是scroll-view
会由于一个兄弟元素的显示隐藏,而忽然置顶。
结构是这样的。
<view>
<scroll-view :scroll-y="true" >
<!-- 此处省略不少 -->
</scroll-view>
<view class="current" v-show="currentShow" > </view>
</view>
复制代码
当scroll-view
滑动的时候,想用变量currentShow
控制scroll-view
显示隐藏,可是 currentShow
一旦改变,就会引发 scroll-view
忽然置顶。
scroll-view
的问题还真是多呀,这个问题曾困扰笔者好久, taro3.0 taro-vue
毕竟不够成熟,会有不少想象不到的问题,若是想用taro
,我这里推荐taro2.0
比较成熟。
废话很少说,这里介绍两个解决方案。
1 将当前元素节点放在 scroll-view
元素内部。
<view>
<scroll-view :scroll-y="true" >
<!-- 此处省略不少 -->
<view class="current" v-show="currentShow" > </view>
</scroll-view>
</view>
复制代码
2 将v-if
改变成 v-show
<view>
<scroll-view :scroll-y="true" >
<!-- 此处省略不少 -->
</scroll-view>
<view class="current" v-if="currentShow" > </view>
</view>
复制代码
① 关于canvas 宽高以及缩放比问题,绘制的元素变形,画布的高度真得等于cavans标签设置的宽高么?
② canvas怎么绘制叠在一块儿的两张图片,并控制层级?
③ 如何用canvas绘制,多行文本?
④ 如何根据设计稿,精确还原海报各个元素位置问题。
⑤ canvas怎么绘制base64的图片?
⑥ 如何绘制网络的图片,两种canvas画布api,绘制图片有什么区别完成?
① 如何正确选型生成二维码工具?
② 生成的二维码,识别不出来怎么办?
③ 如何绘制二维码上的logo?
这些问题都会在笔者的另外一篇文章中找到答案,文章的传送门是:
这些问题都是笔者在实际工做中遇到的问题,吐血总结踩坑实录,为了让你们少走弯路。送人玫瑰,手留余香,阅读的朋友能够给笔者点赞,关注一波 ,陆续更新前端超硬核文章。
回看笔者往期高赞文章,有更多精彩内容等着你!
「react进阶」年终送给react开发者的八条优化建议 800+
赞👍
Vue组件通讯方式及其应用场景总结 250+
赞👍
h5,小程序飞入购物车(抛物线绘制运动轨迹点) 300
赞 👍
vue3.0源码系列
vue3.0 响应式原理(超详细) 200+
赞👍
全面解析 vue3.0 diff算法 100+
赞👍
vue3.0 watch 和 computed源码解析 30+
赞👍
react-hooks系列
玩转react-hooks,自定义hooks设计模式及其实战 150+
👍赞
react-hooks如何使用 70+
赞👍
开源项目系列
230+
赞 👍顺便透露一下,接下来会发布一篇,react-keepalive-router
系列第二篇文章,完善功能。