前端打包工具grunt快速入門(大篇幅完整版)

来源:http://www.cnblogs.com/chuaWeb/archive/2016/04/12/grunt.html
-Advertisement-
Play Games

打包的目的和意義就不用敘述了直接上乾貨 http://www.gruntjs.net/getting-started裡面的教程也太簡單了,需要下一番功夫去研究才行。本文將grunt打包的常用方法都用實例描述,更加清晰易懂。 1. 第一個簡單的grunt打包 1)需要安裝nodejs:http://w ...


打包的目的和意義就不用敘述了直接上乾貨

http://www.gruntjs.net/getting-started裡面的教程也太簡單了,需要下一番功夫去研究才行。本文將grunt打包的常用方法都用實例描述,更加清晰易懂。

 

1.    第一個簡單的grunt打包


 1)需要安裝nodejs:http://www.cnblogs.com/chuaWeb/p/nodejs-npm.html

  本人的nodejs工程目錄為F:\chuaNodejs(後續所有相對路徑都是相對於這個目錄)

2)命令行到nodejs目錄(需要系統管理員許可權,不然後續過程中會報錯)執行npm install -g grunt-cli

3)在nodejs工程目錄下建一個package.json,內容為

{
  "name": "my-first-grunt",
  "file": "jquery",
  "version": "0.1.0",
  "devDependencies": {
    "grunt": "~0.4.5",
    "grunt-contrib-jshint": "~0.10.0",
    "grunt-contrib-nodeunit": "~0.4.1",
    "grunt-contrib-uglify": "~0.5.0"
  }
}

  其中file屬性在Gruntfile.js中要用到的屬性,打包源名稱

  然後將devDependencies下麵的包給下載下來,比如下載grunt: npm install grunt --save-dev 其他包下載方式一樣

  需要註意的是package.json中的數據必須是嚴格的json數據格式(連添加註釋都是不可以的)。

4) 在nodejs工程目錄下建一個Gruntfile.js,內容為

 1 module.exports = function (grunt) {
 2   // 項目配置
 3   grunt.initConfig({
 4     pkg: grunt.file.readJSON('package.json'),//獲取解析package.json將內容保存在pkg中
 5     uglify: {
 6       options: {
 7         banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
 8       },
 9       build: {
10         src: 'src/<%=pkg.file %>.js',
11         dest: 'dest/<%= pkg.file %>.min.js'
12       }
13     }
14   });
15   // 載入提供"uglify"任務的插件
16   grunt.loadNpmTasks('grunt-contrib-uglify');
17   // 預設任務
18   grunt.registerTask('default', ['uglify']);
19 }

  裡面pkg讀取package.json文件,然後可以訪問其內容中的屬性,如pkg.file。build屬性src是待壓縮的文件,dest是壓縮重定向到該文件。

  所以現在我要建立一個src目錄,目錄下麵保存了一個叫做jquery.js的文件

5)命令行運行:grunt

  輸出

Running “uglify:build” (uglify) task
File dest/jquery.min.js created: 277.14 kB ->93.35 kB
>> 1 file created. 
Done.

  創建了dest/jquery.min.js

  

  註意grunt命令和grunt uglify等價。當然也可以帶上任務名稱default:grunt default能等到同樣結果。

