相關(guān)概念
混合開(kāi)發(fā)和前后端分離
混合開(kāi)發(fā)(服務(wù)器端渲染)
前后端分離
后端提供接口,前端開(kāi)發(fā)界面效果(專(zhuān)注于用戶(hù)的交互)
庫(kù)和框架
-
庫(kù)
庫(kù)提供大量API甜孤,需要自己調(diào)用這些API簡(jiǎn)化開(kāi)發(fā)老速。
-
框架
框架提供了一些基礎(chǔ)服務(wù)粥喜,一般不需要自己調(diào)用,會(huì)自動(dòng)完成一些基本功能橘券。
什么是Vue
什么是Vue
一款非常優(yōu)秀的前端 JavaScript 框架额湘,由尤雨溪?jiǎng)?chuàng)建開(kāi)發(fā)
可以輕松構(gòu)建單頁(yè) (SPA) 應(yīng)用程序
通過(guò) 指令 擴(kuò)展了 HTML,通過(guò) 表達(dá)式 綁定數(shù)據(jù)到 HTML
最大程度上解放了 DOM 操作
它能讓你更加的享受編程的樂(lè)趣
-
數(shù)據(jù)驅(qū)動(dòng)旁舰,開(kāi)源
Vue的特點(diǎn)
- 簡(jiǎn)單易用
- 靈活漸進(jìn)式
- 輕量高效
- 虛擬 DOM
- MVVM
- 組件化
Vue初體驗(yàn)
安裝Vue
下載Vue
Vue.js 不支持 IE8 及其以下版本
最新穩(wěn)定版本:2.5.16
-
直接下載
- 開(kāi)發(fā)版本:https://vuejs.org/js/vue.js
- 生產(chǎn)版本:https://vuejs.org/js/vue.min.js
-
CDN
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
-
使用
npm
下載(默認(rèn)安裝最新穩(wěn)定版)npm install vue
Hello World
通過(guò)數(shù)據(jù)綁定的方式锋华,在界面上展示Hello World
<div id="app">
<h1>{{ msg }}</h1>
</div>
<script src="vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
msg: 'Hello World'
}
});
</script>
Vue實(shí)例
創(chuàng)建Vue實(shí)例
每一個(gè)Vue應(yīng)用都是通過(guò)Vue構(gòu)造函數(shù)創(chuàng)建一個(gè)Vue的實(shí)例開(kāi)始
var vm = new Vue({
// Vue的選項(xiàng)
});
- Vue的選項(xiàng)
-
el
選項(xiàng):指定Vue作用的范圍 -
data
選項(xiàng):data提供數(shù)據(jù)對(duì)象,綁定的數(shù)據(jù)
-
模板語(yǔ)法
Vue.js 使用了基于 HTML 的模板語(yǔ)法箭窜,允許開(kāi)發(fā)者聲明式地將 DOM 綁定至底層 Vue 實(shí)例的數(shù)據(jù)毯焕。所有 Vue.js 的模板都是合法的 HTML ,所以能被遵循規(guī)范的瀏覽器和 HTML 解析器解析磺樱。
插值表達(dá)式
數(shù)據(jù)綁定最常見(jiàn)的形式就是使用“Mustache”語(yǔ)法 (雙大括號(hào)) 的文本插值:
<h1>
{{ msg }}
</h1>
JavaScript表達(dá)式
對(duì)于所有的數(shù)據(jù)綁定纳猫,Vue.js 都提供了完全的 JavaScript 表達(dá)式支持。
{{ number + 1 }}
{{ age > 18 ? '年滿(mǎn)18歲' : '未滿(mǎn)18歲' }}
{{ message.split('').reverse().join('') }}
<h1>
{{ msg }}
</h1>
注意:差值表達(dá)式中不能寫(xiě)語(yǔ)句竹捉。例如:var a = 10;
指令
指令 (Directives) 是帶有 v-
前綴的特殊特性续担。指令特性的值預(yù)期是單個(gè) JavaScript 表達(dá)式(v-for
是例外情況,稍后我們?cè)儆懻?活孩。指令的職責(zé)是,當(dāng)表達(dá)式的值改變時(shí)乖仇,將其產(chǎn)生的連帶影響憾儒,響應(yīng)式地作用于 DOM。參考文檔
v-html/v-text
- v-text
- v-text和差值表達(dá)式的區(qū)別
- v-text 標(biāo)簽的指令更新整個(gè)標(biāo)簽中的內(nèi)容
- 差值表達(dá)式乃沙,可以更新標(biāo)簽中局部的內(nèi)容
- v-text和差值表達(dá)式的區(qū)別
- v-html
- 可以渲染內(nèi)容中的HTML標(biāo)簽
- 盡量避免使用起趾,否則會(huì)帶來(lái)危險(xiǎn)(XSS攻擊 跨站腳本攻擊)
v-bind
可以綁定標(biāo)簽上的任何屬性。
-
動(dòng)態(tài)綁定圖片的路徑
<img v-bind:src="src" /> <script> var vm = new Vue({ el: '#app', data: { src: '1.jpg' } }); </script>
-
綁定a標(biāo)簽上的id
<a v-bind:href="'del.php?id=' + id">刪除</a> <script> var vm = new Vue({ el: '#app', data: { id: 11 } }); </script>
-
綁定class
對(duì)象語(yǔ)法和數(shù)組語(yǔ)法
-
對(duì)象語(yǔ)法
如果isActive為true警儒,則返回的結(jié)果為
<div class="active"></div>
<div v-bind:class="{active: isActive}"> hei </div> <script> var vm = new Vue({ el: '#app', data: { isActive: true } }); </script>
-
數(shù)組語(yǔ)法
渲染的結(jié)果
<div class="active text-danger"></div>
<div v-bind:class="[activeClass, dangerClass]"> hei </div> <script> var vm = new Vue({ el: '#app', data: { activeClass: 'active', dangerClass: 'text-danger' } }); </script>
-
-
綁定style
對(duì)象語(yǔ)法和數(shù)組語(yǔ)法
-
對(duì)象語(yǔ)法
渲染的結(jié)果<div style="color: red; font-size: 18px;"></div>
<div v-bind:style="{color: redColor, fontSize: font18 + 'px'}"> hei </div> <script> var vm = new Vue({ el: '#app', data: { redColor: 'red', font18: 18 } }); </script>
-
數(shù)組語(yǔ)法
<div v-bind:style="[color, fontSize]">abc</div> <script> var vm = new Vue({ el: '#app', data: { color: { color: 'red' }, fontSize: { 'font-size': '18px' } } }); </script>
-
-
簡(jiǎn)化語(yǔ)法
<div v-bind:class="{active: isActive}"> </div> <!-- 可以簡(jiǎn)化為训裆,簡(jiǎn)化語(yǔ)法更常用 --> <div :class="{active: isActive}"> </div>
v-model
表單元素的綁定
-
雙向數(shù)據(jù)綁定
- 數(shù)據(jù)發(fā)生變化可以更新到界面
- 通過(guò)界面可以更改數(shù)據(jù)
-
綁定文本框
當(dāng)文本框的值發(fā)生邊框后眶根,div中的內(nèi)容也會(huì)發(fā)生變化
<input type="text" v-model="name"> <div>{{ name }}</div> <script> var vm = new Vue({ el: '#app', data: { name: '' } }); </script>
-
綁定多行文本框
<textarea v-model="name"></textarea> <div>{{ name }}</div>
注意:多行文本框中不能使用
{{ name }}
的方式綁定 -
綁定復(fù)選框
- 綁定一個(gè)復(fù)選框
<input type="checkbox" v-model="checked"> <div>{{ checked }}</div>
-
綁定多個(gè)復(fù)選框
此種方式需要input標(biāo)簽提供value屬性
吃飯:<input type="checkbox" value="eat" v-model="checklist"><br> 睡覺(jué):<input type="checkbox" value="sleep" v-model="checklist"><br> 打豆豆:<input type="checkbox" value="ddd" v-model="checklist"><br> {{ checklist }} <script> var vm = new Vue({ el: '#app', data: { checklist: [] } }); </script>
-
綁定單選框
男<input type="radio" name="sex" value="男" v-model="sex"> 女<input type="radio" name="sex" value="女" v-model="sex"> {{sex}} <script> var vm = new Vue({ el: '#app', data: { sex: '' } }); </script>
-
綁定下拉框
<div id="example-5"> <select v-model="selected"> <option disabled value="">請(qǐng)選擇</option> <option>A</option> <option>B</option> <option>C</option> </select> <span>Selected: {{ selected }}</span> </div>
v-on
綁定事件
-
事件修飾符:
.prevent
.once
-
簡(jiǎn)化語(yǔ)法
<a href="#" @click.prevent="handleDelete">刪除<a>
v-show
v-if
v-for
v-cloak
v-once
- 一次性綁定
Vue的選項(xiàng)對(duì)象
當(dāng)創(chuàng)建一個(gè) Vue 實(shí)例時(shí),你可以傳入一個(gè)選項(xiàng)對(duì)象边琉。你可以在 API 文檔 中瀏覽完整的選項(xiàng)列表属百。
-
el
選項(xiàng)提供一個(gè)在頁(yè)面上已存在的 DOM 元素作為 Vue 實(shí)例的掛載目標(biāo)”湟蹋可以是 CSS 選擇器族扰,也可以是一個(gè) HTMLElement 實(shí)例。
注意:
- 不能作用到
<html>
或者<body>
上 - 也可以通過(guò)
實(shí)例.$mount()
手動(dòng)掛載
- 不能作用到
-
data
選項(xiàng)- Vue 實(shí)例的數(shù)據(jù)對(duì)象定欧,能夠響應(yīng)式數(shù)據(jù)變化(雙向綁定)
- 可以通過(guò)
vm.$data
訪(fǎng)問(wèn)原始數(shù)據(jù)對(duì)象 - Vue 實(shí)例也代理了 data 對(duì)象上所有的屬性渔呵,因此訪(fǎng)問(wèn)
vm.a
等價(jià)于訪(fǎng)問(wèn)vm.$data.a
- 視圖中綁定的數(shù)據(jù)必須顯式的初始化到 data 中
-
methods
選項(xiàng)methods 將被混入到 Vue 實(shí)例中】仇可以直接通過(guò)
vm
實(shí)例訪(fǎng)問(wèn)這些方法扩氢,或者在指令表達(dá)式中使用。方法中的this
自動(dòng)綁定為 Vue 實(shí)例爷辱。注意: 不應(yīng)該使用箭頭函數(shù)來(lái)定義 method 函數(shù) (例如
plus: () => this.a++
)录豺。理由是箭頭函數(shù)綁定了父級(jí)作用域的上下文,所以this
將不會(huì)按照期望指向 Vue 實(shí)例托嚣,this.a
將是 undefined巩检。var vm = new Vue({ data: { a: 1 }, methods: { plus: function () { this.a++ } } }) vm.plus() vm.a // 2
案例:表格操作
- 展示列表數(shù)據(jù)
- 刪除數(shù)據(jù)
- 添加數(shù)據(jù)
總結(jié):
- Vue 最大程度上減少了頁(yè)面上的 DOM 操作
- 讓開(kāi)發(fā)人員更專(zhuān)注于業(yè)務(wù)操作
- 通過(guò)簡(jiǎn)潔的指令結(jié)合頁(yè)面結(jié)構(gòu)與邏輯數(shù)據(jù)
- 代碼結(jié)構(gòu)更合理
- 維護(hù)成本更低
- 數(shù)據(jù)驅(qū)動(dòng)
- VueJS 解放了傳統(tǒng) JavaScript 中頻繁的 DOM 操作
DevTools
https://github.com/vuejs/vue-devtools
MVVM
其它知識(shí)點(diǎn)
過(guò)濾器
Vue.js 允許你自定義過(guò)濾器,可被用于一些常見(jiàn)的文本格式化示启。過(guò)濾器可以用在兩個(gè)地方:雙花括號(hào)插值和 v-bind 表達(dá)式 (后者從 2.1.0+ 開(kāi)始支持)兢哭。
需求:對(duì)表格案例中的日期進(jìn)行格式化。
<td>{{ item.date | fmrTime('YYYY-MM-DD HH:mm:ss') }}</td>
<script>
Vue.filter('fmrTime', function (time, formatStr) {
// 使用moment.js對(duì)日期進(jìn)行格式化
return moment(time).format(formatStr);
});
</script>
計(jì)算屬性
模板內(nèi)的表達(dá)式非常便利夫嗓,但是設(shè)計(jì)它們的初衷是用于簡(jiǎn)單運(yùn)算的迟螺。
計(jì)算屬性當(dāng)依賴(lài)的data中的數(shù)據(jù)發(fā)生變化的時(shí)候執(zhí)行
-
計(jì)算屬性是基于它們的依賴(lài)進(jìn)行緩存的,計(jì)算屬性只有在它的相關(guān)依賴(lài)發(fā)生改變時(shí)才會(huì)重新求值舍咖。
通過(guò)獲取時(shí)間矩父,演示計(jì)算屬性和methods中方法的區(qū)別(緩存數(shù)據(jù)的差異)。
計(jì)算屬性和方法的區(qū)別
- 方法每次調(diào)用都會(huì)執(zhí)行
- 計(jì)算屬性只有當(dāng)依賴(lài)的數(shù)據(jù)方法變化才會(huì)執(zhí)行
需求:表格案例中實(shí)現(xiàn)搜索功能
<tr v-for="(item, index) in newList" :key="index">
....
<tr v-if="newList.length === 0">
<script>
var vm = new Vue({
el: ....
computed: {
newList() {
return this.list.filter((item) => {
return item.name.startsWith(this.searchKey);
});
}
}
})
</script>
ref
在Vue.js中操作DOM排霉。
需求:表格案例中讓文本框默認(rèn)獲得焦窍株。
- 給要獲取焦點(diǎn)的元素增加ref屬性
- 在mounted中通過(guò)$refs獲取DOM元素
<input type="text" ref="username" v-model="name">
<script>
var vm = new Vue({
el: '#app',
// mounted當(dāng)頁(yè)面加載完畢執(zhí)行
mounted: function () {
this.$refs.username.focus();
},
data.....,
});
</script>
注意:Vue.js中不推薦直接操作DOM,除非必須否則不建議這么使用攻柠。
自定義指令
除了核心功能默認(rèn)的指令球订,例如:v-model
和 v-show
,Vue 也允許注冊(cè)自定義指令瑰钮。
需求:表格案例中讓文本框默認(rèn)獲得焦冒滩。 給文本框增加自定義指令 v-focus
<input type="text" v-focus v-model="name">
<script>
// 全局自定義指令
Vue.directive('focus', {
inserted: function (el) {
el.focus();
}
});
</script>
發(fā)送網(wǎng)絡(luò)請(qǐng)求
在Vue.js中發(fā)送網(wǎng)絡(luò)請(qǐng)求本質(zhì)還是ajax,我們可以使用插件方便操作浪谴。
-
vue-resource
Vuejs的插件开睡,已經(jīng)不維護(hù)因苹,作者不推薦使用
-
axios
可以在任何地方使用,推薦
axios
既可以在瀏覽器端又可以在node.js中使用的發(fā)送http請(qǐng)求的庫(kù)篇恒,支持Promise扶檐,默認(rèn)不支持jsonp。官網(wǎng)
-
發(fā)送get請(qǐng)求
axios.get('http://localhost:3000/brands') .then(res => { console.log(res.data); }) .catch(err => { console.dir(err) });
-
發(fā)送delete請(qǐng)求
axios.delete('http://localhost:3000/brands/109') .then(res => { console.log(res.data); }) .catch(err => { console.dir(err) });
-
發(fā)送post請(qǐng)求
axios.post('http://localhost:3000/brands', {name: '小米', date: new Date()}) .then(res => { console.log(res); }) .catch(err => { console.dir(err) });
-
jsonp
https://github.com/axios/axios/blob/master/COOKBOOK.md
jsonp('http://localhost:3000/brands', (err, data) => { if (err) { console.dir(err.msg); } else { console.dir(data); } });
表格案例
數(shù)據(jù)列表
刪除數(shù)據(jù)
添加數(shù)據(jù)
-
查詢(xún)數(shù)據(jù)
-
偵聽(tīng)器
監(jiān)聽(tīng)data對(duì)象的searchKey屬性的變化婚度,執(zhí)行相應(yīng)的操作
watch: { searchKey: function (newValue, oldValue) { // 發(fā)送請(qǐng)求獲取列表數(shù)據(jù) axios.get('http://localhost:3000/brands?name_like=' + newValue) .then(res => { this.list = res.data; }) .catch(err => { console.log(err); }); }
-
過(guò)渡和動(dòng)畫(huà)
Vue 在插入蘸秘、更新或者移除 DOM 時(shí),提供多種不同方式的應(yīng)用過(guò)渡效果蝗茁。
在 CSS 過(guò)渡和動(dòng)畫(huà)中自動(dòng)應(yīng)用 class
Vue 提供了 transition
的封裝組件醋虏,在下列情形中,可以給任何元素和組件添加進(jìn)入/離開(kāi)過(guò)渡
// v要替換成transition組件的name屬性值
v-enter:定義進(jìn)入過(guò)渡的開(kāi)始狀態(tài)哮翘。
v-enter-active:定義進(jìn)入過(guò)渡生效時(shí)的狀態(tài)颈嚼。
v-enter-to: 2.1.8版及以上 定義進(jìn)入過(guò)渡的結(jié)束狀態(tài)。
v-leave: 定義離開(kāi)過(guò)渡的開(kāi)始狀態(tài)饭寺。
v-leave-active:定義離開(kāi)過(guò)渡生效時(shí)的狀態(tài)阻课。
v-leave-to: 2.1.8版及以上 定義離開(kāi)過(guò)渡的結(jié)束狀態(tài)。
示例:
<style>
.box {
position: absolute;
left: 0;
top: 50px;
width: 100px;
height: 100px;
background-color: red;
}
.slide-enter, .slide-leave-to {
left: 200px;
opacity: 0;
}
.slide-enter-active, .slide-leave-active {
transition: all 2s;
}
.slide-enter-to, .slide-leave {
left: 0px;
opacity: 1;
}
</style>
<button @click="isShow = !isShow">顯示/隱藏</button>
<transition name="slide">
<div v-show="isShow" class="box"></div>
</transition>
<script>
var vm = new Vue({
el: '#app',
data: {
isShow: true
}
});
</script>
自定義過(guò)渡動(dòng)畫(huà)的類(lèi)名
可以通過(guò)transition組件自定義過(guò)渡動(dòng)畫(huà)的類(lèi)名艰匙,可以方便結(jié)合第三方的動(dòng)畫(huà)庫(kù)使用限煞,比如:animate.css
// transition組件的屬性
enter-class
enter-active-class
enter-to-class (2.1.8+)
leave-class
leave-active-class
leave-to-class (2.1.8+)
示例:
<button @click="isShow = !isShow">toggle</button>
<transition
enter-active-class="animated fadeIn"
leave-active-class="animated fadeOut">
<div v-show="isShow">hello</div>
</transition>
<script>
var vm = new Vue({
el: '#app',
data: {
isShow: true
}
});
</script>
組件
什么是組件
組件系統(tǒng)是 Vue 的另一個(gè)重要概念,因?yàn)樗且环N抽象员凝,允許我們使用小型署驻、獨(dú)立和通常可復(fù)用的組件構(gòu)建大型應(yīng)用健霹。仔細(xì)想想旺上,幾乎任意類(lèi)型的應(yīng)用界面都可以抽象為一個(gè)組件樹(shù):
組件和模塊
- 模塊:側(cè)重于功能或者數(shù)據(jù)的封裝
- 組件:包含了 template、style 和 script糖埋,而它的 script 可以由各種模塊組成
Vue中的組件開(kāi)發(fā)
組件是可復(fù)用的 Vue 實(shí)例宣吱,且?guī)в幸粋€(gè)名字,比如 <my-breadcrumb>
瞳别。把這個(gè)組件作為自定義元素來(lái)使用征候。組件的好處是寫(xiě)一次可以進(jìn)行任意次數(shù)的復(fù)用。
全局組件
Vue.component('my-breadcrumb', {
template: `<div>
<span>{{ level1 }}</span>
<span>/</span>
<span @click="t">{{ level2 }}</span>
<div>`,
data() {
return {
level1: '用戶(hù)管理1',
level2: '用戶(hù)列表1'
};
},
methods: {
t() {
alert('hello');
}
}
});
注意:
- 組件的模板中必須有且只有一個(gè)根標(biāo)簽
- 組件是一個(gè)特殊的Vue實(shí)例
- 組件中的data是一個(gè)方法祟敛,目的是讓每一個(gè)組件維護(hù)一個(gè)自己的數(shù)據(jù)
- 組件有自己的作用域
私有組件
// 私有組件
var ComponentA = {
template: '<div>{{ msg }}</div>',
data() {
return {
msg: 'hello'
};
}
};
var vm = new Vue({
el: '#app',
components: {
'component-a': ComponentA
}
});
通過(guò)Props給子組件傳值
-
子組件可以通過(guò)
props
選項(xiàng)接收一個(gè)一些值倍奢,通過(guò)props
傳遞的值變成了改組件的一個(gè)屬性。var ComponentA = { template: '<div>{{ title }}</div>', props: ['title'], };
-
當(dāng)然子組件具有
props
選項(xiàng)后垒棋,數(shù)據(jù)可以通過(guò)標(biāo)簽的自定義屬性傳遞給子組件<component-a :title="msg"></component-a>
-
在vue的實(shí)例中提供該屬性值
var vm = new Vue({ el: '#app', data: { msg: 'hello heima', }, components: { 'component-a': ComponentA } });
?
Vue實(shí)例的生命周期
-
什么生命周期
定義:生命周期是指vue實(shí)例或者組件從誕生到消亡經(jīng)歷的每一個(gè)階段,在這些階段的前后可以設(shè)置一些函數(shù)當(dāng)做事件來(lái)調(diào)用痪宰。
-
參考
生命周期中的鉤子函數(shù)
//創(chuàng)造vue實(shí)例之后運(yùn)行此函數(shù)叼架,vm中的data/methods中的成員不可用
beforeCreate: function () {
console.log("beforeCreate")
}
//創(chuàng)造vue實(shí)例之后運(yùn)行此函數(shù)畔裕,vm中的data/methods屬性可用
created: function () {
console.log("created")
}
//當(dāng)vue實(shí)例的el節(jié)點(diǎn)或組件掛載到頁(yè)面以前運(yùn)行次函數(shù)
beforeMount: function () {
console.log("beforeMount")
}
//當(dāng)vue實(shí)例的el節(jié)點(diǎn)或組件掛載到頁(yè)面以后運(yùn)行次函數(shù)
mounted: function () {
console.log("mounted")
}
//當(dāng)vue實(shí)例數(shù)據(jù)發(fā)生改變前觸發(fā)此函數(shù)
beforeUpdate: function () {
console.log("beforeUpdate")
}
//當(dāng)vue實(shí)例數(shù)據(jù)發(fā)生改變后觸發(fā)此函數(shù)
updated: function () {
console.log("updated")
}
前端路由
單頁(yè)應(yīng)用
-
什么是單頁(yè)應(yīng)用
單頁(yè)應(yīng)用(single page web application,SPA)乖订,是在一個(gè)頁(yè)面完成所有的業(yè)務(wù)功能扮饶,瀏覽器一開(kāi)始會(huì)加載必需的HTML、CSS和JavaScript乍构,之后所有的操作都在這張頁(yè)面完成甜无,這一切都由JavaScript來(lái)控制。
-
單頁(yè)應(yīng)用優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn)
- 操作體驗(yàn)流暢
- 完全的前端組件化
- 缺點(diǎn)
- 首次加載大量資源(可以只加載所需部分)
- 對(duì)搜索引擎不友好
- 開(kāi)發(fā)難度相對(duì)較高
- 優(yōu)點(diǎn)
-
單頁(yè)應(yīng)用的原理
-
Hash路由
-
利用URL上的hash哥遮,當(dāng)hash改變不會(huì)引起頁(yè)面刷新岂丘,所以可以利用 hash 值來(lái)做單頁(yè)面應(yīng)用的路由,
并且當(dāng) url 的 hash 發(fā)生變化的時(shí)候眠饮,可以觸發(fā)相應(yīng) hashchange 回調(diào)函數(shù)奥帘。
模擬實(shí)現(xiàn)
var app = document.getElementById('app'); window.onhashchange = function () { var hash = location.hash.replace('#', ''); switch (hash.toLowerCase()) { case '/': app.innerHTML = '首頁(yè)內(nèi)容'; break; case '/users': app.innerHTML = '用戶(hù)管理內(nèi)容'; break; …… } };
-
-
History路由
- History 路由是基于 HTML5 規(guī)范,在 HTML5 規(guī)范中提供了 history.pushState || history.replaceState 來(lái)進(jìn)行路由控制仪召。
-
vue-router
快速體驗(yàn)
導(dǎo)入vue和vue-router
-
設(shè)置HTML中的內(nèi)容
<!-- router-link 最終會(huì)被渲染成a標(biāo)簽寨蹋,to指定路由的跳轉(zhuǎn)地址 --> <router-link to="/users">用戶(hù)管理</router-link> <!-- 路由匹配到的組件將渲染在這里 --> <router-view></router-view>
-
創(chuàng)建組件
// 創(chuàng)建組件 // 組件可以放到單獨(dú)的js文件中 var Home = { template: '<div>這是Home內(nèi)容</div>' }; var Users = { template: '<div>這是用戶(hù)管理內(nèi)容</div>' };
-
配置路由規(guī)則
// 配置路由規(guī)則 var router = new VueRouter({ routes: [ { name: 'home', path: '/', component: Home }, { name: 'users', path: '/users', component: Users } ] });
-
設(shè)置vue的路由選項(xiàng)
var vm = new Vue({ el: '#app', router });
動(dòng)態(tài)路由匹配
假設(shè)有一個(gè)用戶(hù)列表,想要?jiǎng)h除某一個(gè)用戶(hù)扔茅,需要獲取用戶(hù)的id傳入組件內(nèi)已旧,如何實(shí)現(xiàn)呢?
此時(shí)可以通過(guò)路由傳參來(lái)實(shí)現(xiàn)召娜,具體步驟如下:
-
路由規(guī)則中增加參數(shù)运褪,在path最后增加 :id
{ name: 'users', path: '/users/:id', component: Users },
-
通過(guò) <router-link> 傳參,在路徑上傳入具體的值
<router-link to="/users/120">用戶(hù)管理</router-link>
-
在組件內(nèi)部可以使用萤晴,this.$route 獲取當(dāng)前路由對(duì)象
var Users = { template: '<div>這是用戶(hù)管理內(nèi)容 {{ $route.params.id }}</div>', mounted() { console.log(this.$route.params.id); } };
webpack
webpack 是一個(gè)模塊打包器吐句。webpack 的主要目標(biāo)是將 JavaScript 文件打包在一起,打包后的文件用于在瀏覽器中使用。
參考網(wǎng)站: 中文參考網(wǎng)站 官網(wǎng)
安裝webpack
最新webpack版本4.x
- 本地安裝webpack
- 安裝webpack的命令行工具 webpack-cli
$ npm install webpack webpack-cli --save-dev
快速實(shí)踐
- 項(xiàng)目結(jié)構(gòu)店读,默認(rèn)的目錄和文件名稱(chēng)不可修改
webpack-demo
|- package.json
+ |- /dist
+ |- index.html
|- /src
|- index.js
- 入口js文件嗦枢,默認(rèn)名稱(chēng)index.js
math.js
export default {
add(a, b) {
return a + b;
},
sub(a, b) {
return a - b;
}
};
index.js
import Math from './math';
var x = 5;
var y = 6;
console.log(Math.add(5, 6));
console.log(Math.sub(5, 6));
- 運(yùn)行
$ npm webpack
配置文件 webpack.config.js
webpack4.x 以前,必須要有配置文件屯断。在 webpack 4.x 以后文虏,可以無(wú)須任何配置使用(),然而大多數(shù)項(xiàng)目會(huì)需要很復(fù)雜的設(shè)置殖演,這就是為什么 webpack 仍然要支持氧秘。
-
使用步驟
- 項(xiàng)目根目錄下,手動(dòng)新建webpack.config.js
const path = require('path'); module.exports = { // 配置入口文件 entry: './src/index.js', // 配置打包的文件和路徑 output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') } };
- 運(yùn)行命令
$ npm webpack --config webpack.config.js
注意:打包的文件名改變后趴久,要修改index.html的script標(biāo)簽引入的文件名
<script src="bundle.js"></script>
-
NPM腳本
輸入上面的命令太繁瑣丸相,可以直接在終端運(yùn)行 webpack,會(huì)默認(rèn)加載webpack.config.js配置文件彼棍。
- 在package.json中新增
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack" },
- 終端輸入
$ npm run build
webpack常用的Loader
webpack 最出色的功能之一就是灭忠,除了 JavaScript膳算,還可以通過(guò) loader 引入任何其他類(lèi)型的文件。webpack 可以把所有文件作為模塊弛作,動(dòng)態(tài)打包(dynamically bundle)所有依賴(lài)項(xiàng)涕蜂。
打包CSS
-
安裝和配置 style-loader 和 css-loader
- 安裝
$ npm install --save-dev style-loader css-loader
- 配置,在webpack.config.js中
const path = require('path'); module.exports = { entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, + module: { + rules: [ + { + test: /\.css$/, + use: [ + 'style-loader', + 'css-loader' + ] + } + ] + } };
-
在入口index.js中映琳,導(dǎo)入css模塊
import './css/index.css';
-
運(yùn)行webpack命令
$ npm run build
打包less
-
安裝和配置
$ npm install less-loader less --save-dev
{ test: /\.less$/, use: [ 'style-loader', 'css-loader', 'less-loader' ] }
-
less
@color: yellow; body { background-color: @color; }
打包sass
-
安裝和配置
$ npm install sass-loader node-sass --save-dev
{ test: /\.scss$/, use: [ 'style-loader', 'css-loader', 'sass-loader' ] }
-
scss
$color: red; body { background-color: $color; }
加載圖片
使用 file-loader 可以加載圖片和字體
-
安裝和配置
$ npm install --save-dev file-loader
{ test: /\.(png|svg|jpg|gif)$/, use: [ 'file-loader' ] }
加載字體
-
配置
{ test: /\.(woff|woff2|eot|ttf|otf)$/, use: [ 'file-loader' ] }
webpack常用插件
除了通過(guò)loader去處理不同的資源文件以外机隙,webpack還支持插件機(jī)制,通過(guò)插件可以完成更多的事情萨西。
HtmlWebpackPlugin
自動(dòng)生成index.html有鹿,并引入資源文件,還可以通過(guò)配置壓縮HTML原杂。
-
安裝
npm install --save-dev html-webpack-plugin
-
配置
const HtmlWebpackPlugin = require('html-webpack-plugin'); ...... plugins: [ new HtmlWebpackPlugin({ // 文檔的標(biāo)題 title: 'Output Management', // 生成的文檔文件名 filename: 'index.html', // 模板文件 template: 'index.html', minify: { collapseWhitespace: true } }) ] ......
CleanWebpackPlugin
清空dist目錄印颤。
-
安裝
npm install clean-webpack-plugin --save-dev
-
配置
const CleanWebpackPlugin = require('clean-webpack-plugin'); …… new CleanWebpackPlugin(['dist']), ……
使用source map
在webpack.config.js中添加
devtool: 'inline-source-map',
使用 webpack-dev-server
webpack-dev-server
為你提供了一個(gè)簡(jiǎn)單的 web 服務(wù)器,并且能夠?qū)崟r(shí)重新加載(live reloading)穿肄。讓我們?cè)O(shè)置以下:
$ npm install --save-dev webpack-dev-server
webpack.config.js
devServer: {
contentBase: './dist'
},
package.json
"start": "webpack-dev-server --open"
啟用HMR
模塊熱替換(Hot Module Replacement 或 HMR)是 webpack 提供的最有用的功能之一年局。它允許在運(yùn)行時(shí)更新各種模塊,而無(wú)需進(jìn)行完全刷新咸产。
webpack.config.js
const webpack = require('webpack');
.......
devServer: {
contentBase: './dist',
hot: true
},
.......
.......
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin()
.......
綜合案例
單文件組件
可以通過(guò) .vue 文件封裝組件矢否,參考文檔
-
處理 .vue 文件 — 使用 vue-loader
vue-loader使用比較特殊,如下
$ npm install vue-loader --save-dev $ npm install vue-template-compiler --save-dev
// 配置插件
// 配置loader { test: /\.vue$/, loader: 'vue-loader' }
案例演示
搭建項(xiàng)目結(jié)構(gòu)
-
新建項(xiàng)目
- 初始化package.json
# 注意項(xiàng)目名稱(chēng)不能有中文 $ npm init -y
- 拷貝 webpack.config.js 到根目錄
- 拷貝依賴(lài)
"devDependencies": { "clean-webpack-plugin": "^0.1.19", "css-loader": "^0.28.11", "file-loader": "^1.1.11", "html-minifier": "^3.5.16", "html-webpack-plugin": "^3.2.0", "less": "^3.0.4", "less-loader": "^4.1.0", "node-sass": "^4.9.0", "sass-loader": "^7.0.1", "style-loader": "^0.21.0", "url-loader": "^1.0.1", "vue-loader": "^15.2.0", "vue-template-compiler": "^2.5.16", "webpack": "^4.8.3", "webpack-cli": "^2.1.4", "webpack-dev-server": "^3.1.4" }, "dependencies": { "vue": "^2.5.16" }
- 安裝依賴(lài)
$ npm install
- 下載bootstrap3
$ npm install bootstrap@3.3.7 --save
-
項(xiàng)目結(jié)構(gòu)
[圖片上傳失敗...(image-de211b-1527597271494)]
配置根組件
從模板中復(fù)制自定義樣式 index.css 到assets/css目錄
-
入口文件 src/index.js
import Vue from 'vue'; import App from './App.vue'; // 導(dǎo)入bootstrap樣式 import 'bootstrap/dist/css/bootstrap.css'; // 導(dǎo)入自定義樣式 import './assets/css/index.css'; const vm = new Vue({ el: '#app', render: c => c(App) });
-
根組件 src/App.vue
復(fù)制模板中index.html的內(nèi)容到App.vue中
-
運(yùn)行測(cè)試
$ npm start
提取子組件
提取頭部組件 components/header.vue
提取側(cè)邊欄組件 components/sidebar.vue
提取英雄列表組件 views/hero-list.vue
-
根組件 src/App.vue 中加載組件
import Header from './components/header.vue'; import Sidebar from './components/sidebar.vue'; import Heroes from './views/heroes.vue'; export default { components: { Header, Sidebar, Heroes } };
<div> <Header></Header> <div class="container-fluid"> <div class="row"> <Sidebar></Sidebar> <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <h2 class="sub-header">Hero List</h2> <a class="btn btn-success" href="add.html">Add</a> <div class="table-responsive"> <Heroes></Heroes> </div> </div> </div> </div> </div>
使用 Vue-Router 實(shí)現(xiàn)頁(yè)面導(dǎo)航管理
Vue-Router 能幫我們實(shí)現(xiàn)點(diǎn)擊某個(gè)導(dǎo)航鏈接的時(shí)候動(dòng)態(tài)的展示一個(gè)組件
-
安裝路由模塊
$ npm install vue-router --save
-
注冊(cè)路由插件
在index.js中脑溢,加載路由插件
import VueRouter from 'vue-router'; // 注冊(cè)路由插件 Vue.use(VueRouter);
-
加載組件僵朗,配置路由規(guī)則
index.js中
// 加載組件 import Heroes from './views/heroes/heroes.vue'; import Weapons from './views/weapons.vue'; import Equips from './views/equips.vue'; // 配置路由規(guī)則 const router = new VueRouter({ routes: [ // 設(shè)置根路徑跳轉(zhuǎn)到英雄管理界面 {'name': 'home', path: '/', redirect: {name: 'heroes'}}, {'name': 'heroes', path: '/heroes', component: Heroes}, {'name': 'weapons', path: '/weapons', component: Weapons}, {'name': 'equips', path: '/equips', component: Equips} ] }); new Vue({ el: '#app', render: c => c(App), // 設(shè)置路由 router });
-
在
src/App.vue
組件中留路由出口(告訴路由往哪里渲染 path 匹配到的組件)<Sidebar></Sidebar> <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <router-view></router-view> </div>
-
在側(cè)邊欄
src/components/sidebar.vue
組件中 增加兩個(gè)導(dǎo)航鏈接<ul class="nav nav-sidebar"> <router-link to="/heroes" tag="li" active-class="active"> <a>英雄列表</a> </router-link> <router-link to="/weapons" tag="li" active-class="active"> <a>武器列表</a> </router-link> <router-link to="/equips" tag="li" active-class="active"> <a>裝備列表</a> </router-link> </ul>
JSON Server
可以快速開(kāi)啟 REST API 測(cè)試服務(wù)器的工具命令行工具。官網(wǎng)
安裝
$ npm install json-server -g
使用
$ json-server --watch db.json
接口地址
- 獲取英雄列表
- 請(qǐng)求路徑:
http://localhost:3000/heros
- 請(qǐng)求方法:
GET
-
根據(jù)英雄id獲取一個(gè)英雄
-
請(qǐng)求路徑:
http://localhost:3000/heros/:id
-
:id
需要給定一個(gè)英雄的 id
-
請(qǐng)求方法:
GET
-
-
添加英雄
- 請(qǐng)求路徑:
http://localhost:3000/heros
- 請(qǐng)求方法:
POST
- 請(qǐng)求體:
{ name: '英雄名稱(chēng)', gender: '英雄性別' }
- 請(qǐng)求路徑:
-
刪除英雄
-
請(qǐng)求路徑:
http://localhost:3000/heros/:id
-
:id
需要給定一個(gè)英雄的 id
-
請(qǐng)求方法:
DELETE
-
-
編輯英雄
-
請(qǐng)求路徑:
http://localhost:3000/heros/:id
-
:id
需要給定一個(gè)英雄的 id
-
請(qǐng)求方法:
PATCH
-
請(qǐng)求體:
{ name: '英雄名稱(chēng)', gender: '英雄性別' }
-
實(shí)現(xiàn)項(xiàng)目功能
安裝 axios 到項(xiàng)目中
$ npm install axios --save
英雄列表
JS
import axios from 'axios';
export default {
data() {
return {
heroes: []
};
},
mounted() {
this.loadData();
},
methods: {
async loadData() {
const res = await axios.get('http://localhost:3000/heros');
this.heroes = res.data;
}
}
};
HTML
<tr v-for="(item, index) in heroes" :key="item.id">
<td>{{ index + 1 }}</td>
<td>{{ item.name }}</td>
<td>{{ item.gender }}</td>
<td>
<!-- <router-link :to="'/edit/' + item.id"></router-link> -->
<a href="edit.html">edit</a>
<a href="javascript:window.confirm('Are you sure?')">delete</a>
</td>
</tr>
刪除英雄
HTML
<!-- prevent 修飾符屑彻,阻止后續(xù)內(nèi)容的執(zhí)行 -->
<a href="#" @click.prevent="handleClick(item.id)">delete</a>
JS
async handleClick(id) {
const isConfirmed = confirm('確認(rèn)要?jiǎng)h除該英雄验庙?');
if (!isConfirmed) {
return;
}
const res = await axios.delete(`http://localhost:3000/heros/${id}`);
if (res.status === 200) {
this.loadData();
alert('刪除成功');
} else {
alert('刪除失敗');
}
}
添加英雄
路由
新建
src/views/heroes/heroes-add.vue
-
配置路由
import HeroesAdd from '../views/heroes/heroes-add.vue'; // 增加一個(gè)路由規(guī)則 {'name': 'heroesadd', path: '/heroes/add', component: HeroesAdd}, {'name': 'heroes', path: '/heroes', component: Heroes},
-
src/views/heroes/heroes.vue
中點(diǎn)擊添加按鈕<router-link class="btn btn-success" to="/heroes/add">Add</router-link>
HTML
<h2 class="sub-header">添加英雄</h2>
<form>
<div class="form-group">
<label for="name">英雄名稱(chēng)</label>
<input type="text" v-model="formData.name" class="form-control" id="name" placeholder="英雄名稱(chēng)">
</div>
<div class="form-group">
<label for="sex">英雄性別</label>
<input type="text" v-model="formData.gender" class="form-control" id="sex" placeholder="英雄性別">
</div>
<button type="submit" @click.prevent="handleAdd" class="btn btn-success">Submit</button>
</form>
JS
import axios from 'axios';
export default {
data() {
return {
formData: {
name: '',
gender: ''
}
};
},
methods: {
async handleAdd() {
const res = await axios.post('http://localhost:3000/heros', this.formData);
if (res.status === 201) {
// 跳轉(zhuǎn)到列表頁(yè)面
this.$router.push({
name: 'heroes'
});
} else {
alert('添加失敗');
}
}
}
};
編輯英雄
路由
新建
src/views/heroes/heroes-edit.vue
-
配置路由
import HeroesEdit from '../views/heroes/heroes-edit.vue'; // 增加一個(gè)路由規(guī)則 {'name': 'heroes', path: '/heroes', component: Heroes}, {'name': 'heroesadd', path: '/heroes/add', component: HeroesAdd}, {'name': 'heroesedit', path: '/heroes/edit/:id', component: HeroesEdit},
-
src/views/heroes/heroes.vue
中,設(shè)置編輯<router-link :to="{name: 'heroesedit', params: {id: item.id}}">edit</router-link>
HTML
和添加英雄一樣
JS
import axios from 'axios';
export default {
data() {
return {
formData: {
name: '',
gender: ''
},
heroId: -1
};
},
created() {
this.heroId = this.$route.params.id;
this.getHeroById();
},
methods: {
// 根據(jù)id社牲,獲取英雄信息
async getHeroById() {
const res = await axios.get(`http://localhost:3000/heros/${this.heroId}`);
if (res.status === 200) {
this.formData = res.data;
}
},
// 更新英雄信息
async handleEdit() {
const res = await axios.patch(`http://localhost:3000/heros/${this.heroId}`, this.formData);
if (res.status === 200) {
// 跳轉(zhuǎn)到列表頁(yè)面
this.$router.push({
name: 'heroes'
});
} else {
alert('編輯失敗');
}
}
}
};
NPM 緩存安裝
需要曾經(jīng)從網(wǎng)絡(luò)使用NPM安裝過(guò)想要的包
$ npm --cache-min 9999999 install webpack --save-dev