h5新特性杨亚男

发表于2016/10/1721:25:587809人阅读

分类:前端

转载请注明出处:

2014年10月29日,W3C宣布,经过接近8年的艰苦努力,HTML5标准规范终于制定完成。

HTML5将会取代1999年制定的HTML4.01、XHTML1.0标准,以期能在互联网应用迅速发展的时候,使网络标准达到符合当代的网络需求,为桌面和移动平台带来无缝衔接的丰富内容。

作为2010年入坑IT的程序员来说,可以说一步一步见证着HTML5的发展。这些年为了兼容IE6放弃了很多HTML5的新特性。但是今时不同以往,移动设备的流行,天然支持HTML5,以及桌面端IE最终被用户和微软唾弃,更多支持HTML5浏览器的受欢迎,我要重新研究一下HTML5带来的这些新特性。

①语义特性(Semantic)

HTML5赋予网页更好的意义和结构。

②本地存储特性(OFFLINE&STORAGE)

③设备访问特性(DEVICEACCESS)

从Geolocation功能的API文档公开以来,HTML5为网页应用开发者们提供了更多功能上的优化选择,带来了更多体验功能的优势。HTML5提供了前所未有的数据与应用接入开放接口。使外部应用可以直接与浏览器内部的数据直接相连,例如视频影音可直接与microphones及摄像头相联。

④连接特性(CONNECTIVITY)

更有效的连接工作效率,使得基于页面的实时聊天,更快速的网页游戏体验,更优化的在线交流得到了实现。HTML5拥有更有效的服务器推送技术,Server-SentEvent和WebSockets就是其中的两个特性,这两个特性能够帮助我们实现服务器将数据“推送”到客户端的功能。

⑤网页多媒体特性(MULTIMEDIA)

支持网页端的Audio、Video等多媒体功能,与网站自带的APPS,摄像头,影音功能相得益彰。

⑥三维、图形及特效特性(3D,Graphics&Effects)

基于SVG、Canvas、WebGL及CSS3的3D功能,用户会惊叹于在浏览器中,所呈现的惊人视觉效果。

⑦性能与集成特性(Performance&Integration)

没有用户会永远等待你的Loading——HTML5会通过XMLHttpRequest2等技术,解决以前的跨域等问题,帮助您的Web应用和网站在多样化的环境中更快速的工作。

下面分别对这七个新特性进行研究。

HTML5增加了新的内容标签,这些标签带有一定的语义,使搜索引擎爬取你的网站信息更高效。

HTML4中的内容标签级别相同,无法区分各部分内容。而HTML5中的内容标签互相独立,级别不同,搜索引擎以及统计软件等均可快速识别各部分内容。

这些标签在新闻类网站,博客类网站很有用。

最大的问题就是当使用这些新的语义元素时,那些不支持的浏览器如何处理这些元素。

见过的最多的解决方法是这样的。

HTML5提供了网页存储的API,方便Web应用的离线使用。除此之外,新的API相对于cookie也有着高安全性,高效率,更大空间等优点。

先看W3C对离线存储的介绍。

WebAppscanstartfasterandworkevenifthereisnointernetconnection,thankstotheHTML5AppCache,aswellastheLocalStorage,IndexedDB,andtheFileAPIspecifications.

HTML5离线存储包含应用程序缓存,本地存储,索引数据库,文件接口。

下面依次展开介绍。

使用HTML5,通过创建cachemanifest文件,可以轻松地创建web应用的离线版本。

HTML5引入了应用程序缓存,这意味着web应用可进行缓存,并可在没有因特网连接时进行访问。

应用程序缓存为应用带来三个优势:

甭废话,先来感受一下ApplicationCache的魅力。Shutup,showmethedemo!

1.打开这个网页,第一次等待加载完成之后,页面和普通的网页没有区别。

2.点击刷新按钮,或者强制刷新按钮,看一下第二次打开的速度。有没有快到爆。(速度)

3.现在我要求你拔掉网线,断开WiFi,再次点击刷新按钮,或者强制刷新按钮,看一下第三次打开的速度。有没有快到爆。注意,现在并没有联网,和服务器失去连接,依然秒开网页,还能正常操作网页。(离线浏览,减少服务器负载)

看完了效果,看一下AppCache的原理。

当我们第一次正确配置cachemanifest后,浏览器会将清单文件中的资源缓存下来。当我们再次访问该应用时,浏览器会直接返回缓存中的资源,然后检查manifest文件是否有变动,如果有变动就会把相应的变动更新下来,同时改变浏览器里面的appcache。

使用方法

清单文件中写明资源。

CACHEMANIFESTtheme.csslogo.gifmain.jsNETWORK:login.aspFALLBACK:/html5//404.htmlmanifest文件可分为三个部分:

CACHEMANIFEST-在此标题下列出的文件将在首次下载后进行缓存NETWORK-在此标题下列出的文件需要与服务器的连接,且不会被缓存FALLBACK-在此标题下列出的文件规定当页面无法访问时的回退页面(比如404页面)

CACHEMANIFEST,是必需的NETWORK规定文件“login.asp”永远不会被缓存,且离线时是不可用的FALLBACK规定如果无法建立因特网连接,则用“404.html”替代/html5/目录中的所有文件

一旦应用被缓存,它就会保持缓存直到发生下列情况:

需要注意的是,更新后的资源需要下次打开页面才能生效,本次打开的页面在更新资源之前就已经从缓存中拿到资源并加载完毕了。

由程序来更新,需要依赖manifest文件被修改这一条,因为调用的是浏览器提供的接口,检测window.applicationCache.status的值,如果是UPDATEREADY,说明浏览器比较manifest文件完毕,可以更新缓存了。window.applicationCache.swapCache()。更新完了,不会立即生效,window.location.reload();重新加载一下页面。

缓存有这么多状态。