6)總結:

  grunt.initConfig:

  為當前項目初始化一個配置對象,其中傳入的 configObject 參數可以用在後續的task中,可以通過grunt.config 方法訪問。幾乎每個項目的 Gruntfile 都會調用此方法。

  註意,任何 <% %> 模板字元串只會在取到配置數據後才被處理。

  不同的插件有各自的參數,比如例子中的uglify插件用到的參數有options和build。詳細信息需要參考各個插件。

  initConfig詳情參考:http://www.gruntjs.net/api/grunt.config#grunt.config.init

 

  grunt.loadNpmTasks:

  grunt打包主要是用到各種插件,比如上面的壓縮用的插件uglify。載入插件需要使用該方法。

  從指定的 Grunt 插件中載入任務。此插件必須通過npm安裝到本地,並且是參照 Gruntfile.js 文件的相對路徑。

  詳情參考:http://www.gruntjs.net/api/grunt.task#grunt.task.loadnpmtasks

 

  grunt.registerTask:

  註冊 "別名任務" 或 任務函數。此方法支持以下兩種類型:

  別名任務(如果指定了一個任務列表,那麼,新註冊的任務將會是這一個或多個任務的別名(alias)。當此"別名任務"執行時,taskList中的所有任務都將按指定的順序依次執行。taskList 參數必須是一個任務數組。):grunt.task.registerTask(taskName, taskList)

  上面的例子就是別名任務。定義一個"default" 任務,當執行 Grunt 且不通過參數指定任務時,第二個參數中的任務將依序執行

  任務函數(如果傳入description和taskFunction,每當任務運行時,指定的函數(taskFunction)都會被執行。此外,當執行 grunt --help時,前面指定的描述(description)就會顯示出來。特定任務的屬性和方法在任務函數內部通過this對象的屬性即可訪問。如果任務函數返回false表示任務失敗。):grunt.task.registerTask(taskName, description, taskFunction)

  下一個例子我們就試一下這個任務函數,現在剛纔例子每一個步驟目的就清晰了。

  詳情參考:http://www.gruntjs.net/api/grunt.task#grunt.task.registertask

 

2. 使用任務函數方式實現剛纔的那個打包。


  其他的東西都沒有變,Gruntfile.js變成了

 1 module.exports = function (grunt) {
 2   // 載入提供"uglify"任務的插件
 3   grunt.loadNpmTasks('grunt-contrib-uglify');
 4   // 任務函數
 5   grunt.registerTask('build', 'uglify 使用 任務函數版', function () {
 6     //任務列表
 7     var tasks = ['uglify'];
 8     // 項目配置
 9     grunt.initConfig({
10       pkg: grunt.file.readJSON('package.json'),//獲取解析package.json將內容保存在pkg中
11     });
12     var uglifyTask = {
13       options: {
14         banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
15       },
16       build: {
17         src: 'src/<%=pkg.file %>.js',
18         dest: 'dest/<%= pkg.file %>.min.js'
19       }
20     }
21     //將一個或多個任務放入隊列中
22     grunt.task.run(tasks);
23     //給當前項目的 Grunt 配置中的uglify屬性設置一個值。
24     grunt.config.set("uglify", uglifyTask);
25   });
26 }

  然後去命令行運行: grunt bulid

  和第一個不同的是運行命令必須帶上了任務名稱build。

  註意前面提到的任何 <% %> 模板字元串只會在取到配置數據後才被處理。

 

3. 合併壓縮


  有些時候為了減少請求需要合併多個文件,且需要壓縮。使用uglify即可做到這一點。

  Gruntfile.js代碼

 1 module.exports = function (grunt) {
 2   // 項目配置
 3   grunt.initConfig({
 4     pkg: grunt.file.readJSON('package.json'),//獲取解析package.json將內容保存在pkg中
 5     uglify: {
 6       options: {
 7         banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',//壓縮目標文件頭部註釋
 8         mangle: false//變數和函數名稱不壓縮
 9       },
10       my_target: {//該對象名稱隨意
11         files: {
12           'dest/libs.min.js': ['src/jquery.js', 'src/router.js']
13         }
14       }
15     }
16   });
17   // 載入提供"uglify"任務的插件
18   grunt.loadNpmTasks('grunt-contrib-uglify');
19   // 預設任務
20   grunt.registerTask('default', ['uglify']);
21 }

  文件壓縮的順序按照files中定義的數組的順序壓縮。我們可以通過options.mangle來設置變數和函數名稱是否壓縮。還可以有下麵的用法

