StateOfJS 刚刚发布了 2018年的 JavaScript 现状调查报告,今年他们调查了超过 20000 名 JavaScript 开发者,以确定他们正在使用什么,他们对什么感到满意以及他们想要学习什么。 1、JavaScript 现状 —— “方言” 随着 JavaScript 的成熟,开发者基于 JavaScript 创建了许多其他语言,或者叫“方言”,如 ES6、TypeScript、Flow、Reason、Elm、ClojureScript 、CoffeeScript 等等。曾几何时,CoffeeScript 是该方向的唯一支持者,但如今它已被 ES6 、TypeScript、Flow 等取代。 StateOfJS 表示有充分的理由认为这是整个 JavaScript 的未来。因为随着像 Web Assembly 这样的项目的出现,直接使用 JavaScript 编写代码可能很快就会变得古怪。 2018年的两位大赢家是 ES6 和 TypeScript 。另外 Reason 也值得关注,它背后有 Facebook 的支持,并且拥有非常高的满意度和兴趣值。 2、JavaScript 现状 —— 前端框架 结果基本上和其他榜单类似,React 和 Vue 唱主角,Angular 有垮台的趋势。 StateOfJS 表示,两年前有 27% 的受访者表示从未听说过 Vue ,但如今这一比例已降至 1.3% !虽然 React 仍然拥有更大的市场份额,但 Vue 的迅速崛起也没有停止的迹象。 Angular 本身拥有庞大的用户群,但也很难看到它重新登上前端框架的冠亚宝座。 3、JavaScript 现状 —— 数据层 毫无疑问,Redux 是使用最广泛的工具,82% 的满意率也证明了它的成熟程度。不过 GraphQL 也并非没有冲击的可能,其用户在两年内从 5% 上升到了 20% 。 4、JavaScript 现状 —— 后端框架(服务端) JavaScript 在后端(服务端)领域近年来似乎没有取得任何重大突破,虽然每年都有无数的框架出现,但很少有能够获得很大的成功并挑战 Express 的地位的。 即便是拥有 Express 继任者称号的 Koa ,其满意度也相对较低,使用量也有大幅下滑。 该领域有一个有趣的参与者 —— Next.js,最近引起了很多人的兴趣。虽然它与功能齐全的 Node 后端不太可比,但它专注于解决 React 应用的服务器端渲染问题,使其成为一个非常实用的工具。 5、JavaScript 现状 —— 测试 […]
View Details这是一个非常有趣的 非主流前端领域,这个领域要探索的是如何用工程手段解决前端开发和部署优化的综合问题,入行到现在一直在学习和实践中。 在我的印象中,facebook是这个领域的鼻祖,有兴趣、有梯子的同学可以去看看facebook的页面源代码,体会一下什么叫工程化。 接下来,我想从原理展开讲述,多图,较长,希望能有耐心看完。 让我们返璞归真,从原始的前端开发讲起。上图是一个“可爱”的index.html页面和它的样式文件a.css,用文本编辑器写代码,无需编译,本地预览,确认OK,丢到服务器,等待用户访问。前端就是这么简单,好好玩啊,门槛好低啊,分分钟学会有木有! 然后我们访问页面,看到效果,再查看一下网络请求,200!不错,太™完美了!那么,研发完成。。。。了么? 等等,这还没完呢!对于大公司来说,那些变态的访问量和性能指标,将会让前端一点也不“好玩”。 看看那个a.css的请求吧,如果每次用户访问页面都要加载,是不是很影响性能,很浪费带宽啊,我们希望最好这样: 利用304,让浏览器使用本地缓存。但,这样也就够了吗?不成!304叫协商缓存,这玩意还是要和服务器通信一次,我们的优化级别是变态级,所以必须彻底灭掉这个请求,变成这样: 强制浏览器使用本地缓存(cache-control/expires),不要和服务器通信。好了,请求方面的优化已经达到变态级别,那问题来了:你都不让浏览器发资源请求了,这缓存咋更新? 很好,相信有人想到了办法:通过更新页面中引用的资源路径,让浏览器主动放弃缓存,加载新资源。好像这样: 下次上线,把链接地址改成新的版本,就更新资源了不是。OK,问题解决了么?!当然没有!大公司的变态又来了,思考这种情况: 页面引用了3个css,而某次上线只改了其中的a.css,如果所有链接都更新版本,就会导致b.css,c.css的缓存也失效,那岂不是又有浪费了?! 重新开启变态模式,我们不难发现,要解决这种问题,必须让url的修改与文件内容关联,也就是说,只有文件内容变化,才会导致相应url的变更,从而实现文件级别的精确缓存控制。 什么东西与文件内容相关呢?我们会很自然的联想到利用 数据摘要要算法 对文件求摘要信息,摘要信息与文件内容一一对应,就有了一种可以精确到单个文件粒度的缓存控制依据了。好了,我们把url改成带摘要信息的: 这回再有文件修改,就只更新那个文件对应的url了,想到这里貌似很完美了。你觉得这就够了么?大公司告诉你:图样图森破! 唉~~~~,让我喘口气 现代互联网企业,为了进一步提升网站性能,会把静态资源和动态网页分集群部署,静态资源会被部署到CDN节点上,网页中引用的资源也会变成对应的部署路径: 好了,当我要更新静态资源的时候,同时也会更新html中的引用吧,就好像这样: 这次发布,同时改了页面结构和样式,也更新了静态资源对应的url地址,现在要发布代码上线,亲爱的前端研发同学,你来告诉我,咱们是先上线页面,还是先上线静态资源? 1.先部署页面,再部署资源:在二者部署的时间间隔内,如果有用户访问页面,就会在新的页面结构中加载旧的资源,并且把这个旧版本的资源当做新版本缓存起来,其结果就是:用户访问到了一个样式错乱的页面,除非手动刷新,否则在资源缓存过期之前,页面会一直执行错误。 2.先部署资源,再部署页面:在部署时间间隔之内,有旧版本资源本地缓存的用户访问网站,由于请求的页面是旧版本的,资源引用没有改变,浏览器将直接使用本地缓存,这种情况下页面展现正常;但没有本地缓存或者缓存过期的用户访问网站,就会出现旧版本页面加载新版本资源的情况,导致页面执行错误,但当页面完成部署,这部分用户再次访问页面又会恢复正常了。 好的,上面一坨分析想说的就是:先部署谁都不成!都会导致部署过程中发生页面错乱的问题。所以,访问量不大的项目,可以让研发同学苦逼一把,等到半夜偷偷上线,先上静态资源,再部署页面,看起来问题少一些。 但是,大公司超变态,没有这样的“绝对低峰期”,只有“相对低峰期”。So,为了稳定的服务,还得继续追求极致啊! 这个奇葩问题,起源于资源的覆盖式发布,用 待发布资源覆盖 已发布资源,就有这种问题。解决它也好办,就是实现非覆盖式发布。 看上图,用文件的摘要信息来对资源文件进行重命名,把摘要信息放到资源文件发布路径中,这样,内容有修改的资源就变成了一个新的文件发布到线上,不会覆盖已有的资源文件。上线过程中,先全量部署静态资源,再灰度部署页面,整个问题就比较完美的解决了。 所以,大公司的静态资源优化方案,基本上要实现这么几个东西: 1.配置超长时间的本地缓存 —— 节省带宽,提高性能 2.采用内容摘要作为缓存更新依据 —— 精确的缓存控制 3.静态资源CDN部署 —— 优化网络请求 4.更资源发布路径实现非覆盖式发布 —— 平滑升级 全套做下来,就是相对比较完整的静态资源缓存控制方案了,而且,还要注意的是,静态资源的缓存控制要求在 前端所有静态资源加载的位置都要做这样的处理 。是的,所有!什么js、css自不必说,还要包括js、css文件中引用的资源路径,由于涉及到摘要信息,引用资源的摘要信息也会引起引用文件本身的内容改变,从而形成级联的摘要变化,大概示意图就是: 好了,目前我们快速的学习了一下前端工程中关于静态资源缓存要面临的优化和部署问题,新的问题又来了:这™让工程师怎么写码啊!!! 要解释优化与工程的结合处理思路,又会扯出一堆有关模块化开发、资源加载、请求合并、前端框架等等的工程问题,以上只是开了个头,解决方案才是精髓,但要说的太多太多,有空再慢慢展开吧。 总之,前端性能优化绝逼是一个工程问题! 以上不是我YY的,可以观察 百度 或者 facebook 的页面以及静态资源源代码,查看它们的资源引用路径处理,以及网络请中静态资源的缓存控制部分。再次赞叹facebook的前端工程建设水平,跪舔了。 建议前端工程师多多关注前端工程领域,也许有人会觉得自己的产品很小,不用这么变态,但很有可能说不定某天你就需要做出这样的改变了。而且,如果我们能把事情做得更极致,为什么不去做呢? 另外,也不要觉得这些是运维或者后端工程师要解决的问题。如果由其他角色来解决,大家总是把自己不关心的问题丢给别人,那么前端工程师的开发过程将受到极大的限制,这种情况甚至在某些大公司都不少见! 妈妈,我再也不玩前端了。。。。5555 业界实践 Assets Pipeline Rails中的Assets Pipeline完成了以上所说的优化细节,对整个静态资源的管理上的设计思考也是如此,了解rails的人也可以把此答案当做是对rails中assets pipeline设计原理的分析。 rails通过把静态资源变成erb模板文件,然后加入<%= asset_path 'image.png' %>,上线前预编译完成处理,fis的实现思路跟这个几乎完全一样,但我们当初确实不知道有rails的这套方案存在。 相关资料: 英文版:http://guides.rubyonrails.org/asset_pipeline.html 中文版:http://guides.ruby-china.org/asset_pipeline.html FIS的解决方案 用 F.I.S 包装了一个小工具,完整实现整个回答所说的最佳部署方案,并提供了源码对照,可以感受一下项目源码和部署代码的对照。 源码项目:https://github.com/fouber/static-resource-digest-project 部署项目:https://github.com/fouber/static-resource-digest-project-release 部署项目可以理解为线上发布后的结果,可以在部署项目里查看所有资源引用的md5化处理。 这个示例也可以用于和assets pipeline做比较。fis没有assets的目录规范约束,而且可以以独立工具的方式组合各种前端开发语言(coffee、less、sass/scss、stylus、markdown、jade、ejs、handlebars等等你能想到的),并与其他后端开发语言结合。 assets pipeline的设计思想值得独立成工具用于前端工程,fis就当做这样的一个选择吧。 from:https://www.cnblogs.com/minigrasshopper/p/7694053.html
View Details每个参与过开发企业级web应用的前端工程师或许都曾思考过前端性能优化方面的问题。我们有雅虎14条性能优化原则,还有两本很经典的性能优化指导书:《高性能网站建设指南》、《高性能网站建设进阶指南》。经验丰富的工程师对于前端性能优化方法耳濡目染,基本都能一一列举出来。这些性能优化原则大概是在7年前提出的,对于web性能优化至今都有非常重要的指导意义。 然而,对于构建大型web应用的团队来说,要坚持贯彻这些优化原则并不是一件十分容易的事。因为优化原则中很多要求是与工程管理相违背的,比如“把css放在头部”和“把js放在尾部”这两条原则,我们不能让团队的工程师在写样式和脚本引用的时候都去修改一个相同的页面文件。这样做会严重影响团队成员间并行开发的效率,尤其是在团队有版本管理的情况下,每天要花大量的时间进行代码修改合并,这项成本是难以接受的。因此在前端工程界,总会看到周期性的性能优化工作,辛勤的前端工程师们每到月圆之夜就会倾巢出动根据优化原则做一次性能优化。 本文从一个全新的视角来思考web性能优化与前端工程之间的关系,通过解读百度前端集成解决方案小组(F.I.S)在打造高性能前端架构并统一百度40多条前端产品线的过程中所经历的技术尝试,揭示前端性能优化在前端架构及开发工具设计层面的实现思路。 性能优化原则及分类 笔者先假设本文的读者是有前端开发经验的工程师,并对企业级web应用开发及性能优化有一定的思考,因此我不会重复介绍雅虎14条性能优化原则。如果您没有这些前续知识,请移步这里来学习。 首先,我们把雅虎14条优化原则,《高性能网站建设指南》以及《高性能网站建设进阶指南》中提到的优化点做一次梳理,按照优化方向分类,可以得到这样一张表格: 优化方向 优化手段 请求数量 合并脚本和样式表,CSS Sprites,拆分初始化负载,划分主域 请求带宽 开启GZip,精简JavaScript,移除重复脚本,图像优化 缓存利用 使用CDN,使用外部JavaScript和CSS,添加Expires头,减少DNS查找,配置ETag,使AjaX可缓存 页面结构 将样式表放在顶部,将脚本放在底部,尽早刷新文档的输出 代码校验 避免CSS表达式,避免重定向 表格1 性能优化原则分类 目前大多数前端团队可以利用yui compressor或者google closure compiler等压缩工具很容易做到“精简Javascript”这条原则;同样的,也可以使用图片压缩工具对图像进行压缩,实现“图像优化”原则。这两条原则是对单个资源的处理,因此不会引起任何工程方面的问题。很多团队也通过引入代码校验流程来确保实现“避免css表达式”和“避免重定向”原则。目前绝大多数互联网公司也已经开启了服务端的Gzip压缩,并使用CDN实现静态资源的缓存和快速访问;一些技术实力雄厚的前端团队甚至研发出了自动CSS Sprites工具,解决了CSS Sprites在工程维护方面的难题。使用“查找-替换”思路,我们似乎也可以很好的实现“划分主域”原则。 我们把以上这些已经成熟应用到实际生产中的优化手段去除掉,留下那些还没有很好实现的优化原则。再来回顾一下之前的性能优化分类: 优化方向 优化手段 请求数量 合并脚本和样式表,拆分初始化负载 请求带宽 移除重复脚本 缓存利用 添加Expires头,配置ETag,使Ajax可缓存 页面结构 将样式表放在顶部,将脚本放在底部,尽早刷新文档的输出 表格2 较难实现的优化原则 现在有很多顶尖的前端团队可以将上述还剩下的优化原则也都一一解决,但业界大多数团队都还没能很好的解决这些问题。因此,本文将就这些原则的解决方案做进一步的分析与讲解,从而为那些还没有进入前端工业化开发的团队提供一些基础技术建设意见,也借此机会与业界顶尖的前端团队在工业化工程化方向上交流一下彼此的心得。 静态资源版本更新与缓存 如表格2所示,“缓存利用”分类中保留了“添加Expires头”和“配置ETag”两项。或许有些人会质疑,明明这两项只要配置了服务器的相关选项就可以实现,为什么说它们难以解决呢?确实,开启这两项很容易,但开启了缓存后,我们的项目就开始面临另一个挑战:如何更新这些缓存。 相信大多数团队也找到了类似的答案,它和《高性能网站建设指南》关于“添加Expires头”所说的原则一样——修订文件名。即: 最有效的解决方案是修改其所有链接,这样,全新的请求将从原始服务器下载最新的内容。 思路没错,但要怎么改变链接呢?变成什么样的链接才能有效更新缓存,又能最大限度避免那些没有修改过的文件缓存不失效呢? 先来看看现在一般前端团队的做法: 或者 大家会采用添加query的形式修改链接。这样做是比较直观的解决方案,但在访问量较大的网站,这么做可能将面临一些新的问题。 通常一个大型的web应用几乎每天都会有迭代和更新,发布新版本也就是发布新的静态资源和页面的过程。以上述代码为例,假设现在线上运行着index.html文件,并且使用了线上的a.js资源。index.html的内容为: 这次我们更新了页面中的一些内容,得到一个index.html文件,并开发了新的与之匹配的a.js资源来完成页面交互,新的index.html文件的内容因此而变成了: 好了,现在要开始将两份新的文件发布到线上去。可以看到,index.html和a.js的资源实际上是要覆盖线上的同名文件的。不管怎样,在发布的过程中,index.html和a.js总有一个先后的顺序,从而中间出现一段或大或小的时间间隔。对于一个大型互联网应用来说即使在一个很小的时间间隔内,都有可能出现新用户访问。在这个时间间隔中,访问了网站的用户会发生什么情况呢? 如果先覆盖index.html,后覆盖a.js,用户在这个时间间隙访问,会得到新的index.html配合旧的a.js的情况,从而出现错误的页面。 如果先覆盖a.js,后覆盖index.html,用户在这个间隙访问,会得到旧的index.html配合新的a.js的情况,从而也出现了错误的页面。 这就是为什么大型web应用在版本上线的过程中经常会较集中的出现前端报错日志的原因,也是一些互联网公司选择加班到半夜等待访问低峰期再上线的原因之一。此外,由于静态资源文件版本更新是“覆盖式”的,而页面需要通过修改query来更新,对于使用CDN缓存的web产品来说,还可能面临CDN缓存攻击的问题。我们再来观察一下前面说的版本更新手段: 我们不难预测,a.js的下一个版本是“1.0.1”,那么就可以刻意构造一串这样的请求“a.js?v=1.0.1”、“a.js?v=1.0.2”、……让CDN将当前的资源缓存为“未来的版本”。这样当这个页面所用的资源有更新时,即使更改了链接地址,也会因为CDN的原因返回给用户旧版本的静态资源,从而造成页面错误。即便不是刻意制造的攻击,在上线间隙出现访问也可能导致区域性的CDN缓存错误。 此外,当版本有更新时,修改所有引用链接也是一件与工程管理相悖的事,至少我们需要一个可以“查找-替换”的工具来自动化的解决版本号修改的问题。 对付这个问题,目前来说最优方案就是基于文件内容的hash版本冗余机制了。也就是说,我们希望工程师源码是这么写的: 但是线上代码是这样的: 其中”_82244e91”这串字符是根据a.js的文件内容进行hash运算得到的,只有文件内容发生变化了才会有更改。由于版本序列是与文件名写在一起的,而不是同名文件覆盖,因此不会出现上述说的那些问题。同时,这么做还有其他的好处: 线上的a.js不是同名文件覆盖,而是文件名+hash的冗余,所以可以先上线静态资源,再上线html页面,不存在间隙问题; 遇到问题回滚版本的时候,无需回滚a.js,只须回滚页面即可; 由于静态资源版本号是文件内容的hash,因此所有静态资源可以开启永久强缓存,只有更新了内容的文件才会缓存失效,缓存利用率大增; 修改静态资源后会在线上产生新的文件,一个文件对应一个版本,因此不会受到构造CDN缓存形式的攻击 虽然这种方案是相比之下最完美的解决方案,但它无法通过手工的形式来维护,因为要依靠手工的形式来计算和替换hash值,并生成相应的文件。这将是一项非常繁琐且容易出错的工作,因此我们需要借助工具。我们下面来了解一下fis是如何完成这项工作的。 首先,之所以有这种工具需求,完全是由web应用运行的根本机制决定的:web应用所需的资源是以字面的形式通知浏览器下载而聚合在一起运行的。这种资源加载策略使得web应用从本质上区别于传统桌面应用的版本更新方式。为了实现资源定位的字面量替换操作,前端构建工具理论上需要识别所有资源定位的标记,其中包括: css中的@import url(path)、background:url(path)、backgournd-image:url(path)、filter中的src js中的自定义资源定位函数,在fis中我们将其规定为__uri(path)。 html中的<script src=”path”>、<link href=”path”>、<imgsrc=”path”>、已经embed、audio、video、object等具有资源加载功能的标签。 为了工程上的维护方便,我们希望工程师在源码中写的是相对路径,而工具可以将其替换为线上的绝对路径,从而避免相对路径定位错误的问题(比如js中需要定位图片路径时不能使用相对路径的情况)。 fis的资源定位设计思想 fis有一个非常棒的资源定位系统,它是根据用户自己的配置来指定资源发布后的地址,然后由fis的资源定位系统识别文件中的定位标记,计算内容hash,并根据配置替换为上线后的绝对url路径。 要想实现具备hash版本生成功能的构建工具不是“查找-替换”这么简单的。我们考虑这样一种情况: 资源引用关系 由于我们的资源版本号是通过对文件内容进行hash运算得到,如上图所示,index.html中引用的a.css文件的内容其实也包含了a.png的hash运算结果,因此我们在修改index.html中a.css的引用时,不能直接计算a.css的内容hash,而是要先计算出a.png的内容hash,替换a.css中的引用,得到了a.css的最终内容,再做hash运算,最后替换index.html中的引用。 这意味着构建工具需要具备“递归编译”的能力,这也是为什么fis团队不得不放弃gruntjs等task-based系统的根本原因。针对前端项目的构建工具必须是具备递归处理能力的。此外,由于文件之间的交叉引用等原因,fis构建工具还实现了构建缓存等机制,以提升构建速度。 在解决了基于内容hash的版本更新问题之后,我们可以将所有前端静态资源开启永久强缓存,每次版本发布都可以首先让静态资源全量上线,再进一步上线模板或者页面文件,再也不用担心各种缓存和时间间隙的问题了! 在本系列的下一部分,我们将介绍静态资源管理与模板框架的思路和用法。 作者简介:张云龙,百度公司Web前端研发部前端集成解决方案小组技术负责人,目前负责F.I.S项目,读者可以关注他的微博:http://weibo.com/fouber/。 from:http://www.infoq.com/cn/articles/front-end-engineering-and-performance-optimization-part1
View Details浏览器缓存主要有两类 缓存协商:Last-midified ,Etag 彻底缓存:cache-control,Expires 缓存协商的意思是需要去服务器端询问页面有没有修改过,没有修改过则返回304直接使用缓存内容,否则返回新内容 协商步骤: 1、服务器发送带Last-midified:GMTtime 头的http response 2、浏览器下次请求时带上if-modified-since:GMTtime http 请求头 3、服务端用本地Last-midified时间与if-modified-since比较,计算浏览器数据是否过期并发送响应 Etag的工作原理与Last-midified类似,不同点在于Etag的值是用户可自定义的 彻底缓存的意思是在缓存失效之前不再需要跟服务器交互 常用的是Expires,Expires的值是一个绝对时间,由服务器产生 这儿存在一个问题,就是服务器的时间可能给客户端的时间不一致导致缓存时间的偏差 要解决这个问题就要使用cache-control,它保存的是一个相对浏览器的时间 如果同时存在cache-control和Expires怎么办呢? 浏览器总是优先使用cache-control,如果没有cache-control才考虑Expires expire: 如果apache开启了expire模块, 当浏览器发送该资源请求的时候, apache返回资源的同时,会返回一个名为expire的http头,expire头的内容是一个时间值, 这一个值就是资源在本地的过期时间, 这个值会存在本地. 也就是说,在本地缓存阶段,在本地找到了一个对应的资源值,而且当前时间还没超过资源的过期时间, 那么就直接使用这一个资源,不会发送http请求. cache-control: cache-control是http协议中常用的头部之一,顾名思义, 他是负责控制页面的缓存机制,如果该头部指示缓存, 缓存的内容也会存在本地, 操作流程和expire相似,但也有不同的地方, cache-control有更多的选项, 而且也有更多的处理方式. if-modified-since 和 last-modified: 当apache接收到一个资源请求(假设是用户是第一次访问,没有任何缓存), 服务器返回资源的同时,还会发送一个last-modified的http响应头, last-modified响应头的内容值是该资源在服务器上最后修改的时间.浏览器接受到这个http头后,会 把其内容值和资源同时保存起来. 当用户第二发送资源请求(假设这里expire没有生效或者已经过期), 浏览器在本地找到了一个相同的资源,但是不能确定该资源是否和服务器上的一样(有可能在两次访问期间,服务器上的资源已经被修改过),此时浏览器发送请求的时候,请求头内会 附带一个if-modified-since的请求头, 这个头部的内容就是上一次last-modified返回的值, 服务器把这个头的值和请求资源的最后修改时间对比,如果两个值相同,则认为资源没有修改,将会返回304,让浏览器使用本地资源.否则服务器将返回资源,而且 返回200状态 if-none-match 和 etag: 其实这两个头部和if-modified-since, last-modified的工作原理是一样的, if-none-match作为请求头, etag作为响应头.既然工作原理一样, 为什么etag这对头部会出现呢? 原因在于, last-modified请求头的内容是以文件最后修改的时间作为对比的,但是unix系统里面, 文件修改的时间只保存到了秒. 如果某些应用内存在1秒内对文件做了多次修改,这样last-modified是不能完成比较功能的.所以要引入一个新的机制(原因可能不止这一个); etag的值一般由3个数值组成,资源的inode值, 最后修改时间, 资源大小,以16进制组成一个字符串, 例如:1a-182b-10f; 但这个格式不是固定的, 只要保证该值的唯一性,但不限格式. 静态资源的更新:张云龙老师的blog写的很好移步这里 html5离线存储 步骤: 1、配置apache让apache支持manifest文件 2、创建manifest文件test.manifest
1 2 3 4 5 6 |
CACHE MANIFEST # wanz app v1 # 指明缓存入口(指明需要缓存的文件) CACHE: index.html style.css images/logo.png scripts/main.js # 以下资源必须在线访问 NETWORK: login.php # 如果index.php无法访问则用404.html代替 FALLBACK: /index.php /404.html |
3、关联manifest文件到html文档
1 |
<html manifest="test.manifest"> ... </html> |
注意:#是用来注释一行的,但它还有一个小作用,web应用的缓存只有在manifest文件被修改的情况下才会被更新,所以如果你只是修改了被缓存的文件,那么用户本地的缓存还是不会被更新的,但是你可以通过修改manifest文件来告诉浏览器需要更新缓存了。利用这点,你可以像上面的例子中那样,写一句这样的注释一个文件版本: # wanz app v1 优点:你可以很明确的了解离线web应用的版本 通过简单的修改这个版本号就可以轻易的通知浏览器更新 你可以配合JavaScript程序来完成缓存更新 CACHE: 这个是manifest文件的默认入口,在此入口之后罗列的文件 (或直接写在CACHE MANIFEST后的文件)在它们下载到本地后会被缓存起来 NETWORK: […]
View Details写在前面的 评价纯属个人主观感受,有夸张成分,只是一种表达,如有不喜请无视之。欢迎指正不足和提供更多更好的vue库,项目,方便参考和学习使用。 一、前台UI组件库 1.Element 优点:中文文档,ui种类比较全,ui设计简洁清晰 缺点:不够有特点 2.iView 优点:和element的UI很相似,有一些多的补充,可以相互替换 缺点:仍然没有什么特色 3.Vuetify 优点:时间选择器是时钟样式,比较有特色。中文文档 缺点:种类不如前面全 地址:https://vuetifyjs.com/zh-Hans/ 4.Vue-material 优点:日期选择器配色舒适,进度条样式有虚线形式,步骤条更清晰相比有创新。表单字段点击后文字会上浮 缺点:目前种类还比较少,遗憾没有时间选择器。非中文文档 5.Quasar 构建响应式网站,PWA,混合移动应用程序 打不开,应该是被墙了,无法评论,只有项目 6.Buefy 优点:时间选择器数字很大有特点 缺点:非中文文档 7.Vant 优点:移动端界面,轻量化,基本涵盖移动端交互的ui,和微信样式很像 8.At-ui 一款全新的平面UI套件,专门用于桌面应用程序 优点:颜色比较素雅,UI比较秀气 9.Vue-js-modal 关于模态框的ui库,配色和阴影上适合音乐娱乐类项目 10.Vuex-loading 等待相关进度的一些库 缺点:并不是那么好看,使用的话,最好手动调调整一下样式 11.Vue-js-grid 可移动方格子位置的库 12.Dockeron docker上的ui库,使用后再回补 13.mint-ui 优点:风格简洁,文档中移动端看的效果清晰 缺点:中文字体和间距比例上稍稍偏大 14.Keen-UI 优点:移动端框架,日期选择器比较好看。 缺点:非中文文档 15.VueCircleMenu 优点:提供各种从中间蹦跶出半圆形按钮的组件方案,主流ui库给的比较少,有了它可以不用自己写了 缺点:配色视图有点惨 16.vue-carbon 有点:很淡雅的风格,虽然颜色只有一种,但是字体和间距给的很好,一眼过去很舒服,ui相比要做的事情不会喧宾夺主。 缺点:在中国可能不是主流(国人喜欢花花绿绿,字体大大的) 17.vue-calendar 特别中国特色,排版稍稍有点拥挤,但是有农历,好评! 18.vue-datetime-picker 19.vue2-calendar 优点:日期选择器中支持自定义事件的稀缺 ★181 – 支持lunar和日期事件的日期选择器 20.vue-datepicker 日期选择器简洁大气,希望可以有匹配的时间选择器 21.vue-datepicker 优点:很小巧,没有多余的装饰,不占版面 22.vue-date-picker ★59 – VueJS日期选择器组件 23.vue-fullcalendar 大格子化日期选择器,酒店入住等游玩类网站会用到 24.vue-datepicker-simple 月份选择排版蛮特别,极少数用这么正红配色的日期选择器 ★20 – 基于vue的日期选择 25.vue-chartjs 可视化图表的vue版本,主要饼形图,条形图,雷达图等都有 缺点:样式太简,使用还需调整,相比百度的Echart还是少太多图类 26.DataVisualization 提供四个最简单的图类,比较实用 缺点:配色上背景太花,前景色饱和度太低,需要调整 ★149 – 数据可视化 27.vue-charts 样式比较好看,但目前图标类型还是太少 ★101 – 轻松渲染一个图表 28.vue-chartkick […]
View Details打开下载的ueditor目录中ueditor.config.js文件,找到如下标签白名单代码 原文地址:侯哥小博 http://37blog.com/?p=61 在任意处加上如下代码,如果你所添加的iframe中还包含其它标签,只需要在数组中继续添加元素即可。
1 |
iframe: ['frameborder','src','width','height'], |
from:https://blog.csdn.net/houbin99999/article/details/72965385
View Details//日期的正则表达式 var reg = /^[1-9]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/; var regExp = new RegExp(reg); if(!regExp.test(value)){ alert("日期格式不正确,正确格式为:2014-01-01"); return; } //时间的正则表达式 var reg = /^(20|21|22|23|[0-1]\d):[0-5]\d:[0-5]\d$/; var regExp = new RegExp(reg); if(!regExp.test(value)){ alert("时间格式不正确,正确格式为:12:00:00"); return; } //日期+时间的正则表达式 var reg = /^[1-9]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])\s+(20|21|22|23|[0-1]\d):[0-5]\d:[0-5]\d$/; var regExp = new RegExp(reg); if(!regExp.test(value)){ alert("时间格式不正确,正确格式为: 2014-01-01 12:00:00 "); return; } }); from:https://www.cnblogs.com/zhilongblogs/p/4074162.html
View DetailsReferrer的重要性 HTTP请求中有一个referer的报文头,用来指明当前流量的来源参考页。例如在www.sina.com.cn/sports/上点击一个链接到达cctv.com首页,那么就referrer就是www.sina.com.cn/sports/了。在Javascript中,我们可以通过document.referrer来获取同样的信息。通过这个信息,我们就可以知道访客是从什么渠道来到当前页面的。这对于Web Analytics来说,是非常重要的,这可以告诉我们不同渠道带来的流量的分布情况,还有用户搜索的关键词等,都是通过分析这个referrer信息来获取的。 但是,出于各种各样的原因,有时候Javascript中读到的referrer却是空字符串。下面总结一下哪些情况下会丢失referrer。 修改Location对象进行页面导航 Location对象是一个用于页面导航的非常实用的对象。因为他允许你只变更Url的其中一部分。例如从cn域名切换到com域名,其他部分不变: 1 window.location.hostname = "example.com"; 但是,通过修改Location进行页面导航的方法,会导致在IE下丢失Referrer。 IE5.5+ 下返回空字符串 Chrome3.0+,Firefox3.5,Opera9.6,Safari3.2.2均正常返回来源网页 window.open方式打开新窗口 示例: 1 <a href="#" onclick="window.open('http://www.google.com')">访问Google</a> 点击此链接会在新窗口打开Google网站,我们在地址栏中输入以下js代码就可以看到发送的referrer了。 1 javascript:alert(document.referrer) 测试结果: IE5.5+ 下返回空字符串 Chrome3.0+,Firefox3.5,Opera9.6,Safari3.2.2均正常返回来源网页 如果是同个域名下通过此方式跳转的,那么我们可以通过访问windoww.opener对象去获取丢失的referrer信息。代码如下: <script type="text/javascript"> var referrer = document.referrer; if (!referrer) { try { if (window.opener) { // IE下如果跨域则抛出权限异常 // Safari和Chrome下window.opener.location没有任何属性 referrer = window.opener.location.href; } } catch (e) {} } </script> 跨域的话则没辙了~ 鼠标拖拽打开新窗口 鼠标拖拽是现在非常流行的用户习惯,很多浏览器都内置或者可以通过插件的方式来支持鼠标拖拽式浏览。但是通过这种方式打开的页面,基本全都丢失referrer。并且,这种情况下,也无法使用window.opener的方式去获取丢失的referrer了。 已测试: Maxthon2.5.2,Firefox的FireGesture插件,Chrome3.0+,Opera9.6,Safari3.2。 点击Flash内部链接 点击Flash上到达另外一个网站的时候,Referrer的情况就比较杂乱了。 IE下,通过客户端Javascript的document.referrer读取到的值是空的,但是如果你使用流量监控软件看一下的话,你会发现,实际上HTTP请求中的Referer报文头却是有值的,这可能是IE实现的Bug。同时,这个值指向的是Flash文件的地址,而不是来源网页的地址。 Chrome4.0下点击Flash到达新窗口之后,Referrer也是指向的Flash文件的地址,而不是源网页的地址。 Chrome3.0和Safari3.2是一样的,都是会丢失Referrer信息。 Opera则和Firefox一样,Referrer的值都是来源网页的地址。 HTTPS跳转到HTTP 从HTTPS的网站跳转到HTTP的网站时,浏览器是不会发送referrer的。这个各大浏览器的行为是一样的。 例如,我们在HTTPS下使用Google Reader或是Gmail的时候,点击某个链接去到另外一个网站,那么从技术上来说,这样的访问和用户直接键入网址访问是没有什么分别的。 Referrer丢失对于广告流量监控的影响 Referrer如果丢失,Web Analytics就会丢掉很重要的一部分信息了,特别对于广告流量来说,就无法知道实际来源了。目前国内好多用了Google Adsense广告的网站,都使用了window.open的方式来打开广告链接,因此IE下会丢失Referrer,而我们知道,IE是目前市场份额最大的浏览器,因此其影响是很大的。很多流量统计工具会因此将这部分流量归入“直接流量”,和用户直接键入网址等价了。 对于这样的情况,需要让广告投放者在投放广告的时候,给着陆页面的Url加上特定的跟踪参数。 例如,某个Flash广告,点击之后到达的网址是http://www.example.com/,为了监控此流量是从哪个渠道过来的,我们可以修改此投放的着陆Url,改成http://www.example.com/?src=sina,类似这种方式,然后在着陆页面中使用Javascript代码提取此src参数,这样就可以得到广告来源信息。 在投放Google Adwords的时候,后台系统有一个“自动标记”的选项,当启用此选项的时候,Google在生成所有广告的着陆页面Url的时候,就会自动加上一个gclid的参数,这个参数能够将Google Analytics后台和Adwords广告后台的数据进行整合。这样就可以知道广告流量对应于哪个广告系列,哪个广告来源和广告关键词等信息了。和上面提到的思路其实是类似的。只不过Google自动帮你做了Url的修改了而已。 IE下referer为空的解决办法 在IE下采用 window.location.href方式跳转的话,referer值为空。而在标签里面的跳转的话 referer就不会空。所以,通过以下代码就可以解决这个IE问题 function gotoUrl(url){ if(window.VBArray){ var gotoLink = document.createElement('a'); gotoLink .href = url; document.body.appendChild(gotoLink); […]
View Details概述 Notification API是浏览器的通知接口,用于在用户的桌面(而不是网页上)显示通知信息,桌面电脑和手机都适用,比如通知用户收到了一封Email。具体的实现形式由浏览器自行部署,对于手机来说,一般显示在顶部的通知栏。 如果网页代码调用这个API,浏览器会询问用户是否接受。只有在用户同意的情况下,通知信息才会显示。 下面的代码用于检查浏览器是否支持这个API。
1 2 3 4 5 |
if (window.Notification) { // 支持 } else { // 不支持 } |
目前,Chrome和Firefox在桌面端部署了这个API,Firefox和Blackberry在手机端部署了这个API。
1 2 3 4 5 |
if(window.Notification && Notification.permission !== "denied") { Notification.requestPermission(function(status) { var n = new Notification('通知标题', { body: '这里是通知内容!' }); }); } |
上面代码检查当前浏览器是否支持Notification对象,并且当前用户准许使用该对象,然后调用Notification.requestPermission方法,向用户弹出一条通知。 Notification对象的属性和方法 Notification.permission Notification.permission属性,用于读取用户给予的权限,它是一个只读属性,它有三种状态。 default:用户还没有做出任何许可,因此不会弹出通知。 granted:用户明确同意接收通知。 denied:用户明确拒绝接收通知。 Notification.requestPermission() Notification.requestPermission方法用于让用户做出选择,到底是否接收通知。它的参数是一个回调函数,该函数可以接收用户授权状态作为参数。
1 2 3 4 5 6 7 |
Notification.requestPermission(function (status) { if (status === "granted") { var n = new Notification("Hi!"); } else { alert("Hi!"); } }); |
上面代码表示,如果用户拒绝接收通知,可以用alert方法代替。 Notification实例对象 Notification构造函数 Notification对象作为构造函数使用时,用来生成一条通知。
1 |
var notification = new Notification(title, options); |
Notification构造函数的title属性是必须的,用来指定通知的标题,格式为字符串。options属性是可选的,格式为一个对象,用来设定各种设置。该对象的属性如下: dir:文字方向,可能的值为auto、ltr(从左到右)和rtl(从右到左),一般是继承浏览器的设置。 lang:使用的语种,比如en-US、zh-CN。 body:通知内容,格式为字符串,用来进一步说明通知的目的。。 tag:通知的ID,格式为字符串。一组相同tag的通知,不会同时显示,只会在用户关闭前一个通知后,在原位置显示。 icon:图表的URL,用来显示在通知上。 上面这些属性,都是可读写的。 下面是一个生成Notification实例对象的例子。
1 2 3 4 5 6 |
var notification = new Notification('收到新邮件', { body: '您总共有3封未读邮件。' }); notification.title // "收到新邮件" notification.body // "您总共有3封未读邮件。" |
实例对象的事件 Notification实例会触发以下事件。 show:通知显示给用户时触发。 click:用户点击通知时触发。 close:用户关闭通知时触发。 error:通知出错时触发(大多数发生在通知无法正确显示时)。 这些事件有对应的onshow、onclick、onclose、onerror方法,用来指定相应的回调函数。addEventListener方法也可以用来为这些事件指定回调函数。
1 2 3 |
notification.onshow = function() { console.log('Notification shown'); }; |
close方法 Notification实例的close方法用于关闭通知。
1 2 3 4 5 6 7 8 9 |
var n = new Notification("Hi!"); // 手动关闭 n.close(); // 自动关闭 n.onshow = function () { setTimeout(n.close.bind(n), 5000); } |
上面代码说明,并不能从通知的close事件,判断它是否为用户手动关闭。 本篇源自 《阮一峰老师的javascript篇》小篇只是在这里传播一下,绝无抄袭之意,多谢关注~ from:https://blog.csdn.net/u010081689/article/details/51004681
View Details所谓的瀑布流效果就正如轻图床首页效果那样,多个内容相近的栏目紧密排列,尽量使到栏目间的间隙最小(即流体布局),并且随着页面滚动条向下滚动,新的数据会追加至当前页面的尾部直到所有数据加载完毕(滚动触发的 Ajax 翻页)。 瀑布流触发分页 这里说一下思路,虽然下面的实例中不能全都用到: 1.当进入屏幕时,判断内容是否为空,如果不为空,开始初始化数据。 2.当往屏幕下拉时,判断数据的最底部与屏幕高度+滚动的高度的大小。如果最底部小于上面两者之和,重新请求接口,即加载数据。 3.当遇到数据超过某个页数时,停止加载或者用分页的形式显示,点击再显示内容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
var intf_url="http://jb51.net/intf"; var pathUrl = "http://jb51.net/"; var page=1; var isLoadRB=false; var ul_select=$("#fansList"); var btn_more=$("#loading"); if(ul_select.length <1) return ; var is_more =true; //跨域请求接口 function loadjs(src,callback){ var js= document.createElement('script'); js.src = src; js.onreadystatechange = js.onload =function(){ if(!js.readyState || js.readyState=='loaded' || js.readyState=='complete'){ if(callback){callback()||callback}; } }; js.charset="utf-8"; document.getElementsByTagName('head')[0].appendChild(js); } //回调函数 function fill(data){ if(data.pageCount==data.pageNo){ is_more=false;//如果数据全部加载完毕,取消加载 $("#loading").html("加载完毕"); } } //解析接口 function queryIntf(){ var url=page==1?intf_url+".json":intf_url+"_page"+page+".json"; loadJs(url,callback); } function callback(){ page++; } /*判断是否要加载接口*/ function needtoloadRB(){ var btn_top=btn_more.offset().top; var window_height=$(window).height(); var scroll_Top=$(window).scrollTop(); return btn_top<scroll_Top+window_height?true:false; } $(window).scroll(function(){ var _needload=needtoloadRB(); if(_needload && isLoadRB==false &&is_more){isLoadRB=true;queryintf();} }) window.onload = function(){ queryintf(); } |
以上就是比较简单的随着下拉内容不断加载的思路代码。 JSON格式类似于(如果是动态接口,可以通过callback函数,则这里不用加fill()):
1 2 |
fill({"fans":[{"nickname":"蔡宝坚","website":"jb51.net","youzhi":"2.5","time":"3分钟前"},{"nickname":"蔡宝坚","website":"jb51.net","youzhi":"2.5","time":"3分钟前"},{"nickname":"蔡宝坚","website":"jb51.net","youzhi":"2.5","time":"3分钟前"},{"nickname":"蔡宝坚","website":"jb51.net","youzhi":"2.5","time":"3分钟前"},{"nickname":"蔡宝坚","website":"jb51.net","youzhi":"2.5","time":"3分钟前"},{"nickname":"蔡宝坚","website":"jb51.net","youzhi":"2.5","time":"3分钟前"},{"nickname":"蔡宝坚","website":"jb51.net","youzhi":"2.5","time":"3分钟前"},{"nickname":"蔡宝坚","website":"jb51.net","youzhi":"2.5","time":"3分钟前"},{"nickname":"蔡宝坚","website":"jb51.net","youzhi":"2.5","time":"3分钟前"},{"nickname":"蔡宝坚","website":"jb51.net","youzhi":"2.5","time":"3分钟前"}],"pageCount":2,"pageNo":1,"pageSize":10,"totalSize":20 }); |
原来静态也可以做接口回调。通过静态处理,则大大缓解了服务器压力和加速生成内容,是大流量网站必备的处理方式。 jQuery的ajax方法实现分页触发瀑布流 1.通过 Ajax 的方式获取下一页的内容 我们需要网页中具有如下 HTML 结构的导航, next_link 为下一页的 url。
1 2 3 |
<div id="page_nav"> <a href="next_link">下一页</a> </div> |
相应的 css
1 |
#page_nav {clear: both; text-align: center; } |
以下这段代码为通过 Ajax 的方式获取下一页的内容,并追加到当前内容的末尾。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
nextHref = $("#next_page a").attr("href"); // 给浏览器窗口绑定 scroll 事件 $(window).bind("scroll",function(){ // 判断窗口的滚动条是否接近页面底部 if( $(document).scrollTop() + $(window).height() > $(document).height() - 10 ) { // 判断下一页链接是否为空 if( nextHref != undefined ) { // Ajax 翻页 $.ajax( { url: $("#page_nav a").attr("href"), type: "POST", success: function(data) { result = $(data).find("#thumbs .imgbox"); nextHref = $(data).find("#page_nav a").attr("href"); $("#page_nav a").attr("href", nextHref); $("#thumbs").append(result); } }); } else { $("#page_nav").remove(); } } }); |
2.对追加的内容进行流体布局 熟悉 jQuery 的童鞋应该会了解 js 对于通过 Ajax 方式插入到页面中的元素并不起作用,但在这里并不需要作出如使用 live() 等处理,因为 Masonry 已经在内部作出类似的处理并且默认起效,因此只需在 Ajax 成功执行后的回调函数中调用 masonry() 方法即可。
1 2 3 4 |
$newElems = $result; $newElems.imagesLoaded(function(){ $container.masonry( 'appended', $newElems, true ); }); |
3.对 Ajax 翻页过程作出修饰 在上面的过程中已经有完整的瀑布流布局,但是翻页过程中并没有任何提示,而且直接插入多张图片可能会影响用户体验,因此需要对翻页过程作出一些修饰,下面给出完整代码。 这里需要增加一个如下的元素,用于提示正在加载新内容或提示已到了最后一页。
1 2 3 |
<div id="page_loading"> <span>给力加载中……</span> </div> |
相应的 css
1 |
#page_loading {display: none; background: #111111; opacity: 0.7; height: 60px; width: 220px; padding: 10px; position: absolute; bottom: -50px; left: 330px; } |
下面是完整的 Ajax 翻页代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
nextHref = $("#next_page a").attr("href"); // 给浏览器窗口绑定 scroll 事件 $(window).bind("scroll",function(){ // 判断窗口的滚动条是否接近页面底部 if( $(document).scrollTop() + $(window).height() > $(document).height() - 10 ) { // 判断下一页链接是否为空 if( nextHref != undefined ) { // 显示正在加载模块 $("#page_loading").show("slow"); // Ajax 翻页 $.ajax( { url: $("#page_nav a").attr("href"), type: "POST", success: function(data) { result = $(data).find("#thumbs .imgbox"); nextHref = $(data).find("#page_nav a").attr("href"); $("#page_nav a").attr("href", nextHref); $("#thumbs").append(result); // 把新的内容设置为透明 $newElems = result.css({ opacity: 0 }); $newElems.imagesLoaded(function(){ $container.masonry( 'appended', $newElems, true ); // 渐显新的内容 $newElems.animate({ opacity: 1 }); // 隐藏正在加载模块 $("#page_loading").hide("slow"); }); } }); } else { $("#page_loading span").text("木有了噢,最后一页了!"); $("#page_loading").show("fast"); setTimeout("$('#page_loading').hide()",1000); setTimeout("$('#page_loading').remove()",1100); } } }); |
from:http://www.jb51.net/article/84888.htm
View Details