一、什么是闭包和闭包的几种写法和用法 1、什么是闭包 闭包,官方对闭包的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。闭包的特点: 1. 作为一个函数变量的一个引用,当函数返回时,其处于激活状态。 2. 一个闭包就是当一个函数返回时,一个没有释放资源的栈区。 简单的说,Javascript允许使用内部函数—即函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。 2、闭包的几种写法和用法 首先要明白,在JS中一切都是对象,函数是对象的一种。下面先来看一下闭包的5种写法,简单理解一下什么是闭包。后面会具体解释。
1 2 3 4 5 6 7 8 9 10 11 |
//第1种写法 function Circle(r) { this.r = r; } Circle.PI = 3.14159; Circle.prototype.area = function() { return Circle.PI * this.r * this.r; } var c = new Circle(1.0); alert(c.area()); |
这种写法没什么特别的,只是给函数添加一些属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
//第2种写法 var Circle = function() { var obj = new Object(); obj.PI = 3.14159; obj.area = function( r ) { return this.PI * r * r; } return obj; } var c = new Circle(); alert( c.area( 1.0 ) ); |
这种写法是声明一个变量,将一个函数当作值赋给变量。
1 2 3 4 5 6 7 8 |
//第3种写法 var Circle = new Object(); Circle.PI = 3.14159; Circle.Area = function( r ) { return this.PI * r * r; } alert( Circle.Area( 1.0 ) ); |
这种方法最好理解,就是new 一个对象,然后给对象添加属性和方法。
1 2 3 4 5 6 7 8 |
//第4种写法 var Circle={ "PI":3.14159, "area":function(r){ return this.PI * r * r; } }; alert( Circle.area(1.0) ); |
这种方法使用较多,也最为方便。var obj = {}就是声明一个空的对象。
1 2 3 4 |
//第5种写法 var Circle = new Function("this.PI = 3.14159;this.area = function( r ) {return r*r*this.PI;}"); alert( (new Circle()).area(1.0) ); |
说实话,这种写法我是没用过,大家可以参考一下。 总的来说,上面几种方法,第2中和第4中较为常见,大家可以根据习惯选择。 上面代码中出现了JS中常用的Prototype,那么Prototype有什么用呢?下面我们来看一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
var dom = function(){ }; dom.Show = function(){ alert("Show Message"); }; dom.prototype.Display = function(){ alert("Property Message"); }; dom.Display(); //error dom.Show(); var d = new dom(); d.Display(); d.Show(); //error |
我们首先声明一个变量,将一个函数赋给他,因为在Javascript中每个函数都有一个Portotype属性,而对象没有。添加两个方法,分别直接添加和添加打破Prototype上面,来看下调用情况。分析结果如下: 1、不使用prototype属性定义的对象方法,是静态方法,只能直接用类名进行调用!另外,此静态方法中无法使用this变量来调用对象其他的属性! 2、使用prototype属性定义的对象方法,是非静态方法,只有在实例化后才能使用!其方法内部可以this来引用对象自身中的其他属性! 下面我们再来看一段代码:
1 2 3 4 5 6 7 8 9 10 |
var dom = function(){ var Name = "Default"; this.Sex = "Boy"; this.success = function(){ alert("Success"); }; }; alert(dom.Name); alert(dom.Sex); |
大家先看看,会显示什么呢? 答案是两个都显示Undefined,为什么呢?这是由于在Javascript中每个function都会形成一个作用域,而这些变量声明在函数中,所以就处于这个函数的作用域中,外部是无法访问的。要想访问变量,就必须new一个实例出来。
1 2 3 4 5 6 7 8 9 |
var html = { Name:'Object', Success:function(){ this.Say = function(){ alert("Hello,world"); }; alert("Obj Success"); } }; |
再来看看这种写法,其实这是Javascript的一个"语法糖",这种写法相当于:
1 2 3 4 5 6 7 |
var html = new Object(); html.Name = 'Object'; html.Success = function(){ this.Say = function(){ alert("Hello,world"); }; alert("Obj Success"); |
变量html是一个对象,不是函数,所以没有Prototype属性,其方法也都是公有方法,html不能被实例化。否则会出现如下错误: 但是他可以作为值赋给其它变量,如var o = html; 我们可以这样使用它:
1 2 |
alert(html.Name); html.Success(); |
说到这里,完了吗?细心的人会问,怎么访问Success方法中的Say方法呢?是html.Success.Say()吗? 当然不是,上面刚说过由于作用域的限制,是访问不到的。所以要用下面的方法访问:
1 2 3 4 5 6 7 8 9 |
var s = new html.Success(); s.Say(); //还可以写到外面 html.Success.prototype.Show = function(){ alert("HaHa"); }; var s = new html.Success(); s.Show(); |
关于Javascript作用域的问题,不是一两句能说清楚的,有兴趣的大家可以网上找些资料看看。 二、Javascript闭包的用途 事实上,通过使用闭包,我们可以做很多事情。比如模拟面向对象的代码风格;更优雅,更简洁的表达出代码;在某些方面提升代码的执行效率。 1、匿名自执行函数 我们知道所有的变量,如果不加上var关键字,则默认的会添加到全局对象的属性上去,这样的临时变量加入全局对象有很多坏处, 比如:别的函数可能误用这些变量;造成全局对象过于庞大,影响访问速度(因为变量的取值是需要从原型链上遍历的)。 除了每次使用变量都是用var关键字外,我们在实际情况下经常遇到这样一种情况,即有的函数只需要执行一次,其内部变量无需维护, 比如UI的初始化,那么我们可以使用闭包:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
var data= { table : [], tree : {} }; (function(dm){ for(var i = 0; i < dm.table.rows; i++){ var row = dm.table.rows[i]; for(var j = 0; j < row.cells; i++){ drawCell(i, j); } } })(data); |
我们创建了一个匿名的函数,并立即执行它,由于外部无法引用它内部的变量,因此在函数执行完后会立刻释放资源,关键是不污染全局对象。 2、结果缓存 我们开发中会碰到很多情况,设想我们有一个处理过程很耗时的函数对象,每次调用都会花费很长时间, 那么我们就需要将计算出来的值存储起来,当调用这个函数的时候,首先在缓存中查找,如果找不到,则进行计算,然后更新缓存并返回值,如果找到了,直接返回查找到的值即可。闭包正是可以做到这一点,因为它不会释放外部的引用,从而函数内部的值可以得以保留。
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 |
var CachedSearchBox = (function(){ var cache = {}, count = []; return { attachSearchBox : function(dsid){ if(dsid in cache){//如果结果在缓存中 return cache[dsid];//直接返回缓存中的对象 } var fsb = new uikit.webctrl.SearchBox(dsid);//新建 cache[dsid] = fsb;//更新缓存 if(count.length > 100){//保正缓存的大小<=100 delete cache[count.shift()]; } return fsb; }, clearSearchBox : function(dsid){ if(dsid in cache){ cache[dsid].clearSelection(); } } }; })(); CachedSearchBox.attachSearchBox("input"); |
这样我们在第二次调用的时候,就会从缓存中读取到该对象。 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 |
var person = function(){ //变量作用域为函数内部,外部无法访问 var name = "default"; return { getName : function(){ return name; }, setName : function(newName){ name = newName; } } }(); print(person.name);//直接访问,结果为undefined print(person.getName()); person.setName("abruzzi"); print(person.getName()); 得到结果如下: undefined default abruzzi |
4、实现类和继承
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 |
function Person(){ var name = "default"; return { getName : function(){ return name; }, setName : function(newName){ name = newName; } } }; var p = new Person(); p.setName("Tom"); alert(p.getName()); var Jack = function(){}; //继承自Person Jack.prototype = new Person(); //添加私有方法 Jack.prototype.Say = function(){ alert("Hello,my name is Jack"); }; var j = new Jack(); j.setName("Jack"); j.Say(); alert(j.getName()); |
我们定义了Person,它就像一个类,我们new一个Person对象,访问它的方法。 下面我们定义了Jack,继承Person,并添加自己的方法。 from:https://www.cnblogs.com/jiayc/p/9365837.html
View DetailsChimee是由奇舞团开源的一套H5视频播放器解决方案,由奇舞团视频云前端团队结合在业务和视频编解码方向的沉淀积累倾心打造。Chimee支持MP4、M3U8、FLV等多种媒体格式,同时它也帮我们解决了大部分的兼容性、差异化问题,包括全屏、自动播放、内联播放、直播解码等常见媒体播放需求。 通过便捷的可热插拔的插件开发,能满足业务方快速迭代、灰度发布等要求;让开发者能够更轻松快捷地完成不同业务场景下UI、广告等各种功能需求的开发。 在线演示 免费下载 from:https://www.cnblogs.com/lhb25/p/chimee-h5-video-player.html
View Details本文主要通过以下几方面来说明懒加载技术的原理,个人前端小菜,有错误请多多指出 一、什么是图片滚动加载? 通俗的讲就是:当访问一个页面的时候,先把img元素或是其他元素的背景图片路径替换成一张大小为1*1px图片的路径(这样就只需请求一次),只有当图片出现在浏览器的可视区域内时,才设置图片正真的路径,让图片显示出来。这就是图片懒加载。 二、为什要使用这个技术? 比如一个页面中有很多图片,如淘宝、京东首页等等,如果一上来就发送这么多请求,页面加载就会很漫长,如果js文件都放在了文档的底部,恰巧页面的头部又依赖这个js文件,那就不好办了。更为要命的是:一上来就发送百八十个请求,服务器可能就吃不消了(又不是只有一两个人在访问这个页面)。 因此优点就很明显了:不仅可以减轻服务器的压力,而且可以让加载好的页面更快地呈现在用户面前(用户体验好)。 三、怎么实现? 关键点如下: 1、页面中的img元素,如果没有src属性,浏览器就不会发出请求去下载图片(也就没有请求咯,也就提高性能咯),一旦通过javascript设置了图片路径,浏览器才会送请求。有点按需分配的意思,你不想看,就不给你看,你想看了就给你看~ 2、如何获取正真的路径,这个简单,现在正真的路径存在元素的“data-url”(这个名字起个自己认识好记的就行)属性里,要用的时候就取出来,再设置; 3、开始比较之前,先了解一些基本的知识,比如说如何获取某个元素的尺寸大小、滚动条滚动距离及偏移位置距离; 1)屏幕可视窗口大小:对应于图中1、2位置处 原生方法:window.innerHeight 标准浏览器及IE9+ || document.documentElement.clientHeight 标准浏览器及低版本IE标准模式 || document.body.clientHeight 低版本混杂模式 jQuery方法: $(window).height() 2)浏览器窗口顶部与文档顶部之间的距离,也就是滚动条滚动的距离:也就是图中3、4处对应的位置; 原生方法:window.pagYoffset——IE9+及标准浏览器 || document.documentElement.scrollTop 兼容ie低版本的标准模式 || document.body.scrollTop 兼容混杂模式; jQuery方法:$(document).scrollTop(); 3)获取元素的尺寸:对应于图中5、6位置处;左边jquery方法,右边原生方法 $(o).width() = o.style.width; $(o).innerWidth() = o.style.width+o.style.padding; $(o).outerWidth() = o.offsetWidth = o.style.width+o.style.padding+o.style.border; $(o).outerWidth(true) = o.style.width+o.style.padding+o.style.border+o.style.margin; 注意:要使用原生的style.xxx方法获取属性,这个元素必须已经有内嵌的样式,如<div style="…."></div>; 如果原先是通过外部或内部样式表定义css样式,必须使用o.currentStyle[xxx] || document.defaultView.getComputedStyle(0)[xxx]来获取样式值 4)获取元素的位置信息:对应与图中7、8位置处 1)返回元素相对于文档document顶部、左边的距离; jQuery:$(o).offset().top元素距离文档顶的距离,$(o).offset().left元素距离文档左边缘的距离 原生:getoffsetTop(),高程上有具体说明,这边就忽略了; 顺便提一下返回元素相对于第一个以定位的父元素的偏移距离,注意与上面偏移距的区别; jQuery:position()返回一个对象,$(o).position().left = style.left,$(o).position().top = style.top; 4、知道如何获取元素尺寸、偏移距离后,接下来一个问题就是:如何判断某个元素进入或者即将进入可视窗口区域?下面也通过一张图来说明问题。 1)外面最大的框为实际页面的大小,中间浅蓝色的框代表父元素的大小,对象1~8代表元素位于页面上的实际位置;以水平方向来做如下说明! 2)对象8左边界相对于页面左边界的偏移距离(offsetLeft)大于父元素右边界相对于页面左边界的距离,此时可判读元素位于父元素之外; 3)对象7左边界跨过了父元素右边界,此时:对象7左边界相对于页面左边界的偏移距离(offsetLeft)小于 父元素右边界相对于 页面左边界的距离,因此对象7就进入了父元素可视区; 4)在对象6的位置处,对象5的右边界与页面左边界的距离 大于 父元素左边界与页面左边界的距离; 5)在对象5位置处时,对象5的右边界与页面左边界的距离 小于 父元素左边界与页面左边界的距离;此时,可判断元素处于父元素可视区外; 6)因此水平方向必须买足两个条件,才能说明元素位于父元素的可视区内;同理垂直方向也必须满足两个条件;具体见下文的源码; 四、扩展为jquery插件 使用方法:$("selector").scrollLoad({ 参数在代码中有说明 })
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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
(function($) { $.fn.scrollLoading = function(options) { var defaults = { // 在html标签中存放的属性名称; attr: "data-url", // 父元素默认为window container: window, callback: $.noop }; // 不管有没有传入参数,先合并再说; var params = $.extend({}, defaults, options || {}); // 把父元素转为jquery对象; var container = $(params.container); // 新建一个数组,然后调用each方法,用于存储每个dom对象相关的数据; params.cache = []; $(this).each(function() { // 取出jquery对象中每个dom对象的节点类型,取出每个dom对象上设置的图片路径 var node = this.nodeName.toLowerCase(), url = $(this).attr(params["attr"]); //重组,把每个dom对象上的属性存为一个对象; var data = { obj: $(this), tag: node, url: url }; // 把这个对象加到一个数组中; params.cache.push(data); }); var callback = function(call) { if ($.isFunction(params.callback)) { params.callback.call(call); } }; //每次触发滚动事件时,对每个dom元素与container元素进行位置判断,如果满足条件,就把路径赋予这个dom元素! var loading = function() { // 获取父元素的高度 var contHeight = container.outerHeight(); var contWidth = container.outerWidth(); // 获取父元素相对于文档页顶部的距离,这边要注意了,分为以下两种情况; if (container.get(0) === window) { // 第一种情况父元素为window,获取浏览器滚动条已滚动的距离;$(window)没有offset()方法; var contop = $(window).scrollTop(); var conleft = $(window).scrollLeft(); } else { // 第二种情况父元素为非window元素,获取它的滚动条滚动的距离; var contop = container.offset().top; var conleft = container.offset().left; } $.each(params.cache, function(i, data) { var o = data.obj, tag = data.tag, url = data.url, post, posb, posl, posr; if (o) { //对象顶部与文档顶部之间的距离,如果它小于父元素底部与文档顶部的距离,则说明垂直方向上已经进入可视区域了; post = o.offset().top - (contop + contHeight); //对象底部与文档顶部之间的距离,如果它大于父元素顶部与文档顶部的距离,则说明垂直方向上已经进入可视区域了; posb = o.offset().top + o.height() - contop; // 水平方向上同理; posl = o.offset().left - (conleft + contWidth); posr = o.offset().left + o.width() - conleft; // 只有当这个对象是可视的,并且这四个条件都满足时,才能给这个对象赋予图片路径; if ( o.is(':visible') && (post < 0 && posb > 0) && (posl < 0 && posr > 0) ) { if (url) { //在浏览器窗口内 if (tag === "img") { //设置图片src callback(o.attr("src", url)); } else { // 设置除img之外元素的背景url callback(o.css("background-image", "url("+ url +")")); } } else { // 无地址,直接触发回调 callback(o); } // 给对象设置完图片路径之后,把params.cache中的对象给清除掉;对象再进入可视区,就不再进行重复设置了; data.obj = null; } } }); }; //加载完毕即执行 loading(); //滚动执行 container.bind("scroll", loading); }; })(jQuery); |
五、参考: 1、jQuery.lazyload详解 2、张大大:http://www.zhangxinxu.com/wordpress/?p=1259 3、Jquery图片延迟加载插件jquery.lazyload. http://www.daxueit.com/article/3944.html 4、jQuery.lazyload实现延时加载详解步骤 http://www.daxueit.com/article/21.html 5、jquery lazyload延迟加载技术的实现原理分析 http://www.daxueit.com/article/3777.html 6、Lazyload 延迟加载效果 7、图片延迟加载(lazyload)的实现原理
View Details本文分为三个部分 JS 数字精度丢失的一些典型问题 JS 数字精度丢失的原因 解决方案(一个对象+一个函数) 一、JS数字精度丢失的一些典型问题 1. 两个简单的浮点数相加 1 0.1 + 0.2 != 0.3 // true Firebug 这真不是 Firebug 的问题,可以用alert试试 (哈哈开玩笑)。 看看Java的运算结果 再看看Python 2. 大整数运算 1 9999999999999999 == 10000000000000001 // ? Firebug 16位和17位数竟然相等,没天理啊。 又如 1 2 var x = 9007199254740992 x + 1 == x // ? 看结果 三观又被颠覆了。 3. toFixed 不会四舍五入(Chrome) 1 1.335.toFixed(2) // 1.33 Firebug 线上曾经发生过 Chrome 中价格和其它浏览器不一致,正是因为 toFixed 兼容性问题导致 二、JS 数字丢失精度的原因 计算机的二进制实现和位数限制有些数无法有限表示。就像一些无理数不能有限表示,如 圆周率 3.1415926…,1.3333… 等。JS 遵循 IEEE 754 规范,采用双精度存储(double precision),占用 64 bit。如图 意义 1位用来表示符号位 11位用来表示指数 52位表示尾数 浮点数,比如 1 2 0.1 […]
View Details背景: 这个问题不是一天两天了,有时候是网速不行,有时候是被墙了,有时候是github把node-sass的包转移目录导致下载失败。 Cannot download "https://github.com/sass/node-sass/releases/download/xxx/binding.node的问题 另附node-sass的binding.node各个版本的安装包,哪里少,就单独下载哪个,下载完了之后,跟着我,一起把文件放在指定位置即可解决这个问题 https://github.com/sass/node-sass/releases/tag/v4.7.2 1.本机位置 C:\Users\Administrator\AppData\Roaming\npm-cache\node-sass\ 这个里面是各种版本,报错提示你哪个版本下载失败,你就塞到哪个版本的文件夹里,如图所示 2.删除项目的node_moduls目录 3.重新npm install 4.另附全局安装命令
1 2 3 |
npm i sass-loader node-sass webpack <span class="hljs-comment">--g</span> npm i style-loader css-loader <span class="hljs-comment">--g</span> |
qq 43163707 落雨 本文地址:http://www.cnblogs.com/ae6623/p/8711853.html
View Details
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 |
var gulp = require('gulp'); var connect = require('gulp-connect'); var replace = require('gulp-replace'); function defaultTask(cb) { // place code for your default task here cb(); replaceTask(); connect.server({ root: "build", port:8888 }); connect.serverClose(); } function replaceTask(){ /*index*/ gulp.src(['./index.html']) .pipe(replace("@@{user_domain_url}", "http://user.domain.com")) .pipe(replace('@@{nickname}', 'gz')) .pipe(gulp.dest('build/')); /*js*/ gulp.src(['js/*.js']) .pipe(replace("@@{user_domain_url}", "http://user.domain.com")) .pipe(replace('@@{nickname}', 'gz')) .pipe(gulp.dest('build/js')); } exports.default = defaultTask; |
View Details
流程 1. 输入命令(可以使用git bash或者命令控制台cmd) npm install -g gulp 安装全局gulp命令 2. 创建一个项目文件夹, 当前项目文件夹下输入命令npm init 配置package.json文件, 这一部分看情况自己决定是否填, 不想填也可以, 直接按回车 当前项目文件夹下输入命令npm install gulp --save-dev 全局安装gulp后,还需要在每个要使用gulp的项目中都单独安装一次 开始使用gulp 其实, gulp的使用比webpack要简单很多. 配置gulpflie.js文件 在当前项目文件下创建文件名为gulpfile.js文件, 作为该项目配置文件.
1 2 3 4 5 6 |
//gulpfile.js var gulp = require('gulp'); gulp.task('default',function(){ console.log('hello world'); }); |
其实在项目文件夹下输入命令gulp时, 就是触发这个default任务, 因此, 我们定义多个自定义事件, 这样在输入gulp时, 就可以直接将我们写的命令也一起触发. gulp API gulp.src(globs[, options]) globs参数是文件匹配模式(类似正则表达式),用来匹配文件路径(包括文件名),当然这里也可以直接指定某个具体的文件路径。当有多个匹配模式时,该参数可以为一个数组。 options为可选参数。通常情况下我们不需要用到。 下面我们重点说说Gulp用到的glob的匹配规则以及一些文件匹配技巧。 名称 说明 * 匹配文件路径中的0个或多个字符,但不会匹配路径分隔符,除非路径分隔符出现在末尾 ** 匹配路径中的0个或多个目录及其子目录,需要单独出现,即它左右不能有其他东西了。如果出现在末尾,也能匹配文件。 ? 匹配文件路径中的一个字符(不会匹配路径分隔符) […] 匹配方括号中出现的字符中的任意一个,当方括号中第一个字符为^或!时,则表示不匹配方括号中出现的其他字符中的任意一个,类似js正则表达式中的用法 !(pattern|pattern|pattern) 匹配任何与括号中给定的任一模式都不匹配的 ?(pattern|pattern|pattern) 匹配括号中给定的任一模式0次或1次,类似于js正则中的(pattern|pattern|pattern)? +(pattern|pattern|pattern) 匹配括号中给定的任一模式至少1次,类似于js正则中的(pattern|pattern|pattern)+ *(pattern|pattern|pattern) 匹配括号中给定的任一模式0次或多次,类似于js正则中的(pattern|pattern|pattern)* @(pattern|pattern|pattern) 匹配括号中给定的任一模式1次,类似于js正则中的(pattern|pattern|pattern) 例子:
1 2 3 4 5 6 7 8 |
//转换html文件 gulp.task('html', function(){ gulp.src('./src/index.html') .pipe(connect.reload()) .pipe(gulp.dest('./dist'));//写入命令 }); 当有多种匹配模式时可以使用数组 |
1 2 3 4 |
//使用数组的方式来匹配多种文件 gulp.src(['js/*.js','css/*.css','*.html']) 使用数组的方式还有一个好处就是可以很方便的使用排除模式,在数组中的单个匹配模式前加上!即是排除模式,它会在匹配的结果中排除这个匹配,要注意一点的是不能在数组中的第一个元素中使用排除模式 |
1 2 |
gulp.src([*.js,'!b*.js']) //匹配所有js文件,但排除掉以b开头的js文件 gulp.src(['!b*.js',*.js]) //不会排除任何文件,因为排除模式不能出现在 |
数组的第一个元素中 此外,还可以使用展开模式。展开模式以花括号作为定界符,根据它里面的内容,会展开为多个模式,最后匹配的结果为所有展开的模式相加起来得到的结果。展开的例子如下: a{b,c}d 会展开为 abd,acd a{b,}c 会展开为 abc,ac a{0..3}d 会展开为 a0d,a1d,a2d,a3d a{b,c{d,e}f}g 会展开为 abg,acdfg,acefg a{b,c}d{e,f}g 会展开为 abdeg,acdeg,abdeg,abdfg gulp.dest(path[,options]) gulp.dest()方法是用来写文件的 path为写入文件的路径 options为一个可选的参数对象,通常我们不需要用到 要想使用好gulp.dest()这个方法,就要理解给它传入的路径参数与最终生成的文件的关系。 gulp的使用流程一般是这样子的:首先通过gulp.src()方法获取到我们想要处理的文件流,然后把文件流通过pipe方法导入到gulp的插件中,最后把经过插件处理后的流再通过pipe方法导入到gulp.dest()中,gulp.dest()方法则把流中的内容写入到文件中,这里首先需要弄清楚的一点是,我们给gulp.dest()传入的路径参数,只能用来指定要生成的文件的目录,而不能指定生成文件的文件名,它生成文件的文件名使用的是导入到它的文件流自身的文件名,所以生成的文件名是由导入到它的文件流决定的,即使我们给它传入一个带有文件名的路径参数,然后它也会把这个文件名当做是目录名,例如:
1 2 3 4 5 6 7 8 |
var gulp = require('gulp'); gulp.src('script/jquery.js') .pipe(gulp.dest('dist/foo.js')); //最终生成的文件路径为 dist/foo.js/jquery.js,而不是dist/foo.js 要想改变文件名,可以使用插件gulp-rename 下面说说生成的文件路径与我们给gulp.dest()方法传入的路径参数之间的关系。 gulp.dest(path)生成的文件路径是我们传入的path参数后面再加上gulp.src()中有通配符开始出现的那部分路径。例如: |
1 2 3 4 5 6 7 |
var gulp = reruire('gulp'); //有通配符开始出现的那部分路径为 **/*.js gulp.src('script/**/*.js') .pipe(gulp.dest('dist')); //最后生成的文件路径为 dist/**/*.js //如果 **/*.js 匹配到的文件为 jquery/jquery.js ,则生成的文件路径为 dist/jquery/jquery.js 再举更多一点的例子 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
gulp.src('script/avalon/avalon.js') //没有通配符出现的情况 .pipe(gulp.dest('dist')); //最后生成的文件路径为 dist/avalon.js //有通配符开始出现的那部分路径为 **/underscore.js gulp.src('script/**/underscore.js') //假设匹配到的文件为script/util/underscore.js .pipe(gulp.dest('dist')); //则最后生成的文件路径为 dist/util/underscore.js gulp.src('script/*') //有通配符出现的那部分路径为 * //假设匹配到的文件为script/zepto.js .pipe(gulp.dest('dist')); //则最后生成的文件路径为 dist/zepto.js 通过指定gulp.src()方法配置参数中的base属性,我们可以更灵活的来改变gulp.dest()生成的文件路径。 当我们没有在gulp.src()方法中配置base属性时,base的默认值为通配符开始出现之前那部分路径,例如: |
[…]
View Details为了防止客户端的静态资源缓存,我们需要每次更新css或js的时候,通过md5或时间戳等方式重新命名静态资源; 然后涉及到的html模板里的src也要做相应的修改,静态资源需要优化(压缩合并) 文件目录结构 html模板文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <html> <head> <!-- build:css styles/main.min.css --> <link rel="stylesheet" href="../styles/one.css"> <link rel="stylesheet" href="../styles/two.css"> <!-- endbuild --> </head> <body> <!-- build:js scripts/main.min.js --> <script type="text/javascript" src="../scripts/one.js"></script> <script type="text/javascript" src="../scripts/two.js"></script> <!-- endbuild --> </body> </html> gulp配置文件:gulpfile.js 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 […]
View DetailsStateOfJS 刚刚发布了 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写在前面的 评价纯属个人主观感受,有夸张成分,只是一种表达,如有不喜请无视之。欢迎指正不足和提供更多更好的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