• NodeJs前端构建工具 ——————之Grunt篇


    为何使用grunt?

    一句话:自动化。对于需要反复重复的任务,例如压缩(minification)、编译、单元测试、linting等,自动化工具可以减轻你的劳动,简化你的工作。

    Grunt生态系统非常庞大,并且一直在增长。由于拥有数量庞大的插件可供选择,因此,你可以利用Grunt自动完成任何事,并且花费最少的代价。

    常用插件

    1. grunt-contrib-uglifyby
      Js压缩插件
    2. grunt-contrib-cssminby
      Css压缩插件
    3. grunt-contrib-jshintby
      Js代码检测插件:检测标注javascript代码中的出错和规范问题
    4. grunt-contrib-watch
      监控文件插件:每当文件发生修改,自动运行grunt任务,如自动检测代码
    5. grunt-jsdoc
      文档生成插件:根据项目自动生成js文档
    6. grunt-browserify
      javascript模块管理,browserify使用node comnonjs规范,让前端也能使用15万个node插件
    7. grunt-karma
      单元测试框架
    8. jasmine-core
      单元测试内核
    9. phantomjs
      单元测试模拟环境

    如何搭建grunt?

    安装准备:

    1.下载安装NodeJs

    2.将NodeJs资源提取路径 从NPM移到CNPM,CNPM下载点在国内,速度更快。

    npm install -g cnpm --registry=https://registry.npm.taobao.org

    3.在任意位置新建文件夹demo

    开始安装Grunt:

    cnpm install -g grunt-cli

    先将Grunt命令行(CLI)安装到全局环境中。安装时可能需要使用sudo(针对OSX、*nix、BSD等系统中)权限或者作为管理员(对于Windows环境)来执行以下命令。

    注意:安装grunt-cli并不等于安装了 Grunt!Grunt CLI的任务很简单:调用与Gruntfile在同一目录中 Grunt。这样带来的好处是,允许你在同一个系统上同时安装多个版本的 Grunt。

    添加 Grunt 项目配置文件夹

    在demo文件夹中添加两份文件:package.json 和 Gruntfile。

    package.json: 此文件被npm用于存储项目的元数据,以便将此项目发布为npm模块。你可以在此文件中列出项目依赖的grunt和Grunt插件,放置于devDependencies配置段内。

    {
         "name": "my-project-name",
         "version": "0.1.0",
         "devDependencies": {
         }
     }

    Gruntfile.js: 此文件被命名为 Gruntfile.js 或 Gruntfile.coffee,用来配置或定义任务(task)并加载Grunt插件的。

    安装Grunt

    cnpm install grunt --save-dev

    进入下一章节

    开始第一个grunt项目 基础(一)合并js文件

    安装grunt插件:grunt-contrib-concat

    cnpm install grunt-contrib-concat --save-dev

    创建代码开发(src)和构建(build)文档

    —demo
      |-build
      |-src
      |-Gruntfile.js
      |-package.js

    配置grunt配置文件Gruntfile.js

    module.exports = function(grunt) {
        // Grunt 配置.
        grunt.initConfig({
            concat: {
                options: {
                //定义一个字符串插入每个文件之间用于连接输出
                    separator: ';'
                },
                dist: {
                    src: ['src/*.js'],
                    dest: 'build/main.total.js',
                }
            }
        });
        // 加载包含 "uglify" 任务的插件。grunt.loadNpmTasks('grunt-contrib-concat');
        // 默认被执行的任务列表。
        grunt.registerTask('default', ['concat']);
    };

    运行grunt,构建代码

    grunt

    进入下一章节

    开始第一个grunt项目 基础()压缩js

    安装grunt插件:grunt-contrib-uglify

    cnpm install grunt-contrib-uglify --save-dev

    配置grunt配置文件Gruntfile.js

    module.exports = function(grunt) {
        //Grunt 配置.
        grunt.initConfig({
            pkg: grunt.file.readJSON('package.json'),
            //合并js
            concat: {
                options: {
                    //定义一个字符串插入每个文件之间用于连接输出
                    separator: ';'
                },
                dist: {
                    src: ['src/*.js'],
                    dest: 'build/main.total.js',
                }
            },
            //压缩js
            uglify: {
                options: {
                    banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */
    '
                },
                build: {
                    src: 'build/<%= pkg.name %>.js',
                    dest: 'build/<%= pkg.name %>.min.js'
                }
            },
        });
        // 加载包含 "concat" 任务的插件。
        grunt.loadNpmTasks('grunt-contrib-concat');
        // 加载包含 "uglify" 任务的插件。
        grunt.loadNpmTasks('grunt-contrib-uglify');
        // 默认被执行的任务列表。
        grunt.registerTask('default', ['concat','uglify']);
    };

    运行grunt,构建代码

    grunt

    进入下一章节

    开始第一个grunt项目 基础()代码规范检测

    安装grunt插件:grunt-contrib-jshint

    cnpm install grunt-contrib-jshint --save-dev

    配置grunt配置文件Gruntfile.js

    module.exports = function(grunt) {
        // Project configuration.
        grunt.initConfig({pkg: grunt.file.readJSON('package.json'),
            //合并js
            concat: {
                options: {
                    //定义一个字符串插入每个文件之间用于连接输出
                    separator: ';'
                },
                dist: {
                    src: ['src/*.js'],
                    dest: 'build/main.total.js',
                }
            },
            //压缩js
            uglify: {
                options: {
                    banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */
    '
                },
                build: {
                    src: 'build/<%= pkg.name %>.js',
                    dest: 'build/<%= pkg.name %>.min.js'
                }
            },
            //代码检测
            jshint: {
                files: ['src/*.js'],
                options: {
                    "strict": true,
                    "globalstrict"  : true,
                    "node":true,
                    "browser":true,
                    globals: {
                        exports: true
                    }
                }
            }
        });
        // 加载 "concat" 任务的插件。
        grunt.loadNpmTasks('grunt-contrib-concat');
        // 加载 "uglify" 任务的插件。
        grunt.loadNpmTasks('grunt-contrib-uglify');
        // 加载包含 "jshint" 任务的插件。
        grunt.loadNpmTasks('grunt-contrib-jshint');
        // 默认被执行的任务列表。
        grunt.registerTask('default', ['concat','uglify','jshint']);
    };

    运行grunt,构建代码

    grunt

    开始第一个grunt项目 基础()开启自动检测

    安装grunt插件:grunt-contrib-watch

    cnpm install grunt-contrib-watch --save-dev

    配置grunt配置文件Gruntfile.js

    module.exports = function(grunt) {
        // Project configuration.
        grunt.initConfig({pkg: grunt.file.readJSON('package.json'),
            //合并js
            concat: {
                options: {
                    //定义一个字符串插入每个文件之间用于连接输出
                    separator: ';'
                },
                dist: {
                    src: ['src/*.js'],
                    dest: 'build/main.total.js',
                }
            },
            //压缩js
            uglify: {
                options: {
                    banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */
    '
                },
                build: {
                    src: 'build/<%= pkg.name %>.js',
                    dest: 'build/<%= pkg.name %>.min.js'
                }
            },
            //代码检测
            jshint: {
                files: ['src/*.js'],
                options: {
                    "strict": true,
                    "globalstrict"  : true,
                    "node":true,
                    "browser":true,
                    globals: {
                        exports: true
                    }
                }
            },
            watch: {
                scripts: {
                    files: ['<%= jshint.files %>'],
                    tasks: ['jshint'],
                    options: {
                        spawn: false,
                    },
                },
            },
        });
        // 加载包含 "concat" 任务的插件。
        grunt.loadNpmTasks('grunt-contrib-concat');
        // 加载包含 "uglify" 任务的插件。
        grunt.loadNpmTasks('grunt-contrib-uglify');
        // 加载包含 "jshint" 任务的插件。
        grunt.loadNpmTasks('grunt-contrib-jshint');
        // 加载包含 "watch" 任务的插件。
        grunt.loadNpmTasks('grunt-contrib-watch');//grunt watch
        // 默认被执行的任务列表。
        grunt.registerTask('default', ['concat','uglify','jshint']);
    };

    开启自动检测

    grunt watch

    这时候修改src文件夹中内容,则会自动检测代码

    开始第一个grunt项目 提高()Js模块化之browserify

    安装grunt插件:grunt-browserify

    cnpm install grunt-browserify --save-dev

    配置grunt配置文件Gruntfile.js

    module.exports = function(grunt) {
        // Project configuration.
        grunt.initConfig({pkg: grunt.file.readJSON('package.json'),
            //合并js
            concat: {
                options: {
                    //定义一个字符串插入每个文件之间用于连接输出
                    separator: ';'
                },
                dist: {
                    src: ['src/*.js'],
                    dest: 'build/main.total.js',
                }
            },
            //压缩js
            uglify: {
                options: {
                    banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */
    '
                },
                build: {
                    src: 'build/<%= pkg.name %>.js',
                    dest: 'build/<%= pkg.name %>.min.js'
                }
            },
            //代码检测
            jshint: {
                files: ['src/*.js'],
                options: {
                    "strict": true,
                    "globalstrict"  : true,
                    "node":true,
                    "browser":true,
                    globals: {
                        exports: true
                    }
                }
            },
            watch: {
                scripts: {
                    files: ['<%= jshint.files %>'],
                    tasks: ['jshint'],
                    options: {
                        spawn: false,
                    },
                },
            },
            browserify: {
                options: {
                    browserifyOptions: {
                        debug: true
                    }
                },
                demo:{
                    files: {
                        './src/app/build/app.js': ['./src/app/app.main.js']
                    }
                }
            },
        });
        // 加载包含 "concat" 任务的插件。
        grunt.loadNpmTasks('grunt-contrib-concat');
        // 加载包含 "uglify" 任务的插件。
        grunt.loadNpmTasks('grunt-contrib-uglify');
        // 加载包含 "jshint" 任务的插件。
        grunt.loadNpmTasks('grunt-contrib-jshint');
        // 加载包含 "watch" 任务的插件。
        grunt.loadNpmTasks('grunt-contrib-watch');//grunt watch
        //加载包含 "browserify" 任务的插件。
        grunt.loadNpmTasks('grunt-browserify');
        // 默认被执行的任务列表。
        grunt.registerTask('default', ['concat','uglify','jshint']);
        grunt.registerTask('app', ['browserify:demo']);
    };

    创建demo的js文件

    app.main.js、a.js

    —demo
      |-build
         |-index.html
      |-src
         |-app.main.js
         |-a.js
      |-Gruntfile.js
      |-package.js
        

    app.main.js

    'use strict';
    var A=require("./a");
    
    function app(){
        this.a=new A();
    }
    app.prototype={
        init      : function () {
            this.a.say();
        }
    };
    
    module.exports=app;
    var base = new app();
    base.init();
        

    a.js

    'use strict';
    function a(){
    }
    a.prototype={
        say      : function () {
            console.log("hello world!");
        }
    };
    
    module.exports=a;
        

    index.html

    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <meta name="manifest" content="version.json|manifest.json" />
        <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport" />
        <meta content="telephone=no" name="format-detection" />
        <title>平安</title>
    </head>
    <body>
    <header></header>
    <div id="main">123</div>
    <div id="cover"></div>
    <script src="./app.js"></script>
    </body>
    </html>
        

    编译开发代码生成上线代码

    grunt app

    开始第一个grunt项目 提高()单元测试

    安装grunt插件:grunt-karma,karma-browserify,karma-jasmine

    cnpm install grunt-karma --save-dev
    cnpm install karma-browserify --save-dev
    cnpm install karma-jasmine --save-dev

    配置grunt配置文件Gruntfile.js

    module.exports = function(grunt) {
        // Project configuration.
        grunt.initConfig({pkg: grunt.file.readJSON('package.json'),
            //合并js
            concat: {
                options: {
                    //定义一个字符串插入每个文件之间用于连接输出
                    separator: ';'
                },
                dist: {
                    src: ['src/*.js'],
                    dest: 'build/main.total.js',
                }
            },
            //压缩js
            uglify: {
                options: {
                    banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */
    '
                },
                build: {
                    src: 'build/<%= pkg.name %>.js',
                    dest: 'build/<%= pkg.name %>.min.js'
                }
            },
            //代码检测
            jshint: {
                files: ['src/*.js'],
                options: {
                    "strict": true,
                    "globalstrict"  : true,
                    "node":true,
                    "browser":true,
                    globals: {
                        exports: true
                    }
                }
            },
            watch: {
                scripts: {
                    files: ['<%= jshint.files %>'],
                    tasks: ['jshint'],
                    options: {
                        spawn: false,
                    },
                },
            },
            karma: {
                unit: {
                    configFile: 'karma.conf.js'
                }
            },
            browserify: {
                options: {
                    browserifyOptions: {
                        debug: true
                    }
                },
                demo:{
                    files: {
                        './src/app/build/app.js': ['./src/app/app.main.js']
                    }
                }
            },
        });
        // 加载包含 "concat" 任务的插件。
        grunt.loadNpmTasks('grunt-contrib-concat');
        // 加载包含 "uglify" 任务的插件。
        grunt.loadNpmTasks('grunt-contrib-uglify');
        // 加载包含 "jshint" 任务的插件。
        grunt.loadNpmTasks('grunt-contrib-jshint');
        // 加载包含 "watch" 任务的插件。
        grunt.loadNpmTasks('grunt-contrib-watch');//grunt watch
        //加载包含 "browserify" 任务的插件。
        grunt.loadNpmTasks('grunt-browserify');
        grunt.loadNpmTasks('grunt-karma');//grunt karma *****
        // 默认被执行的任务列表。
        grunt.registerTask('default', ['concat','uglify','jshint']);
        grunt.registerTask('app', ['browserify:demo']);
    };

    创建单元测试的js文件

    app.main.js、a.js

    —demo
      |-build
         |-index.html
      |-src
         |-app.main.js
         |-a.js
      |-test
         |-unit.js
         |-demo.js
      |-Gruntfile.js
      |-karma.conf.js
      |-package.js
        

    karma.conf.js

    // Karma configuration
    // Generated on Wed Sep 16 2015 17:29:29 GMT+0800 (CST)
    
    module.exports = function(config) {
      config.set({
    
        // base path that will be used to resolve all patterns (eg. files, exclude)
        basePath: '',
    
    
        // frameworks to use
        // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
        frameworks: ['browserify','jasmine'],
    
    
        // list of files / patterns to load in the browser
        files: [
          {pattern:'./test/**/*.js'}
        ],
    
    
        // list of files to exclude
        exclude: [
        ],
    
    
        // preprocess matching files before serving them to the browser
        // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
        preprocessors    : {
          './test/**/*.js' : ['browserify'],
        },
    
        // test results reporter to use
        // possible values: 'dots', 'progress'
        // available reporters: https://npmjs.org/browse/keyword/karma-reporter
        reporters: ['progress'],
    
    
        // web server port
        port: 9876,
    
    
        // enable / disable colors in the output (reporters and logs)
        colors: true,
    
    
        // level of logging
        // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
        logLevel: config.LOG_INFO,
    
    
        // enable / disable watching file and executing tests whenever any file changes
        autoWatch: true,
    
    
        // start these browsers
        // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
        browsers: ['PhantomJS'],
    
    
        // Continuous Integration mode
        // if true, Karma captures browsers, runs the tests and exits
        singleRun: false
      })
    }
        

    unit.js

    var methods = require("../demo");
    var methdo = new methods();
    
    
    describe("methods tests", function ()
    {
        it("should return 3", function ()
        {
            expect(methdo.add(1,2)).toBe(3);
        });
        it("should return 5", function ()
        {
            expect(methdo.add(2,2)).toBe(4);
        });
    });
        

    demo.js

    /**
     * Created by haoyuandai on 15/9/18.
     */
    function math(){
    
    }
    math.prototype={
     add:function(a,b){
        return a+b;
    }
    }
    module.exports = math;

    运行单元测试

    grunt karma

    开始第一个grunt项目 提高()自动为代码生成API文档

    安装grunt插件:grunt-jsdoc

    cnpm install grunt-jsdoc --save-dev

    配置grunt配置文件Gruntfile.js

    module.exports = function(grunt) {
        // Project configuration.
        grunt.initConfig({pkg: grunt.file.readJSON('package.json'),
            //合并js
            concat: {
                options: {
                    //定义一个字符串插入每个文件之间用于连接输出
                    separator: ';'
                },
                dist: {
                    src: ['src/*.js'],
                    dest: 'build/main.total.js',
                }
            },
            //压缩js
            uglify: {
                options: {
                    banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */
    '
                },
                build: {
                    src: 'build/<%= pkg.name %>.js',
                    dest: 'build/<%= pkg.name %>.min.js'
                }
            },
            //代码检测
            jshint: {
                files: ['src/*.js'],
                options: {
                    "strict": true,
                    "globalstrict"  : true,
                    "node":true,
                    "browser":true,
                    globals: {
                        exports: true
                    }
                }
            },
            watch: {
                scripts: {
                    files: ['<%= jshint.files %>'],
                    tasks: ['jshint'],
                    options: {
                        spawn: false,
                    },
                },
            },
            karma: {
                unit: {
                    configFile: 'karma.conf.js'
                }
            },
            browserify: {
                options: {
                    browserifyOptions: {
                        debug: true
                    }
                },
                demo:{
                    files: {
                        './src/app/build/app.js': ['./src/app/app.main.js']
                    }
                }
            },
            //生成API文档
            jsdoc : {
                dist : {
                    src: ['src/*.js'],
                    options: {
                        destination: 'doc'
                    }
                }
            }
        });
        // 加载包含 "concat" 任务的插件。
        grunt.loadNpmTasks('grunt-contrib-concat');
        // 加载包含 "uglify" 任务的插件。
        grunt.loadNpmTasks('grunt-contrib-uglify');
        // 加载包含 "jshint" 任务的插件。
        grunt.loadNpmTasks('grunt-contrib-jshint');
        // 加载包含 "watch" 任务的插件。
        grunt.loadNpmTasks('grunt-contrib-watch');//grunt watch
        //加载包含 "browserify" 任务的插件。
        grunt.loadNpmTasks('grunt-browserify');
        grunt.loadNpmTasks('grunt-karma');//grunt karma *****
        grunt.loadNpmTasks('grunt-jsdoc');
        // 默认被执行的任务列表。
        grunt.registerTask('default', ['concat','uglify','jshint']);
        grunt.registerTask('app', ['browserify:demo']);
    };

    生成接口文档

    grunt jsdoc

    小技巧

    部分功能IE9以下可能不支持哟

    如何让客户端加载服务器字体文件?

    css中@font-face 能够加载服务器端的字体文件,让客户端显示客户端所没有安装的字体。

    @font-face :{属性: 取值;}

    @font-face{
        font-family://设置文本的字体名称。
        font-style://设置文本样式。
        font-variant://设置文本是否大小写。
        ont-weight://设置文本的粗细。
        font-stretch://设置文本是否横向的拉伸变形。
        font-size://设置文本字体大小。
        src://设置自定义字体的相对路径或者绝对路径,注意,此属性只能在@font-face规则里使用。
    }

    如何在页面做一条(小于1px)很细的线

    body{
        background-image: url("data:image/svg+xml;utf8, <svg xmlns='http://www.w3.org/2000/svg' width='100%' height='100%'> <rect fill='#c1c1c1' x='0' y='0' width='0.75' height='100%'/> <rect fill='#c1c1c1' x='99.8%' y='0' width='0.75' height='100%'/> </svg>");
        background-position-x: 0;
        background-position-y: 100%;
        background-repeat: no-repeat;
        border-bottom: 0;
    }

    如何让页面在ios上滚动的顺滑

    添加css:

    body{
        -webkit-overflow-scrolling: touch;
    }

    如何解决ios上点击300毫秒延迟问题

    使用fastclickJs模块

    <script type='application/javascript' src='/path/to/fastclick.js'></script>
    if ('addEventListener' in document) {
        document.addEventListener('DOMContentLoaded', function() {
                FastClick.attach(document.body);
        }, false);
    }

    如何将特殊的表情字符传到服务器上

    使用nodeJs-base64 模块

    var base64=require('base64-coder-node')();
    var name = 'emojsay%3fwqUds';
    name= base64.encode(name);//string转base64
    name= base64.decode(name);//base64转string

    修复 iOS 下微信浏览器设置页面标题未生效

    /**
     * @function
     * @description 修复 iOS 下设置页面标题未生效。调用方法,设置 document.title = 'Title';,后调用 updatePageTitleiOS();
     * @memberof WeChatHelper.prototype
     */
    function updatePageTitleIniOS(title){
        ////iframe 加载后的回调函数
        //function unloadHandler(){
            //document.body.removeChild(ifrm);
        //}
        document.title = title;
        //创建 iframe
        var ifrm = document.createElement('iframe');
        //iframe 指向图标文件
        ifrm.src = '/favicon.ico';
        ifrm.style.position = 'absolute';
        ifrm.style.top = '-1000px';
        //绑定回调函数
        //ifrm.addEventListener('load', unloadHandler);
        ifrm.addEventListener('load', function () {
            ifrm.removeEventListener('load');
            setTimeout(function(){
            	document.body.removeChild(ifrm);
            },10);
        });
        //添加 iframe 至文档中
        document.body.appendChild(ifrm);
    }
        

    通过 冒泡 来监听 父级元素下 多个自元素

    loadList = document.getElementById("loadList");
        loadList.addEventListener("click", function (e) {
        var thisLi;
        thisLi = e.target.parentNode.parentNode.parentNode;
        var par = thisLi.className;
        var items = par.toString().split(' ');
        switch (items[1]) {
            case "1":
                var params = '{"idApplicant": "' + items[2] + '","claimType": "' + items[1] + '","toaTaskNo": "' + items[3] + '"}';
                router.navigate("wcOnlineClaimInfo/" + params);
                break;
            case "2":
                var params = '{"idApplicant": "' + items[2] + '","claimType": "' + items[1] + '","docuNo": "' + items[3] + '"}';
                router.navigate("wcOfflineClaimInfo/" + params);
                break;
        }
    }, true);
        

    Doc中 Class 操作

    javascript根据 class名称 来获取dom对象

    getElementsByClassName('className')

    classList操作

    body.classList.length //获取类名的数量
    body.classList.item(num) //根据num获取元素的类名
    body.classList.add('className') //增加元素的类
    body.classList.remove('className') //删除元素的类
    body.classList.contains('className') //检测元素是否包含某个类
    body.classList.toggle('className') //存在即删除不存在即添加

    掌控this

    Function.prototype.bind的作用

    this.a=1;
    document.body.addEventListener('click',function(e){
        alert(e.target);
        alert(this.a);//undefined
    });
    //document.body.addEventListener('click',function(e){
    //    alert(e.target);
    //    alert(this.a);//1
    //}.bind(this));
  • 相关阅读:
    iOS中的导航条UINavigationController(UISegmentedControl)的基本使用(界面中传值的3中方法,单例,属性,代理)
    iOS中的分页控件(UIPageControl)
    iOS中的UIScorllView(滑动控件,时机控制)的基本使用
    iOS中ScrollView(滚屏,引导界面,和判段是否是第一次登陆)
    iOS中自定义UIView(用接口获取Lable和TextFile中的值)
    iOS中的手势识别的积累:UIGestureRecognizer(轻拍手势,长按手势,清扫手势,平移手势,捏合手势,旋转手势,屏幕边缘平移手势) ----仿射变换
    iOS中纯手工图片浏览器
    IOS中的TOM(解决缓存,图片加载)
    iOS中的NSString引用计数问题(-1和整数最大值)
    iOS中的内存管理精讲
  • 原文地址:https://www.cnblogs.com/wjglj/p/4968488.html
Copyright © 2020-2023  润新知