Jquery高级编程
在过去几年中,JavaScript 发生了翻天覆地的变化。它曾经是一种处于次要地位的“玩具”语言,但是现在JavaScript已经成为世界上最重要的程序设计语言之一。随着基于Ajax的开发的重要性不断提升,以及各种功能完备的JavaScript 库的出现,围绕在JavaScript周围的魔咒已经一扫而空。jQuery 无疑是最流行的也是对初学者最友好的JavaScript库,它是JavaScript库中的佼佼者。
jQuery不仅仅是初学者的最佳选择,它已经在世界上最大的组织机构中得以应用,每个月都为数以亿计的页面访问增强了交互性。Amazon、 IBM、Twitter. NBC、Best Buy和Dell等大量公司都在其产品中使用了jQuery.
无论采用哪一种程序设计方法学或编程技术,对于Java/Spring. PHP、 .NET、Ruby onRails和Python/Django等各种Web技术,jQuery在前端开发领域都具有突出的特色。本文讲为大家介绍一本书——《Jquery高级编程》。如果读者具有HTML、CSS和JavaScript的开发经验,那么本书非常适合你阅读。
本书分为两个部分,第I部分是jQuery基础,第II部分是jQuery应用。
第I部分一jQuery基础,这一部分包含了下列章节:
第1章“jQuery 入门”这一章介绍了如何建立开发和调试jQuery和JavaScript代码所需的环境,定义了在本书中使用的编码规范和标准。还介绍了将JavaScript代码打包作为产品并创建代码的方法。
第2章\”JavaScript基础”这一章介绍了JavaScript程序设计语言的基础知识,为本书后面的内容打好一个基础。毕竟,jQuery 是一个JavaScript 库,它的很多优秀特性来源于对JavaScript核心技术的巧妙应用。
第3章“jQuery核心技术”这一章介绍了 jQuery 库的基本功能。它描述了核心jQuery函数的使用方法,介绍了很多有用的工具函数,使用这些工具函数可以执行各种各样的编程任务。
第4章“选择和操作DOM元素”这一章深入介绍了jQuery的核心特性,即选择或操作HTML元素的功能。
第5章“事件处理”这一章介绍了jQuery 的另外一个关键特性,即跨浏览器的事件绑定和事件管理功能。
第6章“HTML表单、数据和Ajax\” 这一章介绍了过去10年以来Web开发领域最大的技术变革——Ajax.
第7章“动画和特效\”一这一章介绍了jQuery为页面组件创建动画效果的一些快捷方法,比如移动(move)、淡化(fade)、切换(oggle)和缩放(resize)。
第II部分- jQuery 应用,包含了下面几个主题:
第8章“jQueryUI第I部分:更轻松地创建Web界面\”这一章介绍了jQuery UI。jQuery UI是一个jQuery的用户界面库,它包含了一些部件(widge)特效、动画和交互功能。
第9章“jQueryUI第II部分:鼠标交互”这一章介绍了jQuery Ul鼠标操作的特性,包括移动、排序、缩放和使用鼠标迭取元素。
第10章“编写高效的jQuery代码”这一章介绍了大量jQuery优化技术、最佳实践和设计模式。
第11章\”jQuery模板”这一章专门介绍了 jQuery Template 插件。jQuery 模板是一种将数据与标记代码融合的标准方法。
第12章“编写jQuery插件\” 这一章重点介绍了如何开发jQuery插件。开发人员可以创建户自定义方法以扩展jQuery功能,对于顶尖的jQuery 开发人员来说这是一种基本能力。
第13章“使用jQuery Deferred对象进行高级异步编程”这一章介绍了jQuery的Deferred对象,即$.Deferred 对象。它是在jQuery 1.5版本中引入的一个可链式调用的工具对象,它为回调函数的处理方式提供了精细的控制能力。
第14章“使用QUnit进行单元测试\”这一章介绍了单元测试的常见概念,并详细介绍了jQuery项目自身创建并使用的单元测试框架QUnit。
jquery 简介
JQuery是继prototype之后又一个优秀的Javascript库。它是轻量级的js库 ,它兼容CSS3,还兼容各种浏览器(IE 6.0+, FF1.5+, Safari 2.0+, Opera 9.0+),jQuery2.0及后续版本将不再支持IE6/7/8浏览器。jQuery使用户能更方便地处理HTML(标准通用标记语言下的一个应用)、events、实现动画效果,并且方便地为网站提供AJAX交互。jQuery还有一个比较大的优势是,它的文档说明很全,而且各种应用也说得很详细,同时还有许多成熟的插件可供选择。jQuery能够使用户的html页面保持代码和html内容分离,也就是说,不用再在html里面插入一堆js来调用命令了,只需要定义id即可。
jQuery是一个兼容多浏览器的javascript库,核心理念是write less,do more(写得更少,做得更多)。jQuery在2006年1月由美国人John Resig在纽约的barcamp发布,吸引了来自世界各地的众多JavaScript高手加入,由Dave Methvin率领团队进行开发。如今,jQuery已经成为最流行的javascript库,在世界前10000个访问最多的网站中,有超过55%在使用jQuery。
jQuery是免费、开源的,使用MIT许可协议。jQuery的语法设计可以使开发更加便捷,例如操作文档对象、选择DOM元素、制作动画效果、事件处理、使用Ajax以及其他功能。除此以外,jQuery提供API让开发者编写插件。其模块化的使用方式使开发者可以很轻松的开发出功能强大的静态或动态网页。
jQuery,顾名思义,也就是JavaScript和查询(Query),即是辅助JavaScript开发的库。
历史
大概在 1992 年,一家称作 Nombas 的公司开发了一种叫做 C 减减(C-minus-minus,简称 Cmm)的嵌入式脚本语言。Cmm 背后的理念很简单:一个足够强大可以替代宏操作(macro)的脚本语言,同时保持与 C (和 C ++)足够的相似性,以便开发人员能很快学会。这个脚本语言捆绑在一个叫做 CEnvi 的共享软件中,它首次向开发人员展示了这种语言的威力。
Nombas 最终把 Cmm 的名字改成了 ScriptEase,原因是后面的部分(mm)听起来过于消极,同时字母 C “令人害怕”。
当 Netscape Navigator 崭露头角时,Nombas 开发了一个可以嵌入网页中的 CEnvi 的版本。这些早期的试验被称为 Espresso Page(浓咖啡般的页面),它们代表了第一个在万维网上使用的客户端语言。而 Nombas 丝毫没有料到它的理念将会成为万维网的一块重要基石。
当网上冲浪越来越流行时,对于开发客户端脚本的需求也逐渐增大。此时,大部分因特网用户还仅仅通过 28.8 kbit/s 的调制解调器连接到网络,即便这时网页已经不断地变得更大和更复杂。而更加加剧用户痛苦的是,仅仅为了简单的表单有效性验证,就要与服务器进行多次地往返交互。设想一下,用户填完一个表单,点击提交按钮,等待了 30 秒的处理后,看到的却是一条告诉你忘记填写一个必要的字段。
那时正处于技术革新最前沿的 Netscape,开始认真考虑开发一种客户端脚本语言来解决简单的处理问题。
当时工作于 Netscape 的 Brendan Eich,开始着手为即将在 1995 年发行的 Netscape Navigator 2.0 开发一个称之为 LiveScript 的脚本语言,当时的目的是在浏览器和服务器(本来要叫它 LiveWire)端使用它。Netscape 与 Sun 及时完成 LiveScript 实现。
就在 Netscape Navigator 2.0 即将正式发布前,Netscape 将其更名为 JavaScript,目的是为了利用 Java 这个因特网时髦词汇。Netscape 的赌注最终得到回报,JavaScript 从此变成了因特网的必备组件。
因为 JavaScript 1.0 如此成功,Netscape 在 Netscape Navigator 3.0 中发布了 1.1 版。恰巧那个时候,微软决定进军浏览器,发布了 IE 3.0 并搭载了一个 JavaScript 的克隆版,叫做 JScript(这样命名是为了避免与 Netscape 潜在的许可纠纷)。微软步入 Web 浏览器领域的这重要一步虽然令其声名狼藉,但也成为 JavaScript 语言发展过程中的重要一步。
在微软进入后,有 3 种不同的 JavaScript 版本同时存在:Netscape Navigator 3.0 中的 JavaScript、IE 中的 JScript 以及 CEnvi 中的 ScriptEase。与 C 和其他编程语言不同的是,JavaScript 并没有一个标准来统一其语法或特性,而这 3 种不同的版本恰恰突出了这个问题。随着业界担心的增加,这个语言的标准化显然已经势在必行。
2006年1月,jQuery的第一个版本面世,至今已经有10年多了(注:这个时间点是截止至出书时间)。虽然过了这么久,但它依然以其简洁、灵活的编程风格让人一见倾心。在本篇文章中,我们将讲述jQuery的发展历史,让读者对jQuery有更多的了解。
在jQuery迅速发展的同时,一些大的厂商也看中了商机。2009年9月,微软和诺基亚公司正式宣布支持开源的jQuery库,另外,微软公司还宣称他们将把jQuery作为Visual Studio工具集的一部分。他将提供包括jQuery的智能提示、代码片段、示例文档编制等内容在内的功能。微软和诺基亚公司将长期成为jQuery的用户成员,其他成员还有Google,Intel,IBM,Intuit等公司。 2009年1月,jQuery 1.3版发布,它使用了全新的选择符引擎Sizzle,在各个浏览器下全面超越其他同类型JavaScript框架的查询速度,程序库的性能也因此有了极大提升。这一版本的第2个变化就是提供live()方法,使用live()方法可以为当前及将来增加的元素绑定事件,在1.3版之前,如果要为将来增加的元素绑定事件,需要使用livequery插件,而在1.3版中,可以直接用live()方法。 2005年8月,John Resig提议改进Prototype的“Behaviour”库,于是他在blog上发表了自己的想法,并用了3个例子做说明。
当时John的想法很简单:他发现这种语法相对现有的JavaScript库更为简洁。但他没想到的是,这篇文章一经发布就引起了业界的广泛关注。于是John开始认真思考着这件事情(编写语法更为简洁的JavaScript程序库),直到2006年1月14日,John正式宣布以jQuery的名称发布自己的程序库。随之而来的是jQuery的快速发展。 2006年8月,jQuery的第一个稳定版本,并且已经支持CSS选择符、事件处理和AJAX交互。 2007年7月,jQuery 1.1.3版发布,这次小版本的变化包含了对jQuery选择符引擎执行速度的显著提升。从这个版本开始,jQuery的性能达到了Prototype、Mootools以及Dojo等同类JavaScript库的水平。同年9月,jQuery 1.2版发布,它去掉了对XPath选择符的支持,原因是相对于CSS语法它已经变得多余了。这一版能够对效果进行更为灵活的定制,而且借助新增的命名空间事件,也使插件开发变得更容易。同时,jQuery UI项目也开始启动,这个新的套件是作为曾经流行但已过时的Interface插件的替代项目而发布的。jQuery UI中包含大量预定义好的部件(widget),以及一组用于构建高级元素(例如可拖放、拖拽、排序)的工具。
2010年2月,jQuery 1.4.2版发布,它新增了有关事件委托的两个方法:delegate()和undelegate()。delegate()用于替代1.3.2中的live()方法。这个方法比live()来的方便,而且也可以达到动态添加事件的作用。比如给表格的每个td绑定hover事件
特点
1.动态特效
2.AJAX
3.通过插件来扩展
4.方便的工具 – 例如浏览器版本判断
5.渐进增强
6.链式调用
7.多浏览器支持,支持Internet Explorer6.0+、Opera9.0+、Firefox2+、Safari2.0+、Chrome1.0+(在2.0.0中取消了对Internet Explorer6,7,8的支持)
历史版本
jQuery 1.0
(2006年8月):该库的第一个稳定版本,已经具有了对CSS选择符、事件处理和AJAX交互的稳健支持。
jQuery 1.1
(2007年1月):这一版大幅简化了API。许多较少使用的方法被合并,减少了需要掌握和解释的方法数量。
jQuery 1.1.3
(2007年7月):这次小版本变化包含了对jQuery选择符引擎执行速度的显著提升。从这个版本开始,jQuery的性能达到了Prototype、Mootools以及Dojo等同类JavaScript库的水平。
jQuery 1.2
(2007年9月):这一版去掉了对XPath选择符的支持,原因是相对于CSS语法它已经变得多余了。这一版能够支持对效果的更灵活定制,而且借助新增的命名空间事件,也使插件开发变得更容易。
jQuery UI(2007年9月):这个新的插件套件是作为曾经流行但已过时的Interface插件的替代项目而发布的。jQuery UI中包含大量预定义好的部件(widget),以及一组用于构建高级元素(例如可拖放的界面元素)的工具。
jQuery 1.2.6
(2008年5月):这一版主要是将Brandon Aaron开发的流行的Dimensions插件的功能移植到了核心库中。
jQuery 1.3
(2009年1月):这一版使用了全新的选择符引擎Sizzle,库的性能也因此有了极大提升。这一版正式支持事件委托特性。
jQuery 1.3.2
(2009年2月):这次小版本升级进一步提升了库的性能,例如改进了:visible/:hidden选择符、.height()/.width()方法的底层处理机制。另外,也支持查询的元素按文档顺序返回。
jQuery 1.4
(2010年1月14号):对代码库进行了内部重写组织,开始建立一些风格规范。老的core.js文件被分为attribute.js,css.js,data.js,manipulation.js,traversing.js和queue.js;CSS和attribute的逻辑分离。
重要变化:
1. Ajax重写
Ajax模块完全进行了重写。新增一个jXHR对象,为不同浏览器内置的XMLHttpRequest提供了一致的超集。对于XMLHttpRequest之外的传输机制,比如JSONP请求,jXHR对象也可以进行处理。(详情可以参见:jQuery.ajax文档)
此外,系统的可扩展性大大增强,可以附加各种数据处理器、过滤器和传输机制,为开发新的Ajax插件提供了方便。
2. 延迟对象
延迟对象(Deferred Object,jQuery.Deferred对象)是一个可链接的(chainable)实用工具对象,实现了Promise接口,可以在回调队列中注册多个回调、调用回调队列并转发任何同步/异步函数的成败状态。正如Using Deferreds in jQuery 1.5一文中说明的,其结果是在jQuery中能够将依赖于某个任务(事件)结果的逻辑与任务本身解耦了。这一点在JavaScript中其实并不新鲜,Mochikit和Dojo等已经实现有些日子了。由于jQuery 1.5的Ajax模块内置使用了延迟对象,因此通过jQuery编写Ajax程序将自动获得这一功能。
开发人员借此可以使用无法立即获得的返回值(如异步Ajax请求的返回结果),而且第一次能够附加多个事件处理器。
例如,使用了新的jQuery内部Ajax API就可以实现下面的代码了:
// Assign handlers immediately after making the request,// and remember the jxhr object for this request var jxhr = $.ajax({ url: \”example.php\” }) .success(function() { alert(\”success\”); }) .error(function() { alert(\”error\”); }) .complete(function() { alert(\”complete\”); });// perform other work here … // Set another completion function for the request above jxhr.complete(function(){ alert(\”second complete\”); });
此外,使用jQuery.Deferred还可以开发自己的延迟对象。更多详情参见:延迟对象文档。
3. jQuery.sub()
jQuery 1.5提供了一种创建和修改jQuery副本的方式。可以用来添加不向外部公开的方法,或者对jQuery的某些方法进行重新定义以提供新功能,或者提供更好的封装、避免名称空间冲突。当然,也可以用来开发插件,但Resig强烈建议在开发插件之前,先考虑jQuery UI widget工厂。
值得注意的是,sub函数并不提供真正的隔离,所有方法、数据、调用仍然依靠jQuery本身来支持。
4. 遍历性能提高
在新版本中.children(),.prev(),.next()几个常用的遍历函数性能有了显著提高。
5. 内部开发系统
John Resig还特别提到了jQuery团队内部开发系统的两点改变:一是服务器端用Node.js替换了老的Java/Rhino系统,使得团队可以专注于JavaScript环境的新变化;二是所用的代码优化程序从Google Closure切换到UglifyJS,新工具的压缩效果非常令人满意。
使用方法
jQuery可以下载使用,有两个版本的 jQuery 可供下载
Production version – 用于实际的网站中,已被精简和压缩。
Development version – 用于测试和开发(未压缩,是可读的代码)
jQuery 1.8.0版时压缩前后的对比
插件机制
jQuery的官方插件是jQuery UI。开发者可以任意扩展jQuery的函数库或者按照自己的需求开发UI组件。网上已经有数以万计的jQuery插件,覆盖各种各样的需求。例如Ajax辅助、数据表格、动态列表、XML工具、拖曳、cookie处理、弹出层等等。jQuery 的文档说明很全,而且各种应用也说得很详细,同时还有许多成熟的插件可供选择,例如ComponentOne Studio for ASP NET Wijmo.
随着jQuery插件在网站建设过程中的使用率不断的增加,所以有必要跟进时代步伐开发出一些新的插件/代码片段,以此来巩固并提高前端用户体验,将用户体验提升到一个新的高度。其中包括Flat jQuery Price Slider、Gmaps jQuery Map Plugin 、FormChimp——MailChimp Ajax plugin for jQuery 等。
控件
jQuery Gantt控件是一个基于原生HTML5/jQuery,功能丰富的控件,该控件真正实现了跨平台,在许多设备和浏览器中无缝的运行。
使用项目甘特图中内置的调度,依赖等功能实现任务分层列表的可视化。
使用资源甘特图实现一个资源利用视图。
使用基于API的jQuery或者基于API的MVC可帮您轻松地安装甘特图并加快应用速度。
可与诸如KnockOut(KO),jQuery.tmpl等流行的jQuery模式一同使用。
2025 年应该告别的 5 个 JavaScript 库
随着 JavaScript 的发展,一些库不可避免地落后,无法跟上开发人员社区的最新功能、范式和性能期望。
现在是时候做出一些艰难的决定,告别某些不再像以前那样满足我们需求的库了。下面,我们重点介绍了 2025 年可能过时的五个 JavaScript 库,以及为什么是时候继续前进了。
我们都听说过 JS 的革命性突破,比如 18 岁的 Aiden Bai 创建了 Million.js 来提高 JS 性能,或者有人找到了一种在 React 中查看文档的新方法,但那些拒绝和害群之马呢?
1. jQuery
jQuery 是现代 JavaScript 库的祖父,因其跨浏览器支持、简单的 DOM 操作和简洁的语法而备受喜爱。然而,在 2025 年,是时候正式放手了。原生 JavaScript API 和现代框架(如 React、Vue 和 Angular)已使 jQuery 的核心实用程序过时。
更不用说,原版 JavaScript 现在包括 querySelector、addEventListener 和 fetch 等原生方法,它们更方便地提供了我们曾经依赖 jQuery 提供的功能。此外,现代浏览器已经标准化,因此对 jQuery 等跨浏览器解决方案的需求变得多余。更不用说,今天将 jQuery 捆绑到应用程序中会增加不必要的臃肿,在速度为王的时代减慢加载时间。
如果您仍然依赖 jQuery,请考虑过渡到特定于框架的模块化解决方案或重构代码以使用本机 JS 方法。这是一个很大的飞跃,但它会使您的代码更精简、更快、更易于维护。
2. Moment.js
Moment.js 在很长一段时间内都是默认的日期处理库,它因其解析、验证、操作和显示日期的能力而广受赞誉。然而,与较新的替代方案相比,它现在很沉重且不灵活,更不用说它已被弃用。Moment.js 的计时大小约为 66 KB(缩小),在较小的捆绑包大小带来更快的性能和更好的用户体验的时代,这可能是一个重要的有效负载。
推荐的替代品是 date-fns 或 luxon。两者都提供模块化导入,这意味着您可以只使用您需要的内容,从而大大减小捆绑包的大小。
更棒的是,JavaScript 的 Temporal API 一直在发展,可以直接处理日期和时间任务,从而提供更高效的解决方案,而无需依赖第三方库。如果您仍在使用 Moment.js,请将其视为开始迁移的通知。
3. Lodash
Lodash 是一个通用的实用程序库,曾经是几乎所有 JavaScript 项目的主要内容。它提供了有用的实用程序来简化从深度对象克隆到数组操作的所有内容。但是,Lodash 提供的许多功能现在要么是 JavaScript 原生的,要么可以通过简洁的代码轻松实现。
在 ES6 及更高版本中,Object.assign()、扩展运算符和 Array 方法等功能在很大程度上消除了对 Lodash 的需求。该库也相当大,仅导入单个函数通常会给项目带来大量额外开销。
考虑通过将 Lodash 的函数替换为 ES6+ 等效函数来修剪 Lodash。对于 Lodash 确实提供了独特便利的少数极端情况,模块化导入 (import { cloneDeep } from \’lodash/cloneDeep\’) 可以最大限度地减少库对捆绑包大小的影响。
4. Underscore.js
Underscore.js 是 Lodash 的前身,尽管在很大程度上被其更年轻、功能更丰富的兄弟姐妹所掩盖,但它已经存在多年。现在是彻底告别 Underscore 的时候了。
与 Lodash 一样,Underscore 的实用程序方法现在要么在 JavaScript 中原生支持,要么可以使用较小的库或单个函数更有效地实现。如果你正在使用 Underscore,你可能没有获得 ES6+ 语法已经无法处理的任何实质性内容,并且它会给你的项目增加不必要的体积。
从 Underscore 迁移对于性能和可维护性来说是一个直接的胜利,在 2025 年没有理由再保留它。
5. 需要JS
在 ES6 模块出现之前,RequireJS 在帮助 JavaScript 开发人员管理依赖项方面发挥了关键作用。它的异步模块定义 (AMD) 允许更高效的加载,帮助开发人员在这些功能原生可用之前以模块化方式组织脚本。
但是,随着 ES6 模块的出现和现代浏览器的广泛支持,RequireJS 现在是多余的。ES6 提供了一种更简洁、标准化的方式来导入和导出模块,使得 RequireJS 的额外复杂性变得不必要。
Webpack、Vite 和 Rollup 等流行的捆绑程序也提供了处理依赖项管理的简化方法,使 RequireJS 的使用变得多余。此外,云自动化工具通常补充这些现代捆绑器,提供无缝部署和扩展功能。
如果您的项目中仍有 RequireJS,那么是时候进行现代化改造了。将您的模块转换为 ES6 语法,并依靠 Webpack 等工具甚至本机模块加载来使您的代码库面向未来。
随着上述库的推出,让我们看一下一些现代替代品,它们可以简化您的开发过程并保持您的应用程序的性能和最新状态。
1. 原生 JavaScript(用于 jQuery)
原生 JavaScript API 已经有了巨大的改进,对于 jQuery 过去处理的大部分内容,原版 JavaScript 也可以做到。querySelector、addEventListener 和 fetch 等方法几乎涵盖了开发人员常用 jQuery 处理的所有 DOM 操作和 AJAX 请求,而不会向捆绑包添加不必要的批量。
2. Date-fns 或 Luxon(适用于 Moment.js)
Date-fns 和 Luxon 是 Moment.js 的更轻的模块化替代品。它们允许您仅导入所需的功能,从而显著减小捆绑包大小。此外,JavaScript 不断发展的 Temporal API 直接在语言中提供更强大的日期和时间处理功能。
3. ES6+ 原生功能(适用于 Lodash)
Lodash 的许多实用程序在 ES6+ 中都有原生替代方案。例如,您可以使用扩展运算符 (…)、Object.assign() 和大量新的 Array 方法(map、reduce、filter)来处理 Lodash 曾经简化的相同任务。对于更多小众用例,请考虑仅导入您需要的特定 Lodash 函数。
4. ES6+ 语法(适用于 Underscore.js)
Underscore 的实用程序方法也已在很大程度上被 ES6+ 语法所取代。函数式编程、对象操作和数组迭代的方法都可以使用本机 JavaScript 以更高性能和更简洁的方式实现。将代码迁移到 ES6+ 将使其更简洁、更易于维护。
5. Webpack、Vite 或 ES6 模块(用于 RequireJS)
现在不再需要 RequireJS,因为 ES6 提供了一个标准化的模块系统。Webpack 和 Vite 等工具可以帮助您以更简化的方式捆绑应用程序并处理依赖项。此外,现代浏览器的原生模块支持允许您在没有任何额外依赖项的情况下加载模块。
JavaScript 生态系统发展迅速,曾经不可或缺的东西很快就会过时。继续使用不再相关的库可能会使应用程序面临性能问题,增加维护成本,并降低代码的可读性。采用原生 JavaScript 功能、现代库或内置浏览器 API 可使您的堆栈保持轻量级、应用程序性能并使您的开发实践保持最新状态。
是时候削减脂肪了:放弃 jQuery、Moment.js、Lodash、Underscore 和 RequireJS。现代替代方案不仅更快、更模块化,而且更符合当前 JavaScript 开发的最佳实践——确保您在 2025 年临近时保持领先地位。
本文作者及来源:Renderbus瑞云渲染农场https://www.renderbus.com
文章为作者独立观点不代本网立场,未经允许不得转载。