1 options: {
2   banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',//壓縮目標文件頭部註釋
3   mangle: {
4     except: ["jQuery"]//不壓縮的關鍵字列表
5   }
6 }

  最終jquery.js和router.js合併壓縮成libs.min.js

  詳情參考:https://www.npmjs.com/package/grunt-contrib-uglify

 

4. 合併壓縮require配置的文件。


  首先需要下載grunt-contrib-requirejs插件:npm install grunt-contrib-requirejs --save-dev

  比如我們的執行文件main.js使用的是require來模塊化載入,代碼如下

 1 require.config({
 2   baseUrl: "",
 3   paths: {
 4     "jquery": "src/jquery",
 5     "bootstrap": "src/bootstrap.min",
 6     "validator": "src/bootstrapValidator.min"
 7   },
 8   shim: {
 9     "bootstrap":["jquery"],
10     "beyond": ["bootstrap"],
11     "validator": ["bootstrap"]
12   }
13 });
14 requirejs(['validator'], function (v) {
15   //代碼
16 });

  我們希望jquery/bootstrap/validator幾個文件合併成一個,避免多次請求。

  我們新建一個grunt配置文件gruntCfg.json將main.js的require文件配置代碼段拷貝到這個配置文件。並寫入輸入輸出目標。源碼如下

 1 {
 2   "requirejs": {
 3     "main": {
 4       "options": {
 5         "baseUrl": "",
 6         "paths": {
 7           "jquery": "src/jquery",
 8           "bootstrap": "src/bootstrap.min",
 9           "validator": "src/bootstrapValidator.min"
10         },
11         "shim": {
12           "bootstrap":["jquery"],
13           "validator": ["bootstrap"]
14         },
15         "include":["validator","jquery","bootstrap"],
16         "out":"dest/libs.js"
17       }
18     }
19   }
20 }

  上面include中我打亂了順序,為了測試壓縮順序我在三個庫的前面都添加了console.log(“我是” + 模塊名稱)

  修改Gruntfile.js

 1 module.exports = function (grunt) {
 2   grunt.loadNpmTasks('grunt-contrib-requirejs');
 3   //為了介紹自定義任務搞了一個這個
 4   grunt.registerTask('build', 'require', function () {
 5 
 6     //設置requireJs的信息
 7     var taskCfg = grunt.file.readJSON('gruntCfg.json');
 8     var requireTask = taskCfg.requirejs;
 9 
10     //添加人任務列表
11     grunt.task.run(['requirejs']);
12     grunt.config.set("requirejs", requireTask);
13   });
14 }

  好了現在看一下相關文件的文件結構如下

  

  執行build任務:grunt build

  文件夾dest下多了一個libs.js文件

  

  打開來看

  

  第一行代碼就有我剛纔添加的console。繼續找我添加的標誌的話發現壓縮順序是:jQuery->bootstrap->bootstrapValidator。和我們的shim依賴順序一致。說明合併壓縮的順序沒有問題。

  更多詳情請查看:https://www.npmjs.com/package/grunt-contrib-requirejs

 

