文章来源:小青年原创
发布时间:2016-06-05
关键词:mui,html5+,webview
转载需标注本文原始地址: http://zhaomenghuan.github.io...javascript
前段时间群里某网友的问题,弹出菜单被子页面挡住了这个老生常谈的问题,其实只要明白webview常见的层级问题,这个问题很容易解释,那么解决方案天然很容易想到,若是没有理解错,html5+
里面webview
的建立规则是后来居上原则,因此若是想解决那个问题,有两种解决办法:css
将弹出菜单放在子页面里面,而后父子页面之间传值,这种方法实用于单个子页面的状况,对于多页面可能并不方便。html
第二个方法是将弹出菜单放在一个webview
里面,设置为透明背景,这样就能够在保证在最上面同时能够盖住底部的内容,在android
上建立菜单webview
的时候设置background
为"transparent"
能够实现,可是html5+ webview .WebviewStyles中说iOS平台不支持“transparent”背景透明样式,默认背景使用白色背景。因为没有用苹果测试过,我真的信了,昨天在群里有人再次问这个问题时,我觉得苹果不支持因此说这种方法存在兼容性,然而有人说能够,囧。。。被人呵呵了,实话说有点小受伤,不过也是由于本身没有测就下告终论,这样确实也很差。前端
但是这个问题仍是会有人去问,因此想一想也没什么,就把webview
的其余内容再补充一下,这篇文章不会再贴文档,纯粹作实验,咱们从新认识一下5+
中的webview
,若是对于文章中提到的一些方法不熟悉的能够看看html5+ webview 文档。html5
今天咱们先来从新认识一下webview
,实践是检验真理的惟一标准,咱们经过作实验来试试,其中WebviewObject
对象是很特别的一个对象,我相信对于这个对象的理解,能够帮助咱们理解webview
的一些细节,咱们就详细看看这个对象。java
首先谈谈WebviewObject
对象的id
属性,相信你们必定熟悉id
选择器,id
选择器是最经常使用的选择器之一,咱们经过document.getElementById(id)
就能够可返回对拥有指定 ID 的第一个对象的引用,作过android
开发的必定知道findViewById
经过这个方法能够获得控件对象的引用,相信5+
中的plus.webview.getWebviewById(id)
应该是将原生中的方法进行了封装以便于使用JavaScript
调用。在打开或建立Webview窗口时设置,若是没有设置窗口标识,此属性值为当前应用的APPID,字符串类型。注意,若是是在HBuilder真机运行获取的是固定值“HBuilder”,须要提交App云端打包后运行才能获取真实的APPID值。node
获取当前窗口id:android
var ws=plus.webview.currentWebview(); console.log( "窗口标识: "+ws.id );
咱们首先由id
这个概念才能更加灵活管理webview
,好比经过id
获取对象关闭窗口:ios
var ws = plus.webview.getWebviewById(id); plus.webview.close(ws);
等效于:git
plus.webview.getWebviewById(id).close();
其余的方法相似,具体的能够参考文档 → 5+ webview
咱们应该注意到每建立一个webview
至关于在当前屏幕建立多个重叠的页面层,因此这里的层叠关系是怎么样的呢?咱们不妨作一个实验:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <title></title> </head> <body> <script type="text/javascript" charset="utf-8"> // H5 plus事件处理 function plusReady(){ var ws1=null,ws2=null,ws3=null; // 获取当前全部Webview窗口 var ws1=plus.webview.currentWebview(); console.log("webview"+plus.webview.all().length+":"+ws1.id); setTimeout(function(){ ws2=plus.webview.create("http://weibo.com/dhnetwork"); ws2.show(); console.log("webview"+plus.webview.all().length+":"+ws2.id); },100); setTimeout(function(){ ws3=plus.webview.create("http://zhaomenghuan.github.io/"); ws3.show(); console.log("webview"+plus.webview.all().length+":"+ws3.id); },3000); setTimeout(function(){ ws3.close(); console.log("剩余窗口数量:"+plus.webview.all().length) },6000); setTimeout(function(){ ws2.close(); console.log("剩余窗口数量:"+plus.webview.all().length) },9000); } if(window.plus){ plusReady(); }else{ document.addEventListener("plusready",plusReady,false); } </script> </body> </html>
在控制台会打印这个:
webview1:HBuilder at index.html:16 webview2:http://weibo.com/dhnetwork at index.html:21 webview3:http://zhaomenghuan.github.io/ at index.html:27 剩余窗口数量:2 at index.html:32 剩余窗口数量:1 at index.html:37
其实执行完这个你们就明显能够看出点结论,在层级关系上你能够认为webview
是后来居上原则,咱们能够经过控制webview
建立销毁、显示隐藏实现页面切换。咱们建立的多个webview
实际上是在原生android
中的一个activity
上,webview
之间的页面切换有别于原生android
中的activity
间的跳转。不少人没有搞清楚webview
这个后来居上原则就会乱用一些方法也会有一些搞不清楚的问题:好比:
若是父webview
上的弹出菜单被子webview
挡住了怎么解决?
把mui
中的openWindow()当成
href`跳转使用,形成屡次重复建立页面出现闪屏。
如何实现按下返回键不会退到上一个页面(经常使用于注册登陆这一个场景的)
。。。
这里我没法一一列举,可是能够说说通用的一些东西,当咱们对于html5+ webview
的基本方法很熟悉了,咱们能够再看看mui
中的back()
和openWindow()
方法的实现思路,天然对于这些问题就会理解了。
那咱们如今再作一个系列实验,刚刚咱们是经过一层层的注销对象,并且是用的网络地址,如今咱们在本地建立两个页面。
咱们新建一个项目,建立一个index.html
文件:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <title></title> </head> <body> <script type="text/javascript" charset="utf-8"> // H5 plus事件处理 function plusReady(){ var ws = plus.webview.create("ws1.html"); ws.show(); } if(window.plus){ plusReady(); }else{ document.addEventListener("plusready",plusReady,false); } </script> </body> </html>
再新建ws1.html
文件:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> 这是第二个webview <script type="text/javascript"> // H5 plus事件处理 function plusReady(){ setTimeout(function(){ var ws = plus.webview.create("ws2.html"); ws.show(); },3000) } if(window.plus){ plusReady(); }else{ document.addEventListener("plusready",plusReady,false); } </script> </body> </html>
再新建ws2.html
文件:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> 这是第三个webview <script type="text/javascript"> function plusReady(){ plus.webview.getWebviewById("ws1.html").close(); // 获取全部Webview窗口 var wvs=plus.webview.all(); for(var i=0;i<wvs.length;i++){ console.log("webview"+i+": "+wvs[i].id); } for(var i=0;i<wvs.length;i++){ console.log("webview"+i+": "+wvs[i].opener()); } } if(window.plus){ plusReady(); }else{ document.addEventListener("plusready",plusReady,false); } </script> </body> </html>
结果:
webview0: HBuilder at ws2.html:16 webview1: ws2.html at ws2.html:16 webview0: undefined at ws2.html:19 webview1: null at ws2.html:19
咱们在第三个webview
里面经过id
把第二个webview
正常关闭了,这说明咱们的webview
是能够控制的,经过plus.webview.all()
方法能够获取当前全部的webview
对象,发现被关闭的webview
被销毁了。
这里咱们须要说明的是被咱们关闭的webview
,咱们没法经过opener()
获取当前Webview窗口的建立者,返回值为null
,这有别于undefined
。
有个问题咱们一直都没有去探索,就是这些webview
对象之间有没有什么关系呢?咱们在第二篇说到了父子webview
,那么这里的几个webview
之间是否是父子结构呢,咱们不妨试试看,咱们经过WebviewObject
的parent()
获取父窗口,这里咱们把ws2.html
中修改以下:
for(var i=0;i<wvs.length;i++){ console.log("webview"+i+": "+wvs[i].parent()); }
结果以下:
webview0: undefined at ws2.html:16 webview1: undefined at ws2.html:16
这说明咱们建立的这几个对象是平行关系,不存在父子关系,文档中提到:Webview窗口做为子窗口添加(Webview.append)到其它Webview窗口中时有效,这时其它Webview窗口为父窗口。
那咱们将第三个webview
填充到第二个webview
中试试,咱们将ws1.html
修改以下:
function plusReady(){ var ws = plus.webview.create("ws2.html","",{top:"46px",bottom:"0px"}); plus.webview.currentWebview().append(ws); }
ws2.html
修改以下:
function plusReady(){ // 获取全部Webview窗口 var wvs=plus.webview.all(); for(var i=0;i<wvs.length;i++){ console.log("webview"+i+": "+wvs[i].parent()); } }
输入以下:
webview0: undefined at ws2.html:16 webview1: undefined at ws2.html:16 webview2: [object Object] at ws2.html:16
很明显咱们发现第三个webview
具备父对象,这里也说明了父子对象的应用场景,将另外一个Webview窗口做为子窗口添加到当前Webview窗口中,添加后其全部权归父Webview窗口,父窗口显示时子窗口会自动显示,父窗口隐藏时子窗口自动隐藏,当父窗口关闭时子窗口也自动关闭。
咱们不妨在子webview
关闭父webview
试试,结果发现子webview
也被关闭了,若是不对子webview
进行close()
方法操做,可知子webview
的生命周期是由父webview
决定的。咱们能够经过对子webview
进行show()
、hide()
操做,甚至可使用remove
移除子Webview窗口,从而实现动态子webview
。这种场景最经常使用的是webview
选项卡。
不少人有将wap
站点打包成APP
需求,官方也提供了一些教程,只是不少人没有搞清楚思路,没有明白改造的基本方法,其中有个最多见的问题是如何经过返回键控制网页内容的回退,论坛上有些回答说经过setJsFile
引入mui.js
,而后重写mui.back()
,其实这个回答原本没有错,可是这个答案依然会有不少细节问题,说直接就是mui.back()
怎么去重写的问题,在搞懂这些问题以前咱们不妨看看咱们html5+
有什么解决办法,因为mui
并无给出前端路由的相关解决方法,使用前端技术写app
,总以为在页面管理上会有点混乱,前几天一直在构思基于html5+
和mui
的前端路由解决方案。感受这个问题若是深刻探究须要另开篇再谈,这里先给出一个最简单的将一个网址打包成app
的方案,这个在应用商店估计是通不过的,只是一个基本思路,你们须要的能够拿去看看。
能够经过plus.key.addEventListener
来注册监听返回按键backbutton
事件:
plus.key.addEventListener("backbutton",function(){ alert( "BackButton Key pressed!" ); });
经过WebviewObject
对象的canBack
和canForward
方法能够查询Webview
窗口的状态,经过back
和forward
控制页面加载。
canBack: 查询Webview窗口是否可后退
canForward: 查询Webview窗口是否可前进
back: 后退到上次加载的页面
forward: 前进到上次加载的页面
clear清除原生窗口的内容,用于重置原生窗口加载的内容,清除其加载的历史记录等内容
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <title></title> </head> <body> <script type="text/javascript" charset="utf-8"> var ws=null,nw=null; function plusReady(){ ws=plus.webview.currentWebview(); nw=plus.webview.create("http://weibo.com/dhnetwork"); ws.append(nw); plus.key.addEventListener("backbutton",function(){ //查询Webview窗口是否可后退 nw.canBack( function(e){ var canback=e.canBack; if(canback){ nw.back(); }else{ back(); } }); }); } var first = null; var back = function() { if (!first) { first = (new Date()).getTime(); plus.nativeUI.toast('再按一次退出应用'); setTimeout(function() { first = null; }, 1000); } else { if ((new Date()).getTime() - first < 1000) { plus.runtime.quit(); } } } if(window.plus){ plusReady(); }else{ document.addEventListener("plusready",plusReady,false); } </script> </body> </html>
若是是使用mui,咱们能够这样写:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <title></title> </head> <body> <script src="js/mui.min.js"></script> <script type="text/javascript" charset="utf-8"> mui.init(); var ws=null,nw=null; mui.plusReady(function () { ws=plus.webview.currentWebview(); nw=plus.webview.create("https://www.baidu.com/"); ws.append(nw); }); var _back = mui.back; mui.back = function(){ //查询Webview窗口是否可后退 nw.canBack( function(e){ var canback=e.canBack; if(canback){ nw.back(); }else{ _back(); } }); } </script> </body> </html>
固然WebviewObject
对象的内容不止这些,这里我只列举了其中你们容易出问题的一些内容,详细的讲解再后面的其余模块的讲解中会再作补充,你们也能够本身学习。
WebviewStyles
是JSON
对象,原生窗口设置参数的对象,设置方法有两种:
在plus.webview.create()
或者plus.webview.open()
中做为参数设置,如:
plus.webview.create(url,id,{ top: '0px', bottom: '0px', mask: 'rgba(0,0,0,0.5)' })
使用setStyle()
动态设置,如:
var ws=plus.webview.currentWebview(); // 显示遮罩层 ws.setStyle({mask:"rgba(0,0,0,0.5)"});
zindex: (Number 类型 )窗口的堆叠顺序值
拥有更高堆叠顺序的窗口老是会处于堆叠顺序较低的窗口的上面,拥有相同堆叠顺序的窗口后调用show方法则在前面。
设置方法如:
{ zindex: 999 }
前面咱们讲到了webview
的层叠关系是后来居上原则,有一个前提是默认层级,没有使用zindex
改变默认的层级关系值,你们知道在web
中咱们使用z-index
能够改变控件的层叠关系,说直观点就好是能够定义有重叠的两个部分,谁在上面谁在下面的问题。
那么在必要的时候咱们可使用这个WebviewStyles
的zindex
属性去改变层叠关系。
如上图这种状况,咱们的底部菜单中间有个突出的部分,若是直接用咱们以前将到的那个方法,咱们知道要么是那个突起的一小块被挡住了,要么是中间的内容与底部非得保持必定的距离,这就尴尬了,并且目前官方的demo
没有给这种特殊的需求,那么是否是不能本身作呢?
确定不是的,否则html5plus
也不至于要作为一个标准去提,确定是有通用方法解决不一样的个性化需求的。
咱们很好想到的就是在上次的基础上进行改进就能够知足这个需求:咱们首先思考一个问题,咱们是将父webview
的堆叠顺序改为比子页高仍是说将tabbar
做为一个层独立出来呢?
首先咱们思考一下简单粗暴的提升父webview
会怎么样?首先咱们会发现子webview
会被父webview
盖住,有人可能会说把父webview
搞成透明的,OK,那么问题来了怎么设置透明呢?
background: (String 类型 )窗口的背景颜色
窗口空白区域的背景模式,设置background为颜色值(参考CSS Color Names,可取值/十六进制值/rgb值/rgba值),窗口为独占模式显示(占整个屏幕区域); 设置background为“transparent”,则表示窗口背景透明,为非独占模式。
设置方法如:
{ background: 'transparent' }
这个就是我开篇说到的那个问题,当时犯了错误,误觉得ios
不支持,后来获得果汁的确认后来支持了,文档没有更新而已。
虽然咱们能够经过设置父webview
透明不至于看不到子页面,可是有个更严重的问题就是子webview
被盖住了咱们不能操做,这是多么的坑,因此这个方法走不通。咱们想一下把tabbar
抽离出来做为一个子webview
,只要设置tabbar
的范围,也就是说不全屏幕铺开,设置高度属性限制高度,设置bottom
将tabbar
固定在底部,而后设置tabbar
的zindex
属性比其余子webview
高就ok了。
// 子页参数 var Index = 0; var subpages = ['html/home.html','html/message.html','html/find.html','html/setting.html']; var subpage_style = { top: '45px', bottom: '50px', zindex:99 }; // 底部导航栏 var tabbar = "html/tabbar.html"; var tabbar_style = { height:"60px", bottom:"0px", background: "transparent", zindex:999 }
咱们只须要给tabbar
设置background
和zindex
就能够实现上面那个图那种效果,可是也所以带了一个问题就是,咱们以前点击底部栏直接就能够获取相关的参数进行切换,可是咱们如今把tabbar
单独拿出来了,那么久涉及一个父子webview
通讯的问题,咱们前面一篇文章讲到页面初始化时候经过扩展参数extras传值,这里咱们须要用到自定义事件,经过自定义事件,用户能够轻松实现多webview间数据传递。
咱们这里先贴出tabbar
的局部代码便于讲解,你们能够在【mui demo】仓库下载完整代码,或者在这里c查看【预览效果】。
在此感谢群友们提出demo中的bug,就是在苹果手机中切换tabbar,tabbar依然会被挡住的问题,开篇讲到因为本人没有苹果手机,因此demo不免在苹果手机上有一些小问题,可是问题仍是能够解决的,其实看了文章多思考一下本身没啥问题的,不建议新手直接一上来来demo,否则出现小问题本身都不知道什么缘由,那么这篇文章也没啥意义。再来讲说群友提的问题,我以为有两种可能性,没有用苹果作实验测试,只是猜测:1.zindex在ios无效;2.优先级的问题,多是选项卡切换过程执行show方法,咱们前面说到后来居上原则,这个时候zindx的层级关系优先级低于后来居上原则。你们能够去实验验证,这里没法给出确定答案。不过解决思路,我以为能够试试两种:1.在子页面show后立刻用setStyle设置zindex;2.直接在子页面show后从新执行tabbar show方法。
tabbar.html
html部分:
<nav class="mui-bar mui-bar-tab mui-botton-bar"> <a class="mui-tab-item mui-active" href="html/home.html"> <img class="mui-icon" src="../img/i-home-active.png"/> <span class="mui-tab-label">首页</span> </a> <a class="mui-tab-item" href="html/message.html"> <img class="mui-icon" src="../img/i-star.png"/> <span class="mui-tab-label">消息</span> </a> <a class="mui-tabbar-center" href="popover.html"> <img src="../img/i-pop-active.png"/> </a> <a class="mui-tab-item" href="html/find.html"> <img class="mui-icon" src="../img/i-find.png"/> <span class="mui-tab-label">发现</span> </a> <a class="mui-tab-item" href="html/setting.html"> <img class="mui-icon" src="../img/i-person.png"/> <span class="mui-tab-label">我的</span> </a> </nav>
js部分:
//选项卡点击事件 mui('.mui-bar-tab').on('tap', 'a', function(e) { // 获取当前点击的选项 var targetTab = this.getAttribute('href'); // 若是点击中间的菜单栏弹出菜单 if(targetTab == popTab){ // 建立mask遮罩 plus.webview.create("","mask",{ mask:"rgba(0,0,0,0.4)", background: "transparent" }).show(); // 打开弹出层 plus.webview.show(popWebview,"slide-in-bottom",300); return; } //当前选项值传到父webview var currWs = plus.webview.currentWebview(); var targetTitle = this.querySelector('.mui-tab-label').innerHTML; //触发详情页面的newsId事件 mui.fire(currWs.parent(),'targetTab',{ targetTitle:targetTitle, targetTab:targetTab }); /** * 下面这部分非每一个项目必须的,由于这里为了给 * 你们演示怎么用图片做为图标而不用字体图标。 */ // 获取图标对象 var targetIcon=mui(this.children[0])[0]; //初始化 mui('.mui-bar-tab .mui-tab-item img').each(function (index,item) { var itemSrc = item.getAttribute('src'); if(itemSrc.indexOf('active')){ item.src = itemSrc.replace('-active.png','.png'); } }); //设置当前的图标 targetIcon.src = targetIcon.getAttribute('src').replace('.png','-active.png'); });
这里咱们使用了图片而不是图标,由于考虑有些项目可能设计比较个性化,咱们不必定能够在Iconfont-阿里巴巴矢量图标库上找到合适的图,有时候用字体文件有局限性,因此这个例子里面咱们使用了图片演示。
这个地方须要对几个细节特别说说:
按照文档的说明咱们知道有三个参数:(不知道文档在哪里的请戳这里【文档】)
mui.fire( target , event , data )
target为你要传入数据的那个webview
,咱们这里是要出入到父webview
,因为咱们没有给父webview
指定id
,咱们前面知道这样就不方便拿到父webview
对象,这里就使用当前webview
的parent()
间接获取。
event是你能够指定的自定义事件名称。
data是你要传入的数据,为json
格式 (不知道json为什么物的同窗请戳我上一篇文章mui初级入门教程(三)— html5+ XMLHttpRequest 与mui ajax用法详解) 。
咱们获取数据也很简单:
// 添加targetTab自定义事件监听 window.addEventListener('targetTab',function(event){ // 得到选项卡点击事件参数 var targetTitle = event.detail.targetTitle; var targetTab = event.detail.targetTab; //接下来这里拿到数据后写逻辑代码了... });
不过这里有一个特别须要注意的问题,因为我尚未遇到,可是看官网文档有说明,贴出来方便后来遇到这个问题的同窗:
目标webview必须触发loaded事件后才能使用自定义事件
若新建立一个webview,不等该webview的loaded事件发生,就当即使用webview.evalJS()或mui.fire(webview,'eventName',{}),则可能无效;案例参考:这里
之因此说说这个是由于在写那个用图片代码字体图标的时候出现一个问题就是选中当前选项,选项卡图片要换成对应激活状态的图片。那么问题来了,怎么拿到a
标签下的img
标签对象,若是用过jQuery
,咱们知道直接用下面的代码就能够实现:
$('.mui-bar-tab a').children("img").css("src","xxx-active.png");
然而mui
本着极简的原则没有children
和css
方法,那么咱们只考虑用原生js
操做DOM
。这里推荐你们用mui
和原生js
实现,毕竟就那么一点代码引入一个库不值得,也不利于提升自身的水平。那么咱们这里就补一下基础知识,考虑到每一个人基础不一样,这里尽量精简的说一下。
什么是 DOM?
DOM ,全称Document Object Model(文档对象模型),是 W3C(万维网联盟)的标准。DOM 定义了访问 HTML 和 XML 文档的标准:
“W3C 文档对象模型 (DOM) 是中立于平台和语言的接口,它容许程序和脚本动态地访问和更新文档的内容、结构和样式。”
W3C DOM 标准被分为 3 个不一样的部分:
核心 DOM - 针对任何结构化文档的标准模型
XML DOM - 针对 XML 文档的标准模型
HTML DOM - 针对 HTML 文档的标准模型
什么是 HTML DOM?
HTML DOM 是HTML 的标准对象模型和标准编程接口,W3C 标准。HTML DOM 定义了全部 HTML 元素的对象和属性,以及访问它们的方法。换言之,HTML DOM 是关于如何获取、修改、添加或删除 HTML 元素的标准。
HTML DOM 节点树
HTML DOM 将 HTML 文档视做树结构。这种结构被称为节点树:
节点父、子和同胞:
节点树中的节点彼此拥有层级关系。
父(parent)、子(child)和同胞(sibling)等术语用于描述这些关系。父节点拥有子节点。同级的子节点被称为同胞(兄弟或姐妹)。
HTML DOM 属性
属性是节点(HTML 元素)的值,您可以获取或设置。可经过 JavaScript (以及其余编程语言)对 HTML DOM 进行访问。
1.innerHTML 属性:获取元素内容的最简单方法是使用 innerHTML 属性。
innerHTML 属性对于获取或替换 HTML 元素的内容颇有用。
2.nodeName 属性:nodeName 属性规定节点的名称,是只读的,nodeName 始终包含 HTML 元素的大写字母标签名。
元素节点的 nodeName 与标签名相同
属性节点的 nodeName 与属性名相同
文本节点的 nodeName 始终是 #text
文档节点的 nodeName 始终是 #document
3.nodeValue 属性:nodeValue 属性规定节点的值。
元素节点的 nodeValue 是 undefined 或 null
文本节点的 nodeValue 是文本自己
属性节点的 nodeValue 是属性值
4.nodeType 属性:nodeType 属性返回节点的类型, 是只读的。
比较重要的节点类型有:
元素类型 | NodeType |
---|---|
元素 | 1 |
属性 | 2 |
文本 | 3 |
注释 | 8 |
文档 | 9 |
5.childNodes属性与children属性
childNodes 属性返回包含被选节点的子节点的 NodeList。若是选定的节点没有子节点,则该属性返回不包含节点的 NodeList。childNodes包含的不只仅只有html节点,全部属性,文本、注释等节点都包含在childNodes里面。children只返回元素如input, span, script, div等,不会返回TextNode,注释。
HTML DOM方法
一般使用的最多的就是 Document和 window 对象。简单的说, window 对象表示浏览器中的内容,而 document 对象是文档自己的根节点。Element 继承了通用的 Node 接口, 将这两个接口结合后就提供了许多方法和属性能够供单个元素使用。在处理这些元素所对应的不一样类型的数据时,这些元素可能会有专用的接口。下面是在web和XML页面脚本中使用DOM时,一些经常使用的方法:
方法 | 描述 |
---|---|
getElementById() | 返回带有指定 ID 的元素。 |
getElementsByTagName() | 返回包含带有指定标签名称的全部元素的节点列表(集合/节点数组)。 |
getElementsByClassName() | 返回包含带有指定类名的全部元素的节点列表。 |
appendChild() | 把新的子节点添加到指定节点。 |
removeChild() | 删除子节点。 |
replaceChild() | 替换子节点。 |
insertBefore() | 在指定的子节点前面插入新的子节点。 |
createAttribute() | 建立属性节点。 |
createElement() | 建立元素节点。 |
createTextNode() | 建立文本节点。 |
getAttribute() | 返回指定的属性值。 |
setAttribute() | 把指定属性设置或修改成指定的值。 |
具体更详细的你们能够参考这篇文章JavaScript DOM——“节点层次”的注意要点
咱们上面讲了一下DOM
对象的基本属性和方法,限于篇幅,只是简单说了说,若是说连上面的都不知道的就须要查一下咯,固然DOM
历史悠久,确定不止这么多内容,对于新手来讲熟悉经常使用的DOM
是颇有必要的,我本身在这方面目前就作得不够好,后期还会继续深刻学习。
首先咱们得说mui
对象和dom
对象都咱们是两个对象,都有本身的独有的属性和方法,若是一个对象调用了一个本身没有另一个对象有的属性和方法,确定会报错的。这里咱们先举个小例子:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <script src="../js/mui.js" type="text/javascript" charset="utf-8"></script> <button type="button" id="btn">按钮</button> <script type="text/javascript"> // dom对象实现 var btn = document.getElementById("btn"); btn.addEventListener('click',function(){ console.log("用dom对象获取button元素点击了按钮") }); // mui对象实现 mui("#btn")[0].addEventListener('click',function(){ console.log("用mui对象获取button元素点击了按钮") }); //判断这两个方法是否等同 console.log(document.getElementById("btn")===mui("#btn")[0]) </script> </body> </html>
常常容易犯错的一个就是下面的使用方法:
mui("#btn").addEventListener('click',function(){ console.log("用mui对象获取button元素点击了按钮") });
咱们经过mui("#btn")
获取的是一个mui
对象实例,然而mui
对象没有addEventListener
,就会报错,咱们用jQuery
也会出现这种问题,然而jQuery
中on
方法很经常使用,不会想那么多,可是mui
中的on
方法实现批量元素的事件绑定,非得传入第二个参数,和咱们的需求有时候不相符合,mui
推荐咱们直接使用addEventListener
方法,然而这个是dom
对象的方法,咱们又不想用document.getElementById("btn")
这种一长串的方法怎么办呢?咱们能够考虑将mui
对象转成dom
对象,方法是:mui
对象mui("#btn")
转成dom
对象为mui("#btn")[0],咱们后面也会陆续讲到怎么本身封装一些经常使用的dom
对象操做方法。
咱们接下来讲说mui
对象中的on()
中的this
指向和父子节点问题:
mui('.mui-bar-tab').on('tap', 'a', function(e) { console.log(this.innerHTML) })
咱们这里执行这个会发现这里的this
指向的是当前点击的a
标签。
咱们若是想获取子节点,咱们前面提到了有两个方法:childNodes
和children
,咱们能够用下面的方面遍历:
mui('.mui-bar-tab').on('tap', 'a', function(e) { for(var i=0;i<this.childNodes.length;i++){ console.log("childNodes:"+this.childNodes[i]); } for(var i=0;i<this.children.length;i++){ console.log("children:"+this.children[i]) } })
结果:
childNodes:[object Text] at html/tabbar.html:85 childNodes:[object HTMLImageElement] at html/tabbar.html:85 childNodes:[object Text] at html/tabbar.html:85 childNodes:[object HTMLSpanElement] at html/tabbar.html:85 childNodes:[object Text] at html/tabbar.html:85 children:[object HTMLImageElement] at html/tabbar.html:89 children:[object HTMLSpanElement] at html/tabbar.html:89
咱们会发现使用childNodes
会有[object Text],咱们这里的实际上是由于咱们上面的HTML
结构中有回车和空格的缘由,去掉后会发现和children
结果一致。
注:Internet Explorer 下使用
childNodes
会忽略节点之间生成的空白文本节点(好比换行字符)。
为了简单咱们一般使用children
,好比上面的例子咱们用到了
var targetIcon=mui(this.children[0])[0];
这样咱们就拿到了HTMLImageElement对象,咱们经过getAttribute('src')
方法就能够拿到src
属性。
其实写到这里咱们发现只要掌握了原生js操做DOM
的方法,咱们其实能够不过分依赖jQuery
这种库,固然jQuery
也不只仅只是这么多内容,不少封装的思路值得咱们去学习,小白学习前端的路很长,可是必定要脚踏实地去落实,不要急于求成。
这一篇文章原本上次就应该完成的,可是一直拖了好久,一来是由于时间久了,这么问题感受也不想继续写,毕竟写文章要花时间,可是又有强迫症,想一想仍是完善一下,详不详细都没关系,
可是要把主要的内容写出来就能够。
先看效果图:
就是前面咱们点击中间那个选项弹出的一个菜单,很显然这个问题具备必定的表明性。作过相似需求的朋友确定知道问题所在,咱们把弹出菜单若是放在父webview
,那么在这种状况下会被子webview
盖住,固然咱们能够考虑在点击弹出层时候动态设置父页面的层级比子页面高,而后关闭再设置恢复,可是这个过程很麻烦,不是最佳实战方法,在子webview
的话,那么设计父子webview
通讯的问题,对于这种多子webview
页面的状况是否是过于麻烦呢,这种时候咱们用新建一个webview
装弹出层我以为是一种最合适的方案。
知道思路了,方案实施很简单的,其实就是当咱们点击那个弹出层的时候,而后显示webview
,当关闭的时候隐藏或者关闭webview
。打开时候的关键代码以下:
//弹出菜单 var menuWebview; var menuTab = 'menu.html'; mui.plusReady(function(){ //预加载弹出菜单子页面 menuWebview = mui.preload({ url:menuTab, id:menuTab, styles:{ top: '0px', bottom: '0px', background: 'transparent' } }); }) //...此处略去若干代码 // 若是点击中间的菜单栏弹出菜单 if(targetTab == menuTab){ if(window.plus){ // 建立mask遮罩 plus.webview.create("","mask",{ mask:"rgba(0,0,0,0.4)", background: "transparent" }).show(); // 打开弹出层 plus.webview.show(menuWebview,"slide-in-bottom",300); }else{ mui.alert("请在html5+引擎环境使用"); } return; }
咱们这里作了一些特别的处理,咱们设置弹出层webview
中的background: 'transparent'
,以及弹出层页面的body{background: transparent;}
是为了获得一个透明的弹出层,若是不须要能够忽略,同时能够能够经过设置top
和bottom
设置弹出层的范围,这些具体配置参数在上面的内容中都有讲解,具体的你们能够详细看看。另外考虑到有人须要遮罩这种布局,咱们专门新建了一个webview
建立mask遮罩,具体的参数相似。
至于关闭弹出层也很简单,咱们在弹出层的页面重写mui.back()
方法。
/* * 这里重写mui.back()方法,在须要执行关闭命令的地方 * 加上 mui-action-back 类,能够绑定back()方法。 */ mui.back = function(){ // 隐藏弹出层 plus.webview.currentWebview().hide(); // 关闭遮罩 plus.webview.getWebviewById('mask').close(); }
至此咱们这个弹出层是算完美解决了。
另外不少人老是尝试去关闭webview
,其实webview
开着的时候真正的占多少内存呢,你打开浏览器就知道,不会说你开了几页面就被卡死了,固然暴力操做和页面内面阻塞错误除外,不过通常浏览器也好像限制了页面打开的数量,我手机自带的浏览器是最多能够打开15个窗口。因此咱们尽可能不要开启过多的webview
,可以使用单页去代替的能够考虑单页。这里有个div模式的tabbar切换动画:【demo传送门】。另外webview
不建议都关闭,若是后面会用到的webview
能够用hide()
代替,同时即便要关闭,也不适宜一次性关闭,常常看到有人用all
查找当前的webview
,用循环一次性关闭,形成内存溢出。我首先不想说底层的原理实现,就想用常识想一想,你打开webview
的时候须要执行操做,那么关闭的时候就不执行操做吗?你同时一会儿作那么多事,手机浏览器是否是都被你占用了执行关闭操做,那么这个过程难道不须要内存消耗吗?你根据id
分时去close
天然会好得多,有时候咱们出现问题先考虑一下是否是本身的方式不对。
其实回过头来再看看其实内容并不算多,也不是很复杂,为啥依然有那么多抱怨呢,说来讲去不按套路出牌,不少人用mui
彻底可是不按mui
的思路,想固然的去作,开发前文档都不看,出问题了也不懂缘由,其实有时候再喷的时候能不能把那个时间拿来看看文档再说。我一贯主张是作事前先花时间去搞清楚一些基本规则,花时间去学习,而后再去作事就不会花不少冤枉时间;可是我经常看到的是不少人花不多的时间学习,而后花不少时间去填坑。这种状况一般时间也花了很多,可是没有什么长进,更谈不上深入理解。(彻底我的意见,不满能够忽略)
文章原始地址是我博客地址:
【MUI从入门到精通】专栏地址:
mui demo地址:
写文章不容易,也许写这些代码就几分钟的事,写一篇你们好接受的文章或许须要几天的酝酿,而后加上几天的码字,累并快乐着。若是文章对您有帮助请我喝杯咖啡吧!
近期在segmentfault讲堂开设了一场关于html5+ App开发工程化实践之路的讲座,会讲到5+ 开发中高性能的优化方案以及使用如何结合Vue.js进行开发,欢迎前来围观:https://segmentfault.com/l/15...。