(四十三)常用 10 種演算法——馬踏棋盤演算法
- 1、Vue簡介
- 2、快速上手
- 3、雙向繫結
- 4、元件
- 5、Vue生命週期
- 6、Axios非同步通訊
- 7、計算屬性
- 8、插槽slot
- 9、自定義事件內容分發
- 10、Vue-cli
- 11、webpack
- 12、vue-route路由
1、Vue簡介
Vue(讀音 /vjuː/,類似於 view)是一套用於構建使用者介面的漸進式框架
vue-router
:跳轉,vue-resource
:通訊,vuex
:管理)或既有專案整合。另一方面,當與現代化的工具鏈以及各種支援類庫結合使用時,Vue 也完全能夠為複雜的單頁應用提供驅動。
Vue.js 中文文件:https://cn.vuejs.org/v2/guide/
- MVVM
MVVM 源自於經典的 MVC(Model-View-Controller)模式。MVVM 的核心是 ViewModel 層,負責轉換 Model 中的資料物件來讓資料變得更容易管理和使用,其作用如下:
- 該層向上與檢視層進行雙向資料繫結
- 向下與Model層通過介面請求進行資料互動
Model-ViewModel-View-Controller
上圖描述了 MVVM 一個基本結構,是不是發現比 MVC 架構中多了一個 ViewModel,沒錯,就是這個ViewModel,他是 MVVM 相對於 MVC 改進的核心思想。在開發過程中,由於需求的變更或新增,專案的複雜度越來越高,程式碼量越來越大,此時我們會發現 MVC 維護起來有些吃力,首先被人吐槽的最多的就是 MVC 的簡寫變成了 Massive-View-Controller(意為沉重的Controller)
由於 Controller 主要用來處理各種邏輯和資料轉化,複雜業務邏輯介面的 Controller 非常龐大,維護困難,所以有人想到把 Controller 的資料和邏輯處理部分從中抽離出來,用一個專門的物件去管理,這個物件就是ViewModel,是 Model 和 Controller 之間的一座橋樑
- 為什麼要使用 MVVM
MVVM 模式和 MVC 模式一樣,主要目的是分離檢視(View)和模型(Model),有幾大好處:
- 低耦合:檢視(View)可以獨立於 Model 變化和修改,一個 ViewModel 可以繫結到不同的 View 上,當View 變化的時候 Model 可以不變,當 Model 變化的時候 View 也可以不變。
- 可複用:你可以把一些檢視邏輯放在一個 ViewModel 裡面,讓很多 View 重用這段檢視邏輯。
- 獨立開發:開發人員可以專注於業務邏輯和資料的開發(ViewModel),設計人員可以專注於頁面設計。
- 可測試:介面素來是比較難於測試的,而現在測試可以針對 ViewModel 來寫。
- MVVM 的實現者
- Model:模型層,在這裡表示 JavaScript 物件
- View:檢視層,在這裡表示 DOM(HTML 操作的元素)
- ViewModel:連線檢視和資料的中介軟體,Vue.js 就是 MVVM 中的 ViewModel 層的實現者
在 MVVM 架構中,是不允許資料和檢視直接通訊的,只能通過 ViewModel 來通訊,而 ViewModel 就是定義了一個 Observer 觀察者:
- ViewModel 能夠觀察到資料的變化,並對檢視對應的內容進行更新
- ViewModel 能夠監聽到檢視的控化,並能夠通知資料發生改變
至此,我們就明白了,Vue.js 就是一個 MVVM 的實現者,他的核心就是實現了 DOM 監聽與資料繫結。
- 為什麼要使用 Vue.js
- 輕量級,體積小是一個重要指標。Vue.js 壓縮後有只有 20多kb (Angular 壓縮後56kb+,React 壓縮後44kb+)
- 移動優先,更適合移動端,比如移動端的 Touch 事件易上手,學習曲線平穩,文件齊全
- 吸取了 Angular(模組化)和 React(虛擬DOM)的長處,並擁有自己獨特的功能,如:計算屬性
- 開源,社群活躍度高
- ......
2、快速上手
嘗試 Vue.js 最簡單的方法是使用 Hello World 例子。你可以在瀏覽器新標籤頁中開啟它,跟著例子學習一些基礎用法。或者你也可以建立一個 .html
檔案,然後通過如下方式引入 Vue:
<!-- 開發環境版本,包含了有幫助的命令列警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
或者:
<!-- 生產環境版本,優化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
2.1、基本語法
- 宣告式渲染
Vue.js 的核心是一個允許採用簡潔的模板語法來宣告式地將資料渲染進 DOM 的系統:
<!DOCTYPE html>
<!-- <html lang="en"> -->
<head>
<meta charset="UTF-8">
<title>helloVue</title>
</head>
<body>
<!--view層 模板-->
<div id="app">
{{ message }}
</div>
<!--匯入VUE-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
/*model: 資料*/
data: {
message: 'Hello Vue!'
}
})
</script>
</body>
</html>
我們已經成功建立了第一個 Vue 應用,看起來這跟渲染一個字串模板非常類似,但是 Vue 在背後做了大量工作。現在資料和 DOM 已經被建立了關聯,所有東西都是響應式的。我們要怎麼確認呢?開啟你的瀏覽器的 JavaScript 控制檯(就在這個頁面開啟),並修改 vm.message 的值,你將看到上例相應地更新。
注意我們不再和 HTML 直接互動了。一個 Vue 應用會將其掛載到一個 DOM 元素上(對於這個例子是 #app)然後對其進行完全控制。那個 HTML 是我們的入口,但其餘都會發生在新建立的 Vue 例項內部。
除了文字插值,我們還可以像這樣來繫結元素 attribute:
<!DOCTYPE html>
<!-- <html lang="en"> -->
<head>
<meta charset="UTF-8">
<title>helloVue</title>
</head>
<body>
<!--view層 模板-->
<div id="app">
<span v-bind:title="message">
滑鼠懸停幾秒鐘檢視此處動態繫結的提示資訊!
</span>
</div>
<!--匯入VUE-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
message: '頁面加載於 ' + new Date().toLocaleString()
}
})
</script>
</body>
</html>
這裡我們遇到了一點新東西。你看到的 v-bind
attribute 被稱為指令。指令帶有字首 v-
,以表示它們是 Vue 提供的特殊 attribute。可能你已經猜到了,它們會在渲染的 DOM 上應用特殊的響應式行為。在這裡,該指令的意思是:“將這個元素節點的 title
attribute 和 Vue 例項的 message
property 保持一致”。
如果你再次開啟瀏覽器的 JavaScript 控制檯,輸入 vm.message = '新訊息',就會再一次看到這個綁定了 title attribute 的 HTML 已經進行了更新。
- 條件v-if
控制切換一個元素顯示也相當簡單:
<!DOCTYPE html>
<!-- <html lang="en"> -->
<head>
<meta charset="UTF-8">
<title>helloVue</title>
</head>
<body>
<!--view層 模板-->
<div id="app">
<h1 v-if="type==='A'">A</h1>
<h1 v-else-if="type==='B'">B</h1>
<h1 v-else="type==='C'">C</h1>
</div>
<!--匯入VUE-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
var vm = new Vue({
el: "#app",
data: {
type: 'B'
}
});
</script>
</body>
</html>
繼續在控制檯輸入 vm.type = 1
,你會發現頁面顯示由B變為了C。
- 迴圈v-for
還有其它很多指令,每個都有特殊的功能。例如,v-for
指令可以繫結陣列的資料來渲染一個專案列表:
<!DOCTYPE html>
<!-- <html lang="en"> -->
<head>
<meta charset="UTF-8">
<title>helloVue</title>
</head>
<body>
<!--view層 模板-->
<div id="app">
<ol>
<li v-for="todo in todos">
{{ todo.text }}
</li>
</ol>
</div>
<!--匯入VUE-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
todos: [
{ text: '學習 JavaScript' },
{ text: '學習 Vue' },
{ text: '整個牛專案' }
]
}
})
</script>
</body>
</html>
在控制檯裡,輸入 vm.todos.push({ text: '新專案' })
,你會發現列表最後添加了一個新專案。
2.2、事件
為了讓使用者和你的應用進行互動,我們可以用 v-on
指令新增一個事件監聽器,通過它呼叫在 Vue 例項中定義的方法:
<!DOCTYPE html>
<!-- <html lang="en"> -->
<head>
<meta charset="UTF-8">
<title>helloVue</title>
</head>
<body>
<!--view層 模板-->
<div id="example">
<!-- `greet` 是在下面定義的方法名 -->
<button v-on:click="sat">點我</button>
</div>
<!--匯入VUE-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
var vm = new Vue({
el: "#example",
data: { message: "helloword"},
methods: { //方法必須定義在vue內的methods中
sat: function () {
alert(this.message);
}
}
})
</script>
</body>
</html>
3、雙向繫結
- 什麼是資料雙向繫結?
Vue.js 是一個 MVVM 框架,即資料雙向繫結,即當資料發生變化的時候,檢視也就發生變化,當檢視發生變化的時候,資料也會跟著同步變化。 這也算是 Vue.js 精髓之處了。
值得注意的是,我們所說的資料雙向繫結,一定是對於 UI 控制元件來說的,非 UI 控制元件不會涉及到資料雙向繫結。單向資料繫結是使用狀態管理工具的前提。如果我們使用 vuex,那麼資料流也是單項的,這時就會和雙向資料繫結有衝突。
- 為什麼要實現雙向繫結?
在 Vue.js 中,如果使用 vuex,實際上資料還是單向的,之所以說是數讀雙向繫結,這過用的 UI控制元件來說,對於我們處理表中,Vue.js 雙向資料繫結用起來特別舒服。即兩者並不互斥,在全域性性資料流使用單項,方便跟蹤。同部件資料流使用雙向,簡單易操作。
- 如何實現資料雙向繫結
你可以用 v-model
指令在表單 <input> 、 <textarea> 及 <select>
元素上建立雙向資料繫結。它會根據控制元件型別自動選取正確的方法來更新元素。儘管有些神奇,但 v-model
本質上不過是語法糖。它負責監聽使用者的輸入事件以更新資料,並對一些極端場景進行一些特殊處理。
- 注意:
v-model
會忽略所有表單元素的 value,checked、selected
特性的初始值而總是將 Vue 例項的資料作為資料來源。你應該通過 JavaScript 在元件的 data 選項中宣告初始值。
- 文字演示
<!DOCTYPE html>
<!-- <html lang="en"> -->
<head>
<meta charset="UTF-8">
<title>helloVue</title>
</head>
<body>
<!--view層 模板-->
<div id="example">
輸入文字 <input type="text" v-model="message">{{message}}
</div>
<!--匯入VUE-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
var vm = new Vue({
el: "#example",
data: {
message: "123"
}
})
</script>
</body>
</html>
- 單選框演示
<!DOCTYPE html>
<!-- <html lang="en"> -->
<head>
<meta charset="UTF-8">
<title>helloVue</title>
</head>
<body>
<!--view層 模板-->
<div id="example">
單選框:
<input type="radio" name="sex" value="男" v-model="message">男
<input type="radio" name="sex" value="女" v-model="message">女
{{message}}
</div>
<!--匯入VUE-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
var vm = new Vue({
el: "#example",
data: {
message: ""
}
})
</script>
</body>
</html>
- 下拉框演示
<!DOCTYPE html>
<!-- <html lang="en"> -->
<head>
<meta charset="UTF-8">
<title>helloVue</title>
</head>
<body>
<!--view層 模板-->
<div id="example">
<select v-model="message">
<!--提供一個預留項 disabled預設選中 value為空-->
<option disabled value="">請選擇</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>{{message}}</span>
</div>
<!--匯入VUE-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
var vm = new Vue({
el: "#example",
data: {
message: ""
}
})
</script>
</body>
</html>
4、元件
元件是可複用的 vue 例項,說白了就是一組可以重複使用的模板,跟 JSTL 的自定義標籤、Thymeleaf 的 th:fragment
等框架有著異曲同工之妙。通常一個應用會以一棵巢狀的元件樹的形式來組織:
例如,你可能會有頁頭、側邊欄、內容區等元件,每個元件又包含了其它的像導航連結、博文之類的元件。
為了能在模板中使用,這些元件必須先註冊以便 Vue 能夠識別。這裡有兩種元件的註冊型別:全域性註冊和區域性註冊。
在元件中無法直接取到資料,需要通過 Prop
- 通過
Vue.component
全域性註冊
<!DOCTYPE html>
<!-- <html lang="en"> -->
<head>
<meta charset="UTF-8">
<title>helloVue</title>
</head>
<body>
<!--view層 模板-->
<div id="example">
<!--傳遞元件中的值 props-->
<kuangshen v-for="item in items" v-bind:qin="item"></one>
</div>
<!--匯入VUE-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
//註冊元件
Vue.component('kuangshen',{
/*元件中傳遞資料 props*/
props: ['qin'],
template: '<li>{{qin}}</li>'
});
var vm = new Vue({
el: "#example",
data: {
items: ["Java","Javascript","C++"]
}
});
</script>
</body>
</html>
說明:
v-for="item in items"
:遍歷 Vue 例項中定義的名為 items 的陣列,並建立同等數量的元件v-bind:qin="item"
:將遍歷的 item 項繫結到元件中 props 定義的名為 qin 屬性上, =號左邊的 qin 為props 定義的屬性名,右邊的為 item in items 中遍歷的 item 項的值
- 區域性註冊
全域性註冊往往是不夠理想的。比如,如果你使用一個像 webpack 這樣的構建系統,全域性註冊所有的元件意味著即便你已經不再使用一個元件了,它仍然會被包含在你最終的構建結果中。這造成了使用者下載的 JavaScript 的無謂的增加。
在這些情況下,你可以通過一個普通的 JavaScript 物件來定義元件:
var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }
然後在 components
選項中定義你想要使用的元件:
new Vue({
el: '#app',
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
})
對於 components
物件中的每個 property 來說,其 property 名就是自定義元素的名字,其 property 值就是這個元件的選項物件。
注意區域性註冊的元件在其子元件中不可用。例如,如果你希望 ComponentA
在 ComponentB
中可用,則你需要這樣寫:
var ComponentA = { /* ... */ }
var ComponentB = {
components: {
'component-a': ComponentA
},
// ...
}
5、Vue生命週期
Vue 例項有一個完整的生命週期,也就是從開始建立、初始化資料、編譯模板、掛載 DOM、渲染 --> 更新 --> 渲染、解除安裝等一系列過程,我們稱這是 Vue 的生命週期。通俗說就是 Vue 例項從建立到銷燬的過程,就是生命週期。
在 Vue 的整個生命週期中,它提供了一系列的事件,可以讓我們在事件觸發時註冊 JS 方法,可以讓我們用自己註冊的 JS 方法控制整個大局,在這些事件響應方法中的 this 直接指向的是 Vue 的例項。
6、Axios非同步通訊
- 什麼是 AXIOS
Axios 是一個開源的可以用在瀏覽器端和 Nodes 的非同步通訊框架,她的主要作用就是實現 AJAX 非同步通訊,其功能特點如下:
- 從瀏覽器中建立 XMLHttpRequests
- 從 node.js 建立 http 請求
- 支援 Promise API【JS中鏈式程式設計】攔截請求和響應
- 轉換請求資料和響應資料取消請求
- 自動轉換 JSON 資料
- 客戶端支援防禦 XSRF(跨站請求偽造)
- 為什麼要使用 AXIOS
由於 Vue.js 是一個檢視層框架並且作者(尤雨溪)嚴格準守 SoC(關注度分離原則),所以 Vue. js 並不包含AJAX 的通訊功能,為了解決通訊問題,作者單獨開發了一個名為 vue-resource 的外掛,不過在進入 2.0 版本以後停止了對該外掛的維護並推薦了 Axios 框架。(建議:少用 jQuery,因為它操作 Dom 太頻繁)
- 第一個 AXIOS
- 準備一段 JSON 資料
{
"name":"狂神說java",
"url": "http://baidu.com",
"page": 1,
"isNonProfit": true,
"address": {
"street": "含光門",
"city":"陝西西安",
"country": "中國"
},
"links": [
{
"name": "B站",
"url": "https://www.bilibili.com/"
},
{
"name": "4399",
"url": "https://www.4399.com/"
},
{
"name": "百度",
"url": "https://www.baidu.com/"
}
]
}
- 匯入線上 AXIOS CDN
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
- 編寫程式碼
<!DOCTYPE html>
<!-- <html lang="en"> -->
<head>
<meta charset="UTF-8">
<title>helloVue</title>
</head>
<body>
<!--view層 模板-->
<div id="vue">
<p>{{info.name}}</p>
<p>{{info.links}}</p>
<a v-bind:href="info.url">點我</a>
</div>
<!--匯入VUE-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
var vm = new Vue({
el: "#vue",
//data: 屬性 使用鉤子函式 data()是個方法
data(){
return{
// 請求的引數 必須跟JSON字串格式一樣
info: {
name: null,
url: null,
page: null,
isNonProfit: null,
address: {
street: null,
city: null,
country: null
},
links: [
{name: null,url:null}
]
}
}
},
mounted(){ //鉤子函式 ES6新特性
axios.get("data.json").then(response=>(this.info=response.data));
}
});
</script>
</body>
</html>
7、計算屬性
計算屬性的重點突出在屬性兩個字上(屬性是名詞),首先它是個屬性其次這個屬性有計算的能力(計算是動詞),這裡的計算就是個函式,簡單點說,它就是一個能夠將計算結果快取起來的屬性(將行為轉化成了靜態的屬性),僅此而已,可以想象為快取。
<!DOCTYPE html>
<!-- <html lang="en"> -->
<head>
<meta charset="UTF-8">
<title>helloVue</title>
<style>
[v-clock]{ /* 使用v-clock解決閃爍問題 */
display: none;
}
</style>
</head>
<body>
<!--view層 模板-->
<div id="app" v-clock> <!-- 使用v-clock解決閃爍問題 -->
<p>{{currentTime1()}}</p> <!-- 呼叫方法 -->
<p>{{currentTime2}}</p> <!-- 呼叫屬性 -->
</div>
<!--匯入VUE-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
var vm = new Vue({
el: "#app",
data: {
message: "helloword"
},
methods: {
currentTime1: function () {
return Date.now();//返回一個時間戳
}
},
computed: { //計算屬性 前提methods與computed 方法不能重名 重名之後只會呼叫methods的方法
currentTime2: function () {
return Date.now();//返回一個時間戳
}
}
});
</script>
</body>
</html>
- methods:定義方法,呼叫方法使用 currentTime1(),需要帶括號
- computed:定義計算屬性,呼叫屬性使用 currentTime2,不需要帶括號
呼叫方法時,每次都需要進行計算,既然有計算過程則必定產生系統開銷,那如果這個結果是不經常變化的呢?此時就可以考慮將這個結果快取起來,採用計算屬性可以很方便的做到這一點,計算屬性的主要特性就是為了將不經常變化的計算結果進行快取,以節約我們的系統開銷。
8、插槽slot
在 vue.js 中我們使用 <slot>
元素作為承載分發內容的出口,作者稱其為插槽,可以應用在組合元件的場景中,插槽是元件的一種:
<!DOCTYPE html>
<!-- <html lang="en"> -->
<head>
<meta charset="UTF-8">
<title>helloVue</title>
</head>
<body>
<!--view層 模板-->
<div id="app">
<todo>
<todo-title slot="todo-title" v-bind:title="username"></todo-title>
<todo-times slot="todo-times" v-for="todoitem in todoitems" v-bind:items="todoitem"></todo-times>
</todo>
</div>
<!--匯入VUE-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
/*插槽是元件的一種*/
Vue.component("todo",{
template: '<div>'+
'<slot name="todo-title"></slot>'+
'<ul>' +
'<slot name="todo-times"></slot>'+
'</ul>'+
'</div>'
})
Vue.component("todo-title",{
props: ["title"],
template: '<div>{{title}}</div>'
})
Vue.component("todo-times",{
props: ["items"],
template: '<li>{{items}}</li>'
})
var vm= new Vue({
el: "#app",
data: {
username: "秦疆",
todoitems: ["狂神說Java","狂神說前端"]
}
});
</script>
</body>
</html>
在 <slot>
使用 name
屬性關聯其他元件
9、自定義事件內容分發
通過上面的程式碼不難發現,資料項在 Vue 的例項中,但刪除操作要在元件中完成,那麼元件如何才能刪除 Vue 例項中的資料呢?此時就涉及到引數傳遞與事件分發了,Vue 為我們提供了自定義事件的功能很好的幫助我們解決了這個問題,使用 this.$emit('自定義事件名',引數)
,操作過程如下:
<!DOCTYPE html>
<!-- <html lang="en"> -->
<head>
<meta charset="UTF-8">
<title>helloVue</title>
</head>
<body>
<!--view層 模板-->
<div id="app">
<todo>
<todo-title slot="todo-title" v-bind:title="username"></todo-title>
<!--自定義事件 v-on:remove="removeitems(index)通過自定義事件呼叫VUe例項中的方法" -->
<todo-times slot="todo-times" v-for="(todoitem,index) in todoitems"
v-bind:items="todoitem" v-bind:index="index" v-on:remove="removeitems(index)" v-bind:key="index"></todo-times>
</todo>
</div>
<!--匯入VUE-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
/*插槽是元件的一種*/
Vue.component("todo",{
template: '<div>'+
'<slot name="todo-title"></slot>'+
'<ul>' +
'<slot name="todo-times"></slot>'+
'</ul>'+
'</div>'
})
Vue.component("todo-title",{
props: ["title"],
template: '<div>{{title}}</div>'
})
/*props獲取到陣列元素與陣列下標*/
Vue.component("todo-times",{
props: ["items","index"],
/*繫結點選事件 方法指向元件中methods-remove*/
template: '<li>{{index}}--{{items}}<button v-on:click="remove">刪除</button></li>',
methods: {
remove: function (index) {
alert(index)
/* 引數一: 自定義事件名 引數二: 陣列下標 方法指向頁面中的自定義事件 通過自定義事件呼叫VUe例項中的方法*/
this.$emit('remove',index);
}
}
})
var vm= new Vue({
el: "#app",
data: {
username: "秦疆",
todoitems: ["狂神說Java","狂神說前端","狂神說Liunx"]
},
methods: {
removeitems: function (index) {
//js中移除陣列元素的方法
this.todoitems.splice(index,1);
}
}
});
</script>
</body>
</html>
for 迴圈不僅可以遍歷出陣列元素,還可以遍歷出陣列下標
10、Vue-cli
vue-cli 官方提供的一個腳手架,用於快速生成一個 vue 的專案模板。
預先定義好的目錄結構及基礎程式碼,就好比咱們在建立 Maven 專案時可以選擇建立一個骨架專案,這個骨架專案就是腳手架,我們的開發更加的快速。
- 主要功能:
- 統一的目錄結構
- 本地除錯
- 熱部署
- 單元測試
- 整合打包上線
10.1、安裝Node.js
官網下載Node.js:http://nodejs.cn/
確認 Node.js 安裝成功:
CMD 輸入
node -v
檢視是否正確列印版本號資訊即可CMD 輸入
npm -v
檢視是否正確列印版本號資訊即可,npm 就是一個軟體包管理工具,就和 linux 下的 apt軟體安裝差不多。
檢查環境變數是否存在:
安裝 Node.js 淘寶境像加速器(cnpm),最好是在管理員模式下的CMD安裝:
# -g就是全域性安裝
npm install cnpm -g
# 或使用如下解決速度慢問題
npm install --registry=https://registry.npm.taobao.org
安裝完成會顯示安裝目錄:
10.2、安裝vue-cli
cnpm install vue-cli -g
# 測試是否安裝成功
# 檢視檢視可以基於哪些模板建立vue應用程式,通常我們選擇 webpack
vue list
10.3、第一個vue-cli程式
- 建立專案
- 建立一個 Vue 專案,我們隨便建立一個空的資料夾在電腦上,我這裡在D盤下新建一個目錄
D:\WorkSpace
- 建立一個基於 webpack 模板的 vue 應用程式
- Project name:專案名稱,預設回車即可
- Project description:專案描述,預設回車即可Author:專案作者,預設回車即可
- Install vue-router:是否安裝 vue-router,選擇n不安裝(後期需要再手動新增)
- Use ESLint to lint your code:是否使用 ESLint 做程式碼檢查,選擇n不安裝(後期需要再手動新增)
- Set up unit tests:單元測試相關,選擇n不安裝(後期需要再手動新增)
- Setup e2e tests with Nightwatch:單元測試相關,選擇n不安裝(後期需要再手動新增)
- Should we run npm install for you after the project has been created:建立完成後直接初始化,選擇n,我們手動執行並執行結果!
#這裡的myvue是專案名稱,可以根據自己需求取名
vue init webpack myvue #一路都選No即可
- 初始化並執行
管理員模式 CMD 進入專案目錄下,我這裡是D:\WorkSpace\myvue
npm install
npm run dev
編譯時遇到報錯,根據提示執行命令修復錯誤:
訪問本機8080埠:
11、webpack
11.1、什麼是webpack
本質上,webpack 是一個現代 JavaScript 應用程式的靜態模組打包器(module bundler)。當 webpack 處理應用程式時,它會遞迴地構建一個依賴關係圖(dependency graph),其中包含應用程式需要的每個模組,然後將所有這些模組打包成一個或多個 bundle。
Webpack 是當下最熱門的前端資源模組化管理和打包工具,它可以將許多鬆散耦合的模組按照依賴和規則打包成符合生產環境部署的前端資源。還可以將按需載入的模組進行程式碼分離,等到實際需要時再非同步載入。通過 loader 轉換,任何形式的資源都可以當做模組,比如 CommonsJS、AMD、ES6、Css、JSON、CoffeeScript、LESS等。
11.2、模組化的演進
- script標籤
<script src = "module3.js"></script>
<script src = "module4.js"></script>
這是最原始的 JavaScript 檔案載入方式,如果把每一個檔案看做是一個模組,那麼他們的介面通常是暴露在全域性作用域下,也就是定義在 window 物件中,不同模組的呼叫都是一個作用域。
這種原始的載入方式暴露了一些顯而易見的弊端:
- 全域性作用域下容易造成變數衝突
- 檔案只能按照
<script>
的書寫順序進行載入開發人員必須主觀-解決模組和程式碼庫的依賴關係 - 在大型專案中各種資源難以管理,長期積累的問題導致程式碼庫混亂不堪
- CommonsJS
伺服器端的 NodeJS 遵循 CommonsJS 規範,該規範核心思想是允許模組通過 require
方法來同步載入所需依賴的其它模組,然後通過 exports
或 module.exports
來匯出需要暴露的介面。
require("module");
require("../module.js");
export .doStuff = function(){};
module.exports = somevalue ;
- 優點:
伺服器端模組便於重用
NPM 中已經有超過45萬個可以使用的模組包簡單易用
- 缺點:
同步的模組載入方式不適合在瀏覽器環境中,同步意味著阻塞載入,瀏覽器資源是非同步載入的
不能非阻塞的並行載入多個模組
- 實現:
服務端的 NodeJS
Browserify,瀏覽器端的 CommonsJS 實現,可以使用 NPM 的模組,但是編譯打包後的檔案體積較大
modules-webmake,類似 Browserify,但不如 Browserify 靈活 wreq,Browserify 的前身
- AMD
Asynchronous Module Definition 規範其實主要一個主要介面 define(id ?,
dependencies?, factory); 它要在宣告模組的時候指定所有的依賴 dependencies,並且還要當做形參傳到 factory 中,對於依賴的模組提前執行。
- 優點:
適合在瀏覽器環境中非同步載入模組
可以並行載入多個模組
- 缺點:
提高了開發成本,程式碼的閱讀和書寫比較困難,模組定義方式的語義不暢
不符合通用的模組化思維方式,是一種妥協的實現
- 實現
RequireJS
curl
- CMD
Commons Module Definition 規範和 AMD 很相似,儘量保持簡單,並與 CommonsJS 和 NodeJS 的 Modules 規範保持了很大的相容性。
- 優點:
依賴就近,延遲執行
可以很容易在 Nodejs 中執行
- 缺點:
依賴 SPM 打包,模組的載入邏輯偏重
- 實現:
Sea.js
coolie
- ES6 模組
EcmaScript6 標準增加了 JavaScript 語言層面的模組體系定義。ES6 模組的設計思想,是儘量靜態化,使編譯時就能確定模組的依賴關係,以及輸入和輸出的變數。CommonsJS 和 AMD 模組,都只能在執行時確定這些東西。
import "jquery";
export funetion dostuff(){}
module "localMadule"{}
- 優點:
容易進行靜態分析
面向未來的 EcmaScript 標準
- 缺點:
原生瀏覽器端還沒有實現該標準全新的命令
新版的 NodeJS 才支援
- 實現:
Babel
11.3、安裝並使用webpack
WebPack 是一款模組載入器兼打包工具,它能把各種資源,如 JS、JSX、ES6、SASS、LESS、圖片等都作為模組來處理和使用。
在管理員模式下的CMD安裝:
npm install webpack -g
npm install webpack-cli -g
- 使用
- 新建目錄
webpackTest
測試 webpack - 編寫
hello.js
//暴露一個方法
exports.Hello=function () {
document.write("<h1>狂神說ES6</h1>");
}
- 編寫
main.js
var hello=require("./hello");
hello.Hello();
-
建立
webpack.config.js
配置檔案module.exports={ /*找到程式的入口*/ entry: './modules/main.js', output: { /*生成打包後的檔案*/ filename: './js/bundle.js' } };
- entry:入口檔案,指定 WebPack 用哪個檔案作為專案的入口
- output:輸出,指定 WebPack 把處理完成的檔案放置到指定路徑
- module:模組,用於處理各種型別的檔案
- plugins:外掛,如:熱更新、程式碼重用等,resolve:設定路徑指向
- watch:監聽,用於設定檔案改動後直接打包
- 管理員模式 cmd 下執行
webpack
打包
發現多了一個 bundle.js 檔案:
使用這個 bundle.js 檔案:
# 使用以下命令可以實現熱部署 程式碼一旦改變就會重新打包
webpack --watch
12、vue-route路由
12.1、什麼是 vue-route
由於 vue 的 SOC 原則,所以 vue 本身並不具備頁面跳轉
Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度整合,讓構建單頁面應用變得易如反掌。包含的功能有:
- 巢狀的路由/視圖表
- 模組化的、基於元件的路由配置路由引數、查詢、萬用字元
- 基於 Vue.js 過渡系統的檢視過渡效果細粒度的導骯控制
- 帶有自動啟用的 CSS class 的連結
- HTML5 歷史模式或 hash 模式,在 IE9 中自動降級自定義的滾動條行為
- 安裝
在 vue-cli 快速上手中建立的專案下安裝 vue-route
安裝完成後會在 node_modules 目錄下新增 vue-route 的相關依賴,相當於匯入 maven 依賴
# 安裝vue-route
npm install vue-router --save-dev
12.2、快速上手
- 編寫模板
在 components 目錄下新建 Context.vue
<template>
<h1>內容頁</h1>
</template>
<script>
export default {
name: "Context"
}
</script>
<style scoped>
</style>
- 編寫 route 相關
建立 route 目錄編寫 index.js
import Vue from 'vue'
import VueRouter from "vue-router"; //匯入路由
import Context from '../components/Context' //匯入相關頁面
//vue中需要顯示宣告使用VueRouter 安裝路由
Vue.use(VueRouter);
//配置匯出路由
export default new VueRouter({
//陣列 可以配置多個頁面
routes: [
{
//路由路徑 相當於Java中的@RequestMapping
path: '/content',
//路由名字
name: "context",
//跳轉的元件
component: Context
}
]
})
- 在 main.js 中使用路由
import Vue from 'vue'
import App from './App'
import router from './router' //自動掃描包裡面名字為index的路由配置
Vue.config.productionTip = false
new Vue({
el: '#app',
//配置路由
router,
components: { App },
template: '<App/>'
})
- 在 App.vue 中編寫檢視
<template>
<div id="app">
<!--相當於 <a>標籤 -->
<router-link to="/content">內容頁</router-link>
<!--展示檢視-->
<router-view></router-view>
</div>
</template>
<script>
export default {
name: '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;
}
</style>
- 測試使用
#CMD命令列執行
npm run dev
12.3、重定向
重定向也是通過 routes
配置來完成,下面例子是從 /a 重定向到 /b:
const router = new VueRouter({
routes: [
{ path: '/a', redirect: '/b' }
]
})
重定向的目標也可以是一個命名的路由:
const router = new VueRouter({
routes: [
{ path: '/a', redirect: { name: 'foo' }}
]
})
12.4、404
當我們輸入一些不存在的路徑時會報 404,在路由中也可以實現,編寫一個 404 頁面:
<template>
<div>
<h1>404</h1>
<h2>頁面走丟了</h2>
</div>
</template>
<script>
export default {
name: "Notfaund"
}
</script>
<style scoped>
</style>
在路由配置 index.js
中配置:
{ //404 匹配不到的路徑會走以下頁面
path: "*",
component: Notfaund
}
12.5、HTML5 History模式
vue-router 預設 hash 模式 —— 使用 URL 的 hash 來模擬一個完整的 URL,於是當 URL 改變時,頁面不會重新載入。URL:localhost:8080/#/Main
如果不想要很醜的 hash,我們可以用路由的 history 模式,這種模式充分利用 history.pushState API 來完成 URL 跳轉而無須重新載入頁面。
const router = new VueRouter({
mode: 'history',
routes: [...]
})