varappCache=window.applicationCache;switch(appCache.status){caseappCache.UNCACHED://UNCACHED==0return'UNCACHED';break;caseappCache.IDLE://IDLE==1return'IDLE';break;caseappCache.CHECKING://CHECKING==2return'CHECKING';break;caseappCache.DOWNLOADING://DOWNLOADING==3return'DOWNLOADING';break;caseappCache.UPDATEREADY://UPDATEREADY==4return'UPDATEREADY';break;caseappCache.OBSOLETE://OBSOLETE==5return'OBSOLETE';break;default:return'UKNOWNCACHESTATUS';break;};程序更新缓存的方法。

总的来说,AppCache的三个优点非常明显。但是有几个坑,却会导致没人愿意使用这个新特性。

1.使用了AppCache的页面在清单文件更新之后去更新页面资源,但是只在下次打开页面才能生效,这意味着,我们需要使用代码判断是不是最新版本,不是的话,刷新一次页面。这种体验很不好。

2.使用了AppCache的页面也会被缓存,这对于需要动态更新的页面来说,几乎是个噩梦。用户访问到的页面不是最新的,会导致非常多的问题。

本地存储发展历史.

最早的Cookies自然是大家都知道,问题主要就是太小,大概也就4KB的样子,而且IE6只支持每个域名20个cookies,太少了。优势就是大家都支持,而且支持得还蛮好。很早以前那些禁用cookies的用户也都慢慢的不存在了,就好像以前禁用javascript的用户不存在了一样。

userData是IE的东西,垃圾。现在用的最多的是Flash吧,空间是Cookie的25倍,基本够用。再之后Google推出了Gears,虽然没有限制,但不爽的地方就是要装额外的插件(没具体研究过)。到了HTML5把这些都统一了,官方建议是每个网站5MB,非常大了,就存些字符串,足够了。比较诡异的是居然所有支持的浏览器目前都采用的5MB,尽管有一些浏览器可以让用户设置,但对于网页制作者来说,目前的形势就5MB来考虑是比较妥当的。

首先自然是检测浏览器是否支持本地存储。在HTML5中,本地存储是一个window的属性,包括localStorage和sessionStorage,从名字应该可以很清楚的辨认二者的区别,前者是一直存在本地的,后者只是伴随着session,窗口一旦关闭就没了。二者用法完全相同,这里以localStorage为例。

if(window.localStorage){alert('ThisbrowsersupportslocalStorage');}else{alert('ThisbrowserdoesNOTsupportlocalStorage');}存储数据的方法就是直接给window.localStorage添加一个属性,例如:window.localStorage.a或者window.localStorage[“a”]。它的读取、写、删除操作方法很简单,是以键值对的方式存在的,如下:

localStorage.a=3;//设置a为"3"localStorage["a"]="sfsf";//设置a为"sfsf",覆盖上面的值localStorage.setItem("b","isaac");//设置b为"isaac"vara1=localStorage["a"];//获取a的值vara2=localStorage.a;//获取a的值varb=localStorage.getItem("b");//获取b的值localStorage.removeItem("c");//清除c的值这里最推荐使用的自然是getItem()和setItem(),清除键值对使用removeItem()。如果希望一次性清除所有的键值对,可以使用clear()。另外,HTML5还提供了一个key()方法,可以在不知道有哪些键值的时候使用,如下:

varstorage=window.localStorage;functionshowStorage(){for(vari=0;i");}}写一个最简单的,利用本地存储的计数器:

varstorage=window.localStorage;if(!storage.getItem("pageLoadCount")){storage.setItem("pageLoadCount",0);}storage.pageLoadCount=parseInt(storage.getItem("pageLoadCount"))+1;//必须格式转换document.getElementById("count").innerHTML=storage.pageLoadCount;showStorage();不断刷新就能看到数字在一点点上涨,如下图所示:

需要注意的是,HTML5本地存储只能存字符串,任何格式存储的时候都会被自动转为字符串,所以读取的时候,需要自己进行类型的转换。这也就是上一段代码中parseInt必须要使用的原因。

从本质上说,IndexedDB允许用户在浏览器中保存大量的数据。任何需要发送大量数据的应用都可以得益于这个特性,可以把数据存储在用户的浏览器端。当前这只是IndexedDB的其中一项功能,IndexedDB也提供了强大的基于索引的搜索api功能以获得用户所需要的数据。

用户可能会问:IndexedDB是和其他以前的存储机制(如cookie,session)有什么不同?

Cookies是最常用的浏览器端保存数据的机制,但其保存数据的大小有限制并且有隐私问题。Cookies并且会在每个请求中来回发送数据,完全没办法发挥客户端数据存储的优势。

一般来说,有两种不同类型的数据库:关系型和文档型(也称为NoSQL或对象)。关系数据库如SQLServer,MySQL,Oracle的数据存储在表中。文档数据库如MongoDB,CouchDB,Redis将数据集作为个体对象存储。IndexedDB是一个文档数据库,它在完全内置于浏览器中的一个沙盒环境中(强制依照(浏览器)同源策略)。

对数据库的每次操作,描述为通过一个请求打开数据库,访问一个objectstore,再继续。

打开数据库的请求生命周期

IndexedDB是否适合我的应用程序

现在最关键的问题:“IndexedDB是否适合我的应用程序“像往常一样,答案是肯定的:“视情况而定。“首先当你试图在客户端保存数据时,你会考虑HTML5本地存储。本地存储得到广泛浏览器的支持,有非常易于使用的API。简单有其优势,但其劣势是无法支持复杂的搜索策略,存储大量的数据,并提供事务支持。

IndexedDB是一个数据库。所以,当你想为客户端做出决定,考虑你如何在服务端选择一个持久化介质的数据库。你可能会问自己一些问题来帮助决定客户端数据库是否适合您的应用程序,包括:

IndexedDB用法

现在,你已经有机会熟悉了一些的整体概念,下一步是开始实现基于IndexedDB的应用程序。第一个步骤需要统一IndexedDB在不同浏览器的实现。您可以很容易地添加各种厂商特性的选项的检查,同时在window对象上把它们设置为官方对象相同的名称。下面的清单展示了window.indexedDB,window.IDBTransaction,window.IDBKeyRange的最终结果是如何都被更新,它们被设置为相应的浏览器的特定实现。

打开数据库

//打开我们的数据库,数据库名称,版本号varrequest=indexedDB.open("MyTestDatabase",3);indexedDB的三个事件

//数据库打开成功执行request.onsuccess=function(event){//Betteruse"this"than"req"togettheresulttoavoidproblemswith//garbagecollection.//db=request.result;db=this.result;console.debug("initDbDONE");};//数据库打开失败执行request.onerror=function(event){console.error("initDb:",evt.target.errorCode);};//在数据库第一次被打开时或者当指定的版本号高于当前被持久化的数据库的版本号时,触发此事件,可以在这个地方创建对象存储空间结构,更新结构,加索引等.request.onupgradeneeded=function(event){console.debug("initDb.onupgradeneeded");varstore=event.currentTarget.result.createObjectStore(DB_STORE_NAME,{keyPath:'id',autoIncrement:true});};添加数据或更新数据

//我们的客户数据看起来像这样。constcustomerData=[{ssn:"444-44-4444",name:"Bill",age:35,email:"bill@company.com"},{ssn:"555-55-5555",name:"Donna",age:32,email:"donna@home.org"}];vartransaction=db.transaction(["customers"],"readwrite");//当所有的数据都被增加到数据库时执行一些操作transaction.oncomplete=function(event){alert("Alldone!");};transaction.onerror=function(event){//不要忘记进行错误处理!};varobjectStore=transaction.objectStore("customers");for(variincustomerData){varrequest=objectStore.add(customerData[i]);request.onsuccess=function(event){//event.target.result==customerData[i].ssn};}删除数据

varrequest=db.transaction(["customers"],"readwrite").objectStore("customers").delete("444-44-4444");request.onsuccess=function(event){//删除数据成功!};获取数据

vartransaction=db.transaction(["customers"]);varobjectStore=transaction.objectStore("customers");varrequest=objectStore.get("444-44-4444");request.onerror=function(event){//错误处理!};request.onsuccess=function(event){//对request.result做些操作!alert("NameforSSN444-44-4444is"+request.result.name);};对于一个“简单”的提取这里的代码有点多了。下面看我们怎么把它再缩短一点,假设你在数据库的级别上来进行的错误处理:

db.transaction("customers").objectStore("customers").get("444-44-4444").onsuccess=function(event){alert("NameforSSN444-44-4444is"+event.target.result.name);};使用游标获取数据

使用get()要求你知道你想要检索哪一个键。如果你想要遍历对象存储空间中的所有值,那么你可以使用游标。看起来会像下面这样:

varcustomers=[];varobjectStore=db.transaction("customers").objectStore("customers");objectStore.openCursor().onsuccess=function(event){varcursor=event.target.result;if(cursor){customers.push(cursor.value);cursor.continue();}else{alert("Gotallcustomers:"+customers);}};这里有一个封装好的完整的例子,简化了这些操作。

除了IndexedDB以外,还有一种已经被W3C放弃的WebSQL。

浏览器支持本地数据库并不是从IndexedDB才开始实现,它是在WebSQL实现之后的一种新方法。类似IndexedDB,WebSQL是一个客户端数据库,但它作为一个关系数据库的实现,使用结构化查询语言(SQL)与数据库通信。WebSQL的历史充满了曲折,但底线是没有主流的浏览器厂商对WebSQL继续支持。

如果WebSQL实际上是一个废弃的技术,为什么还要提它呢有趣的是,WebSQL在浏览器里得到稳固的支持。Chrome,Safari,iOSSafari,andAndroid浏览器都支持。另外,并不是这些浏览器的最新版本才提供支持,许多这些最新最好的浏览器之前的版本也可以支持。有趣的是,如果你为WebSQL添加支持来支持IndexedDB,你突然发现,许多浏览器厂商和版本成为支持浏览器内置数据库的某种化身。

因此,如果您的应用程序真正需要一个客户端数据库,你想要达到的最高级别的采用可能,当IndexedDB不可用时,也许您的应用程序可能看起来需要选择使用WebSQL来支持客户端数据架构。虽然文档数据库和关系数据库管理数据有鲜明的差别,但只要你有正确的抽象,就可以使用本地数据库构建一个应用程序。

在之前我们操作本地文件都是使用flash、silverlight或者第三方的activeX插件等技术,由于使用了这些技术后就很难进行跨平台、或者跨浏览器、跨设备等情况下实现统一的表现,从另外一个角度来说就是让我们的web应用依赖了第三方的插件,而不是很独立,不够通用。在HTML5标准中,默认提供了操作文件的API让这一切直接标准化。有了操作文件的API,让我们的Web应用可以很轻松的通过JS来控制文件的读取、写入、文件夹、文件等一系列的操作。

先看一个demo。之前我们操作一个图片文件,都是先将图片上传到服务器端,然后再使用一个img标签指向到服务器的url地址,然后再进行一个使用第三方插件进行图片处理,而现在这一切都不需要服务器端了,因为FileReader对象提供的几个读取文件的方法变得异常简单,而且全部是客户端js的操作。

现在我们自己来使用这些API。

先写好我们的HTML页面。


获取文件名

$("#btnGetFile").click(function(e){varfileList=document.getElementById("fileDemo").files;for(vari=0;itype:"+fileList[i].type+"--******非图片类型*****--name:"+fileList[i].name+"--size:"+fileList[i].size+"
");}else{$("#result").append("type:"+fileList[i].type+"--name:"+fileList[i].name+"--size:"+fileList[i].size+"
");}}});readAsDataURL()

开始读取指定的Blob对象或File对象中的内容.当读取操作完成时,readyState属性的值会成为DONE,如果设置了onloadend事件处理程序,则调用之.同时,result属性中将包含一个data:URL格式的字符串以表示所读取文件的内容.

这个方法很有用,比如,可以实现图片的本地预览.

functionshowDataByURL(){varresultFile=document.getElementById("fileDemo").files[0];if(resultFile){varreader=newFileReader();reader.readAsDataURL(resultFile);reader.onload=function(e){varurlData=this.result;document.getElementById("result").innerHTML+="";};}}readAsBinaryString()

开始读取指定的Blob对象或File对象中的内容.当读取操作完成时,readyState属性的值会成为DONE,如果设置了onloadend事件处理程序,则调用之.同时,result属性中将包含所读取文件的原始二进制数据.

functionshowDataByBinaryString(){varresultFile=document.getElementById("fileDemo").files[0];if(resultFile){varreader=newFileReader();//异步方式,不会影响主线程reader.readAsBinaryString(resultFile);reader.onload=function(e){varurlData=this.result;document.getElementById("result").innerHTML+=urlData;};}}readAsText()

开始读取指定的Blob对象或File对象中的内容.当读取操作完成时,readyState属性的值会成为DONE,如果设置了onloadend事件处理程序,则调用之.同时,result属性中将包含一个字符串以表示所读取的文件内容.

functionshowDataByText(){varresultFile=document.getElementById("fileDemo").files[0];if(resultFile){varreader=newFileReader();reader.readAsText(resultFile,'gb2312');reader.onload=function(e){varurlData=this.result;document.getElementById("result").innerHTML+=urlData;};}}事件处理程序

onabort当读取操作被中止时调用.onerror当读取操作发生错误时调用.onload当读取操作成功完成时调用.onloadend当读取操作完成时调用,不管是成功还是失败.该处理程序在onload或者onerror之后调用.onloadstart当读取操作将要开始之前调用.onprogress在读取数据过程中周期性调用.

在文件上传时,HTML5还支持拖拽功能。

来一段W3C对这个特性的介绍。

BeginningwiththeGeolocationAPI,WebApplicationscanpresentrich,device-awarefeaturesandexperiences.Incredibledeviceaccessinnovationsarebeingdevelopedandimplemented,fromaudio/videoinputaccesstomicrophonesandcameras,tolocaldatasuchascontacts&events,andeventiltorientation.

大致包含地理位置API,媒体访问API,访问联系人及事件,设备方向。

下面分别进行研究。

HTML5GeolocationAPI用于获得用户的地理位置。鉴于该特性可能侵犯用户的隐私,除非用户同意,否则用户位置信息是不可用的。一般网页在调用此信息时,会弹出权限申请窗口。

如果电脑获取不到位置信息的话,就在手机上试一下吧。

getCurrentPosition()

getCurrentPosition()方法来获得用户的位置。

标准用法如下:

-检测是否支持地理定位-如果支持,则运行getCurrentPosition()方法。如果不支持,则向用户显示一段消息。-如果getCurrentPosition()运行成功,则向参数showPosition中规定的函数返回一个coordinates对象-showPosition()函数获得并显示经度和纬度

上面的例子是一个非常基础的地理定位脚本,不含错误处理。

完整的处理应该是这样的.

错误代码:-Permissiondenied-用户不允许地理定位-Positionunavailable-无法获取当前位置-Timeout-操作超时-Unknownerror-未知错误

先上demo。麦克风和摄像头也涉及到用户隐私,所以浏览器会向用户申请访问权限。

getUserMedia()

以上的效果,都是通过getUserMedia()方法实现的。

PICTUREvarvideo=document.getElementById("video");varcontext=canvas.getContext("2d");varerrocb=function(code){console.log(code);};if(navigator.getUserMedia){//标准的APInavigator.getUserMedia({"video":true},function(stream){video.src=stream;video.play();},errocb);}elseif(navigator.webkitGetUserMedia){//WebKit核心的APIconsole.log(navigator.webkitGetUserMedia);navigator.webkitGetUserMedia({"video":true},function(stream){video.src=window.webkitURL.createObjectURL(stream);video.play();},errocb);}//将拍好的照片显示在画布上document.getElementById("picture").addEventListener("click",function(){context.drawImage(video,0,0,640,480);});视频获取就是这个样子,音频获取添加"audio":true即可。

这个纯属于W3C的美好设想,还没有正式纳入标准。目前没有搜到靠谱的资料。

但是有两个类似的变通实现。

FirefoxOS(已结束生命)示例代码。

DeviceOrientation常用于检测重力感应方向,DeviceMotion常用于摇一摇功能。

①DeviceOrientation

重力感应也是原生APP中经常见到的一个功能,在WebApp中的应用多见于判断屏幕的旋转方向,以及在此基础上实现的场景应用,如控制页面上物体的左右移动,加减速等。

在WebApp中实现以上的功能,需要实时获取屏幕的旋转方向参数,这些参数可以从浏览器的利用HTML5的DeviceOrientationAPI获得。

当浏览器的Orientation发生变化时,触发DeviceOrientation事件,并返回一个DeviceOrientationEvent对象,其属性列表如下:

注:不同版本的手机操作系统和浏览器,以及不同的应用程序中内置的浏览器对deviceorientation事件的支持不尽相同。尤其在Android平台上,可能会出现有的设备正常工作,有的则毫无反应的情况。

工作原理

根据event对象的三个方向的参数来确定设备的旋转角度。其中,alpha的取值范围是0-360,这个需要根据设备的指南针设定情况而定,一般来说,设备指向正北方向时为0.beta值为设备绕x轴旋转的角度,取值范围为-180-180。gamma取值范围-90-90.

这里面alpha值的意义并不大,主要参考beta和gamma值。当屏幕从水平沿y轴向左倾斜时gamma值变为负值,向右倾斜变为正值。档屏幕从水平沿x轴向前倾斜时beta值变为正值,向后倾斜时变为负值。所以,如果我们设定一个阈值,当beta和gamma的绝对值大于这个阈值时,我们就认为设备发生了旋转。另外根据beta和gamma的值来判断向左倾斜还是向右倾斜,以及倾斜的程度。

实现方式和示例

首先是为浏览器绑定deviceorientation事件和处理程序。

//adddeviceorientationeventlistenerif(window.DeviceOrientationEvent){window.addEventListener('deviceorientation',DeviceOrientationHandler,false);}else{alert("您的浏览器不支持DeviceOrientation");}functionDeviceOrientationHandler(event){varalpha=event.alpha,beta=event.beta,gamma=event.gamma;if(alpha!=null||beta!=null||gamma!=null){dataContainerOrientation.innerHTML="alpha:"+alpha+"
beta:"+beta+"
gamma:"+gamma;//判断屏幕方向varhtml="";if(Math.abs(gamma)BETA_MAX){html="屏幕方向:Portrait";}if(Math.abs(beta)GAMMA_MAX){html="屏幕方向:Landscape";}vargamma_html="";if(gamma>0){gamma_html="向右倾斜";}else{gamma_html="向左倾斜";}html+="
"+gamma_htmlstage.innerHTML=html;}else{dataContainerOrientation.innerHTML="当前浏览器不支持DeviceOrientation";}}这个示例中展示了如何利用beta和gamma值来展示屏幕的旋转方向和侧翻方向。要实现更精确的物体判断,还需要复杂的算法来计算。

扩展应用

使用DeviceOrientationAPI接口可以实现在web中获取手机设备的屏幕旋转方向参数,在示例的基础上进行改进,可以扩展到在屏幕上控制页面元素的移动,实现动画或游戏的目的。例如通过调整屏幕的方向控制页面上的小球走迷宫,控制小车的移动躲避障碍等。

②DeviceMotion

在WebAPP中HTML5也提供了类似的接口,就是DeviceMotionEvent。DeviceMotion封装了运动传感器数据的事件,可以获取手机运动状态下的运动加速度等数据。

DeviceMotionEvent对象属性列表:

event.accelarationIncludingGravity与event.accelaration的区别在于前者加入了重力加速度,即在z轴方向加了9.8,在x,y方向上的值两者相同。

实现摇一摇

先看W3C的定义。

Moreefficientconnectivitymeansmorereal-timechats,fastergames,andbettercommunication.WebSocketsandServer-SentEventsarepushing(punintended)databetweenclientandservermoreefficientlythaneverbefore.

下面对这两种连接方式分别进行研究。

运行原理

浏览器端示例

varwsServer='ws://localhost:8888/Demo';//服务器地址varwebsocket=newWebSocket(wsServer);//创建WebSocket对象websocket.send("hello");//向服务器发送消息alert(websocket.readyState);//查看websocket当前状态websocket.onopen=function(evt){//已经建立连接};websocket.onclose=function(evt){//已经关闭连接};websocket.onmessage=function(evt){//收到服务器消息,使用evt.data提取};websocket.onerror=function(evt){//产生异常};服务器端

握手协议的客户端数据已经由浏览器代劳了,服务器端需要我们自己来实现,目前市场上开源的实现也比较多如:

KaazingWebSocketGateway(一个Java实现的WebSocketServer);mod_pywebsocket(一个Python实现的WebSocketServer);Netty(一个Java实现的网络框架其中包括了对WebSocket的支持);node.js(一个Server端的JavaScript框架提供了对WebSocket的支持);WebSocket4Net(一个.net的服务器端实现);其实在目前的.net4.5框架中已经实现了WebSocket,不用官方实现,我们自己来写个简单的。服务器端需要根据协议来握手、接收和发送。

握手

///

///生成Sec-WebSocket-Accept//////客户端握手信息///Sec-WebSocket-AcceptprivatestaticstringGetSecKeyAccetp(byte[]handShakeBytes,intbytesLength){stringhandShakeText=Encoding.UTF8.GetString(handShakeBytes,0,bytesLength);stringkey=string.Empty;Regexr=newRegex(@"Sec-WebSocket-Key:(.*)rn");Matchm=r.Match(handShakeText);if(m.Groups.Count!=0){key=Regex.Replace(m.Value,@"Sec-WebSocket-Key:(.*)rn","$1").Trim();}byte[]encryptionString=SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(key+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"));returnConvert.ToBase64String(encryptionString);}如果握手成功,将会触发客户端的onopen事件。

解析接收的客户端信息

///

///打包服务器数据//////数据///数据包privatestaticbyte[]PackData(stringmessage){byte[]contentBytes=null;byte[]temp=Encoding.UTF8.GetBytes(message);if(temp.Length<126){contentBytes=newbyte[temp.Length+2];contentBytes[0]=0x81;contentBytes[1]=(byte)temp.Length;Array.Copy(temp,0,contentBytes,2,temp.Length);}elseif(temp.Length<0xFFFF){contentBytes=newbyte[temp.Length+4];contentBytes[0]=0x81;contentBytes[1]=126;contentBytes[2]=(byte)(temp.Length&0xFF);contentBytes[3]=(byte)(temp.Length>>8&0xFF);Array.Copy(temp,0,contentBytes,4,temp.Length);}else{//暂不处理超长内容}returncontentBytes;}WebSockets是一个非常棒的设计,想要了解更多,参考这里。

浏览器通过HTTP向服务器发送请求,服务器端拿出数据库中的最新的信息,立即返回给客户端,客户端等待三秒后再次发出下一个请求。

客户端示例

服务器端示例

服务器负载

-Long-polling占一小部分CPU资源,但是创建空的进程将浪费系统的内存-Server-SentEvents工作的方式有很多,除非Server-SentEvents不必在每一次响应发出后都关闭连接。-WebSockets,服务器只需要一个进程处理所有的请求,没有循环,不必为每个客户端都分配cpu和内存。

客户端负载

-Long-polling取决于实现方式,但终究是一个异步的方式-Server-SentEvents采用浏览器的内置的实现方式,只花费很少的一部分资源。-WebSockets跟Server-SentEvents一样,采用浏览器的内置的实现方式,只花费很少的一部分资源。

-Long-polling接近实时,但是发送新的请求和发送相应会有一定的时延。-Server-SentEvents默认延时3秒,但是可以调整。-WebSockets真正的实时

实现方式复杂度

-Long-polling实现起来非常简单-Server-SentEvents甚至比Long-polling更简单-需要一个WebSockets服务器处理事件,并开放一个端口

看一下W3C的定义。

AudioandvideoarefirstclasscitizensintheHTML5web,livinginharmonywithyourappsandsites.Lights,camera,action!

看的出来HTML5原生支持音视频让W3C很兴奋。也是广大开发者多年的期待。终于可以将Flash踹入茅坑了。

虽然支持音视频很强大,但是确实没有什么好说的,就是两个标签。

HTML5音频处理接口与Audio标签是不一样的。页面上的Audio标签只是HTML5更语义化的一个表现,而HTML5提供给JavaScript编程用的AudioAPI则让我们有能力在代码中直接操作原始的音频流数据,对其进行任意加工再造。

原理

一段音频到达扬声器进行播放之前,半路对其进行拦截,于是我们就得到了音频数据了,这个拦截工作是由window.AudioContext来做的,我们所有对音频的操作都基于这个对象。通过AudioContext可以创建不同各类的AudioNode,即音频节点,不同节点作用不同,有的对音频加上滤镜比如提高音色(比如BiquadFilterNode),改变单调,有的音频进行分割,比如将音源中的声道分割出来得到左右声道的声音(ChannelSplitterNode),有的对音频数据进行频谱分析。

所有的操作都是基于AudioContext这个对象进行的。

得到AudioContext对象。

搜索了一下,并没有找到与AudioAPI这么强大的功能同一级别的VideoAPI。

来看W3C的介绍。

BetweenSVG,Canvas,WebGL,andCSS33Dfeatures,you’resuretoamazeyouruserswithstunningvisualsnativelyrenderedinthebrowser.

大致包含SVG,Canvas,WebGL,和CSS33D,下面分别进行研究。

SVG是用于描述二维矢量图形的一种图形格式。

与其他图像格式相比,使用SVG的优势在于:-SVG可被非常多的工具读取和修改(比如记事本)-SVG与JPEG和GIF图像比起来,尺寸更小,且可压缩性更强。-SVG是可伸缩的-SVG图像可在任何的分辨率下被高质量地打印-SVG可在图像质量不下降的情况下被放大-SVG图像中的文本是可选的,同时也是可搜索的(很适合制作地图)-SVG可以与Java技术一起运行-SVG是开放的标准-SVG文件是纯粹的XML

SVG有三种用法。

①把SVG直接当成图片放在网页上

②SVG动画

画一个五角星

属性stroke-dasharray是让你指定画出的线段每段的长度,第二个值是各段之间空隙的长度。属性stroke-dashoffset是让你指定每个小段的起始偏移量。

想对SVG了解更多的,可以参考下面的网址。

HTML5的canvas元素使用JavaScript在网页上绘制图像。画布是一个矩形区域,您可以控制其每一像素。canvas拥有多种绘制路径、矩形、圆形、字符以及添加图像的方法。

创建Canvas元素

通过JavaScript来绘制

canvas元素本身是没有绘图能力的。所有的绘制工作必须在JavaScript内部完成:

varc=document.getElementById("myCanvas");varcxt=c.getContext("2d");cxt.fillStyle="#FF0000";cxt.fillRect(0,0,150,75);Canvas与SVG对比

Canvas和SVG都允许您在浏览器中创建图形,但是它们在根本上是不同的。

SVG

SVG是一种使用XML描述2D图形的语言。SVG基于XML,这意味着SVGDOM中的每个元素都是可用的。您可以为某个元素附加JavaScript事件处理器。在SVG中,每个被绘制的图形均被视为对象。如果SVG对象的属性发生变化,那么浏览器能够自动重现图形。

Canvas

Canvas与SVG的比较

Canvas-依赖分辨率-不支持事件处理器-弱的文本渲染能力-能够以.png或.jpg格式保存结果图像-最适合图像密集型的游戏,其中的许多对象会被频繁重绘

SVG-不依赖分辨率-支持事件处理器-最适合带有大型渲染区域的应用程序(比如谷歌地图)-复杂度高会减慢渲染速度(任何过度使用DOM的应用都不快)-不适合游戏应用

想对Canvas了解更多的,可以参考下面链接。

先上demo。

WebGL(全写WebGraphicsLibrary)是一种3D绘图标准,这种绘图技术标准允许把JavaScript和OpenGLES2.0结合在一起,通过增加OpenGLES2.0的一个JavaScript绑定,WebGL可以为HTML5Canvas提供硬件3D加速渲染,这样Web开发人员就可以借助系统显卡来在浏览器里更流畅地展示3D场景和模型了,还能创建复杂的导航和数据视觉化。显然,WebGL技术标准免去了开发网页专用渲染插件的麻烦,可被用于创建具有复杂3D结构的网站页面,甚至可以用来设计3D网页游戏等等。

WebGL基本原理

WebGL的出现使得在浏览器上面实时显示3D图像成为现实,WebGL本质上是基于光栅化的API,而不是基于3D的API。

WebGL对象获取

WebGL也是基于Canvas画布做的,下面看一下WebGL获取方法。

无论要实现的图形尺寸有多大,其投影矩阵的坐标的范围始终是从-1到1。下面是一个关于实现WebGL对象的一个简单例子。

//GetAWebGLcontextvarcanvas=document.getElementById("canvas");vargl=canvas.getContext("experimental-webgl");//setupaGLSLprogramvarprogram=createProgramFromScripts(gl,["2d-vertex-shader","2d-fragment-shader"]);gl.useProgram(program);//lookupwherethevertexdataneedstogo.varpositionLocation=gl.getAttribLocation(program,"a_position");//Createabufferandputasingleclipspacerectanglein//it(2triangles)varbuffer=gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,buffer);gl.bufferData(gl.ARRAY_BUFFER,newFloat32Array([-1.0,-1.0,1.0,-1.0,-1.0,1.0,-1.0,1.0,1.0,-1.0,1.0,1.0]),gl.STATIC_DRAW);gl.enableVertexAttribArray(positionLocation);gl.vertexAttribPointer(positionLocation,2,gl.FLOAT,false,0,0);//drawgl.drawArrays(gl.TRIANGLES,0,6);下面是两个着色器。

attributevec2a_position;voidmain(){gl_Position=vec4(a_position,0,1);}voidmain(){gl_FragColor=vec4(0,1,0,1);//green}它将绘出一个绿色的长方形来填充整个画板。

再往后面实在是太过专业了,需要掌握图形图像学的知识,通过demo确实能看出来非常强大,但是需要更专业的人才能搞了。

想对WebGL了解更多,参考这里。

CSS3允许元素以3D的形式显示。

下面讲解一下这个demo是怎样显示出来的。

@-webkit-keyframesmydhua{0%{-webkit-transform:rotateX(0deg)rotateY(0deg)rotateZ(0deg);-webkit-transform-origin:centercenter;}100%{-webkit-transform:rotateX(180deg)rotateY(180deg)rotateZ(180deg);-webkit-transform-origin:centercenter;}}@-moz-keyframesmydhua{0%{-moz-transform:rotateX(0deg)rotateY(0deg)rotateZ(0deg);-webkit-transform-origin:centercenter;}100%{-moz-transform:rotateX(180deg)rotateY(180deg)rotateZ(180deg);-webkit-transform-origin:centercenter;}}接下来就是使用动画。

.wrap{-webkit-animation:mydhua5seaseinfinite;-moz-animation:mydhua5seaseinfinite;}这样我们就得到了一个CSS33D旋转的效果。

想要对CSS33D了解更多的,可以参考下面网址。

看看W3C的介绍。

MakeyourWebAppsanddynamicwebcontentfasterwithavarietyoftechniquesandtechnologiessuchasWebWorkersandXMLHttpRequest2.Nousershouldeverwaitonyourwatch.

性能与集成特性主要包括两个东西,WebWorkers和XMLHttpRequest2。

下面依次介绍。

当在HTML页面中执行脚本时,页面的状态是不可响应的,直到脚本已完成。

Ajax向服务器端发送请求,是异步接收响应的。不然页面会卡住。

WebWorkers是运行在浏览器后台的JavaScript,独立于其他脚本,不会影响页面的性能。您可以继续做任何愿意做的事情:点击、选取内容等等,而此时WebWorkers在后台运行。

setInterval和setTimeout是单线程执行的。

虽然在JavaScript中有setInterval和setTimeout函数使javaScript看起来好像使多线程执行,单实际上JavaScript是单线程的,一次只能做一件事情。

看一个例子。

WebWorkers

WebWorkers

setTimeout(function(){console.log('timeoutfunction');},1000);alert('donotclose');页面一运行就会弹出一个对话框,如果setTimeout是在另外一个线程运行,那么过一秒钟控制台就会打印“timeoutfunction”,事实是只要不关闭对话框,控制台永远不会输出文字,这两句话确实是在一个线程内运行的。

这样的设计使JavaScript比较简单,但有时候也很令人烦恼,因为单线程的设计意味着JavaScript代码必须很快运行完,常见的问题就是一段复杂的JavaScript脚本会中断页面其它脚本执行,甚至会出现页面失去响应,这也就是为什么Ajax的API要设计成异步的。

WebWorkers用法

在html5规范中引入了webworkers概念,解决客户端JavaScript无法多线程的问题,其定义的worker是指代码的并行线程,不过webworker处于一个自包含的环境中,无法访问主线程的window对象和document对象,和主线程通信只能通过异步消息传递机制。

我们需要把希望单独执行的javascript代码放到一个单独的js文件中,然后在页面中调用Worker构造函数来创建一个线程,参数是该文件路径,参数存放如果是相对地址,那么要以包含调用Worker构造函数语句所在脚本为参照,如果是绝对路径,需要保证同源(协议+主机+端口)。这个文件不需要我们在页面使用script标签显示引用

w=newWorker("/example/html5/demo_workers.js");worker对象只有两个属性,其实是两个回调函数句柄。

onerror:当worker运行出现错误,并且没有在worker中被捕获,会在此捕获onmessage:当worker向主线程发送消息是调用在其prototype内有两个重要方法

postMessage:很熟悉的赶脚,之前我们介绍过window对象的postMessage()方法,woker的postMessage方法和window的比较类似,但参数略有不同,只需要传递消息内容就可以,而且支持所有JavaScript原生数据类型,当然不放心的话同样也可以序列化为字符串传递terminate:终止worker执行,有些worker执行比较慢,主线程可以主动终止其执行

demo_workers.js

vari=0;functiontimedCount(){i=i+1;postMessage(i);setTimeout("timedCount()",500);}timedCount();demo.html

计数:

开始Worker停止Worker

想对WebWorkers了解更多的,参考下面链接。

XMLHttpRequest是一个浏览器接口,使得Javascript可以进行HTTP(S)通信。也就是Ajax。

上一代Ajax有以下缺点。

XMLHttpRequest2也就是新的Ajax。针对老版本的缺点,做出了大幅改进,有下面的特点。

XMLHttpRequest2示例

前台代码.

PrintWriterout=newPrintWriter(response.getOutputStream());FileItemFactoryfactory=newDiskFileItemFactory();//为该请求创建一个DiskFileItemFactory对象,通过它来解析请求。执行解析后,所有的表单项目都保存在一个List中。ServletFileUploadupload=newServletFileUpload(factory);Listitems;try{items=upload.parseRequest(request);Iteratoritr=items.iterator();while(itr.hasNext()){FileItemitem=(FileItem)itr.next();System.out.println("是否是FormField:"+item.isFormField());System.out.println("接收到域:"+item.getFieldName());System.out.println("接收到值:"+item.getString("utf-8"));//检查当前项目是普通表单项目还是上传文件。if(item.isFormField()){//如果是普通表单项目,显示表单内容。StringfieldName=item.getFieldName();out.println("thefieldnameis"+fieldName);//显示表单域名称。}else{//如果是上传文件,显示文件名。out.println("theuploadfilenameis"+item.getName());}}out.flush();out.close();}catch(FileUploadExceptione){e.printStackTrace();}对XMLHttpRequest2进行封装。

varaf=newAjaxForm({id:"uploadForm",url:'upload',method:'POST',timeout:5000,onTimeout:function(event){alert('Itistimeout.');},onProgress:function(loaded,total){varcomplete=(loaded/total*100|0);varprogress=document.getElementById('uploadProgress');progress.value=complete;progress.innerHTML=complete;},onComplete:function(result){alert(result);}});af.request();可以看出,虽然是XMLHttpRequest2,但是还是XMLHttpRequest对象。使用新的特性,需要先判断是否支持window.FormData。

但是我们不应该悲观,解决方法总比困难多,Chrome和Firefox也一直在推动浏览器性能提升。前端再也不是切个图,调调颜色,改改字体大小,放个Flash的时代了。HTML5会给我们一个更加美好的未来,前端开发者也有一个提升技术含量,迎接各种机遇的机会了。

THE END
1.微信文件传输助手使用指南:快速方便的文件传输工具手机命令提示符首先,在手机上打开文件传输助手,点击“发送文件”按钮。选择你想要发送的文件,点击“发送”。然后在电脑上打开微信,进入文件传输助手的对话框,你会看到刚刚发送的文件。 从电脑传输文件到手机 在电脑上打开微信,进入文件传输助手的对话框,点击“添加文件”。选择你想要传输的文件,点击“发送”,www.milkchat.cn,。然后https://www.163.com/dy/article/JJFVDGF40556AWQA.html
2.5.4数据传输功能(data关于数据透传,简单理解就是传输通道(传输链路层)不会修改传输的数据内容,仅负责从发送端传输到接收端。但是传输的过程中,数据在链路上传递是基于链路本身。如果链路数据加密,通过该透传通道注入到链路上的数据也同样会加密传输,到达目的端会随着链路数据一起解析出来。此处的DJI SDK中的数据传输功能,是基于DJI无人机、https://sdk-forum.dji.net/hc/zh-cn/articles/5496379768345
3.数据库数据迁移与同步方案深度探索天翼云开发者社区离线迁移:离线迁移通常在系统停机或业务低峰期进行,数据在迁移过程中无法被访问或修改。这种迁移方式简单直接,但会对业务连续性造成一定影响。 在线迁移:在线迁移允许在数据迁移过程中继续访问和修改数据。这通常通过增量迁移、双写等机制实现,以最小化对业务的影响。在线迁移技术复杂,但能够确保业务连续性。 https://www.ctyun.cn/developer/article/624406507151429
4.QQ中的4G在线标志,技术原理与含义解析五金交电摘要:,,本文探讨了QQ上4G在线的含义及其技术原理。4G在线是QQ状态的一种显示,表示用户当前使用的设备正在通过4G网络连接到QQ。背后的技术原理涉及到移动网络的演进和QQ软件的功能设计。通过了解4G网络的高速数据http://xjxygt.cn/post/15467.html
5.聊天在线与离线传输文件qq转离线发送和转在线发送有区别吗文章浏览阅读623次,点赞12次,收藏17次。微信只支持一种文件发送方式,就是发送方把文件发到文件存储服务,然后接收方从文件服务器进行下载。然而,在古老的QQ软件,是支持在线传输和离线传输(微信模式)。_qq转离线发送和转在线发送有区别吗https://blog.csdn.net/littleschemer/article/details/144161451
6.如何qq转离线发送如何qq转离线发送 相关视频/文章qq邮箱怎么发离线 2024/10/4 qq文件如何移到微信发送 2024/10/4 qq文件在线和离线发送的区别 2024/10/4 转离线发送是什么意思 2024/10/4 qq怎样改成离线请留言 2024/10/4 qq如何变成离线请留言 2024/10/4 https://m.51dongshi.com/sdhzgjztfsdhbvdh/
7.转离线发送是什么意思(qq转离线发送是什么意思)爱问知识人以QQ为例,转离线发送是表示对方不在线,文件暂存在服务器,等对方上线就可以从服务器里提取你发的文件https://iask.sina.com.cn/b/newqpiPuiAqN81.html
8.质检培训完整操作指南针对自定义添加的质检标准,如果是有规律可循的标准,建议选择规则检出,然后把规则配起来,规则支持买家咨询商品/买家咨询时间/买家消息内容/客服消息发送位置/是否下单/客服回复行为/等多条件。 设置自定义规则检出后,满足规则条件的会话会自动打上扣分项或加分项的标签。 https://www.360doc.cn/article/27880450_1075329921.html
9.MCGS威纶触摸屏常用技术问题29、 客户做好程序后离线模拟时好用,但是实际同PLC连接应用时就不好用是为什么? 答:离线模拟的时候只是看画面的布局效果等等,不是实际的跟PLC连接时候的状态。实际跟PLC连接不上还是要检查通讯参数设置和通讯电缆是否正确。 30、 我们8000的产品如果加CF卡或U盘时该怎么把配方等东西存到CF卡或U盘里,怎么找CF卡或Uhttp://www.kunluntongtai.com/index.php?m=content&c=index&a=show&catid=39&id=294
10.LiteGearsLiteGearsOnlineHelpandDocsPage3把SolidWorks工程图转成PDF有两种方式,一种方式是直接转换PDF,另一种方式是通过PDF虚拟打印机打印成PDF。 我们一般推荐使用第一种方式,一般除了可能会遇到一些字体问题,没有别的缺点。而打印成PDF的方式在速度,兼容性,方便性,需要安装额外软件等方面都没有优势。所以不推荐这个方式。 http://help.litegears.com/en/author/litegears/page/3
11.常见问题和群组有什么区别? 一个聊天室支持100万人。聊天室和群组最大的区别在于,聊天室的消息没有推送通知和离线保存,也没有常驻成员的概念,只要进入聊天室即可接收消息,开始聊天, 一旦退出聊天室,不再会接收到任何消息、通知和提醒。注意:进入聊天室会自动获取最近50条消息,客户端目前不支持创建聊天室 实时音视频怎么收费?https://docs.jiguang.cn/jmessage/guideline/faq
12.腾讯QQ会员当好友不在线时,您依然可以向好友发送文件,文件会保存在我们的服务器中,当您的好友下次登录QQ时就能通过我们的提醒,立即获取您向他/她发送的文件了! C2C离线传文件扩容 离线传文件大扩容,流量步入T级时代!QQ会员独享特权,大文件统统秒传!离线文件传送功能面向所有QQ用户,QQ会员享受更大存储容量特权,会员的离线传文https://baike.sogou.com/v57414345.htm
13.QQ密技68招(超强)QQ技巧QQ专栏这些备份数据一般都不大,你完全可以压缩后把它作为附件发送到E-mail里,下次在别处使用QQ时再下载过来,然后通过“消息管理器”把消息数据导入或者用目录文件覆盖同名目录(注意之前要先登录一次,退出后覆盖),这样就大功告成,你的数据资料又奇迹般地回来了!https://www.jb51.net/qq/15144_all.html
14.关于WebQuest在课堂教学中,一个典型的较长期WebQuest一般将持续1周到1个月,其教学目标是知识的拓展和提炼,所以,在完成了一个较长期WebQuest以后,学习者对知识体系进行了深入的分析,能够将知识进行某种方式的转换,并要求他们通过制作一些可供他人在线或离线交互的多媒体作业来证明自己对这些知识的理解。 http://www.360doc.com/content/11/0409/21/6020603_108461870.shtml
15.探索澳元(AUD)兑换人民币(CNY)的条件汇率和优惠。总之,从AUD兑换CNY是一种安全,便捷和经济有效的方式来发送海外资金。具有竞争力的汇率和少量隐藏收费,此交换选项可能是您的资金转移需求的完美选择。 在线与离线AUD转CNY的区别是什么? 涉及汇款时,用户经常注意外汇汇率。如果能准确快速地做好转换,可以极大地方便使用者。因此,越来越多的人开始比较在线和离线AUD到CNYhttps://item.pandaremit.com/article/3538.html
16.前端面试题详细整理总结发送一个请求来取得服务器上的某一资源 2、POST方法 向URL指定的资源提交数据或附加新的数据 3、PUT方法 跟POST方法很像,也是想服务器提交数据。但是,它们之间有不同。PUT指定了资源在服务器上的位置,而POST没有 4、HEAD方法 只请求页面的首部 5、DELETE方法 https://www.imooc.com/article/309425
17.可能不是史上最全但很实用的BOMAPI详解1监听设备在线离线状态:onLine 的用途 window 提供了 online(上线) 和 offline(离线) 两个事件,可以通过监听这两个事件,并配合 onLine 属性进行判断设备是否离线。 window.addEventListener('online', printNetworkState);window.addEventListener('offline', printNetworkState);function printNetworkState() {console.log(navhttps://developer.aliyun.com/article/1266012
18.理解iOS消息推送一文就够:史上最全iOSPush技术详解1)判断app能否在线: 此处可以根据APP自身的后端策略如上一次与后端交互的时间等方法来判断APP能否在线或者者离线。认为在线,会发送在线push,否则,发送离线push。 2)在线push有以下几个特点: 不需要经过苹果APNs; 需要自己实现长链接; 代码在app内部实现。 https://www.songma.com/news/txtlist_i2865v.html
19.qq腾讯文档怎么转成Excel3d溜溜设计问答平台为广大设计师们提供各种qq腾讯文档怎么转成Excel问题解答,3d溜溜素材问答平台汇聚全球各地的设计师、名师名司、设计爱好者等设计灵感和经验,迅速为您解决qq腾讯文档怎么转成Excel的困惑。https://www.3d66.com/answers_relation/relation_3631089_10.html
20.在线音频转文字在线服务华为云帮助中心为你分享云计算行业信息,包含产品介绍、用户指南、开发指南、最佳实践和常见问题等文档,方便快速查找定位问题与能力成长,并提供相关资料和解决方案。本页面关键词:在线音频转文字。https://support.huaweicloud.com/topic/133355-5-Z
21.交易公告3.14.3、铁芯、绕组外部的电气连接线或油箱中的结构件不超过 80K3.15、变压器应装设在线滤油装置,具体设备及配置由厂家提供,厂家应提供国内先进的设备及配件,以满足现场需求。 3.16、过载能力变压器允许短时间过载能力按照 GB1094 执行。 3.17、承受短路电流能力各侧短路容量满足 GBl094.5 的要求,短路后各部位无损坏https://www.qhggzyjy.gov.cn/ggzy/jyxx/001001/001001003/20211224/4629299d-f91b-4656-be33-3d3213b51cd3.html
22.云客服规范及质检规则33.以下关于升级流转的规范哪个是错误的? A当前客户主动要求在线升级转接,小二需优先明确客户问题并 按规范要求进行解答 B不认可解答,可以征询会员同意的前提下升级转接 C当前客户主动要求在线升级且不愿意描述问题,小二可发送转 接承接语后做好转接备注进行转接 https://www.360wenmi.com/f/fileafqhtc3q.html