延续之前的移动端项目开发,需求要求把从后台获取到的一段html显示在界面上。
v-html解析html文本
在Vue.js上有个指令是v-html。具体语法是:
1
| <div v-html="html"></div>
|
其中html部分替换成要绑定的html就可以了,v-html可以解析html代码段并显示出来。
还有一个相似的指令v-text可以将以文字部分显示出来。
以上就完成了将html插入页面的操作。
但是存在着问题,插入的html是web页面格式的,显示在移动端的时候会出现横向滚动条,
不符合我们项目的要求。因此,如何才能适配呢?
通过设置html的meta标签的viewport属性。这里有详细的viewport的介绍
可以在要插入的html文本的head部分加入如下代码
1
| <meta name='viewport' content='width=device-width'>
|
这样即可完成视口的设置,在chrome浏览器和android设备上测试,均可正常显示。
但是在iOS设备上并没有起效。查找原因,发现需要配置config文件。
iOS上设置config文件
需要把config.xml下的EnableViewportScale改为true
1
| <preference name="EnableViewportScale" value="true" />
|
这样即可完成视口的调整,完成web页面和移动端的适配。
但是由于要插入html的页面还有其他内容,大体的结构是
1 2 3
| <div id='div1'></div> <div v-html='html'></div> <div id='div2'></div>
|
在设置了viewport之后会导致整个页面缩放的效果,从而导致div1和div2的内容也进行了缩放,不符合我们的要求。
iframe嵌入html文本
考虑到使用iframe定义一个内联框架,可以用来在当前html文档中嵌入另一个文档。具体语法为
1 2 3 4 5
| <div id='iframeWrapper'> <iframe :srcdoc='content'></iframe> 或者 <iframe src='content.html'></iframe> </div>
|
通过设定iframe的src可以完成嵌入html的操作。在chrome和android设备上测试通过,
但是在iOS设备上,iframe不能正常显示。同样,需要配置config文件。
iOS上设置config文件
查阅资料得知,需要在config.xml里配置权限
1 2 3
| <allow-navigation href="*"/> <allow-intent href="*"/> <access origin="*" />
|
配置完成之后,iOS设备也可显示iframe,接下来要设置iframe的格式了。
iframe动态适配高度和宽度
承接上面的问题,嵌入的html文本是带格式的,我们需要动态设置iframe的高度和宽度,使得它的宽度正好为设备的宽度,不再出现横向滚动条。
具体做法为在iframe的onload事件中设置样式
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| onloaded: function () { var iframe = document.getElementById('iframe') var height = iframe.contentWindow.document.body.scrollHeight || iframe.contentWindow.document.documentElement.scrollHeight var width = iframe.contentWindow.document.body.scrollWidth || iframe.contentWindow.document.documentElement.scrollWidth iframe.height = height iframe.width = width iframe.style.minWidth = width iframe.style.minHeight = height var clientwidth = document.documentElement.clientWidth var scale = clientwidth / width iframe.style.transform = 'scale(' + scale + ')' iframe.style.transformOrigin = '0 0' iframe.style.border = 'none' }
|
如上面代码所示,可以通过设置transform的scale属性完成缩放的操作,在缩放之后需要把transformOrigin属性(默认50% 50%)设置一下,以上完成了缩放的操作。
但是发现scale虽然缩放了,但是并没有影响布局,元素还占用了之前的空间,这里有说明,
导致页面中间有一段空白。
因此,需要动态调整iframe外层的div元素的高度,具体代码示例如下
1
| window.parent.document.getElementById('iframeWrapper').style.height = height * scale + 'px'
|
这样可以实现iframe和父元素的高度随着插入html的高度自适应变化。
onload函数调用了两次
测试过程中发现,onload函数调用了两次。调整代码结构,将html文本中的iframe标签去掉,通过js来动态增加iframe元素。完整代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| onLoaded: function (content) { var ifrWrapper = document.getElementById('iframeWrapper') var iframe = document.createElement('iframe') iframe.onload = function () { var clientwidth = document.documentElement.clientWidth var height = iframe.contentWindow.document.body.scrollHeight || iframe.contentWindow.document.documentElement.scrollHeight var width = iframe.contentWindow.document.body.scrollWidth || iframe.contentWindow.document.documentElement.scrollWidth iframe.height = height iframe.width = width iframe.style.minWidth = width iframe.style.minHeight = height var scale = clientwidth / width iframe.style.transform = 'scale(' + scale + ')' iframe.style.transformOrigin = '0 0' iframe.style.border = 'none' window.parent.document.getElementById('iframeWrapper').style.height = height * scale + 'px' } iframe.srcdoc = content ifrWrapper.appendChild(iframe) }
|
以上的函数在从后台获取到要插入的html的内容的时候调用。
至此,通过iframe插入html文本并动态设置高度和宽度的功能就完成了。
但是页面调整到宽度跟设备宽度一致之后,字号会变小,需求希望用户可以自己手势控制放大。之前想通过设置viewport的user-scalable为yes来允许用户自行缩放,
1
| <meta name="viewport" content="user-scalable=yes, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
|
但是在子页面设置了user-scalable之后会导致整个app的所有页面都可以用户缩放,不符合要求,
希望设置一个开关来完成user-scalable的yes或no,但是没有用,这里有详细的介绍
只能寻求其他的解决方案。
承接以上的问题,在实现缩小之后,字号会变小,需求要求在这个页面可以手势放大(pinch事件).
采用腾讯的AlloyFinger来控制用户两指缩放。
使用方式,首先安装
1
| npm install alloyfinger --save
|
之后在页面引入
1
| import AlloyFinger from 'alloyfinger'
|
然后在components中使用AlloyFinge。至此可以使用v-finger来实现手势的识别了。
参考代码
1 2 3 4 5 6 7 8 9 10 11 12 13
| var pinchRotateImg = document.getElementById("pinchRotateImg"); Transform(pinchRotateImg); new AlloyFinger(pinchRotateImg, { rotate:function(evt){ pinchRotateImg.rotateZ += evt.angle; }, multipointStart: function () { initScale = pinchRotateImg.scaleX; }, pinch: function (evt) { pinchRotateImg.scaleX = pinchRotateImg.scaleY = initScale * evt.zoom; } });
|
在页面新加一个div的时候可以很容易的实现识别,但是在iframe上,由于需要在load完毕之后才有内容,因此,在之前的onLoaded函数里添加代码,
希望实现在只能放大,不能缩小到比原来初始化的时候小。具体完整版代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| onLoaded: function (content) { var ifrWrapper = document.getElementById('iframeWrapper') var iframe = document.createElement('iframe') iframe.onload = function () { var clientwidth = document.documentElement.clientWidth var height = iframe.contentWindow.document.body.scrollHeight || iframe.contentWindow.document.documentElement.scrollHeight var width = iframe.contentWindow.document.body.scrollWidth || iframe.contentWindow.document.documentElement.scrollWidth iframe.height = height iframe.width = width iframe.style.minWidth = width iframe.style.minHeight = height var scale = clientwidth / width iframe.style.border = 'none' iframe.style.transform = 'scale(' + scale + ')' iframe.style.transformOrigin = 'left top' ifrWrapper.style.height = height * scale + 'px' ifrWrapper.style.width = width * scale + 'px' var initScale = scale new AlloyFinger(iframe.contentDocument, { multipointStart: function () { initScale = iframe.style.transform.split('(')[1].split(')')[0] }, pinch: function (evt) { var newScale = initScale * evt.zoom if (newScale < scale) { ifrWrapper.style.overflowX = 'hidden' iframe.style.transform = 'scale(' + scale + ')' ifrWrapper.style.height = height * scale + 'px' ifrWrapper.style.width = width * scale + 'px' return } iframe.style.transform = 'scale(' + newScale + ')' ifrWrapper.style.height = height * newScale + 'px' ifrWrapper.style.width = width * newScale + 'px' if (iframe.width > width) { ifrWrapper.style.overflowX = 'scroll' } else { ifrWrapper.style.overflowX = 'hidden' } } }) } iframe.srcdoc = item.content ifrWrapper.appendChild(iframe) },
|
以上即可实现相关的功能
其他的问题还在不断完善中…
参考文献
1.https://cn.vuejs.org/v2/api/#v-html
2.https://segmentfault.com/a/1190000008767416
3.http://clfsw.iteye.com/blog/1398806
4.http://www.runoob.com/tags/tag-iframe.html
5.http://blog.csdn.net/ilv_xj/article/details/72778501
6.https://segmentfault.com/q/1010000005919829
7.https://yq.aliyun.com/ziliao/167263
8.https://zhuanlan.zhihu.com/p/25140691
9.https://github.com/AlloyTeam/AlloyFinger