5. 多任務


  我們先看一下使用別名任務來執行多個任務的情況,Gruntfile.js源碼如下

 1 module.exports = function (grunt) {
 2   // 項目配置
 3   grunt.initConfig({
 4     pkg: grunt.file.readJSON('package.json'),//獲取解析package.json將內容保存在pkg中
 5     uglify: {
 6       options: {
 7         banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
 8       },
 9       build: {
10         src: 'src/<%=pkg.file %>.js',
11         dest: 'dest/<%= pkg.file %>.min.js'
12       },
13       my_target1: {
14         files: {
15           'dest/libs.min.js': ['src/jquery.js', 'src/router.js']
16         }
17       },
18       my_target2: {
19         files: {
20           'dest/libs.min2.js': ['src/jquery.js', 'src/router.js']
21         }
22       }
23     },
24     requirejs: {
25       "main": {
26         "options": {
27           "baseUrl": "",
28           "paths": {
29             "jquery": "src/jquery",
30             "bootstrap": "src/bootstrap.min",
31             "validator": "src/bootstrapValidator.min"
32           },
33           "shim": {
34             "bootstrap":["jquery"],
35             "validator": ["bootstrap"]
36           },
37           "include":["validator","jquery","bootstrap"],
38           "out":"dest/libs.js"
39         }
40       },
41       "main2": {
42         "options": {
43           "baseUrl": "",
44           "paths": {
45             "jquery": "src/jquery",
46             "bootstrap": "src/bootstrap.min",
47             "validator": "src/bootstrapValidator.min"
48           },
49           "shim": {
50             "bootstrap":["jquery"],
51             "validator": ["bootstrap"]
52           },
53           "include":["validator","jquery","bootstrap"],
54           "out":"dest/libs2.js"
55         }
56       }
57     }
58 
59   });
60   // 載入提供"uglify"任務的插件
61   grunt.loadNpmTasks('grunt-contrib-uglify');
62   grunt.loadNpmTasks('grunt-contrib-requirejs');
63   // 預設任務
64   grunt.registerTask('default', ['uglify',"requirejs"]);
65 }

  執行:grunt

  dest文件夾下多出了5個文件

  

  源碼解析是:任務列表有兩個任務'uglify'和"requirejs",'uglify'有三個子任務:build/ my_target1/ my_target2, "requirejs"有兩個子任務main/main2。最終這五個子任務完成後生成的結果就是dest下多出的5個文件。

 

  還可以使用任務函數方式註冊多個任務。Gruntfile.js源碼如下

 1 module.exports = function (grunt) {
 2   grunt.initConfig({
 3     log: {
 4       l1: [1,2,3],
 5       l2: 'hello world',
 6       l3: false,
 7       l4: {name: "chua"},
 8       l5: 1,
 9       //這個是不行的l6: undefined,
10       //這個是不行的l7: null
11       l8: function(){alert("test")}
12     }
13   });
14 
15   grunt.registerMultiTask('log','log stuff.', function(){
16       grunt.log.writeln(this.target + ': ' + this.data);
17   });
18 }

  執行:grunt log

  

 

  我們使用自定義方式實現先前的多任務Gruntfile.js源碼如下

 1 module.exports = function (grunt) {
 2   // 項目配置
 3   grunt.initConfig({
 4     pkg: grunt.file.readJSON('package.json'),//獲取解析package.json將內容保存在pkg中
 5     log: {
 6       uglify: {
 7         options: {
 8           banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
 9         },
10         build: {
11           src: 'src/<%=pkg.file %>.js',
12           dest: 'dest/<%= pkg.file %>.min.js'
13         },
14         my_target1: {
15           files: {
16             'dest/libs.min.js': ['src/jquery.js', 'src/router.js']
17           }
18         },
19         my_target2: {
20           files: {
21             'dest/libs.min2.js': ['src/jquery.js', 'src/router.js']
22           }
23         }
24       },
25       requirejs: {
26         "main": {
27           "options": {
28             "baseUrl": "",
29             "paths": {
30               "jquery": "src/jquery",
31               "bootstrap": "src/bootstrap.min",
32               "validator": "src/bootstrapValidator.min"
33             },
34             "shim": {
35               "bootstrap":["jquery"],
36               "validator": ["bootstrap"]
37             },
38             "include":["validator","jquery","bootstrap"],
39             "out":"dest/libs.js"
40           }
41         },
42         "main2": {
43           "options": {
44             "baseUrl": "",
45             "paths": {
46               "jquery": "src/jquery",
47               "bootstrap": "src/bootstrap.min",
48               "validator": "src/bootstrapValidator.min"
49             },
50             "shim": {
51               "bootstrap":["jquery"],
52               "validator": ["bootstrap"]
53             },
54             "include":["validator","jquery","bootstrap"],
55             "out":"dest/libs2.js"
56           }
57         }
58       }
59     }
60   });
61   // 載入提供"uglify"任務的插件
62   grunt.loadNpmTasks('grunt-contrib-uglify');
63   grunt.loadNpmTasks('grunt-contrib-requirejs');
64   
65   grunt.registerMultiTask('log','log stuff.', function(){
66     if(this.target == "uglify"){
67       //添加人任務列表
68       grunt.task.run(['uglify']);
69       grunt.config.set("uglify", this.data);
70     }else if(this.target == "requirejs"){
71       //添加人任務列表
72       grunt.task.run(['requirejs']);
73       grunt.config.set("requirejs", this.data);
74     }
75   });
76 }

  執行:grunt log

  照樣得到先前的結果

  

  說到底和先前的別名任務沒有什麼不同。

 

6. 壓縮整個文件夾下的js文件


  壓縮src下的所有js文件,Gruntfile.js源碼

 1 module.exports = function (grunt) {
 2   grunt.initConfig({
 3     uglify: {
 4       my_target: {
 5         files: [{
 6           expand: true,
 7           cwd: 'src',
 8           src: '**/*.js',
 9           dest: 'dest'
10         }]
11       }
12     }
13   });
14   grunt.loadNpmTasks('grunt-contrib-uglify');
15   grunt.registerTask('default', ['uglify']);
16 }

  源碼文件結構(註意src/router下麵還有一個js文件)

  

  執行:grunt

  目標文件結構

  

  所以這個方法還是比較方便的,他會遍歷源文件夾下的所有文件(包括子文件夾)然後壓縮。

 

  剛纔上面的方式沒有拷貝src文件夾,下麵這種方式拷貝了src文件夾

 1 module.exports = function (grunt) {
 2   grunt.initConfig({
 3     uglify: {
 4       my_target: {
 5         files: [{
 6           expand: true,
 7           //cwd: 'src',
 8           src: 'src/**/*.js',
 9           dest: 'dest'
10         }]
11       }
12     }
13   });
14   grunt.loadNpmTasks('grunt-contrib-uglify');
15   grunt.registerTask('default', ['uglify']);
16 }

  執行:grunt

  目標文件結構變成

  

  src下所有的js都被壓縮並保持原來的目錄結構。

 

7. grunt-contrib-requirejs插件的更詳細使用


  我們用實例來說明。現在我們的文件結構是這樣子的

  

  main.js是我們使用require的真實配置文件,源碼如下

 1 require.config({
 2   baseUrl: "",
 3   paths: {
 4     "jquery": "src/jquery",
 5     "bootstrap": "src/bootstrap.min",
 6     "validator": "src/bootstrapValidator.min"
 7   },
 8   shim: {
 9     "bootstrap":["jquery"],
10     "beyond": ["bootstrap"],
11     "validator": ["bootstrap"]
12   }
13 });
14 requirejs(['validator'], function (v) {
15   //代碼
16 });

  Gruntfile.js的源碼

 1 module.exports = function (grunt) {
 2   grunt.initConfig({
 3     "requirejs": {
 4       "main": {
 5         "options": {
 6           "baseUrl": ".",
 7           "mainConfigFile": "main.js",//指定配置文件
 8           "name": "test",//會將對應的文件壓縮到main.js依賴的文件的前面壓縮。但是會在main.js非依賴文件後面壓縮(比如router.js)
 9           "include":["jquery","bootstrap","validator","src/router/router.js"],//要壓縮在一起的文件(會包括name對應的文件)
10           "out":"dest/libs.js"
11         }
12       }
13     }
14   });
15   grunt.loadNpmTasks('grunt-contrib-requirejs');
16   grunt.registerTask('default', ['requirejs']);
17 }

  需要說明的是name指定的文件內容會在main.js配置的依賴文件壓縮之前壓縮,但是如果include中還包含其他非main.js依賴的文件,則會在main.js非依賴文件後面壓縮。

  我們的test.js源碼為

1 console.log("這是我隨便測試用的一個js");

  然後我們執行:grunt

  結果在dest下生成一個libs.js壓縮文件

  

  並且這個文件裡面包含的壓縮文件的順序是:router.js->test.js->jquery.js-> bootstrap.min.js-> bootstrapValidator.min.js。

  所以說配置include中文件會依序壓縮到libs.js,但是main.js依賴的文件會放在最後(依賴會逐層往上查找依賴),而name指定的文件會在非依賴文件之後依賴文件之前壓縮。

 

  require模板文件打包

  模板文件使用到require工程上的text.js文件,路徑:http://github.com/requirejs/text

  我們這裡建立一個模板文件test.html

1 <!DOCTYPE html>
2 <html>
3 <head>
4   <title>test</title>
5 </head>
6 <body>
7 </body>
8 </html>

  實際上現在test.html沒有用到任何模板相關的運用,我們只是做打包例子,所以不管其他,我們只需要知道模板文件一般是html文件即可

  現在工程的文件結構是

  

  Gruntfile.js的源碼為

 1 module.exports = function (grunt) {
 2   grunt.initConfig({
 3     "requirejs": {
 4       "main": {
 5         "options": {
 6           baseUrl: ".",
 7           paths: {
 8             "jquery": "src/jquery",
 9             "bootstrap": "src/bootstrap.min",
10             "validator": "src/bootstrapValidator.min",
11             "text": "text"//引入requirejs項目下解析模板引擎
12           },
13           shim: {
14             "bootstrap":["jquery"],
15             "beyond": ["bootstrap"],
16             "validator": ["bootstrap"]
17           },
18           "include":["jquery","bootstrap","validator","text!test.html"],          "out":"dest/libs.js"
19         }
20       }
21     }
22   });
23   grunt.loadNpmTasks('grunt-contrib-requirejs');
24   grunt.registerTask('default', ['requirejs']);
25 }

  執行命令行:grunt

  dest文件下多了一個libs.js,查看其中是否有模板文件test.html中的內容

  

  說明模板被一同壓縮進去了。關鍵是"text!test.html"這句話。test會將模板test.html解析成js腳本形式。

 

8.  cssmin打包樣式文件


  需要用npm下載cssmin插件:npm install grunt-contrib-cssmin --save-dev

  Gruntfile.js文件源碼

 1 module.exports = function (grunt) {
 2   grunt.initConfig({
 3     cssmin: {
 4       compress: {
 5         files: {
 6           'dest/t.min.css': ["src/t1.css","src/t2.css"]
 7         }
 8       }
 9     }
10   });
11 
12   grunt.loadNpmTasks('grunt-contrib-cssmin');
13 
14 }

  命令行執行:grunt cssmin

  兩個css文件壓縮打包到dest/t.min.css

 

9. htmlmin打包html文件


  需要用npm下載cssmin插件:npm install grunt-contrib-htmlmin --save-dev

  Gruntfile.js源碼

 1 module.exports = function (grunt) {
 2   grunt.initConfig({ 
 3     htmlmin: {
 4       main: {
 5         options:{
 6           removeComments: true,
 7           collapseWhitespace: true
 8         },
 9         files:{
10           "dest/test.html": "test.html"
11         }
12       }
13     }
14   });
15 
16   grunt.loadNpmTasks('grunt-contrib-htmlmin');
17   grunt.registerTask("default",["htmlmin"]);
18 }

  執行命令:grunt

  test.html壓縮到dest/test.html

  

