004 年 Google Maps 的面世标志着 Java 桌面时代的终结,也改变了桌面环境下“跨平台”的基本定义。
本文作者以个人视角对 Java 桌面发展历程做了回顾,内容来自他在上世纪九十年代后期担任 Java 开发者时的所见所感,主要讲述曾经的“杀手级”桌面语言 Java 是为何从 21 世纪开始颓势尽显、步入衰落的。值得一提的是,作者如今在做一款开发者友好型 Java 桌面部署工具(jDeploy),其实他还是希望 Java 可以重拾风采,再度变得对桌面开发具有吸引力。
本文是该回顾系列文章中的第二篇,在上期文章中,作者回顾了 Java 制霸桌面的鸿图如何在 1999 至 2005 的短短几年间烟消云散。当初的 Java 可谓志得意满、凭 Applet 小程序技惊四座,下决心要在互联网时代下重新定义“桌面”。互联网的未来在于“跨平台”,而 Java 的血管中涌动的正是“跨平台”的血液,优势在握!可遗憾的是,事后来看,此跨平台似乎并非彼跨平台。接下来,让我们继续跟着作者的脚步去看看,具体在 2004 至 2007 年间,Java 桌面又经历了什么。
2002 年左右,我在客服中心为客户提供计算机与打印机技术支持。我和小伙伴们挤在小小的隔间里,面对着一款桌面程序。通过这款软件,我们可以快速查询客户和产品信息,并把通话中的重要信息记录进去。
在典型的客服来电中,我们会询问客户的产品序列号,再把结果输入系统。如果他们之前就打过电话,系统就会输出窗口,里面包含产品的完整历史记录和之前的求助细节。在参考其他同事留下的事由记录后,我还能操作界面中的选项卡和功能按钮,例如帮客户更换新机。
我不记得这款软件叫什么名字了,可能是为公司或者客服中心专门定制的吧。印象里这应该是 PeopleSoft(仁科公司,2005 年已被甲骨文收购)的产品,但我也不太确定。总之,这款桌面软件运行在 Windows 2000 系统上,肯定不是 Web 应用程序。它其实挺复杂,里面包含不少菜单和表单;不过一旦上手,整个使用体验相当棒——速度快、反应灵敏,几乎没有任何延迟。以输入电话号码查询客户记录为例,我们只需要在“电话”字段里输入号码,其余空白表格就会立刻被客户信息填充完整。
据我所知,这款程序肯定不是用 Swing 编写的。但如今全球各地无数公司都在使用由 Swing 编写的企业级桌面软件,它们在使用体验上跟我当初接触的这款程序非常相似。换句话说,Swing 已经满足了我们在 2001、2002 年那会对于桌面业务软件的全部期望和想象。
在工作半年之后,上边来了新指示,要求我们用 Web 应用程序替换掉之前的桌面软件。据说新系统会让我们的工作更轻松,但在第一节培训课刚刚过去十分钟后,我们就意识到这根本就是胡说八道:新系统简直烂透了!
我不太记得当时使用的是 IE 5.5 还是 IE 6 了,总之就是前 AJAX 时代的 Web 环境。现在在产品字段中输入序号后,系统会弹出一个窗口,上面写着“正在加载……请勿关闭此窗口”。几秒后,窗口自行消失,客户详细信息出现在表单当中。反正每当需要从服务器获取内容时,这个倒霉窗口就会跳出来。领导还提醒我们别随便在浏览器里点“刷新”,说是这样会破坏系统状态。于是每每出现问题,我就只能先登出、再重新登录。
我不太理解公司为什么要用这款“傻了吧唧”的 Web 应用程序替代之前的桌面软件。可能是出于成本考虑吧,毕竟跟桌面软件相比,Web 应用程序的开发和维护成本都更低。或者是软件供应商强行施压,比如“Web 才是未来,每个人都必须接受!”但,真有这么强势的乙方吗?
无论如何,这里透露出一个重要的信息:Web 应用程序还没等发展完善,就已经开始蚕食桌面软件的生存空间。唯一的问题就是 Web 应用需要多久才能追平桌面软件的使用体验。而事实证明,用不了多久。
再回到 Java 这边。热情的支持者们正不断扩大 Java 帝国的桌面版图,对 WORA(一次编写、随处运行)的热情也引导他们最终迈向跨平台小程序与“本机”应用程序之间的秘密山谷。那时候的 Java IDE 主要面向三大构建目标:
从 2022 年的角度回顾,Java 身上其实有很多显而易见的问题。应用程序可以作为 Web 部署、也可以按本机部署,但这两种形式都没有一丁点“原生”感。Web 部署的小程序运行在自己的“沙箱”内并被集成到网页当中,整个运行过程又慢又迟钝。
虽然 Java 总想在 Web 和桌面之间建起一道桥梁,但它自身却被 Web 所裹挟。到 2002 年,很多企业开始把原本的桌面软件功能迁移到 Web 端。这些 Web 应用程序的构建、维护和部署成本确实比桌面软件低得多,代价就是在用户体验上做出妥协。
大约也是在这个时候,Java 开始推崇“富互联网应用”的概念,希望把好 Web 应用跟差 Web 应用区分开来。但到 2004 年 Google Maps 正式亮相时,Java 的小把戏彻底宣告破产。Google Maps 以令人震惊的效果为富 Web 应用程序树立了标杆,而人家用的是 HTML5。
我最近又看了一次 Bill Atkinson 第一次向苹果爱好者们展示 MacPaint 的旧视频。在他第一次通过鼠标用画笔工具绘出图案时,现场一片“哇哦”和掌声。这就叫开创性。我第一次看到 Google Maps 也是类似的感觉,地图可以无缝缩放、万向平移,压根看不出来任何拼接的痕迹。这里使用的全新技术被称为 AJAX(异步 JavaScript 与 XML),这也是人们第一次能够在 Web 应用程序中向服务器后台无缝发出请求。现在这一切当然被视为理所当然,可 2004 年那会,开发者需要绞尽脑汁才能把那些让人想吐的框架或者弹窗隐藏起来,确保不用刷新整个页面就能从服务器处加载新数据。
身为 Web 开发者,我当然对其中的无穷可能性心生向往。但从桌面开发的角度看,这场历史性的变革似乎没有给桌面、特别是 Java 带来任何影响。
在 HTML5 之前,“跨平台”的意思是“跨 Windows、Mac 和 Linux”,所以跨的范围还是在桌面范畴之内。当时我并没意识到,但现在来看 HTML5 的亮相代表着新平台时代的降临——它将成为客户端应用程序的客观标准;更重要的是,Java 支持不了这个平台。突然之间,WORA 理念就出现空白了——Swing 应用程序适用于一切平台,除了最重要的那个:网络浏览器。
那 Java 桌面开发者们都跑哪去了?方向主要有三:
2000 年初,JavaScript 开发工具尚处于起步阶段。大多数 Web 开发者只能使用文本编辑器来编写.js 文件。简单的验证脚本和交互设计倒是没问题,但这种粗糙的方法肯定不能扩展并支持大型企业应用程序项目。另外,当时的 JavaScript 语言还不具备开发者在重构等重要操作时所需要的功能,例如静态类型。
相比之下,Java 已经拥有一套全面的开发工具,能够轻松扩展至任何规模的项目。到 2004 年,领先且成熟的 Java IDE 已经成为开发环境中的标杆,其中的静态类型更是大大简化了大型项目的维护难度。到这时,唯一的遗憾就是 Java 应用程序无法在网络浏览器中运行(只有小程序可以)。
为了解决这个难题,Google 打造出 GWT(Google Web Toolkit)。这是一套 Java 到 JavaScript 的编译器加运行时库,允许开发者借助 Java 那一整套领先的开发工具编写应用程序,再把成果部署成 JavaScript 应用的形式在浏览器内原生运行。这套运行时库包含诸多核心 Java API(例如 java.lang、java.util 等)的实现,确保业务逻辑能够在 GWT 应用程序与服务器应用程序间顺畅共享。
在用户界面方面,GWT 也提供自己的功能部件,其实质就是以 Java 的形式将各部件与浏览器中的本机 HTML 部件相绑定。虽然我们还是没法直接使用 Swing 代码、大部分第三方库也不在支持之列,但我们至少可以用到自己最熟悉的 Java 开发环境和核心 API。
所以这不能算是让 Java 真正走进了浏览器——标准 JavaSE 库仍然大部分不受支持,线程等核心功能也无法起效。但至少对多数用例来说,这已经够了。
Google 用 GWT 开发出很多流行一时的 HTML5 应用程序,其中最著名的就是 Gmail,这个项目还催生出一个规模不大、但却相当活跃的开源社区。虽然影响力已经今非昔比,但这个社区直到现在也仍然存在。与此同时,JavaScript 工具的逐步改进也在挤占 GWT 的生存空间,过去十年来诞生的一系列更为现代的解决方案也允许我们在浏览器中更“无脑”地使用 Java。
HTML5 的出现颠覆了 Java 制霸桌面的野心,但这里也有好消息。由于不必分神于桌面端,Java 在服务器端迎来了全面发展。Java 做好了战斗准备、努力满足开发者对后端服务的种种新需求——毕竟没有后端,再好的 Web 应用也出不来。
Java 在服务器端的受欢迎程度在接下来几年中持续增长,也吸引到整个生态系统的高度关注。第三方库不断涌现,而 2005 年 Maven 的诞生也让第三方库的使用不再复杂繁琐。无需额外下载、不必寻找依赖项,直接把片段粘贴到 pom 文件中,它就能自动下载一切相应依赖项。
Java 的开发工具也在不断改进,这在很大程度上要归功于 Java 在服务器端的优势地位。这些改进也对桌面开发者产生了积极影响,让我们用上了跟服务器端相同的 IDE、编译器、虚拟机和库。然而,代表 Java 世界“最后的坚持”的这帮桌面开发者眼界还是没能打开,仍在围着 UI 库的改进和部署打转。
遇到问题时,我的习惯是上 Google 搜一搜,看看有没有其他人遇到或者已经解决过相同的问题。但在 Swing 开发上,我发现最新的搜索结果也基本是 2005 年左右的内容了,之后基本再无新增。在找不到答案时,我偶尔会写一篇问题分析博文。而在两年后再次遇到类似问题时,我在 Google 上找到的就是自己两年前那篇博文……说真的,现在还有喘气的 Swing 开发者吗?感觉真的说不好。
从各个方面来看,Web 的兴起让“桌面应用”的概念清晰了起来。Java 最初的跨平台客户端开发愿景并没有把瘦客户端(主要与远程服务器交互)跟本机完整桌面应用程序区分开来。这不仅提高了理解难度,更让安全模型的设计有些无所适从。Java 理解中的“平台”就是计算机本身,所以会使用笨拙的沙箱来限制可能引发安全威胁的 API 访问,例如访问文件系统。这是 Java 一切安全漏洞的根源,也是导致 Java 被逐出浏览器世界的原因。
这种基于“沙箱”的开发体验相当糟糕,因为我们很容易意外“越界”并触发安全异常。最终结果是,几乎所有客户端都会请求对系统进行“可信”访问,这样也就完全绕过了沙箱的限制。
相比之下,HTML5 在 Web 和桌面之间设立了明确的边界。Web 应用程序默认无权访问客户端计算机,而浏览器才是那个“平台”,这就让客户端应用程序的安全保障变得更轻松、更易行。
经过此番变革,“桌面”的范畴变得更小,以往很多被视为“桌面应用程序”的软件现在被划入“客户端应用程序”类别。具体来讲,如果应用程序只负责在用户与服务器交互时提供 UI,那它就属于客户端应用程序。“桌面”这个概念现在指的就是那些以某种方式与本机设备相集成的应用程序,包括访问文件系统(开发工具、文件转换工具等)、调用浏览器中不存在的某些平台本机 API、以及执行算力密集型任务的软件。
这倒不是说“客户端”应用程序跟“桌面”应用程序间就毫无交集——当然有,这两者都涉及 GUI,而且不少现代桌面应用程序也都需要接入服务器。所以无论是桌面还是客户端应用程序,都能享受到 GUI 工具包改进、媒体(音频/视频)及网络等技术层面的改进成果。
2004 年,我曾在 Mac 和 Windows 上都开发出一些商用级别的 Java 桌面应用程序。HTML5 对这类应用程序基本没有任何直接影响。结合自身需求,Swing 还是完全够用,我用来构建本机捆绑包的各种桌面部署工具也都能正常起效。
但很遗憾,科技行业就是个不进则退的世界。在接下来的几年中,Web 平台一路突飞猛进、而 Swing 却始终停滞不前。到 2007 年,Swing 已经到了不变革、就消亡的危难关头。它需要响应 HTML5 这波历史性潮流,而最终答案就是 JavaFX。这是一种新奇的 Java UI 工具包,能够把 Java 带入 GPU 加速、场景图、3D 图形、Web 视图的现代新世界,同时支持 MP3 和 MP4 等现代音视频编解码器。
在下一篇文章中,我们将回顾 JavaFX 的火爆人气、深远影响,以及 2011 年 Mac 应用商店出现前 Java 领域的其他发展趋势。别小瞧 Mac 应用商店,它的出现堪称对 Java for Mac 桌面开发生态的“斩首行动”。
原文链接:
https://jdeploy.substack.com/p/the-decline-and-fall-of-java-on-the-970
了解更多软件开发与相关领域知识,点击访问 InfoQ 官网:https://www.infoq.cn/,获取更多精彩内容!
作为一名Web开发者,可能你并没有对这个“H5”这个字眼投入太多的关注,但实际上它早已不知不觉进入到你的开发中,并且总有一天会让你不得不正视它,了解它并运用它
打个比方:《海贼王》中的主角路飞在“顶上战争两年前”,会在一些危急关头“不经意”地使用霸王色霸气,但对”霸气“的结构体系和具体运用都不太了解,这让他在香波地群岛等诸多重大战役中大吃苦头。此后, 他不惜花费两年时间跟随雷利修炼霸气。因为,如果不去了解这个崭新的战斗方法的话,他们在残酷的新世界一天也生存不了。
咳咳, 回到主题,为什么我们要学HTML5呢?
1. 了解HTML5的囊括范围的一大好处是:当你不小心使用了一个H5的东东的时候(例如你试图通过百度找到的答案解决一个紧张的需求),你会很及时的关注它的兼容性
2. H5有些新增的特性也许你从没接触过,也感觉无需用到它。但就在不久的将来,你可能就会用到,甚至依赖于它(毕竟这就是HTML的未来)
在下面, 我将学习H5中的知识点分成两类:主要知识点和针对特定功能的知识点,其中对主要知识点的部分,从学习成本的角度对其进行了难度分级
(仅属个人观点!如有改进意见,欢迎讨论)
一.主要知识点
(从需求层面上来说,普及范围相对较广)
相对容易的部分:
1.在线和离线事件(Online/Offline) (相对容易)
2. 众多的新增元素 如<output>, <progress>等 (相对容易)
3. history关于历史状态管理的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中主要知识点中,学习成本相对较高的四个点(仅个人观点):
一.Web Worker
二.canvas
三.indexedDB
四.拖放操作
【注意】因为下面介绍的H5的特性在一些比较老的浏览器里可能遇到兼容性问题,所以你在使用前必须要能力检测,例如这样
Web Worker的机制让你能够创建一个在后台线程运行的脚本,这个脚本不会对我们当前执行任务的脚本造成任何干扰(例如阻塞),同时Web Worker提供了一套API使你能够在当前脚本和后台脚本间进行数据的互相传输(worker)
“一套API, 两个对象”
我们现在已知的关于Web Worker的机制是: 有一个当前脚本, 和一个在后台运行的worker脚本,所以我们问题的关键就落在了这两个脚本的通信(数据交互)上
通过
生成了“两个对象”(你可能会问:为什么是两个不是一个呢?请往下看)
“第一个”对象是我们在当前脚本中通过构造函数显式创建出来的worker对象,它拥有一套API:postMessage和onmessage,通过postMessage方法可以向worker脚本(上文worker.js)发送数据, 通过onmessage方法可以从worker脚本接收数据
“第二个”对象是在Web Worker脚本(上文的worker.js)中隐式创建出来的全局变量对象,它叫DedicatedWorkerGlobalScope(这个时候在work.js全局变量对象是它而不是Window!!),而它也拥有一套API:postMessage和onmessage,通过postMessage方法可以向当前执行任务的脚本发送数据, 通过onmessage方法可以从当前执行任务的脚本接收数据
【注意】关于DedicatedWorkerGlobalScope
1. 它是在Web Worker脚本中生成的特殊的全局变量对象,也就是在全局执行环境中使用this指向的不是Window而是它
2. 它不能像Windows那样通过变量名直接访问,但在Web Worker脚本中你能通过this取到它
所以现在数据传递方向有两条:
1. 调用当前脚本中worker对象的postMessage方法, 然后在Web Worker脚本(上文的worker.js)中通过onmessage这个回调方法接收数据
2. 调用Web Worker脚本中的this.postMessage方法(this指向DedicatedWorkerGlobalScope),然后在当前脚本中worker对象的onmessage回调方法接收数据
看到这里可能有点懵,来让我们通过一个例子看看1中的数据传递:
先看示例吧,这是我们的目录结构
index.html:
main.js:
worker.js:
点击按钮后,在main.js中调用worker对象的postMessage方法, 这个数据就被发给了work.js中的全局变量对象DedicatedWorkerGlobalScope, 所以我们在work,js中通过this.onmessage接收数据并输出
【注意】postMessage传递的参数会被“原封不动”地传递给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}
我们上面的例子展现的是从当前任务脚本向worker脚本传递数据,那么同样的道理,我们也能从work脚本向当前任务脚本传递数据(方式相同)
例子:
index.html:
同上
main.js:
worker.js:
demo如下
点击传递数据输出:
cancas是H5新增的一个标签,把canvas翻译过来就是画布,顾名思义,这是用来”画画的“,那画画的”画笔“是什么呢? 它就是和canvas元素对象对应的一个”上下文对象“(context),这里的这个上下文对象可能和你印象中的”上下文“有较大的差异,它只是个单纯的包含了一系列“绘画”方法的对象,下面我们介绍的关于canvas的内容都要围绕这个"canvas上下文对象"展开
我们可以通过这种方式取得canvas上下文对象:
假设这是我们的HTML:
这样取得上下文对象:
下面展现的是上下文对象的一些绘制图形的方法(它们都可以被ctx调用)
上面的x,y代表相对于canvas画布左上角的横纵坐标:
例子:
html部分:
JS部分:
【注意】. canvas标签内的内容(例如上面的文本)是否呈现取决于浏览器是否支持canvas,如果支持,则不出现,如果不支持,则会呈现出来
demo:
我们以上面的为基础稍作修改:
demo:
demo:
这里要稍微提一下, 也许上面的那些绘制图形,绘制文本的操作对你来说都没有触动,因为它们离我们的直接需求似乎还有一定的距离,但我想接下来的这几个上下文API你或许有些兴趣。
例如我们可能有一个需求是载入已有的图片,对它截图(裁剪)后保存为一张新的图片,这个时候我们就可以使用到canvas的绘制图片,裁剪图片,保存图片的API了
通过canvas上下文对象的drawImage方法可直接绘制图片
我们可以通过下面的一段代码动态获取img元素对象
废话不多说,直接上demo!
在相同目录下有这么一张图片
JS代码:
demo:
我们发现, 图片加载完成后被写入了画布当中!
canvas上下文对象的clip方法可根据路径对canvas画布进行裁剪
让我们在原来的基础上添加一点东西:
【注意】clip方法的调用要在drawImage方法之前,否则不能成功! 也就是说要“先裁剪,再画图”
canvas的保存和导出
我们通过document.getElementById("canvas")取得的画布对象,有一个toDataURL()方法,可将当前画布作为一张图片,并返回其base64编码格式的数据,这在保存图片的时候非常有用
toDataURL接受两个参数:图片类型和质量参数
canvas.toDataURL(图片类型,质量参数)
看下面的例子
控制台输出了base64格式的数据:
我们通过网上的还原软件看看会把这个base64数据还原成什么图片:
正是我们想要的图片
indexedDB是存在于浏览器中的数据库,它和一般的数据库一样有写改删查的功能,不同之处在于:常见的数据库一般是在服务器上,并且要求我们的应用在线时才可以工作,而indexedDB使得在离线的时候读取数据成为了可能。下面,我就给大家介绍一下这个“驻扎”在浏览器上的特殊的数据库吧
我们首先要做的事情,当然是创建(或打开)一个数据库,这要用到indexedDB对象的open方法
它接收两个参数: 数据库名称和数据库版本(第二个参数是可选的)
调用open方法时候,如果对应名称的数据库不存在,则创建一个新的数据库,如果已存在,则打开已存在的那个数据库
需要说明的是, indexedDB里面绝大多数操作都是异步的, 上述的indexedDB.open并不会立即创建一个数据库, 你需要在异步的回调里面判断数据库是否创建成功,并对可能出现的错误做判断和处理
只有在onsuccess回调中,你才能通过request.result取得创建成功的数据库
通过open返回的request对象有三个回调:
onsuccess 每次创建/打开数据库时候都会调用
onerror 创建/打开数据库发生错误的时候调用
onupgradeneeded 数据库版本变化的时候调用 (onupgradeneeded 是我们唯一可以修改数据库结构的地方)
open一个indexedDB数据库后,一般在onupgradeneeded回调中初始化(或修改)数据库结构(划重点!!)
这包括两个方面的操作:
1. 通过db.createObjectStore创建对象存储空间,并取得ObjectStore对象(类似于SQL数据库中的建表操作)
2. 通过调用ObjectStore.createIndex创建该存储空间内的索引( 以便于提高查询时候的速度)
具体的可看下面的例子:
运行一下, 然后让我们看看效果:
打开chrome的Application面板,点击左栏的Storage下的indexedDB使其展开
就可以看到我们新创建的phwDataBase数据库, 以及它内部的people数据存储空间了
(右边展示的是people数据存储空间的具体内容,因为现在什么数据都还没添加,所以key和value两列下是没有内容的)
看了上面的代码你可能会有些疑惑
onupgradeneeded 和onsuccess回调的关系是怎样的? 为什么我们必须在.onupgradeneeded中初始化数据库的结构,而不是在onsuccess中?
这主要是由两个回调调用的时机决定的:
1.对 onsuccess回调,在每次数据库创建/打开的时候都会调用(不仅是第一次创建的时候会调用,每次打开的时候也都会调用)
2. 对onupgradeneeded回调,在open提供第二个版本参数的前提下:
2.1 第一次调用open方法创建一个新的数据库的时候,onupgradeneeded一定会被调用
2.2 第二次或以后open该数据库,只在版本参数改变的时候, onupgradeneeded才会被调用
【注意】在缺少第二个版本参数的情况下,onupgradeneeded永远不会被调用!!
所以说:
1.open数据库的时候,最(yi)好(ding)要带上第二个参数(版本参数)
2. 修改数据库结构(例如创建和删除对象存储空间以及构建和删除索引。)要在onupgradeneeded回调中运行
(很显然每次打开都会被调用的onsuccess并不适合用于初始化数据库结构)
首先说一下,在下面的展示例子中,我们的HTML是这样的
demo:
这里要说明一下的是,indexedDB的操作是以事务为基础的。 所以,对存储空间(objectStore)的操作都要基于事务来进行。 具体点说,就是需要先通过db.transaction()方法取得transaction对象,然后再通过transaction.objectStore()方法取得目标objectStore,再然后才能调用objectStore的API进行“写改删查”
打个比方, 如果说我们存储的数据是粮食的话, objectStore就是一个个并排的粮仓,你可以往里面运粮食,也可以把粮食运出去, 但你对“粮食”做任何行为前, 都要和粮仓门前的守卫—— transaction(事务)“打声招呼”,得到准许才能进入粮仓
有两个方法要说一下
1. transaction方法
transaction 方法 一般接受两个参数,并返回一个事务对象。
1.1第一个参数是一个数组, 一个我们希望事务能够操作的objectStore所组成的数组,如果你希望这个事务能够操作所有的objectStore,那么传入空数组[]即可
1.2 第二个参数是一个字符串, 默认是“onlyread”, 如果我们有需要对数据进行写操作的需求的话可传入“readwrite”
例如我们下面的一行代码:
2. transaction.objectStore方法
这个方法接受一个参数: 指定的objectStore的名称, 方法返回的是获取到的objectStore
例如我们下面的一行代码:
写操作的关键在于objectStore.add(XXX);方法,其中XXX是我们初始化objectStore时候写入的“主键”
也就是 var objectStore = db.createObjectStore("people", { keyPath: "id" }); (这段代码在上面)中keyPath的值——id
demo:
点击“增加数据”后弹出
再看看application面板下的indexedDB:
我们已经成功添加了三条数据进去了
删操作的关键在于objectStore.delete(XXX);方法,其中XXX是我们初始化objectStore时候写入的“主键”
也就是 var objectStore = db.createObjectStore("people", { keyPath: "id" }); 中keyPath的值——id
点击上面的“删除数据”按钮(删除id = 1的数据)
再来看看, id为1的那一行已经被删除了
删操作的关键在于objectStore.get(XXX);方法
demo:
点击“获取数据”按钮,弹出
(这里固定查找id为2的数据)
遍历数据需要用到游标
通过 objectStore.openCursor()可创建一个游标对象(cursor), 这个cursor对象包含两个属性值: key和value
key就是我们一直说的那个“主键”, 而value是我们存入的时候的那个对象,通过 cursor.continue方法可以使得游标向下移动
点击“遍历全部数据”按钮,看看控制台
我们通过objectStore.get方法,通过查找主键的方式查找对应的对象数据的方式是很快的。
但如果我们通过非主键的数据去查找对应的那个对象就非常慢了,这个时候我们需要创建一个索引并通过索引来查找, 从而获得较快的速度:
点击“通过索引获取数据”按钮:
好! 现在让我们对indexedDB做一个小小的总结:
1. indexedDB是面向对象的, 与传统的以二维表为基础的数据库不同
2. IndexedDB是一个事务型数据库系统
3. indexedDB大多数API都是异步的,这意味着调用一个方法你不能马上得到关键的那个对象,而在对应的success回调中才能取得
一个典型的拖放操作是这样开始的:用户用鼠标选中一个可拖动的(draggable)元素,移动鼠标到一个可放置的(droppable)元素,然后释放鼠标。 在操作期间,会触发一系列的拖放类型的事件
其中我们主要关心的事件有三个:
1. ondragstart 发生在可拖拽(draggable)的元素上, 在元素被拖动的时候调用
2. ondragover 发生在可放置(droppable)的元素上, 当某被拖动的对象在可放置对象范围内(上方)时触发此事件
3. ondrop 发生在可放置(droppable)的元素上,当释放鼠标使可拖拽元素“放进”可放置元素内的瞬间触发。
需思考的问题:
1. 如何使得被拖拽元素可拖拽?(因为元素默认的行为是不可拖拽的),以及如何使得被放置的容器元素可放置? (因为元素默认是不可放置的)
对前者, 我们可以为元素设置draggable属性,并且设置为true
对后者, 我们可以在被放置的容器元素中的ondragover事件里通过event.preventDefault();阻止默认行为——禁止放置
2.如何实现“脱 — 放”过程的数据传递?
这里首先需要知道的是,当我们拖动一个图片到另一个地方的时候,我们是不能“直接把图片拖拽进去”的,也就是说,我们还是要通过以下的思路实现拖放:
在被放置的元素中取得被拖拽元素的相关数据(如id),然后通过appendChild之类的API实现添加被拖拽的元素,从而模拟整个拖拽的过程
也就是说, 拖拽其实可分为三个过程: 拖动—传递被拖动元素的数据(如id)—在容器元素中添加该元素
关键在于如何在被拖动元素和被放置元素中传递数据,这可以通过event.dataTransfer对象来实现
dataTransfer可以通过setData方法添加拖动数据,并通过getDate方法取得拖动数据,我们可以在
ondragstart事件和ondrop事件中调用这两个方法, 实现关键性的数据传递。
具体请看下面的例子:
拖拽前
拖拽后
参考资料:
HTML5-MDN https://developer.mozilla.org/zh-CN/docs/Web/Guide/HTML/HTML5
【完】
TML5不仅拥有强大的应用功能和广泛的使用范围,而且它的学习门槛也比Java、C++、Javascript等语言低很多,可以说是非常适合作为零基础小白打开IT世界大门的第一把钥匙!
接下来,小编就和大家一起来了解一下,到底什么是HTML5?它究竟好在哪?
HTML5是什么
从技术层面来说,HTML5就是HTML5+CSS3+JS的合集。HTML5用于实现我们能够看到的所有网站,是包含一定特效的移动端营销网页,简单概括,就是用代码实现一张由设计师设计好的网页图片。HTML5做出的作品也会被称为场景应用,有些作品与移动端PPT类似。经常能见到的形式就是滑动翻页。
HTML5的基本组成
HTML5=HTML+CSS+JavaScript
HTML指的是结构,使整个网页中有标题,有列表,有图片等。
CSS指样式,也就是标题文字的字体大小、颜色、字体;图片的大小;某个块的背景色或背景图等
JS即JavaScript,指的是行为,例如在网页上四处飘动的广告;图片滚动;浏览淘宝时鼠标移动到商品时,放大商品的效果等。
如果说HTML是人体的骨架,CSS就好比人体的血肉架,JavaScript就好比人的各类动作,这些合在一起基本就是前端工程师的基本要求了。
HTML5未来发展前景
HTML5作为移动互联网的行业新贵,它的快速发展撼动着Android和iOS在应用层面的地位。
由于HTML5的富媒体化与富应用化,目前还没有一门前端的开发语言能取代HTML5的主流开发地位,无论做PC端网站还是App应用,前端样式均由HTML5开发,毫无疑问,未来几年,HTML5依然会是Web应用的最佳解决方案,就业前景十分广阔。
免责声明:内容和图片源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。
IT行业、互联网、开发语言(Java、前端HTML5、Python、UI/UE、云计算、自动化测试、大数据、人工智能、物联网、游戏开发、网络安全、GO语言、PHP)相关资讯,大连千锋会第一时间送到大家身边,也可以关注微信公众号【dalianqianfengjiaoyu】了解相关行业资讯。
*请认真填写需求信息,我们会在24小时内与您取得联系。