小程序应用中WebView中原生组件限制问题解析

###背景

在微信的文档中有一个章节说明了『 [原生组件的使用限制](https://developers.weixin.qq.com/miniprogram/dev/component/native-component.html#%E5%8E%9F%E7%94%9F%E7%BB%84%E4%BB%B6%E7%9A%84%E4%BD%BF%E7%94%A8%E9%99%90%E5%88%B6) 』有这么一段话

```

『由于原生组件脱离在 WebView 渲染流程外,因此在使用时有以下限制:

原生组件的层级是最高的,所以页面中的其他组件无论设置 z-index 为多少,都无法盖在原生组件上。

后插入的原生组件可以覆盖之前的原生组件。

原生组件还无法在 scroll-view、swiper、picker-view、movable-view 中使用。

部分CSS样式无法应用于原生组件,例如:

无法对原生组件设置 CSS 动画

无法定义原生组件为 position: fixed

不能在父级节点使用 overflow: hidden 来裁剪原生组件的显示区域

原生组件的事件监听不能使用 bind:eventname 的写法,只支持 bindeventname。原生组件也不支持 catch 和 capture 的事件绑定方式

在iOS下,原生组件暂时不支持触摸相关事件。

在工具上,原生组件是用web组件模拟的,因此很多情况并不能很好的还原真机的表现,建议开发者在使用到原生组件时尽量在真机上进行调试。』

```

###解析

所谓的原生组件,即非Web组件系统扩展Native组件。因为小程序在视图渲染层面使用了WebView,而在Video,Map这类组件,使用WebView的WebCore渲染之后体验不佳的诟病一直存在,而且标准不一。小程序上因使用原生的WebView进行渲染,而不是用修改的WebView内核(至少在iOS上没有这么干),而无法对web原生标签扩展。基于用户体验,和坑爹的技术限制,小程序提出了原生组件的概念,也就是在WebView上面使用原生组件填充占位元素的方式修补这类组件用户体验问题。因为WebView和原生组件在应用层本身就不是一个渲染层级,于是出现Web上面的标签无法浮于Video之上(直播应用的恶梦),在不修改技术思路的前提下,position: fixed, overflow: hidden这样的属性是不可能用于原生组件的样式的。不过伪同层渲染也不是说不可能,即在渲染原生组件时候根据层级镂空面积。

特别在Map上使用WebView作为渲染之后体验不佳的诟病一直存在,特别是地图上marker标记过多的重度场景下,笔者所在的公司的在使用高德地图Web端提供出来的C端具备反人类的体验,地图拖拉龟速,点击响应缓慢,加载loading地图区域等待时间过长。而Video则支持的格式有限,列出部分浏览器的支持的如下:

```

Firefox:支持 Ogg Vorbis和WAV

Opera :支持Ogg Vorbis和WAV

Safari :支持MP3,AAC格式 ,和MP4

Chrome :支持Ogg Vorbis,MP3,WAV,AAC和MP4

Internet Explorer 9+ :支持MP3,AAC格式 ,和MP4

IOS :支持MP3,AAC格式 ,和MP4

Android :支持AAC和MP3

```

上述,可以知道视频支持有限(限于版权)。而就我们关注的移动端iOS和Andoroid,实现一个视频播放,我们可能都会有以下几点的需求:

1、全屏处理;

2、覆盖层效果;

3、自动播放;

4、播放控制;

5、隐藏播放控件;

在iOS上如果使用WebView,你无法修改全屏下的工具这一点体验已经足够让所有的产品经理抓狂,更不用说Android的这么多的机型。覆盖层效果在微信上不得不使用微信提供原生组件cover-view实现,而限于原生实现限制,cover-view的支持有限。

###设计方案

####1、组件层于WebView层之上

这也应该是微信小程序团队现阶段使用的方案,通过特殊的占位标签,使用getBoundingClientRect获取组件位置,而原生组件跟随Webview滚动。

Talking is cheap. Show me your code,那么用代码实现的效果的如下。

![now_lowest_gif.gif](https://upload-images.jianshu.io/upload_images/5924885-be4474af1eb4613f.gif?imageMogr2/auto-orient/strip)

从图中可见,覆盖层确实位于原生组件之下。

####2、组件层于WebView层之下

此方式略微复杂。需要通过与Webview scroll联动的置于Webview之下的Component Layer实现,而Webview背景设置为透明。至于事件,通过Webview的事件透传,传递到Component Layer,需要通过缓存webview中元素再计算是否被点中通过重写hitTest方法实现。通过此技术方案实现的好处也是明显的,因为原生组件层很多时候都是置于最底层,而Web上的组件可以轻松覆盖于Native之上,无需使用cover-view之类的hack方法。

效果如下所示

![图片发自简书App](http://upload-images.jianshu.io/upload_images/5924885-96a7b1f5ac697045.gif)

###Tips

在iOS上还特别需要注意一点UIWebview的坑。在使用-webkit-overflow-scrolling 使用,你会发现momentum scroll阶段并不会触发scroll事件,而且 scrollTop 属性不会变化,当然getBoundingClientRect也同样失效。如果考虑使用touchmove 这样事件你也仅仅在手指还在屏幕上的时候触发,检测滚动区域内部元素的getBoundingClientRect 同样无效。

当然幸运的是,这么大一个坑只是发生在UIWebview,对WKWebview并没有影响。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

OpenApplus

1 篇文章1 人订阅

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏无原型不设计

三步教你做酷炫的“倒计时”原型效果

日常生活中,我们会看到各种各样的倒计时设计: 或是在一段视频的开头;或是隐蔽在屏幕右上角,用于显示广告的时长;或是在软件启动页面,用于增强用户对后面出现内容的...

2414
来自专栏从零开始学 Web 前端

从零开始学 Web 之 移动Web(九)微金所案例

相关源代码已放置github:https://github.com/Daotin/Web/blob/master/Code/src/11/wjs.zip

1352
来自专栏Nian糕的私人厨房

Vue2.0 歌手列表滚动及右侧快速入口实现

本次的系列博文的知识点讲解和代码,主要是来自于 黄轶 在慕课网的 Vue 2.0 高级实战-开发移动端音乐WebApp 课程,由个人总结并编写,其代码及知识点...

1565
来自专栏向治洪

react-native-android之初次相识

作为一名Android开发者,我的感觉就是,一步一卡,卡的潇洒。 但是我还是要学react-native,不要问我为什么,因为我相信一门解决了原生app,开...

1896
来自专栏xingoo, 一个梦想做发明家的程序员

CSS布局那点事儿

布局 最开始老的一代网站开发,布局都是通过表格实现的。 这样可以形成规整的网格布局,但是也会带来一定的复杂性。比如想要新增某个页面元素,就有可能要改动整个表格...

2345
来自专栏Java技术分享圈

杨老师课堂之网页制作HTML的学习入门-含有案例

l HTML的标记通常是由开始标签和结束标签组成:<b>内容</b> <br/>

1942
来自专栏编程微刊

当鼠标聚焦时输入框变色(focus事件实例)

5682
来自专栏Guangdong Qi

iOS开发常用之 HUD 弹窗

5162
来自专栏贾鹏辉的技术专栏@CrazyCodeBoy

React Native 学习资源精选仓库

React Native Awesome汇集了各类react-native学习资料、工具、组件、开源App、资源下载、以及相关新闻等,只求精不求全。 如果你是...

5247
来自专栏程序员宝库

神奇的选择器 :focus-within

有个错误有必要每次讲到伪类都提一下,有时你会发现伪类元素使用了两个冒号 (::) 而不是一个冒号 (:),这是 CSS3 规范中的一部分要求,目的是为了区分伪类...

1072

扫码关注云+社区

领取腾讯云代金券