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") %> */\n'
            },
            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") %> */\n'
            },
            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") %> */\n'
            },
            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") %> */\n'
            },
            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") %> */\n'
            },
            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") %> */\n'
            },
            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));


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM