Vue學習之五DIY腳手架、webpack使用、vue-cli的使用、element-ui
本節目錄javascript
以前咱們獲取dom是經過原生js或者jQuery的選擇器來獲取的,那麼vue也給咱們提供了一些獲取dom的方法。css
方式:給標籤或者組件添加ref屬性,未來咱們經過this.$refs屬性能夠獲取到這個標籤或者組件。html
<div ref="chao"></div> <p ref="a"></p> <Home ref="b"></Home> 子組件 <script> this.$refs.chao 獲取原始的DOM對象 this.$refs.b 父組件中獲取的是子組件實例化對象 </script>
簡單使用一下:讓某個input標籤在瀏覽器加載完以後,自動獲取到光標(焦點)前端
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> </div> </body> <script src="vue.js"></script> <script src="vue-router.js"></script> <script> Vue.component('Test',{ data(){ return{ } }, //若是這個全局組件中沒有template或者render方法,會報個錯誤給你,這個補充和我們今天的內容沒有關係昂 template: ` <div>這是全局Test組件</div> `, }) ; let App = { data(){ return{ } }, template:` <div> <input ref="username" type="text"> <Test ref="abc"></Test> </div> `, //讓上面的input默認是獲取焦點的狀態,剛開始打開頁面的時候,input是沒有獲取到焦點(光標)的狀態 mounted(){ //操做dom的方式 console.log(this.$refs.username); this.$refs.username.focus();//focus()方法是原生js方法,讓前面這個input標籤自動獲取焦點用的。 //操做組件的方式 console.log(this.$refs);//全部含有ref屬性的標籤或者組件:{username: input, abc: VueComponent},發現就是個自定義屬性(字典) console.log(this.$refs.abc);//VueComponent {_uid: 2, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …} console.log(this.$refs['abc']); //VueComponent {_uid: 2, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …} console.log(this.$refs.abc.$parent);//就是this,abc的父級組件App組件 console.log(this.$children);//就是this當前的組件的全部子組件,順序是按照template中使用組件的時候的順序,還有好多其餘的方法等等,之後再說 //循環全部含有ref屬性的標籤或者組件 for (let key in this.$refs){ console.log(this.$refs[key]); } }, }; let vm = new Vue({ el:'#app', data(){ return{ } }, template:` <div> <App></App> </div> `, components:{ App, } }) </script> </html>
首先咱們先到YEOMAN中看一個圖,這個YEOMAN是集合了前端全部的腳手架,包括服務器的、js的、jQuery的、react、angular、vue等等的腳手架都在這裏面有,網址:https://yeoman.io/,咱們不用去研究裏面的內容,我只想讓你們看一個圖:vue
這個圖的意思就是每一個工程師都拿着本身現成的工具來作火箭這個項目,未來咱們要經過vue-cli來作組件化開發,在組件化開發中就使用到了咱們的webpack工具(這是前端的工具),前端最開始用的grunt後來是gulp,再後來就是咱們如今主流的webpack工具了,那到底這個工具作了什麼,咱們日後看。java
webpack介紹
webpack是一個現代JavaScript應用程序的靜態模塊打包器(好比python中一個.py文件就是一個模塊,那麼前端中一個js、html、css等文件就能夠稱爲一個模塊)。當 webpack 處理應用程序時,它會遞歸地構建一個*依賴關係圖(dependency graph)*,其中包含應用程序須要的每一個模塊,而後將全部這些模塊打包成一個或多個 *bundle*。這個webpack已經內置在了vue-cli中,因此咱們下載安裝了vue-cli以後就能直接使用webpack工具了。接下來咱們看一下下面這張圖,圖片來自於webpack官網(中文文檔)https://www.webpackjs.com/node
歷史介紹(瞭解)
- 2009年初,commonjs異步模塊規範還未出來,此時前端開發人員編寫的代碼都是非模塊化的,使用閉包來完成相似模塊化的開發。commonjs是在nodejs中產生的,是服務器語言,也就是有他以後,前端語言就能夠作服務端的開發了。 - 那個時候開發人員常常須要十分留意文件加載順序所帶來的依賴問題,好比你使用不少的script標籤,而後每一個標籤的src屬性指向一個js文件,那麼要注意這些標籤的引入順序,而且有一個js文件出問題了,後面的js文件都加載不上,這就是一個同步加載的問題。 - 與此同時 nodejs開啓了js全棧大門,而requirejs在國外也帶動着前端逐步實現模塊化 - 同時國內seajs也進行了大力推廣,中國人淘寶玉伯寫的,他的規範叫作AMD - AMD 規範 ,具體實現是requirejs define('模塊id',[模塊依賴1,模塊依賴2],function(){ return ;}) , ajax請求文件並加載,例如:你有三個js文件,a.js、b.js、c.js,使用c.js的時候須要依賴a和b,那麼寫法 define('c.js',(a.js,b.js),function(){}) - Commonjs || CMD規範 - commonjs和cmd很是類似的 - cmd require(相似於import,引入的意思)/module.exports(輸出的意思)
- commonjs是js在後端語言的規範: 模塊、文件操做、操做系統底層 - CMD 僅僅是模塊定義 - UMD 通用模塊定義,一種既能兼容amd也能兼容commonjs 也能兼容瀏覽器環境運行的萬能代碼 - npm/bower集中包管理的方式備受青睞,12年browserify/webpack誕生 - npm 是能夠下載先後端的js代碼475000個包 - bower 只能下載前端的js代碼,bower 在下載bootstrap的時候會自動的下載jquery - browserify 解決讓require能夠運行在瀏覽器,分析require的關係,組裝代碼 - webpack 打包工具,佔市場主流
後面的內容須要咱們學習~~~
1. require和module.exports
require和module.exports的使用舉例,注意這兩個方法必須在nodejs的環境下才能使用,否則瀏覽器是識別不了這兩個方法,就會報錯,而且咱們平時建立的.js文件在nodejs環境中會識別成nodejs類型的文件,不過不要緊,基本都是支持的,建立文件的時候仍是xx.js文件。python
假如咱們如今有三個文件,index.html和time.js和index.js文件react
index.html最開始引入js文件的方法是這樣的:jquery
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!-- 同步引入的方式 --> <script src="index.js"></script> <script src="time.js"></script> </body> </html>
而後咱們經過CMD規範來寫一下經過require和module.exports兩個方法實現模塊化開發
index.js內容以下:
// var person1 = { // name:'張三', // // }; // //能夠拋出,自定義對象,變量,函數等等內容,可是這些js文件的這樣的用法必須在nodejs環境下執行,而nodejs是從原生js加工出來的,支持咱們寫js語言,可是有些功能不支持,好比說alert,window彈框等操做 // var person2 = { // name:'李四', // }; //將咱們在index.js中的person拋出,而後其餘js文件就能夠經過require方法來引用了 // module.exports = person1; function add(){ console.log('add函數'); } module.exports = add; //將add函數拋出,其餘js文件才能經過require引入使用,未來咱們就將咱們的組件寫到一個js文件中,經過這個拋出組件,而後其餘文件中require來使用這個組件
time.js內容以下,time.js文件的運行須要index.js中的內容
var p = require('./index.js'); // console.log(p.name); p();//執行一下index.js文件中引入的add函數
說了,咱們須要在nodejs的環境下使用這兩個方法,那麼咱們在pycharm這個IDE的終端來調用一下node來執行一下time.js文件。
先看個人文件目錄結構:
而後終端切換到這個nodejs模塊的文件夾下,執行一下下面的指令:就獲得了index.js函數中的執行結果。
上面就是CMD的規範,其實vue更加但願咱們使用es6的module(模塊)規範,咱們來看看module規範的語法。
一個export拋出,一個import引入,阮一峯的博客上介紹的比較詳細,就在他es6的那個博客裏面有個module語法的那個章節裏面有。
好,那麼咱們先來學一下export和import的應用:
2.export和import
簡單鋪墊:歷史上,JavaScript 一直沒有模塊(module)體系,沒法將一個大程序拆分紅互相依賴的小文件,再用簡單的方法拼裝起來。其餘語言都有這項功能,好比 Ruby 的require
、Python 的import
,甚至就連 CSS 都有@import
,可是 JavaScript 任何這方面的支持都沒有,這對開發大型的、複雜的項目造成了巨大障礙。
在 ES6 以前,社區制定了一些模塊加載方案,最主要的有 CommonJS 和 AMD 兩種。前者用於服務器,後者用於瀏覽器。ES6 在語言標準的層面上,實現了模塊功能,並且實現得至關簡單,徹底能夠取代 CommonJS 和 AMD 規範,成爲瀏覽器和服務器通用的模塊解決方案。
ES6 模塊的設計思想是儘可能的靜態化,使得編譯時就能肯定模塊的依賴關係,以及輸入和輸出的變量。CommonJS 和 AMD 模塊,都只能在運行時肯定這些東西。好比,CommonJS 模塊就是對象,輸入時必須查找對象屬性。
// CommonJS模塊 let { stat, exists, readFile } = require('fs'); // 等同於 let _fs = require('fs'); let stat = _fs.stat; let exists = _fs.exists; let readfile = _fs.readfile;
上面代碼的實質是總體加載fs
模塊(即加載fs
的全部方法),生成一個對象(_fs
),而後再從這個對象上面讀取 3 個方法。這種加載稱爲「運行時加載」,由於只有運行時才能獲得這個對象,致使徹底沒辦法在編譯時作「靜態優化」。
ES6 模塊不是對象,而是經過export
命令顯式指定輸出的代碼,再經過import
命令輸入。
// ES6模塊 import { stat, exists, readFile } from 'fs';
上面代碼的實質是從fs
模塊加載 3 個方法,其餘方法不加載。這種加載稱爲「編譯時加載」或者靜態加載,即 ES6 能夠在編譯時就完成模塊加載,效率要比 CommonJS 模塊的加載方式高。固然,這也致使了無法引用 ES6 模塊自己,由於它不是對象。
因爲 ES6 模塊是編譯時加載,使得靜態分析成爲可能。有了它,就能進一步拓寬 JavaScript 的語法,好比引入宏(macro)和類型檢驗(type system)這些只能靠靜態分析實現的功能。
export命令
模塊功能主要由兩個命令構成:export
和import
。export
命令用於規定模塊的對外接口,import
命令用於輸入其餘模塊提供的功能。
一個模塊就是一個獨立的文件。該文件內部的全部變量,外部沒法獲取。若是你但願外部可以讀取模塊內部的某個變量,就必須使用export
關鍵字輸出該變量。下面是一個 JS 文件,裏面使用export
命令輸出變量。
// profile.js export var firstName = 'Michael'; export var lastName = 'Jackson'; export var year = 1958;
上面代碼是profile.js
文件,保存了用戶信息。ES6 將其視爲一個模塊,裏面用export
命令對外部輸出了三個變量。
export
的寫法,除了像上面這樣,還有另一種。
// profile.js var firstName = 'Michael'; var lastName = 'Jackson'; var year = 1958; export {firstName, lastName, year};
上面代碼在export
命令後面,使用大括號指定所要輸出的一組變量。它與前一種寫法(直接放置在var
語句前)是等價的,可是應該優先考慮使用這種寫法。由於這樣就能夠在腳本尾部,一眼看清楚輸出了哪些變量。
export
命令除了輸出變量,還能夠輸出函數或類(class)。
export function multiply(x, y) { return x * y; };
上面代碼對外輸出一個函數multiply
。
一般狀況下,export
輸出的變量就是原本的名字,可是可使用as
關鍵字重命名。
function v1() { ... } function v2() { ... } export { v1 as streamV1, v2 as streamV2, v2 as streamLatestVersion };
上面代碼使用as
關鍵字,重命名了函數v1
和v2
的對外接口。重命名後,v2
能夠用不一樣的名字輸出兩次。
須要特別注意的是,export
命令規定的是對外的接口,必須與模塊內部的變量創建一一對應關係。
// 報錯 export 1; // 報錯 var m = 1; export m;
上面兩種寫法都會報錯,由於沒有提供對外的接口。第一種寫法直接輸出 1,第二種寫法經過變量m
,仍是直接輸出 1。1
只是一個值,不是接口。正確的寫法是下面這樣。
// 寫法一 export var m = 1; // 寫法二 var m = 1; export {m}; // 寫法三 var n = 1; export {n as m};
上面三種寫法都是正確的,規定了對外的接口m
。其餘腳本能夠經過這個接口,取到值1
。它們的實質是,在接口名與模塊內部變量之間,創建了一一對應的關係。
一樣的,function
和class
的輸出,也必須遵照這樣的寫法。
// 報錯 function f() {} export f; // 正確 export function f() {}; // 正確 function f() {} export {f};
另外,export
語句輸出的接口,與其對應的值是動態綁定關係,即經過該接口,能夠取到模塊內部實時的值。
export var foo = 'bar'; setTimeout(() => foo = 'baz', 500);
上面代碼輸出變量foo
,值爲bar
,500 毫秒以後變成baz
。
這一點與 CommonJS 規範徹底不一樣。CommonJS 模塊輸出的是值的緩存,不存在動態更新,詳見下文《Module 的加載實現》一節。
最後,export
命令能夠出如今模塊的任何位置,只要處於模塊頂層就能夠。若是處於塊級做用域內,就會報錯,下一節的import
命令也是如此。這是由於處於條件代碼塊之中,就無法作靜態優化了,違背了 ES6 模塊的設計初衷。
function foo() { export default 'bar' // SyntaxError } foo()
上面代碼中,export
語句放在函數之中,結果報錯。
import命令
使用export
命令定義了模塊的對外接口之後,其餘 JS 文件就能夠經過import
命令加載這個模塊。
// main.js import {firstName, lastName, year} from './profile.js'; function setName(element) { element.textContent = firstName + ' ' + lastName; }
上面代碼的import
命令,用於加載profile.js
文件,並從中輸入變量。import
命令接受一對大括號,裏面指定要從其餘模塊導入的變量名。大括號裏面的變量名,必須與被導入模塊(profile.js
)對外接口的名稱相同。
若是想爲輸入的變量從新取一個名字,import
命令要使用as
關鍵字,將輸入的變量重命名。
import { lastName as surname } from './profile.js';
import
命令輸入的變量都是隻讀的,由於它的本質是輸入接口。也就是說,不容許在加載模塊的腳本里面,改寫接口。
import {a} from './xxx.js' a = {}; // Syntax Error : 'a' is read-only;
上面代碼中,腳本加載了變量a
,對其從新賦值就會報錯,由於a
是一個只讀的接口。可是,若是a
是一個對象,改寫a
的屬性是容許的。
import {a} from './xxx.js' a.foo = 'hello'; // 合法操做
上面代碼中,a
的屬性能夠成功改寫,而且其餘模塊也能夠讀到改寫後的值。不過,這種寫法很難查錯,建議凡是輸入的變量,都看成徹底只讀,輕易不要改變它的屬性。
import
後面的from
指定模塊文件的位置,能夠是相對路徑,也能夠是絕對路徑,.js
後綴能夠省略。若是隻是模塊名,不帶有路徑,那麼必須有配置文件,告訴 JavaScript 引擎該模塊的位置。
import {myMethod} from 'util';
上面代碼中,util
是模塊文件名,因爲不帶有路徑,必須經過配置,告訴引擎怎麼取到這個模塊。
注意,import
命令具備提高效果,會提高到整個模塊的頭部,首先執行。
foo(); import { foo } from 'my_module';
上面的代碼不會報錯,由於import
的執行早於foo
的調用。這種行爲的本質是,import
命令是編譯階段執行的,在代碼運行以前。
因爲import
是靜態執行,因此不能使用表達式和變量,這些只有在運行時才能獲得結果的語法結構。
// 報錯 import { 'f' + 'oo' } from 'my_module'; // 報錯 let module = 'my_module'; import { foo } from module; // 報錯 if (x === 1) { import { foo } from 'module1'; } else { import { foo } from 'module2'; }
上面三種寫法都會報錯,由於它們用到了表達式、變量和if
結構。在靜態分析階段,這些語法都是無法獲得值的。
最後,import
語句會執行所加載的模塊,所以能夠有下面的寫法。
import 'lodash';
上面代碼僅僅執行lodash
模塊,可是不輸入任何值。
若是屢次重複執行同一句import
語句,那麼只會執行一次,而不會執行屢次。
import 'lodash'; import 'lodash';
上面代碼加載了兩次lodash
,可是隻會執行一次。
import { foo } from 'my_module'; import { bar } from 'my_module'; // 等同於 import { foo, bar } from 'my_module';
上面代碼中,雖然foo
和bar
在兩個語句中加載,可是它們對應的是同一個my_module
實例。也就是說,import
語句是 Singleton 模式。
目前階段,經過 Babel 轉碼,CommonJS 模塊的require
命令和 ES6 模塊的import
命令,能夠寫在同一個模塊裏面,可是最好不要這樣作。由於import
在靜態解析階段執行,因此它是一個模塊之中最先執行的。下面的代碼可能不會獲得預期結果。
require('core-js/modules/es6.symbol'); require('core-js/modules/es6.promise'); import React from 'React';
模塊總體加載
除了指定加載某個輸出值,還可使用總體加載,即用星號(*
)指定一個對象,全部輸出值都加載在這個對象上面。
下面是一個circle.js
文件,它輸出兩個方法area
和circumference
。
// circle.js export function area(radius) { return Math.PI * radius * radius; } export function circumference(radius) { return 2 * Math.PI * radius; }
如今,加載這個模塊。
// main.js import { area, circumference } from './circle'; console.log('圓面積:' + area(4)); console.log('圓周長:' + circumference(14));
上面寫法是逐一指定要加載的方法,總體加載的寫法以下。
import * as circle from './circle'; console.log('圓面積:' + circle.area(4)); console.log('圓周長:' + circle.circumference(14));
注意,模塊總體加載所在的那個對象(上例是circle
),應該是能夠靜態分析的,因此不容許運行時改變。下面的寫法都是不容許的。
import * as circle from './circle'; // 下面兩行都是不容許的 circle.foo = 'hello'; circle.area = function () {};
export default命令
從前面的例子能夠看出,使用import
命令的時候,用戶須要知道所要加載的變量名或函數名,不然沒法加載。可是,用戶確定但願快速上手,未必願意閱讀文檔,去了解模塊有哪些屬性和方法。
爲了給用戶提供方便,讓他們不用閱讀文檔就能加載模塊,就要用到export default
命令,爲模塊指定默認輸出。
// export-default.js export default function () { console.log('foo'); }
上面代碼是一個模塊文件export-default.js
,它的默認輸出是一個函數。
其餘模塊加載該模塊時,import
命令能夠爲該匿名函數指定任意名字。
// import-default.js import customName from './export-default'; customName(); // 'foo'
上面代碼的import
命令,能夠用任意名稱指向export-default.js
輸出的方法,這時就不須要知道原模塊輸出的函數名。須要注意的是,這時import
命令後面,不使用大括號。
export default
命令用在非匿名函數前,也是能夠的。
// export-default.js export default function foo() { console.log('foo'); } // 或者寫成 function foo() { console.log('foo'); } export default foo;
上面代碼中,foo
函數的函數名foo
,在模塊外部是無效的。加載的時候,視同匿名函數加載。
下面比較一下默認輸出和正常輸出。
// 第一組 export default function crc32() { // 輸出 // ... } import crc32 from 'crc32'; // 輸入 // 第二組 export function crc32() { // 輸出 // ... }; import {crc32} from 'crc32'; // 輸入
上面代碼的兩組寫法,第一組是使用export default
時,對應的import
語句不須要使用大括號;第二組是不使用export default
時,對應的import
語句須要使用大括號。
export default
命令用於指定模塊的默認輸出。顯然,一個模塊只能有一個默認輸出,所以export default
命令只能使用一次。因此,import命令後面纔不用加大括號,由於只可能惟一對應export default
命令。
本質上,export default
就是輸出一個叫作default
的變量或方法,而後系統容許你爲它取任意名字。因此,下面的寫法是有效的。
// modules.js function add(x, y) { return x * y; } export {add as default}; // 等同於 // export default add; // app.js import { default as foo } from 'modules'; // 等同於 // import foo from 'modules';
正是由於export default
命令其實只是輸出一個叫作default
的變量,因此它後面不能跟變量聲明語句。
// 正確 export var a = 1; // 正確 var a = 1; export default a; // 錯誤 export default var a = 1;
上面代碼中,export default a
的含義是將變量a
的值賦給變量default
。因此,最後一種寫法會報錯。
一樣地,由於export default
命令的本質是將後面的值,賦給default
變量,因此能夠直接將一個值寫在export default
以後。
// 正確 export default 42; // 報錯 export 42;
上面代碼中,後一句報錯是由於沒有指定對外的接口,而前一句指定對外接口爲default
。
有了export default
命令,輸入模塊時就很是直觀了,以輸入 lodash 模塊爲例。
import _ from 'lodash';
若是想在一條import
語句中,同時輸入默認方法和其餘接口,能夠寫成下面這樣。
import _, { each, forEach } from 'lodash';
對應上面代碼的export
語句以下。
export default function (obj) { // ··· } export function each(obj, iterator, context) { // ··· } export { each as forEach };
上面代碼的最後一行的意思是,暴露出forEach
接口,默認指向each
接口,即forEach
和each
指向同一個方法。
export default
也能夠用來輸出類。
// MyClass.js export default class { ... } // main.js import MyClass from 'MyClass'; let o = new MyClass();
export 和 import的複合用法
若是在一個模塊之中,先輸入後輸出同一個模塊,import
語句能夠與export
語句寫在一塊兒。
export { foo, bar } from 'my_module'; // 能夠簡單理解爲 import { foo, bar } from 'my_module'; export { foo, bar };
上面代碼中,export
和import
語句能夠結合在一塊兒,寫成一行。但須要注意的是,寫成一行之後,foo
和bar
實際上並無被導入當前模塊,只是至關於對外轉發了這兩個接口,致使當前模塊不能直接使用foo
和bar
。
模塊的接口更名和總體輸出,也能夠採用這種寫法。
// 接口更名 export { foo as myFoo } from 'my_module'; // 總體輸出 export * from 'my_module';
默認接口的寫法以下。
export { default } from 'foo';
具名接口改成默認接口的寫法以下。
export { es6 as default } from './someModule'; // 等同於 import { es6 } from './someModule'; export default es6;
一樣地,默認接口也能夠更名爲具名接口。
export { default as es6 } from './someModule';
下面三種import
語句,沒有對應的複合寫法。
import * as someIdentifier from "someModule"; import someIdentifier from "someModule"; import someIdentifier, { namedIdentifier } from "someModule";
爲了作到形式的對稱,如今有提案,提出補上這三種複合寫法。
export * as someIdentifier from "someModule"; export someIdentifier from "someModule"; export someIdentifier, { namedIdentifier } from "someModule";
好,總結一下,export和export default都是拋出接口的,而import是獲取接口的。
下面咱們就經過export default先來個例子玩玩:
咱們先建立兩個文件,main.js文件和index.html文件和module.js文件
index.html內容以下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!-- 只引入main.js,由於main.js用來做爲全部js文件的入口文件 --> <script src="main.js"></script> </body> </html>
main.js內容以下:
//這個文件裏面咱們可能會寫不少的js代碼,而且如今咱們的場景是這個文件裏面的代碼依賴一些module.js文件中的內容 import person from './module.js' //person這個名字隨便起,由於export default把他們都放到了一個default變量上,任何變量名均可以接收到 console.log(person.name); console.log(person.f1());
module.js內容以下:
var person = { name:'張三', f1:function(){ alert(1); //彈出一個1對話框 } }; export default person;
可是咱們經過瀏覽器打開這個index.html文件,你會發現報錯了,瀏覽器不支持import等的寫法,既然瀏覽器不支持這樣的模塊化,那怎麼辦呢,這就要藉助咱們的webpack工具了。
我說過webpack須要找到咱們全部js文件(或者其餘文件好比css文件)的一個入口文件,而後將全部的文件(js\css等)打包輸出成爲一個js文件,下面咱們就來看看,如何經過webpack進行打包並實現模塊化開發,記住一點,webpack工具必須在nodejs的環境下才能使用,這也是爲何咱們要先下載nodejs。
看webpack的用法,咱們先在pycharm的終端指令中執行一個webpack指令:
那麼main.js和module.js文件內容不變,index.html文件中的引入改一下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!-- 只引入main.js,由於main.js用來做爲全部js文件的入口文件 --> <!--<script src="main.js"></script>--> <!-- 直接引用咱們經過webpack打包好的js文件 --> <script src="bundle.js"></script> </body> </html>
而後經過瀏覽器打開咱們的index.html文件,效果就出來了,
具體的這個打包出來的文件內容,你暫時不須要理解,會用就能夠了。
接下來咱們使用一下export來拋出多個內容:
main.js的寫法:
// export拋出後咱們import來接收的方式:console.log(person,num); import {person,num} from './module.js' console.log(person,num) //可是這裏要注意的就是,person和num要和別的文件拋出的變量名字相同 //一下接收全部的變量,*,可是*符號和咱們的css有衝突,因此搞個別名,我這裏起了個別名叫a import * as a from './module.js' console.log(a);
module.js的寫法
var person = { name:'張三', f1:function(){ alert(1); } }; var num = 32; // export default person; export {person,num}; //經過export拋出多個變量,還能拋出函數,類等內容,我這裏就沒有寫啦
index.html文件不用改:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!-- 直接引用咱們經過webpack打包好的js文件 --> <script src="bundle.js"></script> </body> </html>
別忘了,咱們將js文件修改了,那麼咱們須要從新執行一下打包過程,webpack ./main.js ./bundle.js,中間的空格別忘了寫,有朋友可能要說了,每次都手動打包一下嗎?後面我們就不用手動打包了,會有自動打包的方法,日後面學。
而後瀏覽器打開index.html文件看效果:在瀏覽器調試臺的console的地方看
簡單總結一下:
CMD:
拋出:module.exports = xxx; 引用:require()
ES6:
拋出:export export var num=10; export function add(){} var n = 100; var s = 'chao'; export {n,s} 引用: import * as a from './module.js' //as起別名 拋出:export default var person = { name:'張三', f1:function(){ alert(1); } }; export default person; 引用: import xxx from './module.js' xxx.name; xxx.f1();
你們如今爲止是否是以爲很麻煩啊,每次都須要自行webpack打包一下,每次改動都要打包,那麼腳手架提供給咱們方便咱們使用的框架,像這種 打包的事情就不須要本身作了,上面咱們學習的export和import就是咱們進行模塊化開發的基礎。
還記得咱們上面本身下載的vue.js嗎,這個文件是默認支持模塊化開發的,下面咱們看一個例子:
看我文件的目錄結構:
其中main.js是咱們要寫的js代碼,內容以下:
import Vue from './vue.js' //咱們想要進行模塊化開發,那麼要作的就是將每一個組件單獨放到一個js文件中,而不是在這裏在let一個組件了,固然咱們能夠寫在這個js文件中,可是每一個組件裏面可能還嵌套着其餘的組件而且有不少其餘的結構和代碼,若是都寫在這一個js文件中,會很亂,很難維護,因此咱們爭取將這些組件進行解耦,因此你看咱們又建立了一個App.js文件,文件名稱我用首字母大寫來寫的,目的是讓別人知道這是個組件 // let App = {}; // 引入咱們寫的App組件 import App from './App.js' new Vue({ el:'#app', data(){ return{ } }, template: ` <div> <div>我是Vue實例對象</div> <App></App> </div> `, components:{ App, } });
App.js內容以下:
//定義一個組件 let App = { template: ` <div> 我是App組件 </div> ` }; //將組件拋出 export default App;
index.html文件內容以下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"></div> <script src="bundle.js"></script> </body> </html>
而後咱們執行webpack指令打包一下js文件,js入口文件就是咱們的main.js,由於都是經過main.js引入的其餘的js文件中的內容,首先在終端cd切換到咱們的存放這些文件的文件夾下,而後執行指令:webpack ./main.js ./bundle.js,而後在index.html文件中引入一下咱們打包出來的bundle.js文件。
而後經過瀏覽器打開咱們的index.html文件,就看到了效果:
此時咱們發現,咱們每次改動js文件都要在終端輸入webpack指令來打包一下,比較麻煩:
因此咱們須要用一個簡單的方式來執行webpack指令,打包咱們的文件,那麼咱們就來學一下webpack的使用:
1.須要安裝nodejs,這個咱們已經安裝好了
2.執行npm init --yes 指令(不加--yes,你看看是什麼效果),默認會生成一個package.json文件(管理整個項目中的包資源,相似於咱們python的django框架中的settings.py配置文件,配置某些東西用的)
首先,修改一下咱們的目錄結構,把項目文件夾名稱改成英文的(否則會有一些編碼錯誤問題):
而後咱們在咱們的項目目錄下執行一下這個指令:其實這個指令也不要記了,後面咱們會有一鍵生成這個package.json文件的操做。
package.json文件建立好了以後,咱們就須要用它來管理咱們的包了,首先咱們要在咱們的項目裏面下載webpack包(以前webpack咱們是安裝在了全局,如今是搞到咱們的項目裏面,由於之後你的項目要打包上線的,現上不必定有你webpack的工具),執行指令npm i webpack@3.12.0 -D (-D,開發環境依賴,寫上就好了),執行完這個指令以後,咱們的項目目錄下就多了這個node_modules文件夾,未來你這個項目打包上線,咱們這個腳手架以及webpack工具須要的依賴就都在這個文件夾裏面了,直接把它也打包給咱們的線上環境。
而後看一下咱們的package.json文件:
{ "name": "03module_deep", "version": "1.0.0", "description": "", "main": "main.js", "scripts": { //如今主要看這裏,未來咱們執行num run test,就會執行這個scripts屬性裏面的test屬性對應的後面的腳本指令 "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "webpack": "^3.12.0" } }
好,既然如此,咱們想經過npm run dev,來執行webpack ./main.js ./bundle.js這個命令,寫起來就簡單多了,因此咱們須要配置一下上面這個文件中的scripts裏面的屬性,看配置:
{ "name": "03module_deep", "version": "1.0.0", "description": "", "main": "main.js", "scripts": { // "test": "echo \"Error: no test specified\" && exit 1", 注意,你使用我這個配置的時候,把我寫的這些註釋所有去掉,否則沒辦法打包編譯,會出錯 "dev": "webpack ./main.js ./bundle.js" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { //這是咱們當前項目裏面有的開發工具或者說是開發依賴,此時咱們的工具備一個,叫作webpack,未來若是須要其餘的工具,咱們安裝一下,這個地方就會顯示出來,此時咱們只安裝了webpack,因此只顯示了這個webpack的信息。 "webpack": "^3.12.0" } }
而後咱們把剛纔生成的bundle.js文件刪掉,而後執行一下num run dev指令,那麼這個指令就會執行咱們在package.json中配置的scripts屬性中的dev屬性對應的值,也就是咱們的那個webpack指令,那麼一樣會生成咱們的出口文件bundle.js ,看效果:
好,咱們經過npm run dev,代替了咱們咱們以前寫的打包指令webpack ./main.js ./bundle.js,下面咱們玩點webpack更高端的用法。
咱們如今經過webpack想DIY一個腳手架,那麼咱們必須知道webpack的四個核心概念:
1.入口(entry):就是入口文件
2.出口(output):出口文件
3.loader :文件類型轉換器
4.插件(plugins)
看webpack中文文檔:
文檔裏面有關於上面四個核心概念的解釋及應用。
入口和出口:
入口起點(entry point)指示 webpack 應該使用哪一個模塊,來做爲構建其內部依賴圖的開始。進入入口起點後,webpack 會找出有哪些模塊和庫是入口起點(直接和間接)依賴的。
每一個依賴項隨即被處理,最後輸出到稱之爲 bundles 的文件中,咱們將在下一章節詳細討論這個過程。
能夠經過在 webpack 配置中配置 entry
屬性,來指定一個入口起點(或多個入口起點)。默認值爲 ./src
。
出口(output) 屬性告訴 webpack 在哪裏輸出它所建立的 bundles,以及如何命名這些文件,默認值爲 ./dist
。基本上,整個應用程序結構,都會被編譯到你指定的輸出路徑的文件夾中。你能夠經過在配置中指定一個 output
字段,來配置這些處理過程。下面咱們來搞一搞。
首先建立一個名爲webpack.config.js的文件,必須是這個名字,這個文件就是用來配置咱們上面說的webpack的四個核心概念(功能)的地方,那麼先配置一下入口和出口,裏面寫下面的內容:
module.exports = { //入口配置 entry: { 'main':'./main.js', //入口文件路徑 }, //出口配置 output:{ 'filename':'./bundle.js', //出口文件名稱和路徑 } };
寫完這些東西后,咱們的package.json中的scripts的地方也須要修改一下:
{ "name": "03module_deep", "version": "1.0.0", "description": "", "main": "main.js", "scripts": { // "dev": "webpack ./main.js ./bundle.js" //配置完webpack.config.js文件以後,這裏就不這樣寫了,使用我這個內容的時候,別忘了將註釋都去掉 "dev": "webpack" //執行npm run dev,那麼就會找到webpack指令,而且這個webpack指令會找到webpack.config.js裏面的配置,來執行打包指令 }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "webpack": "^3.12.0" } }
而後咱們執行npm run dev指令,照樣生成咱們的bundle.js文件,打開咱們的index.html文件照樣可以實現頁面效果。
可是又一想,每次修改了咱們js文件裏面的代碼,好比修改了App.js組件裏面的代碼,咱們都須要手動的執行一下這個npm run dev的打包指令,比較麻煩,我想讓它自動執行怎麼辦,須要咱們在webpack.config.js文件中配置一個watch屬性,看配置:
module.exports = { //入口配置 entry: { 'main': './main.js', //入口文件路徑 }, //出口配置 output: { 'filename': './bundle.js', //出口文件名稱和路徑 }, //監聽,實時監聽代碼的改動,一旦改動了,自動進行打包,那麼就不要咱們手動執行npm run dev指令了 watch: true, };
那麼咱們只須要再執行一次npm run dev打包指令,之後咱們修改什麼App.js等文件的代碼以後,程序會自動會執行這個打包指令,來完成實時檢測代碼改動自動打包文件的效果,看操做:
首先執行一下npm run dev,你會發現終端的地方卡住了沒有結束(由於在實時監聽),而後經過瀏覽器打開index.html文件看效果:
而後,咱們改一下App.js這個組件中的代碼:
//定義一個組件 let App = { template: ` <div> 我是App組件aaaaa //以前這裏是沒有aaaaa的 </div> ` }; //將組件拋出 export default App;
以前咱們改完代碼,都須要再執行npm run dev打包指令,如今咱們就不須要了,直接到瀏覽器上刷新咱們的index.html看效果:
那麼咱們之後在咱們的開發環境中,只要配置好了webpack.config.js文件,那麼就執行一次打包指令,之後其餘js文件中有任何的改動,都會自動打包,省去了咱們手動執行打包指令的操做,方便了不少。
而後你可能又想,咱們開發環境中的關於webpack的配置有可能和咱們生產環境中使用這個項目的時候的配置不太同樣,因此咱們能不能單獨給開發環境和生產環境都作一個配置呢,也就是準備兩個webpack.config.js文件。
固然能夠了啦,往下看,首先咱們準備兩個配置文件,名爲webpack.dev.config.js(給開發環境準備的)和webpack.pro.config.js(給生產環境準備的),文件名字能夠隨便起昂,兩個文件我都用的相同的配置,這裏只是給你們演示一下。
webpack.dev.config.js內容以下:
module.exports = { //入口配置 entry: { 'main': './main.js', //入口文件路徑 }, //出口配置 output: { 'filename': './bundle.js', //出口文件名稱和路徑 }, //監聽,實時監聽代碼的改動,一旦改動了,自動進行打包,那麼就不要咱們手動執行npm run dev指令了 watch: true, };
webpack.pro.config.js內容以下:
module.exports = { //入口配置 entry: { 'main': './main.js', //入口文件路徑 }, //出口配置 output: { 'filename': './bundle.js', //出口文件名稱和路徑 }, //監聽,實時監聽代碼的改動,一旦改動了,自動進行打包,那麼就不要咱們手動執行npm run dev指令了 watch: true, };
好,咱們的文件配置完了,那麼咱們須要修改一下package.json文件中關於webpack指令的配置:
{ "name": "03module_deep", "version": "1.0.0", "description": "", "main": "main.js", "scripts": {
//修改了這裏:dev指令咱們在開發的時候用,build咱們在生產環境中一次性打包的時候使用, "dev": "webpack --config ./webpack.dev.config.js", //執行npm run dev,會找這個路徑的配置文件 "build": "webpack --config ./webpack.pro.config.js" //執行npm run build,會找這個路徑的配置文件 }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "webpack": "^3.12.0" } }
而後將咱們的bundle.js文件和咱們以前的webpack.config.js刪了,而後咱們再執行npm run dev看看效果,而後刪除生成的bundle.js文件,而後再執行npm run build看看效果,就完成了咱們給生產環境和開發環境的單獨配置,生產環境咱們執行npm run build,開發環境咱們執行npm run dev。
而後咱們將咱們的index.html和打包編譯好的bundle.js文件給服務器就能夠拿去上線了。
再想,咱們如今是否是隻完成了js文件的打包啊,也就js文件的模塊化開發,那咱們的項目還須要css、圖片等好多其餘類型的文件呢,怎麼搞,能不能經過webpack一塊兒打包呢,能夠的,往下看。
首先,咱們建立一個index.css文件,內容以下;
body{ background-color: red; }
以前咱們使用這個css文件是在咱們的html文件的head標籤中經過link標籤的來引入,可是咱們如今想,能不能將這個文件也經過打包,一塊兒打包到咱們的bundle.js文件中,而後讓html文件來使用呢?看騷操做:
首先咱們說咱們執行webpack打包指令的時候,打包的文件都是從一個入口文件開始打包的,由於入口文件裏面是開始引入其餘文件的最開始的地方,也就是咱們前面建立的那個main.js文件,那麼好,咱們須要在這個入口也引入一下這個css文件,
看main.js文件的內容:
import Vue from './vue.js' import App from './App.js' import './index.css' //關於文件的引入,直接就這樣引入就能夠了,上面兩個的引入是由於咱們引入的是文件中的變量,而這裏咱們直接引入的是文件,因此寫法上略有不一樣 new Vue({ el:'#app', data(){ return{ } }, template: ` <div> <div>我是Vue實例對象</div> <App></App> </div> `, components:{ App, } });
那麼此時咱們還須要webpack的第三個核心概念的配置,loader轉換器,其實對於webpack來講css文件也是一個模塊。
loader介紹
loader 讓 webpack 可以去處理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 能夠將全部類型的文件轉換爲 webpack 可以處理的有效模塊,而後你就能夠利用 webpack 的打包能力,對它們進行處理。
本質上,webpack loader 將全部類型的文件,轉換爲應用程序的依賴圖(和最終的 bundle)能夠直接引用的模塊。
好,首先咱們須要下載配置一些對應文件類型的loader轉換器,對於css文件的loader,咱們須要下載這兩個loader:css-loader和style-loader,css-loader是解析css文件的,而style-loader是解析style標籤的,是將css文件中的css屬性內容放到style標籤中,並將這個style標籤放到html文件的head標籤的轉換器,執行下面的指令:
npm i css-loader style-loader -D
執行指令以後,你看一下package.json文件,你就會發現這個package.json文件裏面多了一些內容,這下你就該明白這個文件是幹什麼的了吧,看文件內容
{ "name": "03module_deep", "version": "1.0.0", "description": "", "main": "main.js", "scripts": { "dev": "webpack --config ./webpack.dev.config.js", "build": "webpack --config ./webpack.pro.config.js" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { //這裏面多了這兩個loader,及對應的版本信息 "css-loader": "^2.1.1", "style-loader": "^0.23.1", "webpack": "^3.12.0" } }
而後咱們還須要在咱們的webpack.dev.config.js和webpack.pro.config.js文件中作一些loader的相關配置,我就把一個文件的內容給你們列舉出來吧,兩個文件如今是同樣的配置,看webpack.dev.config.js的內容:
module.exports = { //入口配置 entry: { 'main': './main.js', //入口文件路徑 }, //出口配置 output: { 'filename': './bundle.js', //出口文件名稱和路徑 }, //監聽,實時監聽代碼的改動,一旦改動了,自動進行打包,那麼就不要咱們手動執行npm run dev指令了 watch: true,
//這是關於webpack的核心指令中的loader的配置 module: { loaders: [ { test: /\.css$/, //正則表達式 loader: 'style-loader!css-loader' //注意寫法,!的做用是先執行後面的loader再執行前面的loader // 遇到後綴爲.css的文件,webpack先用css-loader加載器去解析這個文件 // 最後計算完的css,將會使用style-loader生成一個內容爲最終解析完的css代碼的style標籤,放到head標籤裏。 // webpack在打包過程當中,遇到後綴爲css的文件,就會使用style-loader和css-loader去加載這個文件。 } ] } };
修改了配置文件以後,咱們仍是須要執行npm run dev指令的,執行一下,而後瀏覽器打開index.html文件,你就看到css的效果了:
好,如今咱們看到了body的背景顏色已經有了,那麼若是是圖片呢,咱們怎麼玩,接着看,首先咱們先到網上下載一個圖片放到本地,放到咱們的項目目錄下,或者用圖片的網絡地址
首先,咱們先看看在哪裏顯示圖片呢,咱們如今就App.js這個插件,那咱們就在這個插件裏面顯示圖片把,因此咱們如今修改一下App.js這個文件內容,看代碼:
//引入本地圖片文件,將圖片內容做爲一個變量引入,也就是給這個圖片對象起了個變量名,後面咱們要經過這個變量名來使用這個圖片 import imgSrc from './meinv.jpg' //定義一個組件 let App = { data(){ return{ img:imgSrc,//使用數據屬性來接收一下圖片對象,而後在template中使用一下 } }, template: ` <div> 我是App組件aaaaa <div>
<!-- 執行了後面的npm run dev指令以後,默認會將咱們的圖片的名稱用base64來編碼,生成一個新的base64編碼名字的圖片文件 --> <img :src="img" alt="">
<img src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1554823994028&di=db5686fc98db2a66a0b4738645922f09&imgtype=0&src=http%3A%2F%2Fpic.feizl.com%2Fupload%2Fallimg%2F170614%2F1311511X7-2.jpg" alt="" width="200" height="200"> </div> </div> `, }; //將組件拋出 export default App;
而後下載安裝一下對應的loader,執行下面的指令:
npm i url-loader file-loader -D
而後看一下package.json文件的內容,又自動增長了一下內容:
{ "name": "03module_deep", "version": "1.0.0", "description": "", "main": "main.js", "scripts": { "dev": "webpack --config ./webpack.dev.config.js", "build": "webpack --config ./webpack.pro.config.js" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "css-loader": "^2.1.1", "file-loader": "^3.0.1", //多了它 "style-loader": "^0.23.1", "url-loader": "^1.1.2", //多了它 "webpack": "^3.12.0" } }
而後在咱們的webpack.dev.config.js和webpack.pro.config.js中添加一下咱們的圖片loader相關配置
module.exports = { entry: { 'main': './main.js', }, output: { 'filename': './bundle.js', }, watch: true, module: { loaders: [ { test: /\.css$/, loader: 'style-loader!css-loader' }, //配置圖片的loader { test:/\.(jpg|png|jpeg|gif|svg)$/, //正則 loader:'url-loader?limit=4000&name=pic/[name].[ext]' //對應的loader,limit是限制圖片大小的,單位是bytes } ] } };
其中limit=4000
表示小於4000bytes
的圖片將直接以base64的形式內聯在代碼中,能夠減小一次http請求;name=pic/[name].[ext]
表示大於4000bytes
的圖片將存入輸出路徑的pic/
文件夾下,而且圖片命名格式不變。
而後執行npm run dev指令,而後咱們用瀏覽器打開index.html文件看效果,兩個圖片都顯示出來了:
若是說咱們的html文件中須要引入其餘的html文件怎麼辦呢,能不能也把其餘的html經過webpack打包呢,也是能夠的,接着看:
執行下面的指令:
npm i html-webpack-plugin --save-dev
而後在配置文件中配置loader
module.exports = { entry: { 'main': './main.js', //入口文件路徑 }, output: { 'filename': './bundle.js', //出口文件名稱和路徑 }, watch: true, module: { loaders: [ { test: /\.css$/, //正則表達式 loader: 'style-loader!css-loader' //注意寫法,!的做用是先執行後面的loader再執行前面的loader }, //配置圖片的loader { test:/\.(jpg|png|jpeg|gif|svg)$/, //正則 loader:'url-loader?limit=4000' //對應的loader }, //配置html文件的 { test:/\.less$/, loader:'style-loader!css-loader!less-loader' } ] } };
而後執行npm run dev指令就能夠了,App.js中引入html文件也是用import,寫法和引入圖片的寫法相同,就很少演示了。
好,到目前位置,咱們已經能夠完成整個頁面中資源的加載和引用了,也就是完成了模塊化的開發,可是如今發現咱們的目錄結構太亂了,咱們來調整一下目錄結構,如今的目錄結構是這樣的:
調整一下目錄,咱們在咱們的項目目錄下建立一個src文件夾存放咱們的main.js、App.js、index.css等文件,也就是咱們開發時寫的內容文件,放到src文件夾中,而後咱們的打包輸出的bundle.js先給他刪除,還有個vue.js文件,這是vue的功能文件,若是咱們下載的這個vue.js文件的形式來使用的vue,那麼這個vue.js文件通常也是放到src文件夾中的,若是咱們是經過npm install vue的形式下載的,那麼這個vue會在咱們目錄中的那個node_modules文件夾中,圖片文件好比咱們的meinv.jpg文件放到一個static文件夾下面的pic文件夾下面,而後調整後的目錄結構是下面這樣的:
圖片位置發生變化了,別忘了改咱們的引入圖片的地方的代碼,咱們在App.js這個模塊中引入的圖片,因此咱們修改一下App.js文件,看代碼:
//引入圖片文件,將圖片內容做爲一個變量引入,也就是給這個圖片對象起了個變量名,後面咱們要經過這個變量名來使用這個圖片 import imgSrc from '../static/pic/meinv.jpg' //修改成這個路徑 // let imgSrc = require('../meinv.jpg'); 這樣寫也行 console.log(imgSrc); //定義一個組件 let App = { data(){ return{ img:imgSrc,//使用數據屬性來接收一下圖片對象,而後在template中使用一下 } }, template: ` <div> 我是App組件aaaaa <div> <img :src="img" alt=""> <img src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1554823994028&di=db5686fc98db2a66a0b4738645922f09&imgtype=0&src=http%3A%2F%2Fpic.feizl.com%2Fupload%2Fallimg%2F170614%2F1311511X7-2.jpg" alt="" width="200" height="200"> </div> </div> `, }; //將組件拋出 export default App;
咱們未來想將打包的那個bundle.js文件保存在一個叫作dist的文件夾下怎麼搞呢,須要配置一下咱們的webpack.dev.config.js和webpack.pro.config.js文件,看配置後的內容:
//引入nodejs的path模塊,解析路徑用的 const path = require('path'); module.exports = { entry: { 'main': './src/main.js', //main的路徑變了,別忘了修改 }, //出口配置也須要改一下 output: { // 'filename': './bundle.js', //出口文件名稱和路徑 //文件目錄調整以後,咱們的出口文件配置也須要該一下,意思是將咱們打包以後的那個js文件保存到一個咱們設定的位置,看下面的寫法 path:path.resolve('./dist'),//相對轉絕對,這個path至關於python中的os.path功能模塊,它是nodejs的模塊,咱們須要在上面引入一下這個模塊 filename:'bundle.js' //出口文件名稱,如今這個配置的意思是在咱們的項目目錄下生成一個dist文件夾,而且將全部打包的模塊(也就是文件),以bundle.js文件名稱保存在這個dist文件夾中 }, watch: true, module: { loaders: [ { test: /\.css$/, loader: 'style-loader!css-loader' }, { test:/\.(jpg|png|jpeg|gif|svg)$/, loader:'url-loader?limit=4000' }, { test:/\.less$/, loader:'style-loader!css-loader!less-loader' } ] } };
而後咱們執行npm run dev指令,看效果,目錄結構中就多了dist文件夾,文件夾中就有了咱們打包的bundle.js文件,還有咱們配置的圖片,也就是這個dist文件夾是給咱們未來上線的服務器用的,其中圖片是咱們須要的,也就幫你一塊兒打包到了這個dist文件夾裏面,未來咱們在服務器上作一下相關路徑配置就能夠了,好,看看咱們的目錄結構:
咱們說這個dist文件夾是未來給咱們的服務器的,那麼咱們html文件好比咱們的index.html文件是否是也要發給服務器啊,固然啦,因此咱們也但願咱們的html文件資源也會自動打包到咱們的dist文件夾下,那麼此時咱們就須要在進行一些配置,往下看:
先下載一個loader,執行下面的指令:
npm i html-webpack-plugin --save-dev #--save-dev就是 -D的意思
而後咱們看一下package.json文件的變化:
{ "name": "03module_deep", "version": "1.0.0", "description": "", "main": "main.js", "scripts": { "dev": "webpack --config ./webpack.dev.config.js", "build": "webpack --config ./webpack.pro.config.js" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "css-loader": "^2.1.1", "file-loader": "^3.0.1", "html-webpack-plugin": "^3.2.0", //多了一個它 "style-loader": "^0.23.1", "url-loader": "^1.1.2", "webpack": "^3.12.0" } }
執行完上面的指令,此時就須要用咱們webpack中的另一個核心內容,插件plugins。
插件plugins
loader 被用於轉換某些類型的模塊,而插件則能夠用於執行範圍更廣的任務。插件的範圍包括,從打包優化和壓縮,一直到從新定義環境中的變量。插件接口功能極其強大,能夠用來處理各類各樣的任務。
想要使用一個插件,你只須要 require()
它,而後把它添加到 plugins
數組中。多數插件能夠經過選項(option)自定義。你也能夠在一個配置文件中由於不一樣目的而屢次使用同一個插件,這時須要經過使用 new
操做符來建立它的一個實例。
好,咱們來配置一下咱們的那兩個配置文件,webpack.dev.config.js和webpack.pro.config.js,內容以下:
const path = require('path'); //引入咱們下載好的html文件的插件包 const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: { 'main': './src/main.js', }, output: { path:path.resolve('./dist'), filename:'bundle.js' }, watch: true, module: { loaders: [ { test: /\.css$/, loader: 'style-loader!css-loader' }, { test:/\.(jpg|png|jpeg|gif|svg)$/, loader:'url-loader?limit=4000&name=pic/[name].[ext]' / }, { test:/\.less$/, loader:'style-loader!css-loader!less-loader' }, ] }, //配置插件 plugins:[ new HtmlWebpackPlugin({ //插件的執行運行與元素索引有關 template:'./index.html', //參照物,也就是未來打包的時候,打包哪一個html文件啊,要給他一個參照 }) ] };
而後咱們執行npm run dev指令,而後看咱們的目錄結構
那麼打開這個dist文件夾下的index.html文件看一下里面的內容:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"></div> <script src="./dist/bundle.js"></script>
<!-- 自動幫咱們在index.html爲你暗中添加了下面這個script標籤,並引入了bundle.js,因此之後咱們打包html文件的時候,以前的html裏面的用來引入bundle.js的script就能夠刪除了,也就是上面這個咱們以前寫的script標籤 --> <script type="text/javascript" src="bundle.js"></script></body> </html>
用瀏覽器打開這個index.html文件,看看效果,徹底ok:
其實最後咱們無論怎麼開發,開發完成以後都要交給運維部署到線上,而咱們給運維人員的東西就這個打包好的dist文件夾,裏面有咱們開發好的項目的全部資源。
其實咱們要進行組件化開發,咱們如今尚未作完,咱們繼續完善昂,首先咱們src裏面都是咱們開發的內容,其中咱們的App組件應該是.vue結尾的文件,而後進行單文件引入功能,若是想進行單文件引入,那麼須要兩個工具,一個是vue-loader,一個是vue-template-compiler,那咱們來下載一下,執行下面的指令: vue-loader就是用來解析咱們的.vue結尾的文件的,vue-template-compiler是用來編譯.vue結尾的文件中的template模板的。
npm install vue-loader@14.1.1 vue-template-compiler@2.5.16 -D #注意這個vue-template-compiler要和你的vue版本一致
那麼未來咱們進行組件化開發,寫.vue結尾的文件組件時的結構是這樣的,看代碼:
//組件的模板結構 <template> <div> {{ text }} </div> </template> //組件的業務邏輯 <script> export default { data(){ return { text:'hello Single file' } } } </script> //組件的樣式 <style> body{ background-color: green; } </style>
好,上面的命令執行完以後,咱們之後在寫組件就用.vue結尾的文件來寫,那麼咱們將咱們的App.js文件改成App.vue文件,而後App.vue文件裏面的內容就要按照上面的這種模板樣式來寫了。
而後咱們還須要在咱們的webpack.dev.config.js中配置一些內容:
const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: { 'main': './src/main.js', }, output: { path: path.resolve('./dist'), filename: 'bundle.js' }, watch: true, module: { loaders: [ { test: /\.css$/, loader: 'style-loader!css-loader' }, { test: /\.(jpg|png|jpeg|gif|svg)$/, loader: 'url-loader?limit=4000&name=pic/[name].[ext]' }, { test: /\.less$/, loader: 'style-loader!css-loader!less-loader' }, // 處理Vue文件,注意,就多了下面這個loader的配置 { test: /\.vue$/, loader: 'vue-loader' } ] }, plugins: [ new HtmlWebpackPlugin({ template: './index.html', }) ] };
而後咱們在App.vue文件中寫上下面的內容,看代碼:
//template是個標籤,咱們下載的那個vue-template-compiler解析提供的,也是經過它來編譯這個標籤內容,而咱們下載的安格vue-loader是解析vue文件的 <template> <div> 我是Jedan </div> </template> <script> export default { name:'App',//能夠給這個組件起個名字 data(){ return{ } }, methods:{ }, //以前組件裏面咱們會寫一個template的屬性,如今不用了,由於咱們下載的工具自動幫咱們建立了一個template模板標籤,咱們在上面直接使用就能夠了 //template:``, } </script> <style> </style>
別忘了咱們以前是在main.js裏面引入的App.js,如今咱們的文件叫App.vue了,你引入的地方也要改,看main.js的代碼:
import Vue from './vue.js' import App from './App.vue' //這個文件的名字別忘了改 import './index.css' new Vue({ el:'#app', data(){ return{ } }, template: ` <div> <div>我是Vue實例對象</div> <App></App> </div> `, components:{ App, } });
而後執行一下npm run dev,而後經過瀏覽器打開index.html文件看效果:完美:
那麼未來關於咱們寫的全部組件,咱們均可以放到src文件夾下的一個叫作components的文件夾中,看目錄結構
而後咱們基於這種結構作一個單頁面應用:
首先,作單頁面應用會用到咱們的vue-router,因此咱們須要給咱們的項目下載一下vue-router,咱們也能夠將咱們以前用過的vue-router.js文件拿過來用,可是之後不建議下載文件來使用了,咱們都直接經過指令給咱們的項目來如今這些功能,包括vue.js,因此咱們將vue.js文件刪了吧,咱們經過npm下載,來執行下面指令,注意執行下載項目中須要的工具的時候,在終端下載的時候,咱們要確保咱們在本身項目目錄下執行的指令。
npm install vue@2.5.16 vue-router -S #下載vue(注意版本要和上面的vue-template-compiler版本一致)和vue-router,-S的是項目環境依賴,而以前咱們下載的webpack會用到的一些工具,是開發環境依賴,沒有那些東西,你的項目照樣能跑起來,只不過不太方便,可是沒有vue和vue-router,你的單頁面應用是跑不起來的
執行上面的指令以後,咱們看一下package.json文件的內容:
{ "name": "03module_deep", "version": "1.0.0", "description": "", "main": "main.js", "scripts": { "dev": "webpack --config ./webpack.dev.config.js", "build": "webpack --config ./webpack.pro.config.js" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "css-loader": "^2.1.1", "file-loader": "^3.0.1", "html-webpack-plugin": "^3.2.0", "style-loader": "^0.23.1", "url-loader": "^1.1.2", "vue-loader": "^14.1.1", "vue-template-compiler": "^2.5.16", "webpack": "^3.12.0" }, "dependencies": { //多了它 "vue": "^2.6.10", "vue-router": "^3.0.3" } }
而後別忘了,咱們以前main.js裏面是導入vue.js文件來使用vue功能的,可是如今咱們已經把vue.js刪了,而且是經過npm下載的vue,那麼引用vue的時候,引用方式要改一改,看mian.js的內容:
// 再也不是引用文件的形式引用vue了 // import Vue from './vue.js' import Vue from 'vue' //而是直接這樣引用,像引用內置模塊的形式 import App from './App.vue' import './index.css' new Vue({ el:'#app', data(){ return{ } }, template: ` <div> <div>我是Vue實例對象</div> <App></App> </div> `, components:{ App, } });
既然咱們要作單頁面應用使用main.js,那麼咱們把main.js的代碼改一改,引用vue-router,看代碼:
// 再也不是引用文件的形式引用vue了 // import Vue from './vue.js' import Vue from 'vue' //而是直接這樣引用,像引用內置模塊的形式 import App from './App.vue' import './index.css' //引入vue-router import VueRouter from 'vue-router' //注意,引入咱們下載好的包的時候,from後面必定是包的名字,前面import後面的名字你能夠隨便起,儘可能不要和你的包名字相同,如今的意思是個人vue-router功能包被引入進來了,而且起了個名字叫作VueRouter //聲明組件(引入組件) import Home from './components/Home/Home.vue' import Course from './components/Course/Course.vue' //別忘了,基於模塊化開發的時候,咱們還要執行一下Vue.use(VueRouter) Vue.use(VueRouter); //接下來就能夠寫咱們的路由了,建立路由對象,別忘了將這個路由對象寫到vue實例中 const router = new VueRouter({ //配置路由信息 routes:[ { path:'/', name:'Home', component:Home //對應Home組件,而咱們的Home組件在src文件夾下的components文件夾的Home文件夾下面,因此咱們在上面就須要引入一下咱們的Home組件了 }, { path:'/course', name:'Course', component:Course //對應Home組件,而咱們的Home組件在src文件夾下的components文件夾的Home文件夾下面,因此咱們在上面就須要引入一下咱們的Home組件了 } ] }); new Vue({ el:'#app', router,//給vue實例綁定路由對象 data(){ return{ } }, //使用render方法來渲染,由於後面我們要下載一個個webpack-dev-server,高級一些的webpack打包工具,可是不太支持下面原來的寫法,因此我換成了render方法 render:c=>c(App), // template: // ` // <div> // <div>我是Vue實例對象</div> // <App></App> // </div> // `, // components:{ // App, // } });
而後咱們的App.vue裏面就可使用咱們的router-link和router-view了,看代碼:
//template是個標籤,咱們下載的那個vue-template-compiler解析提供的,也是經過它來編譯這個標籤內容,而咱們下載的安格vue-loader是解析vue文件的 <template> <div> 我是Jedan <router-link :to="{name:'Home'}">首頁</router-link> <router-link :to="{name:'Course'}">課程頁</router-link> <router-view></router-view> </div> </template> <script> export default { name:'App',//能夠給這個組件起個名字 data(){ return{ } }, methods:{ }, //以前組件裏面咱們會寫一個template的屬性,如今不用了,由於咱們下載的工具自動幫咱們建立了一個template模板標籤,咱們在上面直接使用就能夠了 //template:``, } </script> <style> </style>
而後咱們寫一下咱們的Home組件和Course組件:
Home.vue代碼以下:
<template> <div> 這裏是首頁 </div> </template> <script> export default { data(){ return{ } } } </script>
Course.vue代碼以下:
<template> <div> 這裏是課程頁 </div> </template> <script> export default { data(){ return{ } } } </script>
組件都寫好了以後,咱們再學一個新東西,叫作webpack-dev-server,比webpack更高級一些的打包工具,是基於服務器的,他可以在前端起服務器,來服務端的形式打開咱們的vue項目,這個工具能夠自動打開瀏覽器、熱更新、自動刷新等功能,下面咱們來下載一下,執行指令:
npm install webpack-dev-server --save-dev
這個webpack-dev-server模塊的經常使用配置參數以下:
經常使用配置參數 --open 自動打開瀏覽器 --hot 熱更新 ,不在刷新的狀況下替換 css樣式 --inline 自動刷新 --port 9999 指定端口 --process 顯示編譯進度
下載好了之後,咱們來使用一下,還記得咱們以前在package.json文件中如何配置咱們的webpack指令的嗎,就是執行那個npm run dev,就會執行webpack打包的那個地方,咱們須要改一改寫法了,我下面只修改一下開發環境的那個webpack指令,看packag.json的內容:
{ "name": "03module_deep", "version": "1.0.0", "description": "", "main": "main.js", "scripts": { "dev": "webpack-dev-server --open --hot --inline --config ./webpack.dev.config.js", //就是這個地方,以前是用的webpack --config ./webpack.dev.config.js,如今用咱們的webpack-dev-server了,使用webpack-dev-server,不會幫你生成dist文件夾,由於你是開發環境,webpack會幫你生成 "build": "webpack --config ./webpack.pro.config.js" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "css-loader": "^2.1.1", "file-loader": "^3.0.1", "html-webpack-plugin": "^3.2.0", "style-loader": "^0.23.1", "url-loader": "^1.1.2", "vue-loader": "^14.1.1", "vue-template-compiler": "^2.5.16", "webpack": "^3.12.0", "webpack-dev-server": "^2.11.5" }, "dependencies": { "vue": "^2.5.16", "vue-router": "^3.0.3" } }
好,配置好之後,咱們把以前webpack打包出來的那個dist文件夾刪除,而後再執行npm run dev,就會經過webpack-dev-server來打包,而且它自動會幫咱們打開頁面
而後你就看到了頁面效果,看瀏覽器的地址欄,是一個服務端的形式:
而後你在組件的模板中隨便改寫內容,頁面會自動刷新,不須要你手動刷新了。
好,到這裏,咱們的DIY腳手架就算是搭建完成了,那麼咱們說一下咱們的目錄結構,其實咱們未來用腳手架,dist文件夾是沒有的,咱們本身開發完以後,經過打包才生成的,好了,感覺了一下搭建腳手架的過程,DIY腳手架你們不用會,理解過程就好了,咱們仍是學習怎麼用人家vue給咱們提供的腳手架吧,繼續下面的學習~~
首先咱們對比一下vue-cli2x版本和vue-cli3x版本的一些區別,如今2x版本的:
安裝
npm install -g vue-cli
用法
$ vue init < template-name模塊名 > < project-name項目名 >
建立一個例子:
$ vue init webpack my-project
目前除了webpack以外,其餘的一些可用模塊:
目前可用的模塊包括: - [webpack](https://github.com/vuejs-templates/webpack) - 一個功能齊全的Webpack + vue-loader設置,具備熱重載,linting,測試和css提取功能。 - [webpack-simple](https://github.com/vuejs-templates/webpack-simple) - 一個簡單的Webpack + vue-loader設置,用於快速原型設計。
目前主要用的上面兩個,webpack-simple簡單一些,webpack功能更加齊全
- [browserify](https://github.com/vuejs-templates/browserify) -全功能Browserify + vueify設置用熱重裝載,linting&單元測試。 - browserify [-simple](https://github.com/vuejs-templates/browserify-simple) - 一個簡單的Browserify + vueify設置,用於快速原型設計。 - [pwa](https://github.com/vuejs-templates/pwa) - 基於webpack模板的vue-cli的PWA模板,主要應用於移動端的開發 - [simple](https://github.com/vuejs-templates/simple) - 單個HTML文件中最簡單的Vue設置
而後咱們下用webpack-simple來建立一個項目,在你的目錄下執行下面的指令:
而後咱們的目錄下就有了這個項目的文件,咱們看一下目錄結構:
而後說幾個目錄下的其餘文件是幹什麼的,做爲了解吧:
那麼node_modules這些依賴包怎麼下載呢,咱們看一下咱們都少了哪些依賴包和工具啊,看一下自動生成的package-lock.json文件:
好,咱們切換到咱們的項目目錄下,而後執行一個npm install指令,就會自動幫咱們下載項目的依賴了:
而後執行指令npm run dev指令,你就會發現,頁面自動打開了:
頁面效果:
好,一個vue的項目就成型了,就像咱們學python的時候,經過django建立一個項目,直接一運行,看到django給大家提供的首頁似的那個感受。
而後咱們看一下執行npm run dev指令後的一個項目執行順序:
若是未來咱們項目寫完了,想打包發給上線人員,那麼咱們執行npm run build指令,就會生成打包好的dist文件夾,裏面有我們的圖片文件,js文件等,若是你安裝了我們說的那個html文件打包插件,那麼這個dist文件夾裏面也有我們的html文件。
而後看一下webpack.config.js裏面的內容:
var path = require('path') //引入路徑解析墓模塊 var webpack = require('webpack') //引入webpack module.exports = { entry: './src/main.js', //webpack打包時的入口文件,未來咱們就先從這個文件開始玩我們的項目 output: { //出口文件配置 path: path.resolve(__dirname, './dist'), //__dirname是項目的絕對路徑,resolve將他倆拼接了一下 publicPath: '/dist/', filename: 'build.js' }, module: { rules: [ //能夠寫成loaders { test: /\.css$/, //打包css文件用的 use: [ 'vue-style-loader', 'css-loader' ], }, { test: /\.vue$/, //打包vue文件用的 loader: 'vue-loader', options: { loaders: { } // other vue-loader options go here } }, { test: /\.js$/, //打包js文件用的 loader: 'babel-loader', exclude: /node_modules/ }, { test: /\.(png|jpg|gif|svg)$/, //打包圖片文件用的 loader: 'file-loader', options: { name: '[name].[ext]?[hash]' } } ] }, resolve: { alias: { //別名 'vue$': 'vue/dist/vue.esm.js' //esm是esmodule }, extensions: ['*', '.js', '.vue', '.json'] //擴展,凡是後綴名有他們幾個的文件,後綴名能夠忽略不寫 }, //在下面的那些配置咱就很少看了 devServer: { historyApiFallback: true, noInfo: true, overlay: true }, performance: { hints: false }, devtool: '#eval-source-map' } if (process.env.NODE_ENV === 'production') { module.exports.devtool = '#source-map' // http://vue-loader.vuejs.org/en/workflow/production.html module.exports.plugins = (module.exports.plugins || []).concat([ new webpack.DefinePlugin({ 'process.env': { NODE_ENV: '"production"' } }), new webpack.optimize.UglifyJsPlugin({ sourceMap: true, compress: { warnings: false } }), new webpack.LoaderOptionsPlugin({ minimize: true }) ]) }
項目的入口是main.js文件,打開看看,你會發現你很熟悉:
import Vue from 'vue' //引入vue import App from './App.vue' //引入App組件,也是咱們建立項目時自動給你生成好的,有import,那麼App.vue文件中確定有export new Vue({ el: '#app', render: h => h(App) //掛載,使用APP組件,和template+components同樣,可是webpack-dev-server支持這個方法,不支持template, })
而後看一下App.vue組件中的內容:就是我們建立完項目,下載完依賴,而後執行npm run dev指令以後你看到的那個頁面裏面的內容:
<template>//還記得.vue結尾的文件的模板嗎,template script style三個標籤,template是組件中頁面渲染的標籤,script標籤中拋出組件,style標籤中寫css樣式,之後,咱們直接把下面這些內容清空,也咱們的單頁面應用就能夠了 <div id="app"> <img src="./assets/logo.png"> <h1>{{ msg }}</h1> <h2>Essential Links</h2> <ul> <li><a href="https://vuejs.org" target="_blank">Core Docs</a></li> <li><a href="https://forum.vuejs.org" target="_blank">Forum</a></li> <li><a href="https://chat.vuejs.org" target="_blank">Community Chat</a></li> <li><a href="https://twitter.com/vuejs" target="_blank">Twitter</a></li> </ul> <h2>Ecosystem</h2> <ul> <li><a href="http://router.vuejs.org/" target="_blank">vue-router</a></li> <li><a href="http://vuex.vuejs.org/" target="_blank">vuex</a></li> <li><a href="http://vue-loader.vuejs.org/" target="_blank">vue-loader</a></li> <li><a href="https://github.com/vuejs/awesome-vue" target="_blank">awesome-vue</a></li> </ul> </div> </template> <script> export default { name: 'app', data () { return { msg: 'Welcome to Your Vue.js App' } } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } h1, h2 { font-weight: normal; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; } </style>
好,接下來咱們就要玩咱們的單頁面應用了,還記得單頁面應用須要什麼嗎,vue-router,首先下載,執行下面的指令:
npm i vue-router -S 注意,別用-g,而是用-S,由於-g是下載到全局了,全局的意思就是咱們下載安裝vue的我們那個電腦目錄裏面了,而-S是下載到咱們當前項目的依賴中了,不同的昂
而後咱們須要寫咱們路由配置了,在哪裏配置呢,還記得嗎,就是咱們的main.js文件,而且以前咱們寫路由配置信息的時候,都是寫在了這個文件裏面,那麼隨着咱們項目愈來愈大,你會發現路由信息會愈來愈多,那麼爲了方便管理,咱們應該將路由信息單獨的放到一個文件裏面去,而且,咱們路由確定都對應着組件,也就是說未來的組件也會愈來愈多,因此組件咱們也單獨的存放起來,而且咱們之後開發,都只關注src文件夾裏面的內容,因此路由和組件都放到src文件夾裏面,看下面的目錄結構:
目錄結構搞好了,咱們就開始開發了,看代碼:
main.js代碼以下:
import Vue from 'vue' import App from './App.vue' //導入router路由配置信息,由於咱們要在vue實例對象裏面掛載一下,還記得嗎 // import router from './router/router-config' //還記得webpack.config.js裏面有個配置說,凡是.js等結尾的文件,能夠不寫後綴名嗎,寫不寫均可以 import router from './router/router-config.js' //有import,就確定要在router-config.js文件中有個export拋出router對象 new Vue({ el: '#app', router,//掛載router對象 render: h => h(App) });
router-config.js路由配置信息代碼以下:
//引用vue,由於vue-router依賴於vue import Vue from 'vue' import VueRouter from 'vue-router' //引入對應的組件 import Home from '../components/Home/Home' import Course from '../components/Course/Course' //給Vue加載一下VueRouter,其實相似於繼承一下 Vue.use(VueRouter); const router = new VueRouter({ routes:[ { path:'/home', name:'Home', component:Home, }, { path:'/course', name:'Course', component:Course, } ] }); export default router;
接下來是對應組件,Home.vue組件代碼以下:
<template> <div> 這是首頁 </div> </template> <script> export default { //拋出組件,供別的地方引用 name:'Home', // 這個name在作全局組件的時候比較有用,還記得全局組件怎麼建立嗎?vue.component('Home',{}),第一個參數就是組件名稱,其餘組件使用這個全局組建的時候就靠的這個組件名稱,而咱們這裏寫的name,就能夠起到這個做用,未來別人掛載你的組件的時候,就用它 data(){ return{ } } } </script> <style> </style>
Course.vue組件代碼以下:
<template> <div> 這是課程頁 </div> </template> <script> export default { name:'Course', data(){ return{ } } } </script> <style> </style>
而後是App.vue組件中要引入這兩個組件了,看App.vue文件的代碼以下:
<template> <div id="app"> <!-- 經過路由對應路徑,自動生成a標籤,href屬性指向對應的路徑,還記得嗎? --> <router-link :to="{name:'Home'}">首頁</router-link> <router-link :to="{name:'Course'}">課程頁</router-link> <!-- 組件出口 --> <router-view></router-view> </div> </template> <script> export default { name: 'App', data () { return { msg: 'Jaden' } } } </script> <style> </style>
而後執行npm run dev,直接就看到了咱們頁面效果,點擊首頁就看到了首頁內容,點擊課程頁,就看到了課程頁內容:
齊活,咱們的項目就寫完了,哈哈
接下來咱們玩一下CSS樣式,學一個scoped屬性。
我給App組件還有Home和Course組件都加了個h2標籤,而後App組件的style標籤中給h2標籤設置了樣式,你們看圖:
看效果:
因爲App組件算是咱們整個頁面的大組件,全局組件,因此若是直接按照上面的方式來設置樣式,那麼App組件中嵌套的其餘組件也會應用上這個樣式,而且若是咱們在其餘組件裏面給h2標籤設置了其餘的樣式,那麼只要點擊加載過這個組件,那麼全局的全部的組件的h2標籤的樣式就會編程這個樣式,因此很很差控制,看圖:
看效果,首先剛開始的時候,咱們頁面加載了App組件,效果是這樣的:
可是隻要點擊了Course組件,看效果:
你會發現,這樣很難控制咱們每一個組件的本身的樣式,這怎麼搞呢,style標籤的scoped屬性,注入的意思。
看效果:
這就是scoped屬性的做用。
以上是咱們使用webpack-simple模塊建立的項目的玩法,但實際工做中咱們用的通常都是webpack模塊,複雜一些的模塊,功能也多,並且文件夾都給我們分好了。可是學了webpack-simple以後,webpack對你來講也簡單了,接下來咱們學一下wepack模塊建立項目的玩法。
首先咱們經過webpack來建立一個項目,在IDE終端執行下面的指令
vue init webpack 05-webpack-project(項目名稱)
而後終端會給我們一些提示輸入信息的選項,看下圖:
除了上面這些提示,還有一些提示,接着看:
這裏項目的依賴,我選擇的是npm下載,回車,而後等一會就下載完了,下載完以後還有提示:
而後按照提示,咱們cd到咱們的項目目錄下,執行npm run dev指令,就啓動咱們的項目了,在終端你會看到這個:
而後拿着這個ip地址和端口,到咱們的瀏覽器上訪問一下,就看到咱們的頁面了:
下面咱們看一下新生成的項目的目錄結構:
而後咱們執行npm run dev會執行什麼呢,還記得嗎,是否是找package.json裏面的scripts屬性裏面的dev對應的那個指令啊:
而後看一下這個webpack.dev.conf.js文件:
而後看一下這個webpack.base.conf.js文件,就看到了咱們熟悉的內容:
那麼這些配置文件我們其實都不用管,咱們只須要專一的玩咱們src文件夾裏面的內容就能夠了,開發者只須要關心src這個文件夾,那麼咱們先從入口文件main.js看看裏面的內容:
而後你會發現,其實這個main.js文件你都不用管了,咱們只須要在咱們的src文件夾裏面的App.vue組件寫一寫,而後把components文件下的組件寫一寫、分一分,而後把router文件夾下的index.js路由配置信息改一改,就完事兒了。下面我就簡單的寫一個單頁面應用,你們感覺一下吧,先看目錄結構:
而後直接上代碼:
main.js文件內容以下:
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import router from './router' Vue.config.productionTip = false /* eslint-disable no-new */ new Vue({ el: '#app', router, components: { App }, template: '<App/>' })
router文件夾下的index.js路由配置信息內容以下:
import Vue from 'vue' import Router from 'vue-router' // import HelloWorld from '@/components/HelloWorld' //@還記得嗎,表示src文件夾的根路徑 //引入組件 import Course from '@/components/Course/Course' import Home from '@/components/Home/Home' // console.log(Course); //給Vue添加vue-router功能,使用別人提供的功能都要用Vue來use一下 Vue.use(Router) //建立路由對象 export default new Router({ mode:'history', //去掉瀏覽器地址欄的#號 //配置路由信息 routes: [ { path: '/', // redirect:'Home' //直接跳轉Home名字對應的path路徑上 redirect:'/home' }, { path: '/home', name: 'Home', component: Home }, { path: '/course', name: 'Course', component: Course } ] })
App.vue組件文件的內容以下:
<template> <div id="app"> <router-link :to="{name:'Home'}">首頁</router-link> <!--<router-link :to="{name:'Home',query:{user_id:2}}">首頁</router-link>--> <!--query:{user_id:2} 是query參數,拼接到路徑上是這樣的/home?user_id=2,這也是動態路由的一種,以前咱們說了一個param參數,這個param參數是/home/2,拼接在路徑上的--> <router-link :to="{name:'Course'}">免費課程</router-link> <!-- 組件出口 --> <router-view></router-view> </div> </template> <script> export default { name: 'App', data(){ return{ } }, } </script> <style> </style>
Home.vue組件內容以下:
<template> <div> 這是Home頁面 </div> </template> <script> export default { name: 'Home', data(){ return{ } }, } </script> <style> </style>
Course.vue組件內容以下:
<template> <div> 這是Course頁面 </div> </template> <script> export default { name: 'Course', data(){ return{ } }, } </script> <style> </style>
把這幾個文件寫好,那麼咱們執行npm run dev,就啓動咱們的項目了,按照ip地址和端口的提示,咱們在瀏覽器上訪問一下這個地址,就看到咱們的頁面應用了:
效果:
很是好,單頁面應用咱們就寫完了,剩下的就是完善網站的功能和美化頁面效果了。
簡單總結一下:
1. webpack:
entry:整個項目的程序入口(通常是main.js或index.js)
output:輸出的出口
loader:加載器、轉化器和對es6代碼的解析(這個解析用的是babel編譯器,你們能夠去看看babel),有些低版本的瀏覽器不能識別es6的代碼,爲了作這種兼容性,也就是爲了讓低版本的瀏覽器可以識別es6的代碼,前端在webpack通常用這個babel loader去處理,去解析,看babel官網。
再好比還有什麼css-loader解析css文件和style-loader將css代碼添加一個style標籤,插入到header標籤中,而且支持模塊化。還有一些圖片引入等用的是url-loader,還有不少其餘的loader,他的做用就是對咱們的靜態文件資源作支持的。
plugins:插件,好比那個html-webpack-plugin,打包html文件用的,還有一些插件作代碼壓縮的(那個醜陋js插件),還有分割js文件的插件,好比js文件比較大的時候,會一部分一部分的加載,還有咱們知道我們如今是組件化開發,每一個組件都有本身的js文件,而目前爲止咱們都是將全部的js文件所有打包了,每次使用都是將全部的js代碼所有加載到瀏覽器上,可是若是作個很是大型的項目,咱們應該考慮,點擊一個頁面,這個頁面對應的那些組件的js代碼才加載到頁面上,也就是將js代碼或者js文件分開,這個就稍微麻煩一些了,你們能夠去研究一下webpack。前端作的工做還有就是項目上線以前,對整個項目進行優化。webpack內容不少,若是想作一個專業的前端,須要好好學習和關注webpack,還有其餘的前端社區,最新的技術都是須要學習的,不光前端如此,後端也是如此,機會是給有準備的人的。
2.使用vue-cli
a.電腦上(linux,windows等)須要安裝nodejs,使用npm包管理器
b.npm下載腳手架,若是你下載的是最新的3.x版本的,那麼別忘了拉一下2.x版本的橋接工具,爲了兼容2.x版本,目前公司裏用的比較多的仍是2.x版本的。3.x版本和2.x版本建立項目的命令也是不一樣的,你們自行看看吧。
安裝3.x版本:npm install -g @vue/cli ,拉取2.x版本的:npm install -g @vue/cli-init
建立項目:vue init webpack my-project
執行指令的時候先看清楚當前終端的根目錄,若是不是咱們的項目目錄,必定要先切換到項目目錄下,而後執行npm install 來下載項目的全部依賴包
執行項目:npm run dev(固然dev這個名字,本身能夠配置,在package.json文件中的scripts屬性中改)
3. .vue組件文件,結合咱們學的基礎,怎麼玩,看代碼:
<template> <!--當前組件的結構--> <div> <h2>{{ msg }}</h2> <!-- 模板語法,渲染組件的數據屬性 --> <!-- 指令系統 v-html、v-for(別忘了:key,否則咱們若是更改了組件中的一些內容,從新排版頁面的時候,可能會出現問題,出現混亂,改的數據跑到了別的地方), --> <!--<span(或者組件標籤) v-for="(value,index) in nameList" :key="index或者value.id"></span>--> <!-- v-bind(:), v-on(@),v-model雙向數據綁定 --> <!-- 使用element-ui組件,做爲咱們組件的子組件,裏面的數據經過父子組件,平行組件傳值 --> </div> </template> <script> //當前組件的業務邏輯 export default { name: 'Test', data(){ return{ msg:'Jaden', nameList:[] } }, methods:{ }, //計算屬性 computed:{ }, //還有各類鉤子函數 created(){ }, watch:{}, //過濾器 filter:{ myTime:function (val) { } } } </script> <style scoped> /*當前組件的樣式*/ </style>
補充一點,怎們將咱們的組件作成一個全局組件呢?那就想一下全局組件怎麼建立,是否是vue.component('組件名',{}),好,要使用vue,那麼哪一個文件引用的vue,是否是咱們的main.js啊,因此咱們在main.js裏面就能夠將咱們的組件作成全局組件,大概的寫法看下面的代碼,main.js的:
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import router from './router' import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; Vue.use(ElementUI); import '../static/global/index.css' Vue.config.productionTip = false //將咱們以前的Home組件作成一個全局組件 // import HomeContent from './components/Home/Home' // Vue.component('HomeContent.name',HomeContent); /* eslint-disable no-new */ new Vue({ el: '#app', router, components: { App }, template: '<App/>' })
element-ui是餓了麼開發的一套前端框架,相似於bootstrap,可是他是協同vue進行開發的,它提供好了不少vue可以直接下載使用的組件,組件裏面封裝好了html、css、js等代碼,拿來就能用,就能獲得對應的效果。
好,咱們進入官網看一下http://element-cn.eleme.io/#/zh-CN/,其中咱們就看組件的部分:
首先下載安裝,推薦使用 npm 的方式安裝,它能更好地和 webpack 打包工具配合使用。執行下面的指令來安裝:
npm i element-ui -S
而後怎麼玩呢,看下圖:
那麼好,知道了步驟,咱們就來項目裏面搞一搞,首先終端執行上面的下載安裝命令,安裝完成後咱們去配置咱們的main.js,看代碼:
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import router from './router' //引入element-ui import ElementUI from 'element-ui'; //引入element-ui的css樣式,這個須要單獨引入 import 'element-ui/lib/theme-chalk/index.css'; //給Vue添加一下這個工具 Vue.use(ElementUI); Vue.config.productionTip = false /* eslint-disable no-new */ new Vue({ el: '#app', router, components: { App }, template: '<App/>' })
而後使用一下element-ui的組件:
而後在咱們的App.vue組件中使用一下,看App.vue文件的代碼:
<template> <div id="app"> <el-container> <!-- 這是個組件,全局組件,是當前App組件的子組件,這些element-ui裏面的這些組件確定都是些全局組件,咱們引入了element-ui,而且vue.use()了一下,將像vue.component(element-ui組件,{}),這些子組件裏面的數據就是咱們父子組件傳值傳進去的,是說對不對 --> <el-header> <!-- 將組件入口寫到了這header裏面 --> <router-link :to="{name:'Home'}">首頁</router-link> <router-link :to="{name:'Course'}">免費課程</router-link> </el-header> <el-main> <!-- 組件出口寫到了el-main裏面 --> <router-view></router-view> </el-main> </el-container> </div> </template> <script> export default { name: 'App', data() { return {} }, } </script> <style> </style>
而後執行npm run dev指令,啓動咱們的項目,而後在頁面上看效果:
以前的頁面效果是這樣的:
加上element-ui的佈局容器以後,效果是這樣的:
好,那麼咱們再添加一些css樣式:
咱們在static文件夾下建立一個文件夾存放css樣式,先建立一個全局的css樣式文件夾,裏面建立一個index.css文件,來寫全局的一些css樣式,看目錄結構:
而後咱們在main.js裏面引入一下這個全局css樣式,看main.js的內容:
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import router from './router' //引入element-ui import ElementUI from 'element-ui'; //引入element-ui的css樣式,這個須要單獨引入 import 'element-ui/lib/theme-chalk/index.css'; //給Vue添加一下這個工具 Vue.use(ElementUI);
//引入咱們本身建立的css樣式文件 import '../static/global/index.css' Vue.config.productionTip = false /* eslint-disable no-new */ new Vue({ el: '#app', router, components: { App }, template: '<App/>' })
看頁面效果:這樣咱們的css樣式就有了。
再舉一個例子吧,好比說來一個時間選擇器:
而後好比說咱們在Home組件中使用一下,看一下Home.vue文件內容:
<template> <div> 這是Home頁面 <el-time-select v-model="value1" :picker-options="{ start: '08:30', step: '00:15', end: '18:30' }" placeholder="選擇時間"> </el-time-select> </div> </template> <script> export default { name: 'Home', data() { return { value1:'', //時間選擇器,這裏別忘了return一個value1來對應上面的v-model } }, } </script> <style> </style>
效果就出來了:
而後你們本身過一下element-ui都給我們提供了哪些組件就行啦,之後直接就用。
咱們再說一個組件怎麼用吧,就是element-ui提供的Carousel走馬燈(輪播圖)
看這個走馬燈怎麼玩:
好,到這裏咱們就說的差很少了,你們完成一個內容吧:
而後主要寫免費課的那個組件,也就是點擊免費課的那個頁面:
行,完成這些內容吧!