整合營銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          HTML5 崛起之時,Java 桌面時代就已經(jīng)終結(jié)了

          004 年 Google Maps 的面世標(biāo)志著 Java 桌面時代的終結(jié),也改變了桌面環(huán)境下“跨平臺”的基本定義。


          本文作者以個人視角對 Java 桌面發(fā)展歷程做了回顧,內(nèi)容來自他在上世紀(jì)九十年代后期擔(dān)任 Java 開發(fā)者時的所見所感,主要講述曾經(jīng)的“殺手級”桌面語言 Java 是為何從 21 世紀(jì)開始頹勢盡顯、步入衰落的。值得一提的是,作者如今在做一款開發(fā)者友好型 Java 桌面部署工具(jDeploy),其實他還是希望 Java 可以重拾風(fēng)采,再度變得對桌面開發(fā)具有吸引力。


          本文是該回顧系列文章中的第二篇,在上期文章中,作者回顧了 Java 制霸桌面的鴻圖如何在 1999 至 2005 的短短幾年間煙消云散。當(dāng)初的 Java 可謂志得意滿、憑 Applet 小程序技驚四座,下決心要在互聯(lián)網(wǎng)時代下重新定義“桌面”。互聯(lián)網(wǎng)的未來在于“跨平臺”,而 Java 的血管中涌動的正是“跨平臺”的血液,優(yōu)勢在握!可遺憾的是,事后來看,此跨平臺似乎并非彼跨平臺。接下來,讓我們繼續(xù)跟著作者的腳步去看看,具體在 2004 至 2007 年間,Java 桌面又經(jīng)歷了什么。

          桌面王朝的最后時光

          2002 年左右,我在客服中心為客戶提供計算機(jī)與打印機(jī)技術(shù)支持。我和小伙伴們擠在小小的隔間里,面對著一款桌面程序。通過這款軟件,我們可以快速查詢客戶和產(chǎn)品信息,并把通話中的重要信息記錄進(jìn)去。


          在典型的客服來電中,我們會詢問客戶的產(chǎn)品序列號,再把結(jié)果輸入系統(tǒng)。如果他們之前就打過電話,系統(tǒng)就會輸出窗口,里面包含產(chǎn)品的完整歷史記錄和之前的求助細(xì)節(jié)。在參考其他同事留下的事由記錄后,我還能操作界面中的選項卡和功能按鈕,例如幫客戶更換新機(jī)。


          我不記得這款軟件叫什么名字了,可能是為公司或者客服中心專門定制的吧。印象里這應(yīng)該是 PeopleSoft(仁科公司,2005 年已被甲骨文收購)的產(chǎn)品,但我也不太確定。總之,這款桌面軟件運行在 Windows 2000 系統(tǒng)上,肯定不是 Web 應(yīng)用程序。它其實挺復(fù)雜,里面包含不少菜單和表單;不過一旦上手,整個使用體驗相當(dāng)棒——速度快、反應(yīng)靈敏,幾乎沒有任何延遲。以輸入電話號碼查詢客戶記錄為例,我們只需要在“電話”字段里輸入號碼,其余空白表格就會立刻被客戶信息填充完整。


          據(jù)我所知,這款程序肯定不是用 Swing 編寫的。但如今全球各地?zé)o數(shù)公司都在使用由 Swing 編寫的企業(yè)級桌面軟件,它們在使用體驗上跟我當(dāng)初接觸的這款程序非常相似。換句話說,Swing 已經(jīng)滿足了我們在 2001、2002 年那會對于桌面業(yè)務(wù)軟件的全部期望和想象。


          在工作半年之后,上邊來了新指示,要求我們用 Web 應(yīng)用程序替換掉之前的桌面軟件。據(jù)說新系統(tǒng)會讓我們的工作更輕松,但在第一節(jié)培訓(xùn)課剛剛過去十分鐘后,我們就意識到這根本就是胡說八道:新系統(tǒng)簡直爛透了!


          我不太記得當(dāng)時使用的是 IE 5.5 還是 IE 6 了,總之就是前 AJAX 時代的 Web 環(huán)境。現(xiàn)在在產(chǎn)品字段中輸入序號后,系統(tǒng)會彈出一個窗口,上面寫著“正在加載……請勿關(guān)閉此窗口”。幾秒后,窗口自行消失,客戶詳細(xì)信息出現(xiàn)在表單當(dāng)中。反正每當(dāng)需要從服務(wù)器獲取內(nèi)容時,這個倒霉窗口就會跳出來。領(lǐng)導(dǎo)還提醒我們別隨便在瀏覽器里點“刷新”,說是這樣會破壞系統(tǒng)狀態(tài)。于是每每出現(xiàn)問題,我就只能先登出、再重新登錄。


          我不太理解公司為什么要用這款“傻了吧唧”的 Web 應(yīng)用程序替代之前的桌面軟件。可能是出于成本考慮吧,畢竟跟桌面軟件相比,Web 應(yīng)用程序的開發(fā)和維護(hù)成本都更低。或者是軟件供應(yīng)商強(qiáng)行施壓,比如“Web 才是未來,每個人都必須接受!”但,真有這么強(qiáng)勢的乙方嗎?


          無論如何,這里透露出一個重要的信息:Web 應(yīng)用程序還沒等發(fā)展完善,就已經(jīng)開始蠶食桌面軟件的生存空間。唯一的問題就是 Web 應(yīng)用需要多久才能追平桌面軟件的使用體驗。而事實證明,用不了多久。

          恐怖谷效應(yīng)

          再回到 Java 這邊。熱情的支持者們正不斷擴(kuò)大 Java 帝國的桌面版圖,對 WORA(一次編寫、隨處運行)的熱情也引導(dǎo)他們最終邁向跨平臺小程序與“本機(jī)”應(yīng)用程序之間的秘密山谷。那時候的 Java IDE 主要面向三大構(gòu)建目標(biāo):


          1. 小程序
          2. Java Web 開發(fā)
          3. 可執(zhí)行 Jar 文件是的,沒有直接開發(fā)本機(jī)應(yīng)用程序的選項。雖然有第三方工具可以把 Jar 文件轉(zhuǎn)換為本機(jī)應(yīng)用程序,但這類工具相當(dāng)復(fù)雜而且操作流程極為繁瑣。只有對自己最“狠”的人才能堅持用得下去。而 Java 之所以有勇氣忽視這一點,靠的就是對未來的判斷——本機(jī)桌面應(yīng)用程序終于被淘汰。其實這個預(yù)言是正確的,只是在時間上有所偏差。


          從 2022 年的角度回顧,Java 身上其實有很多顯而易見的問題。應(yīng)用程序可以作為 Web 部署、也可以按本機(jī)部署,但這兩種形式都沒有一丁點“原生”感。Web 部署的小程序運行在自己的“沙箱”內(nèi)并被集成到網(wǎng)頁當(dāng)中,整個運行過程又慢又遲鈍。

          HTML5 的崛起

          雖然 Java 總想在 Web 和桌面之間建起一道橋梁,但它自身卻被 Web 所裹挾。到 2002 年,很多企業(yè)開始把原本的桌面軟件功能遷移到 Web 端。這些 Web 應(yīng)用程序的構(gòu)建、維護(hù)和部署成本確實比桌面軟件低得多,代價就是在用戶體驗上做出妥協(xié)。


          大約也是在這個時候,Java 開始推崇“富互聯(lián)網(wǎng)應(yīng)用”的概念,希望把好 Web 應(yīng)用跟差 Web 應(yīng)用區(qū)分開來。但到 2004 年 Google Maps 正式亮相時,Java 的小把戲徹底宣告破產(chǎn)。Google Maps 以令人震驚的效果為富 Web 應(yīng)用程序樹立了標(biāo)桿,而人家用的是 HTML5。


          我最近又看了一次 Bill Atkinson 第一次向蘋果愛好者們展示 MacPaint 的舊視頻。在他第一次通過鼠標(biāo)用畫筆工具繪出圖案時,現(xiàn)場一片“哇哦”和掌聲。這就叫開創(chuàng)性。我第一次看到 Google Maps 也是類似的感覺,地圖可以無縫縮放、萬向平移,壓根看不出來任何拼接的痕跡。這里使用的全新技術(shù)被稱為 AJAX(異步 JavaScript 與 XML),這也是人們第一次能夠在 Web 應(yīng)用程序中向服務(wù)器后臺無縫發(fā)出請求。現(xiàn)在這一切當(dāng)然被視為理所當(dāng)然,可 2004 年那會,開發(fā)者需要絞盡腦汁才能把那些讓人想吐的框架或者彈窗隱藏起來,確保不用刷新整個頁面就能從服務(wù)器處加載新數(shù)據(jù)。


          身為 Web 開發(fā)者,我當(dāng)然對其中的無窮可能性心生向往。但從桌面開發(fā)的角度看,這場歷史性的變革似乎沒有給桌面、特別是 Java 帶來任何影響。


          在 HTML5 之前,“跨平臺”的意思是“跨 Windows、Mac 和 Linux”,所以跨的范圍還是在桌面范疇之內(nèi)。當(dāng)時我并沒意識到,但現(xiàn)在來看 HTML5 的亮相代表著新平臺時代的降臨——它將成為客戶端應(yīng)用程序的客觀標(biāo)準(zhǔn);更重要的是,Java 支持不了這個平臺。突然之間,WORA 理念就出現(xiàn)空白了——Swing 應(yīng)用程序適用于一切平臺,除了最重要的那個:網(wǎng)絡(luò)瀏覽器。

          Java 開發(fā)者紛紛“外逃”

          那 Java 桌面開發(fā)者們都跑哪去了?方向主要有三:

          1. 服務(wù)器
          2. 瀏覽器(HTML5)
          3. 桌面應(yīng)用如果大家對自己的基本定位首先是“Java 開發(fā)者”、其次是“客戶端開發(fā)者”,那最終應(yīng)該會選擇 Java 在當(dāng)下仍然占據(jù)主動的平臺——服務(wù)器。如果你對面向用戶開發(fā)(客戶端)更感興趣,而且主要看中 Java 的跨平臺價值主張,那接下來的目標(biāo)很可能是 HTML5 (Javascript/HTML/CSS)開發(fā)。如果你是鐵桿“保皇黨”(比如說我),那就繼續(xù)堅守 Java 桌面開發(fā),同時滿腹狐疑地看著自己這個圈子越來越小。

          GWT:讓 Java 走進(jìn)瀏覽器

          2000 年初,JavaScript 開發(fā)工具尚處于起步階段。大多數(shù) Web 開發(fā)者只能使用文本編輯器來編寫.js 文件。簡單的驗證腳本和交互設(shè)計倒是沒問題,但這種粗糙的方法肯定不能擴(kuò)展并支持大型企業(yè)應(yīng)用程序項目。另外,當(dāng)時的 JavaScript 語言還不具備開發(fā)者在重構(gòu)等重要操作時所需要的功能,例如靜態(tài)類型。


          相比之下,Java 已經(jīng)擁有一套全面的開發(fā)工具,能夠輕松擴(kuò)展至任何規(guī)模的項目。到 2004 年,領(lǐng)先且成熟的 Java IDE 已經(jīng)成為開發(fā)環(huán)境中的標(biāo)桿,其中的靜態(tài)類型更是大大簡化了大型項目的維護(hù)難度。到這時,唯一的遺憾就是 Java 應(yīng)用程序無法在網(wǎng)絡(luò)瀏覽器中運行(只有小程序可以)。


          為了解決這個難題,Google 打造出 GWT(Google Web Toolkit)。這是一套 Java 到 JavaScript 的編譯器加運行時庫,允許開發(fā)者借助 Java 那一整套領(lǐng)先的開發(fā)工具編寫應(yīng)用程序,再把成果部署成 JavaScript 應(yīng)用的形式在瀏覽器內(nèi)原生運行。這套運行時庫包含諸多核心 Java API(例如 java.lang、java.util 等)的實現(xiàn),確保業(yè)務(wù)邏輯能夠在 GWT 應(yīng)用程序與服務(wù)器應(yīng)用程序間順暢共享。


          在用戶界面方面,GWT 也提供自己的功能部件,其實質(zhì)就是以 Java 的形式將各部件與瀏覽器中的本機(jī) HTML 部件相綁定。雖然我們還是沒法直接使用 Swing 代碼、大部分第三方庫也不在支持之列,但我們至少可以用到自己最熟悉的 Java 開發(fā)環(huán)境和核心 API。


          所以這不能算是讓 Java 真正走進(jìn)了瀏覽器——標(biāo)準(zhǔn) JavaSE 庫仍然大部分不受支持,線程等核心功能也無法起效。但至少對多數(shù)用例來說,這已經(jīng)夠了。


          Google 用 GWT 開發(fā)出很多流行一時的 HTML5 應(yīng)用程序,其中最著名的就是 Gmail,這個項目還催生出一個規(guī)模不大、但卻相當(dāng)活躍的開源社區(qū)。雖然影響力已經(jīng)今非昔比,但這個社區(qū)直到現(xiàn)在也仍然存在。與此同時,JavaScript 工具的逐步改進(jìn)也在擠占 GWT 的生存空間,過去十年來誕生的一系列更為現(xiàn)代的解決方案也允許我們在瀏覽器中更“無腦”地使用 Java。

          服務(wù)器上的淘金熱

          HTML5 的出現(xiàn)顛覆了 Java 制霸桌面的野心,但這里也有好消息。由于不必分神于桌面端,Java 在服務(wù)器端迎來了全面發(fā)展。Java 做好了戰(zhàn)斗準(zhǔn)備、努力滿足開發(fā)者對后端服務(wù)的種種新需求——畢竟沒有后端,再好的 Web 應(yīng)用也出不來。


          Java 在服務(wù)器端的受歡迎程度在接下來幾年中持續(xù)增長,也吸引到整個生態(tài)系統(tǒng)的高度關(guān)注。第三方庫不斷涌現(xiàn),而 2005 年 Maven 的誕生也讓第三方庫的使用不再復(fù)雜繁瑣。無需額外下載、不必尋找依賴項,直接把片段粘貼到 pom 文件中,它就能自動下載一切相應(yīng)依賴項。


          Java 的開發(fā)工具也在不斷改進(jìn),這在很大程度上要歸功于 Java 在服務(wù)器端的優(yōu)勢地位。這些改進(jìn)也對桌面開發(fā)者產(chǎn)生了積極影響,讓我們用上了跟服務(wù)器端相同的 IDE、編譯器、虛擬機(jī)和庫。然而,代表 Java 世界“最后的堅持”的這幫桌面開發(fā)者眼界還是沒能打開,仍在圍著 UI 庫的改進(jìn)和部署打轉(zhuǎn)。


          遇到問題時,我的習(xí)慣是上 Google 搜一搜,看看有沒有其他人遇到或者已經(jīng)解決過相同的問題。但在 Swing 開發(fā)上,我發(fā)現(xiàn)最新的搜索結(jié)果也基本是 2005 年左右的內(nèi)容了,之后基本再無新增。在找不到答案時,我偶爾會寫一篇問題分析博文。而在兩年后再次遇到類似問題時,我在 Google 上找到的就是自己兩年前那篇博文……說真的,現(xiàn)在還有喘氣的 Swing 開發(fā)者嗎?感覺真的說不好。

          重新定義“桌面應(yīng)用”

          從各個方面來看,Web 的興起讓“桌面應(yīng)用”的概念清晰了起來。Java 最初的跨平臺客戶端開發(fā)愿景并沒有把瘦客戶端(主要與遠(yuǎn)程服務(wù)器交互)跟本機(jī)完整桌面應(yīng)用程序區(qū)分開來。這不僅提高了理解難度,更讓安全模型的設(shè)計有些無所適從。Java 理解中的“平臺”就是計算機(jī)本身,所以會使用笨拙的沙箱來限制可能引發(fā)安全威脅的 API 訪問,例如訪問文件系統(tǒng)。這是 Java 一切安全漏洞的根源,也是導(dǎo)致 Java 被逐出瀏覽器世界的原因。


          這種基于“沙箱”的開發(fā)體驗相當(dāng)糟糕,因為我們很容易意外“越界”并觸發(fā)安全異常。最終結(jié)果是,幾乎所有客戶端都會請求對系統(tǒng)進(jìn)行“可信”訪問,這樣也就完全繞過了沙箱的限制。


          相比之下,HTML5 在 Web 和桌面之間設(shè)立了明確的邊界。Web 應(yīng)用程序默認(rèn)無權(quán)訪問客戶端計算機(jī),而瀏覽器才是那個“平臺”,這就讓客戶端應(yīng)用程序的安全保障變得更輕松、更易行。


          經(jīng)過此番變革,“桌面”的范疇變得更小,以往很多被視為“桌面應(yīng)用程序”的軟件現(xiàn)在被劃入“客戶端應(yīng)用程序”類別。具體來講,如果應(yīng)用程序只負(fù)責(zé)在用戶與服務(wù)器交互時提供 UI,那它就屬于客戶端應(yīng)用程序。“桌面”這個概念現(xiàn)在指的就是那些以某種方式與本機(jī)設(shè)備相集成的應(yīng)用程序,包括訪問文件系統(tǒng)(開發(fā)工具、文件轉(zhuǎn)換工具等)、調(diào)用瀏覽器中不存在的某些平臺本機(jī) API、以及執(zhí)行算力密集型任務(wù)的軟件。


          這倒不是說“客戶端”應(yīng)用程序跟“桌面”應(yīng)用程序間就毫無交集——當(dāng)然有,這兩者都涉及 GUI,而且不少現(xiàn)代桌面應(yīng)用程序也都需要接入服務(wù)器。所以無論是桌面還是客戶端應(yīng)用程序,都能享受到 GUI 工具包改進(jìn)、媒體(音頻/視頻)及網(wǎng)絡(luò)等技術(shù)層面的改進(jìn)成果。

          Java 桌面的新征程

          2004 年,我曾在 Mac 和 Windows 上都開發(fā)出一些商用級別的 Java 桌面應(yīng)用程序。HTML5 對這類應(yīng)用程序基本沒有任何直接影響。結(jié)合自身需求,Swing 還是完全夠用,我用來構(gòu)建本機(jī)捆綁包的各種桌面部署工具也都能正常起效。


          但很遺憾,科技行業(yè)就是個不進(jìn)則退的世界。在接下來的幾年中,Web 平臺一路突飛猛進(jìn)、而 Swing 卻始終停滯不前。到 2007 年,Swing 已經(jīng)到了不變革、就消亡的危難關(guān)頭。它需要響應(yīng) HTML5 這波歷史性潮流,而最終答案就是 JavaFX。這是一種新奇的 Java UI 工具包,能夠把 Java 帶入 GPU 加速、場景圖、3D 圖形、Web 視圖的現(xiàn)代新世界,同時支持 MP3 和 MP4 等現(xiàn)代音視頻編解碼器。


          在下一篇文章中,我們將回顧 JavaFX 的火爆人氣、深遠(yuǎn)影響,以及 2011 年 Mac 應(yīng)用商店出現(xiàn)前 Java 領(lǐng)域的其他發(fā)展趨勢。別小瞧 Mac 應(yīng)用商店,它的出現(xiàn)堪稱對 Java for Mac 桌面開發(fā)生態(tài)的“斬首行動”。


          原文鏈接:

          https://jdeploy.substack.com/p/the-decline-and-fall-of-java-on-the-970

          了解更多軟件開發(fā)與相關(guān)領(lǐng)域知識,點擊訪問 InfoQ 官網(wǎng):https://www.infoq.cn/,獲取更多精彩內(nèi)容!

          于HTML5 淺析

          前言:

          作為一名Web開發(fā)者,可能你并沒有對這個“H5”這個字眼投入太多的關(guān)注,但實際上它早已不知不覺進(jìn)入到你的開發(fā)中,并且總有一天會讓你不得不正視它,了解它并運用它

          打個比方:《海賊王》中的主角路飛在“頂上戰(zhàn)爭兩年前”,會在一些危急關(guān)頭“不經(jīng)意”地使用霸王色霸氣,但對”霸氣“的結(jié)構(gòu)體系和具體運用都不太了解,這讓他在香波地群島等諸多重大戰(zhàn)役中大吃苦頭。此后, 他不惜花費兩年時間跟隨雷利修煉霸氣。因為,如果不去了解這個嶄新的戰(zhàn)斗方法的話,他們在殘酷的新世界一天也生存不了。


          為什么學(xué)習(xí)HTML5?

          咳咳, 回到主題,為什么我們要學(xué)HTML5呢?

          1. 了解HTML5的囊括范圍的一大好處是:當(dāng)你不小心使用了一個H5的東東的時候(例如你試圖通過百度找到的答案解決一個緊張的需求),你會很及時的關(guān)注它的兼容性

          2. H5有些新增的特性也許你從沒接觸過,也感覺無需用到它。但就在不久的將來,你可能就會用到,甚至依賴于它(畢竟這就是HTML的未來)


          H5中的知識點分布

          在下面, 我將學(xué)習(xí)H5中的知識點分成兩類:主要知識點和針對特定功能的知識點,其中對主要知識點的部分,從學(xué)習(xí)成本的角度對其進(jìn)行了難度分級

          (僅屬個人觀點!如有改進(jìn)意見,歡迎討論)

          一.主要知識點

          (從需求層面上來說,普及范圍相對較廣)

          相對容易的部分:

          1.在線和離線事件(Online/Offline) (相對容易)

          2. 眾多的新增元素 如<output>, <progress>等 (相對容易)

          3. history關(guān)于歷史狀態(tài)管理的API (相對容易)

          4 Storage(localStorage和sessionStorage) (相對容易)

          相對較難的部分:

          5. Web Worker (相對較難)

          6. canvas (相對較難)

          7. indexedDB (相對較難)

          8. 拖放操作 (相對較難)

          9. Web Sockets (相對較難)

          二. 針對特定功能的知識點

          (對需求來說,主要針對某一方面的特殊需求場景)

          1. 對音視頻的支持

          2. Camera API (操作攝像頭)

          3. WebGL (3D圖像)

          4. 地理位置定位 (geolocation對象)

          本文主要講述H5中主要知識點中,學(xué)習(xí)成本相對較高的四個點(僅個人觀點):

          一.Web Worker

          二.canvas

          三.indexedDB

          四.拖放操作

          【注意】因為下面介紹的H5的特性在一些比較老的瀏覽器里可能遇到兼容性問題,所以你在使用前必須要能力檢測,例如這樣


          Web Worker

          Web Worker的機(jī)制讓你能夠創(chuàng)建一個在后臺線程運行的腳本,這個腳本不會對我們當(dāng)前執(zhí)行任務(wù)的腳本造成任何干擾(例如阻塞),同時Web Worker提供了一套API使你能夠在當(dāng)前腳本和后臺腳本間進(jìn)行數(shù)據(jù)的互相傳輸(worker)

          “一套API, 兩個對象”

          我們現(xiàn)在已知的關(guān)于Web Worker的機(jī)制是: 有一個當(dāng)前腳本, 和一個在后臺運行的worker腳本,所以我們問題的關(guān)鍵就落在了這兩個腳本的通信(數(shù)據(jù)交互)上

          通過

          生成了“兩個對象”(你可能會問:為什么是兩個不是一個呢?請往下看

          “第一個”對象是我們在當(dāng)前腳本中通過構(gòu)造函數(shù)顯式創(chuàng)建出來的worker對象,它擁有一套API:postMessage和onmessage,通過postMessage方法可以向worker腳本(上文worker.js)發(fā)送數(shù)據(jù), 通過onmessage方法可以從worker腳本接收數(shù)據(jù)

          “第二個”對象是在Web Worker腳本(上文的worker.js)中隱式創(chuàng)建出來的全局變量對象它叫DedicatedWorkerGlobalScope(這個時候在work.js全局變量對象是它而不是Window!!),而它也擁有一套API:postMessage和onmessage,通過postMessage方法可以向當(dāng)前執(zhí)行任務(wù)的腳本發(fā)送數(shù)據(jù), 通過onmessage方法可以從當(dāng)前執(zhí)行任務(wù)的腳本接收數(shù)據(jù)

          【注意】關(guān)于DedicatedWorkerGlobalScope

          1. 它是在Web Worker腳本中生成的特殊的全局變量對象,也就是在全局執(zhí)行環(huán)境中使用this指向的不是Window而是它

          2. 它不能像Windows那樣通過變量名直接訪問,但在Web Worker腳本中你能通過this取到它

          所以現(xiàn)在數(shù)據(jù)傳遞方向有兩條:

          1. 調(diào)用當(dāng)前腳本中worker對象的postMessage方法, 然后在Web Worker腳本(上文的worker.js)中通過onmessage這個回調(diào)方法接收數(shù)據(jù)

          2. 調(diào)用Web Worker腳本中的this.postMessage方法(this指向DedicatedWorkerGlobalScope),然后在當(dāng)前腳本中worker對象的onmessage回調(diào)方法接收數(shù)據(jù)

          看到這里可能有點懵,來讓我們通過一個例子看看1中的數(shù)據(jù)傳遞:

          先看示例吧,這是我們的目錄結(jié)構(gòu)

          index.html:

          main.js:

          worker.js:

          點擊按鈕后,在main.js中調(diào)用worker對象的postMessage方法, 這個數(shù)據(jù)就被發(fā)給了work.js中的全局變量對象DedicatedWorkerGlobalScope, 所以我們在work,js中通過this.onmessage接收數(shù)據(jù)并輸出


          postMessage中的參數(shù)會“原封不動”傳遞給onmessage中的event.data

          【注意】postMessage傳遞的參數(shù)會被“原封不動”地傳遞給onmessage中event對象的data屬性

          例如:

          postMessage([1,2,3]) ——> this.onmessage = function (e) { } 中 e.data === [1,2,3]

          postMessage({a:1,b: 2}) ——> this.onmessage = function (e) { } 中 e.data === {a:1,b: 2}


          當(dāng)前任務(wù)腳本和worker腳本完整的通信流程

          我們上面的例子展現(xiàn)的是從當(dāng)前任務(wù)腳本向worker腳本傳遞數(shù)據(jù),那么同樣的道理,我們也能從work腳本向當(dāng)前任務(wù)腳本傳遞數(shù)據(jù)(方式相同)

          例子:

          index.html:

          同上

          main.js:

          worker.js:

          demo如下

          點擊傳遞數(shù)據(jù)輸出:

          canvas

          cancas是H5新增的一個標(biāo)簽,把canvas翻譯過來就是畫布,顧名思義,這是用來”畫畫的“,畫畫的”畫筆“是什么呢? 它就是和canvas元素對象對應(yīng)的一個”上下文對象“(context),這里的這個上下文對象可能和你印象中的”上下文“有較大的差異,它只是個單純的包含了一系列“繪畫”方法的對象,下面我們介紹的關(guān)于canvas的內(nèi)容都要圍繞這個"canvas上下文對象"展開

          我們可以通過這種方式取得canvas上下文對象:

          假設(shè)這是我們的HTML:

          這樣取得上下文對象:


          繪制基本形狀

          下面展現(xiàn)的是上下文對象的一些繪制圖形的方法(它們都可以被ctx調(diào)用)

          上面的x,y代表相對于canvas畫布左上角的橫縱坐標(biāo):

          例子:

          html部分:

          JS部分:

          【注意】. canvas標(biāo)簽內(nèi)的內(nèi)容(例如上面的文本)是否呈現(xiàn)取決于瀏覽器是否支持canvas,如果支持,則不出現(xiàn),如果不支持,則會呈現(xiàn)出來

          demo:


          給畫筆添加顏色和樣式

          我們以上面的為基礎(chǔ)稍作修改:

          demo:


          繪制文本

          demo:

          這里要稍微提一下, 也許上面的那些繪制圖形,繪制文本的操作對你來說都沒有觸動,因為它們離我們的直接需求似乎還有一定的距離,但我想接下來的這幾個上下文API你或許有些興趣。

          例如我們可能有一個需求是載入已有的圖片,對它截圖(裁剪)后保存為一張新的圖片,這個時候我們就可以使用到canvas的繪制圖片,裁剪圖片,保存圖片的API了


          直接繪制已有圖片

          通過canvas上下文對象的drawImage方法可直接繪制圖片

          我們可以通過下面的一段代碼動態(tài)獲取img元素對象

          廢話不多說,直接上demo!

          在相同目錄下有這么一張圖片

          JS代碼:

          demo:

          我們發(fā)現(xiàn), 圖片加載完成后被寫入了畫布當(dāng)中!


          圖片裁剪功能

          canvas上下文對象的clip方法可根據(jù)路徑對canvas畫布進(jìn)行裁剪

          讓我們在原來的基礎(chǔ)上添加一點東西:

          【注意】clip方法的調(diào)用要在drawImage方法之前,否則不能成功! 也就是說要“先裁剪,再畫圖”

          canvas的保存和導(dǎo)出

          我們通過document.getElementById("canvas")取得的畫布對象,有一個toDataURL()方法,可將當(dāng)前畫布作為一張圖片,并返回其base64編碼格式的數(shù)據(jù),這在保存圖片的時候非常有用

          toDataURL接受兩個參數(shù):圖片類型和質(zhì)量參數(shù)

          canvas.toDataURL(圖片類型,質(zhì)量參數(shù))

          看下面的例子

          控制臺輸出了base64格式的數(shù)據(jù):

          我們通過網(wǎng)上的還原軟件看看會把這個base64數(shù)據(jù)還原成什么圖片:

          正是我們想要的圖片

          indexedDB — — H5的“瀏覽器數(shù)據(jù)庫”

          indexedDB是存在于瀏覽器中的數(shù)據(jù)庫,它和一般的數(shù)據(jù)庫一樣有寫改刪查的功能,不同之處在于:常見的數(shù)據(jù)庫一般是在服務(wù)器上,并且要求我們的應(yīng)用在線時才可以工作,而indexedDB使得在離線的時候讀取數(shù)據(jù)成為了可能。下面,我就給大家介紹一下這個“駐扎”在瀏覽器上的特殊的數(shù)據(jù)庫吧

          使用open方法創(chuàng)建/打開數(shù)據(jù)庫

          我們首先要做的事情,當(dāng)然是創(chuàng)建(或打開)一個數(shù)據(jù)庫,這要用到indexedDB對象的open方法

          它接收兩個參數(shù): 數(shù)據(jù)庫名稱和數(shù)據(jù)庫版本(第二個參數(shù)是可選的)

          調(diào)用open方法時候,如果對應(yīng)名稱的數(shù)據(jù)庫不存在,則創(chuàng)建一個新的數(shù)據(jù)庫,如果已存在,則打開已存在的那個數(shù)據(jù)庫

          需要說明的是, indexedDB里面絕大多數(shù)操作都是異步的, 上述的indexedDB.open并不會立即創(chuàng)建一個數(shù)據(jù)庫, 你需要在異步的回調(diào)里面判斷數(shù)據(jù)庫是否創(chuàng)建成功,并對可能出現(xiàn)的錯誤做判斷和處理

          只有在onsuccess回調(diào)中,你才能通過request.result取得創(chuàng)建成功的數(shù)據(jù)庫

          通過open返回的request對象有三個回調(diào):

          onsuccess 每次創(chuàng)建/打開數(shù)據(jù)庫時候都會調(diào)用

          onerror 創(chuàng)建/打開數(shù)據(jù)庫發(fā)生錯誤的時候調(diào)用

          onupgradeneeded 數(shù)據(jù)庫版本變化的時候調(diào)用 (onupgradeneeded 是我們唯一可以修改數(shù)據(jù)庫結(jié)構(gòu)的地方)

          open一個indexedDB數(shù)據(jù)庫后,一般在onupgradeneeded回調(diào)中初始化(或修改)數(shù)據(jù)庫結(jié)構(gòu)(劃重點!!)

          這包括兩個方面的操作:

          1. 通過db.createObjectStore創(chuàng)建對象存儲空間,并取得ObjectStore對象(類似于SQL數(shù)據(jù)庫中的建表操作)

          2. 通過調(diào)用ObjectStore.createIndex創(chuàng)建該存儲空間內(nèi)的索引( 以便于提高查詢時候的速度)

          具體的可看下面的例子:

          運行一下, 然后讓我們看看效果:

          打開chrome的Application面板,點擊左欄的Storage下的indexedDB使其展開

          就可以看到我們新創(chuàng)建的phwDataBase數(shù)據(jù)庫, 以及它內(nèi)部的people數(shù)據(jù)存儲空間了

          (右邊展示的是people數(shù)據(jù)存儲空間的具體內(nèi)容,因為現(xiàn)在什么數(shù)據(jù)都還沒添加,所以key和value兩列下是沒有內(nèi)容的)

          看了上面的代碼你可能會有些疑惑

          onupgradeneeded 和onsuccess回調(diào)的關(guān)系是怎樣的? 為什么我們必須在.onupgradeneeded中初始化數(shù)據(jù)庫的結(jié)構(gòu),而不是在onsuccess中?

          這主要是由兩個回調(diào)調(diào)用的時機(jī)決定的:

          1.對 onsuccess回調(diào),在每次數(shù)據(jù)庫創(chuàng)建/打開的時候都會調(diào)用(不僅是第一次創(chuàng)建的時候會調(diào)用,每次打開的時候也都會調(diào)用)

          2. 對onupgradeneeded回調(diào),在open提供第二個版本參數(shù)的前提下:

          2.1 第一次調(diào)用open方法創(chuàng)建一個新的數(shù)據(jù)庫的時候,onupgradeneeded一定會被調(diào)用

          2.2 第二次或以后open該數(shù)據(jù)庫,只在版本參數(shù)改變的時候, onupgradeneeded才會被調(diào)用

          【注意】在缺少第二個版本參數(shù)的情況下,onupgradeneeded永遠(yuǎn)不會被調(diào)用!!

          所以說:

          1.open數(shù)據(jù)庫的時候,最(yi)好(ding)要帶上第二個參數(shù)(版本參數(shù))

          2. 修改數(shù)據(jù)庫結(jié)構(gòu)(例如創(chuàng)建和刪除對象存儲空間以及構(gòu)建和刪除索引。)要在onupgradeneeded回調(diào)中運行

          (很顯然每次打開都會被調(diào)用的onsuccess并不適合用于初始化數(shù)據(jù)庫結(jié)構(gòu))

          indexedDB的具體操作

          首先說一下,在下面的展示例子中,我們的HTML是這樣的

          demo:

          這里要說明一下的是,indexedDB的操作是以事務(wù)為基礎(chǔ)的。 所以,對存儲空間(objectStore)的操作都要基于事務(wù)來進(jìn)行。 具體點說,就是需要先通過db.transaction()方法取得transaction對象,然后再通過transaction.objectStore()方法取得目標(biāo)objectStore,再然后才能調(diào)用objectStore的API進(jìn)行“寫改刪查”

          打個比方, 如果說我們存儲的數(shù)據(jù)是糧食的話, objectStore就是一個個并排的糧倉,你可以往里面運糧食,也可以把糧食運出去, 但你對“糧食”做任何行為前, 都要和糧倉門前的守衛(wèi)—— transaction(事務(wù))“打聲招呼”,得到準(zhǔn)許才能進(jìn)入糧倉

          有兩個方法要說一下

          1. transaction方法

          transaction 方法 一般接受兩個參數(shù),并返回一個事務(wù)對象。

          1.1第一個參數(shù)是一個數(shù)組, 一個我們希望事務(wù)能夠操作的objectStore所組成的數(shù)組,如果你希望這個事務(wù)能夠操作所有的objectStore,那么傳入空數(shù)組[]即可

          1.2 第二個參數(shù)是一個字符串, 默認(rèn)是“onlyread”, 如果我們有需要對數(shù)據(jù)進(jìn)行寫操作的需求的話可傳入“readwrite”

          例如我們下面的一行代碼:

          2. transaction.objectStore方法

          這個方法接受一個參數(shù): 指定的objectStore的名稱, 方法返回的是獲取到的objectStore

          例如我們下面的一行代碼:

          寫操作

          寫操作的關(guān)鍵在于objectStore.add(XXX);方法,其中XXX是我們初始化objectStore時候?qū)懭氲摹爸麈I”

          也就是 var objectStore = db.createObjectStore("people", { keyPath: "id" }); (這段代碼在上面)中keyPath的值——id

          demo:

          點擊“增加數(shù)據(jù)”后彈出

          再看看application面板下的indexedDB:

          我們已經(jīng)成功添加了三條數(shù)據(jù)進(jìn)去了

          刪操作

          刪操作的關(guān)鍵在于objectStore.delete(XXX);方法,其中XXX是我們初始化objectStore時候?qū)懭氲摹爸麈I”

          也就是 var objectStore = db.createObjectStore("people", { keyPath: "id" }); 中keyPath的值——id

          點擊上面的“刪除數(shù)據(jù)”按鈕(刪除id = 1的數(shù)據(jù))

          再來看看, id為1的那一行已經(jīng)被刪除了

          查操作

          刪操作的關(guān)鍵在于objectStore.get(XXX);方法

          demo:

          點擊“獲取數(shù)據(jù)”按鈕,彈出

          (這里固定查找id為2的數(shù)據(jù))

          遍歷全部數(shù)據(jù)

          遍歷數(shù)據(jù)需要用到游標(biāo)

          通過 objectStore.openCursor()可創(chuàng)建一個游標(biāo)對象(cursor), 這個cursor對象包含兩個屬性值: key和value

          key就是我們一直說的那個“主鍵”, 而value是我們存入的時候的那個對象,通過 cursor.continue方法可以使得游標(biāo)向下移動

          點擊“遍歷全部數(shù)據(jù)”按鈕,看看控制臺

          通過索引查找

          我們通過objectStore.get方法,通過查找主鍵的方式查找對應(yīng)的對象數(shù)據(jù)的方式是很快的。

          但如果我們通過非主鍵的數(shù)據(jù)去查找對應(yīng)的那個對象就非常慢了,這個時候我們需要創(chuàng)建一個索引并通過索引來查找, 從而獲得較快的速度:

          點擊“通過索引獲取數(shù)據(jù)”按鈕:

          好! 現(xiàn)在讓我們對indexedDB做一個小小的總結(jié):

          1. indexedDB是面向?qū)ο蟮模?與傳統(tǒng)的以二維表為基礎(chǔ)的數(shù)據(jù)庫不同

          2. IndexedDB是一個事務(wù)型數(shù)據(jù)庫系統(tǒng)

          3. indexedDB大多數(shù)API都是異步的,這意味著調(diào)用一個方法你不能馬上得到關(guān)鍵的那個對象,而在對應(yīng)的success回調(diào)中才能取得


          拖放事件

          一個典型的拖放操作是這樣開始的:用戶用鼠標(biāo)選中一個可拖動的(draggable)元素,移動鼠標(biāo)到一個可放置的(droppable)元素,然后釋放鼠標(biāo)。 在操作期間,會觸發(fā)一系列的拖放類型的事件

          其中我們主要關(guān)心的事件有三個:

          1. ondragstart 發(fā)生在可拖拽(draggable)的元素上, 在元素被拖動的時候調(diào)用

          2. ondragover 發(fā)生在可放置(droppable)的元素上, 當(dāng)某被拖動的對象在可放置對象范圍內(nèi)(上方)時觸發(fā)此事件

          3. ondrop 發(fā)生在可放置(droppable)的元素上,當(dāng)釋放鼠標(biāo)使可拖拽元素“放進(jìn)”可放置元素內(nèi)的瞬間觸發(fā)。

          需思考的問題:

          1. 如何使得被拖拽元素可拖拽?(因為元素默認(rèn)的行為是不可拖拽的),以及如何使得被放置的容器元素可放置? (因為元素默認(rèn)是不可放置的)

          對前者, 我們可以為元素設(shè)置draggable屬性,并且設(shè)置為true

          對后者, 我們可以在被放置的容器元素中的ondragover事件里通過event.preventDefault();阻止默認(rèn)行為——禁止放置

          2.如何實現(xiàn)“脫 — 放”過程的數(shù)據(jù)傳遞?

          這里首先需要知道的是,當(dāng)我們拖動一個圖片到另一個地方的時候,我們是不能“直接把圖片拖拽進(jìn)去”的,也就是說,我們還是要通過以下的思路實現(xiàn)拖放:

          在被放置的元素中取得被拖拽元素的相關(guān)數(shù)據(jù)(如id),然后通過appendChild之類的API實現(xiàn)添加被拖拽的元素,從而模擬整個拖拽的過程

          也就是說, 拖拽其實可分為三個過程: 拖動—傳遞被拖動元素的數(shù)據(jù)(如id)—在容器元素中添加該元素

          關(guān)鍵在于如何在被拖動元素和被放置元素中傳遞數(shù)據(jù),這可以通過event.dataTransfer對象來實現(xiàn)

          dataTransfer可以通過setData方法添加拖動數(shù)據(jù),并通過getDate方法取得拖動數(shù)據(jù),我們可以在

          ondragstart事件和ondrop事件中調(diào)用這兩個方法, 實現(xiàn)關(guān)鍵性的數(shù)據(jù)傳遞。

          具體請看下面的例子:

          拖拽前

          拖拽后

          參考資料:

          HTML5-MDN https://developer.mozilla.org/zh-CN/docs/Web/Guide/HTML/HTML5

          【完】

          TML5不僅擁有強(qiáng)大的應(yīng)用功能和廣泛的使用范圍,而且它的學(xué)習(xí)門檻也比Java、C++、Javascript等語言低很多,可以說是非常適合作為零基礎(chǔ)小白打開IT世界大門的第一把鑰匙!

          接下來,小編就和大家一起來了解一下,到底什么是HTML5?它究竟好在哪?

          HTML5是什么

          從技術(shù)層面來說,HTML5就是HTML5+CSS3+JS的合集。HTML5用于實現(xiàn)我們能夠看到的所有網(wǎng)站,是包含一定特效的移動端營銷網(wǎng)頁,簡單概括,就是用代碼實現(xiàn)一張由設(shè)計師設(shè)計好的網(wǎng)頁圖片。HTML5做出的作品也會被稱為場景應(yīng)用,有些作品與移動端PPT類似。經(jīng)常能見到的形式就是滑動翻頁。

          HTML5的基本組成

          HTML5=HTML+CSS+JavaScript

          HTML指的是結(jié)構(gòu),使整個網(wǎng)頁中有標(biāo)題,有列表,有圖片等。

          CSS指樣式,也就是標(biāo)題文字的字體大小、顏色、字體;圖片的大小;某個塊的背景色或背景圖等

          JS即JavaScript,指的是行為,例如在網(wǎng)頁上四處飄動的廣告;圖片滾動;瀏覽淘寶時鼠標(biāo)移動到商品時,放大商品的效果等。

          如果說HTML是人體的骨架,CSS就好比人體的血肉架,JavaScript就好比人的各類動作,這些合在一起基本就是前端工程師的基本要求了。

          HTML5未來發(fā)展前景

          HTML5作為移動互聯(lián)網(wǎng)的行業(yè)新貴,它的快速發(fā)展撼動著Android和iOS在應(yīng)用層面的地位。

          由于HTML5的富媒體化與富應(yīng)用化,目前還沒有一門前端的開發(fā)語言能取代HTML5的主流開發(fā)地位,無論做PC端網(wǎng)站還是App應(yīng)用,前端樣式均由HTML5開發(fā),毫無疑問,未來幾年,HTML5依然會是Web應(yīng)用的最佳解決方案,就業(yè)前景十分廣闊。

          免責(zé)聲明:內(nèi)容和圖片源自網(wǎng)絡(luò),版權(quán)歸原作者所有,如有侵犯您的原創(chuàng)版權(quán)請告知,我們將盡快刪除相關(guān)內(nèi)容。

          IT行業(yè)、互聯(lián)網(wǎng)、開發(fā)語言(Java、前端HTML5、Python、UI/UE、云計算、自動化測試、大數(shù)據(jù)、人工智能、物聯(lián)網(wǎng)、游戲開發(fā)、網(wǎng)絡(luò)安全、GO語言、PHP)相關(guān)資訊,大連千鋒會第一時間送到大家身邊,也可以關(guān)注微信公眾號【dalianqianfengjiaoyu】了解相關(guān)行業(yè)資訊。


          主站蜘蛛池模板: 无码一区二区三区在线观看| 国产福利视频一区二区| 精品成人一区二区三区四区| 国产午夜精品一区二区三区| ...91久久精品一区二区三区| 一区二区三区四区无限乱码 | 精品视频在线观看你懂的一区 | 成人精品一区二区户外勾搭野战| 一区二区三区无码高清| 天堂va在线高清一区| 国产av天堂一区二区三区| 国产91精品一区| 无码人妻啪啪一区二区| 无码一区二区三区视频| 中文字幕人妻无码一区二区三区| 国产精品亚洲一区二区三区 | 中文乱码人妻系列一区二区| 亚洲av午夜福利精品一区人妖| 无码人妻AⅤ一区二区三区水密桃| 中文无码一区二区不卡αv| 精品无码一区在线观看| 久久99精品一区二区三区| 久久精品中文字幕一区| 亚洲福利精品一区二区三区| 韩国精品一区视频在线播放| 无码夜色一区二区三区| 国产精品视频一区二区猎奇| 亚洲综合无码一区二区| 无码少妇一区二区三区浪潮AV| 色老板在线视频一区二区| 中文字幕在线一区二区三区| 一区视频在线播放| 一区二区三区在线视频播放| 精品无码一区二区三区水蜜桃| 欧洲精品一区二区三区| 亚洲AV无码一区二区三区鸳鸯影院 | 国产精品视频一区二区三区不卡| 精品中文字幕一区二区三区四区| 国产在线一区二区三区av| 国产传媒一区二区三区呀| 又紧又大又爽精品一区二区|