10. copy拷貝文件


  需要下載copy插件npm install grunt-contrib-copy --save-dev

  將src文件夾(包括內容和子文件內容)拷貝到dest目錄下,Gruntfile.js源碼

 1 module.exports = function (grunt) {
 2   grunt.initConfig({ 
 3     copy: {
 4       main: {
 5         expand: true,
 6         src: 'src/**',
 7         dest: 'dest/'
 8       }
 9     }
10   });
11 
12   grunt.loadNpmTasks('grunt-contrib-copy');
13   grunt.registerTask("default",["copy"]);
14 }

  運行:grunt

  src被完美的拷貝到dest下

   

 

  只拷貝src的第一層子文件,Gruntfile.js源碼

 1 module.exports = function (grunt) {
 2   grunt.initConfig({ 
 3     copy: {
 4       main: {
 5         expand: true,
 6         src: 'src/*',
 7         dest: 'dest/'
 8       }
 9     }
10   });
11 
12   grunt.loadNpmTasks('grunt-contrib-copy');
13   grunt.registerTask("default",["copy"]);
14 }

  運行結果

  

  這個時候router是空文件夾。

  所以這裡我們需要明白路徑中“*”只表示當前這一層,“**”表示需要遞歸子文件夾   

 

  如果只是拷貝src中的內容而不用src包

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 乾貨|建議初創團隊起初也要構建分散式應用 本文內容整理自W-Time技術分享沙龍-天津站現場演講《一切都是分佈的》,演講者:李傲,問啊聯合創始人,前中交車聯網總架構。 好多人都會問什麼是架構師?其實架構師的定義很寬泛,前端後端的定義都不一樣。作為後端出身的架構師,我認為後端並不是大家想的封裝組件,它 ...
  • 網頁可見區域寬: document.body.clientWidth網頁可見區域高: document.body.clientHeight網頁可見區域寬: document.body.offsetWidth (包括邊線的寬)網頁可見區域高: document.body.offsetHeight (包 ...
  • 頁面如下: 我們現在想實現這樣的功能,在div1 點擊的時候,彈出 "你好,我是最外層div。",點擊div2 的時候,彈出 "你好,我是第二層div";點擊span 的時候,彈出"您好,我是span。"。 但是當點擊span時,三個對話框會先後彈出來,無論是body,body 的子元素div1,還 ...
  • 一、前言 上章我們提到過開發一個插件所需要的步驟: 瀏覽器插件-自動登錄淘寶(-) 並且還介紹瞭如何在頁面上面註入腳本代碼,並且成功的完成用戶名和密碼的自動輸入功能。 本章將會以一些案例來介紹插件的一些新的開發技巧。案例將包括: 關於案例 涉及的技術點包括: 如何使用popup.html popup ...
  • 本篇主要介紹HTML5增加的語義元素中關於頁面結構方面的,包含: <article>、<aside>、<figure>、<figcaption>、<footer>、<header>、<main>、<nav>、<section>等元素。 目錄 1. 語義元素介紹 1.1 何為語義元素 1.2 特點 2 ...
  • 什麼是web app? WebApp是指基於Web的系統和應用,其作用是向廣大的最終用戶發佈一組複雜的內容和功能。 說的淺顯易懂點兒就是因為移動互聯網特別火爆,很多企業公司也都想擁有一個屬於自己的app,但是因為原生app開發的成本比較高,而且後期維護比較困難,這些開發成本和後期維護成本對於個人創業 ...
  • function db_connect()//連接資料庫 { @$db =mysql_connect('localhost','root','test'); if(!$db) throw new Exception('連接資料庫失敗!請重試!'); mysql_select_db('book'); ...
  • 上一篇文章介紹瞭如何利用CSS選擇器為元素應用各種豐富的樣式,每個合法的文檔都會生成一個結構樹,瞭解這一點,就能根據元素的祖先、屬性、兄弟等元素穿件選擇器選擇元素。 本篇文章將討論3中機制之間的關係:特殊性、繼承和層疊 特殊性 有的時候我們為同一個元素設置了不同的CSS樣式代碼,那麼元素會啟用哪一個 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...