大綱
核心成員
vue:核心功能—插件,組件,數據管理,生命週期
vue-router:路由機制—拆分,拆開,將文件劃分大小
vuex:vue官方提供的數據共享機制,全局性管理數據
編譯打包
webpack:打包—js,css,圖片,包的分隔,提供了很多開發功能
vue-loader:轉換器
cli:腳手架,創建默認啓動項目
開發支持
vue-devtools:按照組件查找
後端渲染
前端渲染:性能更高,用戶體驗更好;所有的代碼都需要用js寫,所有的頁面都需要被用戶看到;
後端渲染:安全性高,SEO
結合:
vue-server-renderer:後端渲染的核心組件
nuxt.js:整合環境
UI組件
element-UI
vue-element-admin
Vue基礎
歷史介紹
angular 09年,複雜,學習曲線長,一開始被大家拒絕
react 13年,用戶體驗良好
vue 14年,用戶體驗良好,尤雨溪,無錫人
前端框架與庫的區別
- jquery庫 -> DOM(操作DOM) +請求
- art-template庫 -> 模板引擎
- 框架 = 全方位功能齊全
- 簡單的DOM體驗 + 發請求 + 模板引擎 + 路由功能
- KFC的世界裏,庫就是一個小小的套餐,框架就是全家桶
- 代碼上的不同
- 一般使用庫的代碼,是調用某個函數,我們自己把控庫的代碼
- 一般使用框架,其框架在幫助我們運行編寫好的代碼
- 框架:初始化一些行爲
- 執行你所編寫的代碼
- 釋放一些資源
- 框架:初始化一些行爲
vue起步
-
引包
-
啓動new Vue({el: 目的地,template:模板內容});
-
opations
- 目的地 el
- 數據源 data
- 模板 template
插值表達式({{}})
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>vue的基本使用</title>
<!-- 1 引入vue包 -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
<!-- 數據綁定 -->
<!-- vue的模板語法 {{}} 雙括號 -->
<h2>{{ name }}</h2> <!-- 綁定數據值 -->
<h3>{{ 1+1 }}</h3> <!-- 做運算 -->
<h4>{{ isTure }}</h4> <!-- 判斷真假 -->
<h5>{{ str.split('').reverse().join('') }}</h5> <!-- 使用js中的方法 -->
<h1>{{ 1 > 2 ? '真' : '假' }}</h1> <!-- 使用三元表達式 -->
<h6>{{ {"name" : "張三"} }}</h6> <!-- 插入對象 -->
</div>
<script type="text/javascript">
// 2 創建實例化對象
var app = new Vue({
el: '#app', // el 掛載點,vue操作的對象
data: { // 數據屬性
// 操作對象綁定的數據
// 既可以是一個對象,也可以是一個函數
name: '小陳',
hobby: '電子競技', //data中數據發生改變,視圖也會發生改變,簡而言之,數據驅動視圖
isTure: 1===1,
str: 'hello vue'
},
// 如果template中定義了內容 那麼優先渲染 template 模板中的內容
// 如果沒有定義內容,則加載的是#app中的模板
<!-- template: `<div>{{ hobby }}</div>` -->
template: ``
});
// 除了數據屬性 vue 實例還暴露了一些有用的實例屬性和方法
// 她們都有前綴$
console.log(app);
// 我們可以通過app.$數據名來獲取vue實例中的數據
console.log(app.$data);
</script>
</body>
</html>
指令
- 在vue中提供了一些對於頁面 + 數據的 跟爲方便的輸出,這些輸出就成爲指令,以v-xxx爲例。
- 比如html中的屬性
<div v-xxx></div>
- 比如html中的屬性
- 在angular中以
ng-xxx
開頭 - 在微信小程序中以
vx-xxx
開頭 - 在vue中以
v-xxx
開頭的就叫做指令 - 指令中封裝了一些DOM行爲,結合屬性作爲一個暗號,暗號有對應的值,根據不同的值,框架會進行相關的DOM操作的綁定
vue中常用的指令
-
v-text:元素的innerText屬性,必須是雙標籤,跟{{}}效果是一樣的,使用較少
-
v-html:元素的innerHtml
-
v-if :判斷是否插入這個元素,相當於元素的銷燬和創建
-
v-else-if
-
v-else
-
v-show:隱藏元素,如果元素確定要隱藏,會給元素的style加上
display:none
,是基於css樣式的切換 -
v-bind:給標籤進行屬性綁定(類似於:hover–給元素添加屬性)【簡寫 :bind】
-
v-on:綁定事件
- v-on:原生事件名 = ‘函數名’ 【簡寫 @】
-
v-for:遍歷
- v-for = “(item, index) in 數組名/對象名” ----> 使用{{ itme.字段名 }}
v-text:只能在雙標籤中使用,其實就是給元素的innerText賦值 v-html:其實就是給元素的innerHTML賦值 v-if:如果值爲false,不在頁面上渲染,會留下<!---->作爲標記,但是可視化界面上面沒有顯示,如果值爲true就將值顯示在可視化界面上面 v-if,v-else-if都有相對應的值,v-else直接寫 v-show是控制DOM元素顯示與否,true顯示,false隱藏
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>vue的基本使用</title>
<style type="text/css">
.obj {
width: 200px;
height: 200px;
border: 1px solid;
}
.obj2 {
width: 200px;
height: 200px;
border: 1px solid;
}
.active {
background-color: aqua;
}
table{
/* 去掉表格中的橫向 內部邊框線 */
border-collapse: collapse; /* 表格單元格間距樣式 */
}
</style>
<!-- 1 引入vue包 -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
</div>
<script type="text/javascript">
// 2 創建實例化對象
new Vue({
el: '#app',
data: function() {
return {
msg: 'v-text指令',
msg2: '<i>斜體i標籤</i>',
isShow: false,
isBlue: false,
isRed: false,
text: 'chenhaha',
listData: [
{id: 1, name: '小陳', sex: '女'},
{id: 2, name: '小王', sex: '女'},
{id: 3, name: '小姜', sex: '女'},
{id: 4, name: '小唐', sex: '女'},
{id: 5, name: '小黎', sex: '女'},
{id: 6, name: '小肖', sex: '女'}
],
person: {
name: '筱辰',
hobby: '街舞,rap,吉他',
age: 20
}
}
},
template: `
<div id="app">
// 通過text做數據的增加
<h2 v-text = "1 + 1"></h2>
<!-- 給標籤添加text值 -->
<h3 v-text = "msg"></h3>
<!-- 給標籤嵌套html標籤innerHTML -->
<div v-html = "msg2"></div>
<!-- 根據條件的真假輸出對應項的值 -->
<div v-if = 'isShow'>雨天,寫作業</div>
<div v-if = '!isShow'>晴天,出去耍,曬太陽</div>
<div v-if = 'Math.random() > 0.5'>隨機數大於0.5</div>
<div v-else>隨機數小於0.5</div>
<!-- 根據屬性值來讓元素顯示隱藏,實際上是改變display的值 none|block -->
<div v-show = 'isShow'>夏天</div>
<div v-show = '!isShow'>夏天</div>
<!-- v-bind 綁定class 通過屬性值來讓元素增加隱藏 -->
<div class = "obj" v-bind:class = "{active:!isBlue}" v-on:click = 'clickDiv'></div>
<!-- v-bind還可以綁定自定義屬性 -->
<div v-bind:aaa = 'text'></div>
<!-- 遍歷數組 -->
<table border="1">
<tr>
<th>編號</th>
<th>姓名</th>
<th>性別</th>
</tr>
<tr v-for = '(item, index) in listData'>
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>{{ item.sex }}</td>
</tr>
</table>
<!-- 遍歷對象 -->
<ul>
<li v-for = "(value,key) in person">
{{ key }} -------> {{ value }}
</li>
</ul>
</div>
`,
methods: {
clickDiv(e) {
this.isBlue = !this.isBlue;
}
}
});
</script>
</body>
</html>
v-if和v-show的區別
v-if 是 “真正”的條件渲染,因爲他會確保在切換過程中條件塊內的事件監聽器和子組件適當的被銷燬和重建
v-if也是惰性的:如果在初始渲染時條件爲假,則什麼也不做——知道條件第一次變爲真時,纔開始渲染條件塊。
相比之下,v-show就簡單得多——不管初始條件是什麼,元素總是會被渲染,並且只是簡單的基於css進行切換。(導航欄)
一般來說,v-if有更高的切換開銷,而v-show有更高的初始渲染開銷。因此,如果需要非常頻繁地切換,則使用v-show較好,如果在運行時條件很少改變,則使用v-if較好。
vue的雙向綁定(v-model)
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<!-- 1 引入vue包 -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
<!-- 單項數據綁定 -->
<span>單項數據綁定:</span>
<input type="text" :value="mag"/>
<hr />
<!-- 雙向數據綁定 只會體現在UI控件上面 只能應用在value屬性上 -->
<span>雙向數據綁定:</span>
<input type="text" v-model="msg"/>
<h1>{{ msg }}</h1>
<hr />
<!-- 實際上就是一個 語法糖,它是v-bind:value v-on:input的體現 -->
<span>雙向數據實現原理:</span>
<input type="text" v-bind:value="mfg" v-on:input="valueChange"/>
<h1>{{ mfg }}</h1>
</div>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
mag: "小豬佩奇",
msg: "好友記",
mfg: "肖申克的救贖"
}
},
methods: {
valueChange(e){
console.log(e.target.value);
this.mfg = e.target.value;
}
}
});
</script>
</body>
</html>
vue中的template(入口組件)
入口組件包含了:html,css,js
局部組件
打油詩:聲子 掛子 用子
創建:(類似於自定義全局組件,使用時直接在父組件中,通過局部組件的聲明名調用即可)
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<!-- 1 引入vue包 -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 局部入口組件的的聲明
var App = {
data() {
return {
}
},
// 局部入口組件的內容
template:
`
<h2>我是局部入口組件</h2>
`
};
// 2 實例化對象
new Vue({
el: "#app",
data() {
return {
}
},
<!-- 掛載子組件 -->
components: {
App <!-- 類似於App:App -->
},
<!-- 父組件可以直接使用子組件 -->
template:
`
<app></app>
`
});
</script>
</body>
</html>
全局組件
// 全局組件
// 第一個參數是組件的名字,第二個參數是組件的樣式
Vue.component('V-button',{
template:
`
<button>按鈕</button>
`
});
注意:在使用局部組件和全局組件時,不能單獨使用,每個組件都是一個整體,在組件中使用全局組件和局部組件時,必須要寫在組件的內部,它們是一個整體。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<!-- 1 引入vue包 -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 全局組件
// 第一個參數是組件的名字,第二個參數是組件的樣式
Vue.component('V-button',{
template:
`
<button>按鈕</button>
`
});
// 聲子
var Rightcentent = {
data() {
return {
}
},
template:
`
<div>
<div>我是右邊內容組件</div>
<V-button></V-button>
</div>
`
};
<!-- 側邊欄組件 -->
var Leftcentent = {
data() {
return {
}
},
template:
`
<div>我是左邊菜單欄組件</div>
`
};
<!-- 頭部組件 -->
var Header = {
data() {
return {
}
},
template:
`
<div>我是頭部組件</div>
`
};
// 局部入口組件的的聲明
var App = {
data() {
return {
}
},
template: <!-- 用子 注意:在使用創建的子組件是是一個整體,不能分散開來,不然只能顯示第一個子組件的值-->
`
<div>
<Header></Header>
<div>
<Leftcentent></Leftcentent>
<Rightcentent></Rightcentent>
</div>
</div>
`,
<!-- 掛子 -->
components: {
Header,
Leftcentent,
Rightcentent
}
};
// 2 實例化對象
new Vue({
el: "#app",
data() {
return {
}
},
<!-- 掛載子組件 -->
components: {
App <!-- 類似於App:App -->
},
<!-- 父組件可以直接使用子組件 -->
template:
`
<app></app>
`
});
</script>
</body>
</html>
父組件往子組件中傳值
1 先給父組件綁定自定義屬性
2 在子組件中使用prop接收父組件傳遞的數據
3 只要使用props接收了數據之後,就可以在子組件中任意使用
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<!-- 1 引入vue包 -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 聲明全局組件 子組件
Vue.component('Child',{
template:
`
<div>
<p>我是孩子</p>
<input type="text" v-model="childData"/>
</div>
`,
<!-- 接收自定義屬性 -->
props: ['childData']
});
<!-- 聲明全局組件 父組件 -->
<!-- 1 先給父組件綁定自定義屬性 -->
<!-- 2 在子組件中使用prop接收父組件傳遞的數據 -->
<!-- 3 只要使用props接收了數據之後,就可以在子組件中任意使用 -->
Vue.component('Parent',{
data() {
return {
msg: '我是父組件中的數據'
}
},
template:
`
<div>
<p>我是父親</p>
<!-- 在子組件中掛載自定義屬性 -->
<Child :childData = 'msg'/>
</div>
`
});
// 聲子
var App = {
template:
`
<div>
<Parent />
</div>
`
};
// 2 實例化對象
new Vue({
el: "#app",
data() {
return {
}
},
<!-- 掛載子組件 -->
components: {
App <!-- 類似於App:App -->
},
<!-- 父組件可以直接使用子組件 -->
template:
`
<app></app>
`
});
</script>
</body>
</html>
子組件往父組件中傳值
1.在父組件中綁定自定義事件
2.在子組件中觸發原生的事件,在函數中使用$emit觸發自定義函數
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<!-- 1 引入vue包 -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 聲明全局組件 子組件
Vue.component('Child',{
template:
`
<div>
<p>我是孩子</p>
<input type="text" v-model="childData" @input="changeValue(childData)"/>
</div>
`,
<!-- 接收自定義屬性 -->
props: ['childData'],
methods: {
changeValue(val){
<!-- 自定義的時間一定通過thi.$emit()去觸發 -->
<!-- 在函數中使用$emit(自定義的事件名,傳遞的消息) -->
this.$emit('childHeader',val);
}
}
});
<!-- 1.在父組件中綁定自定義事件 -->
<!-- 2.在子組件中觸發原生的事件,在函數中使用$emit觸發自定義函數 -->
Vue.component('Parent',{
data() {
return {
msg: '我是父組件中的數據'
}
},
template:
`
<div>
<p>我是父親</p>
<!-- 在子組件中掛載自定義屬性 -->
<Child :childData = 'msg' @childHeader = 'childHeader'/>
</div>
`,
methods: {
childHeader(val){
console.log(val);
}
}
});
// 聲子
var App = {
template:
`
<div>
<Parent />
</div>
`
};
// 2 實例化對象
new Vue({
el: "#app",
data() {
return {
}
},
<!-- 掛載子組件 -->
components: {
App <!-- 類似於App:App -->
},
<!-- 父組件可以直接使用子組件 -->
template:
`
<app></app>
`
});
</script>
</body>
</html>
vue內置全局組件(插槽)
插槽:slot 插槽,作爲承載分發內容的出口
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<style type="text/css">
.default {
display: inline-block;
line-height: 1;
white-space: nowrap;
cursor: pointer;
background: #fff;
border: 1px solid #dcdfe6;
color: #606266;
-webkit-appearance: none;
text-align: center;
box-sizing: border-box;
outline: none;
margin: 0;
transition: .1s;
font-weight: 500;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
padding: 12px 20px;
font-size: 14px;
border-radius: 4px;
}
.primary {
color: #fff;
background-color: #409eff;
border-color: #409eff;
}
.success {
color: #fff;
background-color: green;
border-color: #409eff;
}
</style>
<!-- 1 引入vue包 -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 通過插槽的方式封裝全局組件
Vue.component('Vbtn', {
template: `
<button class = 'default' :class = 'type'>
<slot>
按鈕
</slot>
</button>
`,
props: ['type']
});
<!-- 聲子 -->
var Vcontent = {
template: `
<div>
我是內容組件
<Vbtn type = 'primary'>主要按鈕</Vbtn>
<Vbtn type = 'success'>成功按鈕</Vbtn>
</div>
`
};
// 2 實例化對象
new Vue({
el: "#app",
data() {
return {
}
},
<!-- 掛子 -->
components: {
Vcontent <!-- 類似於App:App -->
},
<!-- 用子 -->
template: `
<Vcontent></Vcontent>
`
});
</script>
</body>
</html>
具名插槽(通過slot上的name)
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<script src="./node_modules/vue/dist/vue.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
Vue.component('myli',{
template:
`
<li>
預留的第一個空白
<slot name = 'two'></slot>
預留的第二個空白
<slot name = 'three'></slot>
</li>
`
})
var App = {
template:
`
<div>
<ul>
<myli>
<h2 slot = 'two'>我是第一個空白</h2>
<h2 slot = 'three'>我是第二個空白</h2>
</myli>
</ul>
</div>
`
}
<!-- 實例化vue -->
new Vue({
el: '#app',
components: {
App
},
template: `<App></App>`
});
</script>
</body>
</html>
過濾器
過濾器的功能:就是爲頁面中的數據進行添油加醋的功能
過濾器的分類:
- 局部過濾器
- 全局過濾器
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<script src="./node_modules/vue/dist/vue.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 過濾器的功能:就是爲頁面中的數據進行添油加醋的功能
// 有兩種:局部過濾器 全局過濾器
// 聲明全局過濾器
Vue.filter('myReverse', function(value,arg) {
return arg + value.split('').reverse().join('');
});
var App = {
data() {
return {
price: 0,
msg: 'filter'
}
},
template:
`
<div>
<input type="number" v-model = 'price'/>
<!-- 使用局部過濾器 {{ 數據 | 過濾器名 }} -->
<h2>{{ price | myCurrentcy }}</h2>
<!-- 使用全局過濾器 -->
<h4>{{ msg | myReverse('I am going to study well you ') }}</h4>
</div>
`,
filters: {
<!-- 1 聲明局部過濾器 -->
myCurrentcy: function(value) {
return "¥" + value;
}
}
}
<!-- 實例化vue -->
new Vue({
el: '#app',
components: {
App
},
template: `<App></App>`
});
</script>
</body>
</html>
監視(watch)
watch監聽的是單個屬性。
基本的數據類型,簡單監視。
複雜的數據類型深度監視。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<script src="./node_modules/vue/dist/vue.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="msg">
<h2>{{ msg }}</h2>
<button type="button" @click="stus[0].name = 'rose'">獲取用戶名</button>
<h4>{{ stus[0].name }}</h4>
</div>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
msg: '',
stus: [{name: 'jack'}]
}
},
watch: {
//簡單監視
// 字符串
msg: function(newV, oldV) {
console.log(newV, oldV);
},
//深度監視
stus:{
deep: true,
handler:function(newV, oldV) {
console.log(newV, oldV);
console.log(newV[0].name);
}
}
}
})
</script>
</body>
</html>
計算屬性
利用computed計算屬性寫網頁版音樂播放器。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<style type="text/css">
*{
padding: 0;
margin: 0;
}
ul{
list-style: none;
}
ul li {
margin: 20px 20px;
padding: 20px 20px;
}
.active{
background-color: aquamarine;
}
</style>
<script src="./node_modules/vue/dist/vue.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<audio :src='getCurrentSongSrc' autoplay="autoplay" controls="controls"></audio>
<ul>
<li v-for="(item,index) in musicData" @click="clickHander(index)" :class="{active:currentIndex == index}">
<h2>{{ item.id }} - 歌名:{{ item.name }}h2>
<p>歌曲來源:{{ item.sonSrc }}</p>
</li>
</ul>
</div>
<script type="text/javascript">
var musicData = [
{
id: 1,
name: '世界美好與你環環相扣',
author: '柏松',
sonSrc: 'music/世界美好與你環環相扣.mp3'
},
{
id: 2,
name: '昨天的你現在的未來',
author: '易烊千璽',
sonSrc: 'music/昨天的你現在的未來.mp3'
},
{
id: 3,
name: '精彩纔剛剛開始',
author: '易烊千璽',
sonSrc: 'music/精彩纔剛剛開始.mp3'
}
];
new Vue({
el: '#app',
data() {
return {
musicData:musicData,
currentIndex:0
}
},
computed:{
// 計算屬性默認只有getter
// setter也可以
// 使用getter
// getCurrentSongSrc:function(){
// return this.musicData[this.currentIndex].sonSrc
// }
// 使用setter
getCurrentSongSrc:{
set: function(newV){
console.log(newV);
this.currentIndex = newV;
},
get:function(){
return this.musicData[this.currentIndex].sonSrc
}
}
},
methods:{
clickHander(index){
// 使用getter
// 直接修改數據的屬性
// this.currentIndex = index;
// 使用setter
console.log(this.getCurrentSongSrc);
this.getCurrentSongSrc = index;
}
}
})
</script>
</body>
</html>
組件的生命週期
-
beforeCreate
- 組件創建之前
-
created
- 組件創建之後,就可以拿到自定義組件裏面的內容
-
beforeMount
- 掛載數據到DOM之前會調用
-
mounted
- 掛載數據到DOM之後
-
beforeUpdate
- 在更新DOM之前調用該鉤子,應用:可以獲取原始的DOM
-
updated
-
在更新DOM之後調用該鉤子,應用:可以獲取原始的DOM
-
beforeDeatory
- 銷燬數據之前
-
destroyed
- 銷燬數據之後
-
activated
- 激活組件
-
deactivated
- 停用組件
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title></title> <script src="./node_modules/vue/dist/vue.min.js" type="text/javascript" charset="utf-8"></script> </head> <body> <div id="app"> <App></App> </div> <script type="text/javascript"> Vue.component('Test', { data() { return { msg: 'lorry' } }, template: ` <div> <h2>{{ msg }}</h2> <button @click = 'changerHanlder'>改變</button> </div> `, methods: { changerHanlder() { this.msg = this.msg + 'hello'; } }, beforeCreate: function() { <!-- 組件創建之前 --> console.log(this.msg); <!-- 打印輸出undefined --> }, created: function() { <!-- 組件創建之後 --> console.log(this.msg); <!-- 打印輸出lorry --> <!-- 使用該組件,就會調用created方法 --> <!-- 在created這個方法中可以操作後端的數據,數據驅動視圖 --> <!-- 應用:發起ajax請求 --> }, beforeMount: function() { <!-- 掛載數據之前 --> <!-- 打印輸出<div id="app"><app></app></div> --> console.log(document.getElementById('app')); }, mounted: function() { <!-- 掛載數據到DOM之後 Vue作用之後的DOM--> <!-- 打印輸出<div id="app"><div class="app"><div><h2>lorry</h2></div></div></div> --> console.log(document.getElementById('app')); }, beforeUpdate: function() { <!-- 在更新Dom之前使用改方法 --> <!-- 打印輸出 <div class="app"><div><h2>lorry</h2> <button>改變</button></div></div> --> console.log(document.getElementById('app').innerHTML); }, updated: function() { <!-- 在更新DOM之後使用該方法 --> <!-- 打印輸出 <div class="app"><div><h2>lorryhello</h2> <button>改變</button></div></div> --> console.log(document.getElementById('app').innerHTML); }, beforeDeatory: function() { <!-- 銷燬數據之前 --> console.log('beforeDeatory'); <!-- Test組件中內容的顯示隱藏的時候,打印輸出beforeDeatory --> }, destroyed: function() { <!-- 銷燬數據之後 --> console.log('destroyed'); <!-- Test組件中內容的顯示顯示的時候,打印輸出destroyed --> }, activated: function() { console.log('組件被激活了'); }, deactivated: function() { console.log('組件被停用了'); }, }); var App = { data() { return { isShow: true } }, template: ` <div class = "app"> <!-- <Test v-if = 'isShow'></Test> --> <!-- vue中的內置組件<keep-alive></keep-alive>,能在組件的切換過程中將所有的狀態保存在內存中,重複渲染DOM --> <keep-alive> <Test v-if = 'isShow'></Test> </keep-alive> <!-- 根據按鈕點擊事件確定 Test組件中內容的顯示隱藏--> <!-- 點擊兩次後,再次點擊切換,後臺會重新創建Test,然後再次調用beforeDeatory和destroyed --> <button @click = 'isShow = !isShow'>點擊切換</button> </div> ` }; new Vue({ el: '#app', data() { return { } }, components: { App } }) </script> </body> </html>
keep-alive標籤
在組件的切換過程中將所有的狀態保存在內存中,重複渲染DOM(緩存)
keep-alive在路由中的使用
keep-alive保存加載過的數據,使用時直接調用,不用再次加載,節省項目運行時間,提高用戶體驗。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script src="./node_modules/vue-router/dist/vue-router.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
var Timeline = {
template:
`
<div id = 'timeline'>
<h2>首頁</h2>
</div>
`,
created() {
console.log('首頁組件創建了');
},
mounted() {
console.log('首頁組件DOM加載了');
},
destroyed() {
console.log('首頁組件銷燬了');
}
};
var Pins = {
template:
`
<div>
<h2 @click = 'clickHandle'>沸點</h2>
</div>
`,
methods: {
clickHandle(e) {
e.target.style.color = 'red';
}
},
created() {
console.log('沸點組件創建了');
},
mounted() {
console.log('沸點組件DOM加載了');
},
destroyed() {
console.log('沸點組件銷燬了');
}
};
<!-- // 創建路由對象 -->
var router = new VueRouter({
<!-- mode: 'history', 哈希模式,頁面跳轉時路由不會出現# -->
routes:[
{
path: '/timeline',
component: Timeline
},
{
path: '/pins',
component: Pins
}
]
});
<!-- // 實例化app組件 -->
var App = {
template:
`
<div>
<!-- 動態路由路徑 -->
<router-link to = '/timeline'>首頁</router-link>
<router-link to = '/pins'>沸點</router-link>
<!-- 路由匹配組件的出口 -->
<!-- <router-view></router-view> -->
<!-- 使用keep-alive後,如果前面的數據緩存過後,就不會重新加載,直接調用 -->
<keep-alive>
<router-view></router-view>
</keep-alive>
</div>
`
}
<!-- // 實例化對象 -->
new Vue({
el: '#app',
router,
template: `<App></App>`,
<!-- 掛載組件 -->
components: {
App
}
})
</script>
</body>
</html>
vue組件的通信方式
vue組件之間通信可分爲:
props和$emit(也就是常說的父子組件通信,常用)【父子組件中的傳值】
父組件向子組件傳遞數據是通過props傳遞的,子組件傳遞數據給父組件是通過$emit觸發事件來做到的。
解決父子組件層數較少的情況
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.js"></script>
<script type="text/javascript">
/*
在下面的例子中,有父組件App和子組件Child。
1).父組件傳遞了message數據給子組件,並且通過v-on綁定了一個getChildData事件來監聽子組件的觸發事件;
2).子組件通過props得到相關的message數據,最後通過this.$emit觸發了getChildData事件。
*/
Vue.component('Child',{
data(){
return {
aaa:this.message
}
},
template:`
<div>
<input type="text" v-model="aaa" @input="passData(aaa)"/>
</div>
`,
props:['message'],
methods:{
passData(val){
// $emit(自定義事件名,傳遞的值)
this.$emit('getChildData',val);
}
}
});
var App = {
data(){
return {
msg:'我是父組件的內容'
}
},
methods:{
getChildData(val){
console.log(`我是子組件傳進來的${val}`);
}
},
template:`<div>
<p>這是一個父組件</p>
<Child :message = 'msg' @getChildData = "getChildData"></Child>
</div>`
}
new Vue({
el:"#app",
data(){
return {
}
},
components:{
App
},
template:`<App />`
});
</script>
</body>
</html>
listeners(監聽) 【父子組件中的傳值】
pops的集合
解決多層組件之間的嵌套和傳值方法
綁定事件,傳值,然後通過事件來接收傳遞的值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
<script type="text/javascript">
/*
$attrs和$listeners
第一種方式處理父子組件之間的數據傳輸有一個問題: 如果父組件A下面有子組件B, 組件B下面有組件C, 這時如果組件A想傳遞數據給組件C怎麼辦呢?
如果採用第一種方法, 我們必須讓組件A通過prop傳遞消息給組件B, 組件B在通過prop傳遞消息給組件C; 要是組件A和組件C之間有更多的組件, 那採用這種方式就很複雜了。 Vue 2.4 開始提供了$attrs和$listeners來解決這個問題, 能夠讓組件A之間傳遞消息給組件C。
*/
Vue.component('C', {
data() {
return {
}
},
template: `
<div>
<div @click = 'cClickHandler'>{{$attrs.messagec}}</div>
</div>
`,
methods: {
cClickHandler(){
alert(1);
this.$emit('getCData','我是c的數據')
}
}
});
Vue.component('B', {
data() {
return {
}
},
template: `
<div>
<C v-bind="$attrs" v-on = '$listeners'></C>
</div>
`,
methods: {
}
});
Vue.component('A', {
data() {
return {
}
},
// props:['message'],
template: `
<div>
<B v-bind="$attrs" v-on = '$listeners'></B>
<!--<input type="text" v-model = '$attrs.messagec' />-->
</div>
`,
methods: {
}
});
var App = {
data() {
return {
msg: '我是父組件的內容',
messagec:'hello c'
}
},
methods: {
},
template: `<div>
<p>這是一個父組件</p>
<A :messagec = 'messagec' v-on:getCData="getCData" ></A>
</div>`,
methods:{
// 執行c組件的觸發的函數
getCData(val){
console.log(val);
}
}
};
new Vue({
el: "#app",
data() {
return {
}
},
components: {
App
},
template: `<App />`
});
</script>
</body>
</html>
中央事件總線(非父子組件間通信)(創建公共的類)
$on
綁定自定義事件,$emit
觸發自定義事件
$on
和$emit
綁定同一個實例化對象
解決兄弟組件之間的傳值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
<script type="text/javascript">
/*
上面兩種方式處理的都是父子組件之間的數據傳遞,而如果兩個組件不是父子關係呢?這種情況下可以使用中央事件總線的方式。新建一個Vue事件bus對象,然後通過bus.$emit觸發事件,bus.$on監聽觸發的事件。
*/
// 中央事件總線
var bus = new Vue();
Vue.component('brother2', {
data() {
return {
msg:"hello brother1"
}
},
template: `
<div>
<p>我是老大</p>
<input type="text" v-model = 'msg' @input = 'passData(msg)' />
</div>
`,
methods: {
passData(val){
// //觸發全局事件globalEvent
bus.$emit('globalEvent',val)
}
}
});
Vue.component('brother1', {
data() {
return {
msg:"hello brother1",
brother2Msg:''
}
},
template: `
<div>
<p>我是老二</p>
<p>老大傳遞過來的數據:{{brother2Msg}}</p>
</div>
`,
mounted(){
// 綁定全局事件globalEvent事件,
bus.$on('globalEvent',(val)=>{
bus.brother2Msg = val;
})
}
});
var App = {
data() {
return {
msg: '我是父組件的內容',
messagec:'hello c'
}
},
methods: {
},
template: `<div>
<brother1></brother1>
<brother2></brother2>
</div>`,
methods:{
// 執行c組件的觸發的函數
getCData(val){
console.log(val);
}
}
}
new Vue({
el: "#app",
data() {
return {
}
},
components: {
App
},
template: `<App />`
});
</script>
</body>
</html>
provide(傳值)和inject(接收)【父組件傳值,子組件接收】
父組件中通過provide來提供變量,然後在子組件中通過inject來注入變量。不論子組件有多深,只要調用了inject那麼就可以注入provider中的數據。而不是侷限於只能從當前父組件的prop屬性來獲取數據,只要在父組件的生命週期內,子組件都可以調用。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
<script type="text/javascript">
Vue.component('Child',{
data(){
return {
msg:''
}
},
template:`
<div>我是孩子{{msg}}</div>
`,
inject:['for'],
created(){
// 拿到傳遞過來的值
this.msg = this.for;
}
});
Vue.component('Parent',{
template:`
<div>
<p>我是父親</p>
<Child />
</div>
`
});
var App = {
data(){
return {
}
},
provide:{
for:'他爹'
},
template:`
<div>
<h2>我是入口組件</h2>
<Parent />
</div>
`
}
new Vue({
el:"#app",
template:`<App />`,
data(){
return {
}
},
components:{
App
}
});
</script>
</body>
</html>
children
掛載父組件,在子組件中通過props去接收
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
<script type="text/javascript">
Vue.component('Child', {
props: {
value: String, //v-model會自動傳遞一個字段爲value的prop屬性
},
data() {
return {
// 將value 的值賦值給 mymessage
mymessage: this.value
}
},
methods: {
changeValue() {
console.log(this.mymessage);
this.$parent.message = this.mymessage; //通過如此調用可以改變父組件的值
console.log(this.$parent);
}
},
template: `
<div>
<input type="text" v-model="mymessage" @change="changeValue">
</div>
`
})
Vue.component('Parent',{
// 點擊按鈕,將mymessage的值傳遞給子組件
template:` <div >
<p>我是父親組件{{message}}</p>
<button @click = "changeChildValue" > test < /button >
<Child ></Child>
</div>
`,
methods:{
changeChildValue(){
this.$children[0].mymessage = 'hello';
}
},
data(){
return {
message:'hello'
}
}
})
var App = {
data(){
return {
}
},
template:`
<div>
<h2>我是入口組件</h2>
<Parent />
</div>
`
}
var vm = new Vue({
el:'#app',
components:{
App
},
template:`
<App></App>
`
})
console.log(vm);
</script>
</body>
</html>
vuex流程圖
Vuex原理
Vuex實現了一個單向數據流,在全局擁有一個State存放數據,當組件要更改State中的數據時,必須通過Mutation進行,Mutation同時提供了訂閱者模式供外部插件調用獲取State數據的更新。而當所有異步操作(常見於調用後端接口異步獲取更新數據)或批量的同步操作需要走Action,但Action也是無法直接修改State的,還是需要通過Mutation來修改State的數據。最後,根據State的變化,渲染到視圖上。
各模塊之間的工作流程
- Vue Components:Vue組件。HTML頁面上,負責接收用戶操作等交互行爲,執行dispatch方法觸發對應action進行迴應。
- dispatch:操作行爲觸發方法,是唯一能執行action的方法。
- actions:操作行爲處理模塊,由組件中的
$store.dispatch('action 名稱', data1)
來觸發。然後由commit()來觸發mutation的調用 , 間接更新 state。負責處理Vue Components接收到的所有交互行爲。包含同步/異步操作,支持多個同名方法,按照註冊的順序依次觸發。向後臺API請求的操作就在這個模塊中進行,包括觸發其他action以及提交mutation的操作。該模塊提供了Promise的封裝,以支持action的鏈式觸發。 - commit:狀態改變提交操作方法。對mutation進行提交,是唯一能執行mutation的方法。
- mutations:狀態改變操作方法,由actions中的
commit('mutation 名稱')
來觸發。是Vuex修改state的唯一推薦方法。該方法只能進行同步操作,且方法名只能全局唯一。操作之中會有一些hook暴露出來,以進行state的監控等。 - state:頁面狀態管理容器對象。集中存儲Vue components中data對象的零散數據,全局唯一,以進行統一的狀態管理。頁面顯示所需的數據從該對象中進行讀取,利用Vue的細粒度數據響應機制來進行高效的狀態更新。
- getters:state對象讀取方法。圖中沒有單獨列出該模塊,應該被包含在了render中,Vue Components通過該方法讀取全局state對象。
Vuex與localStorage
vuex 是 vue 的狀態管理器,存儲的數據是響應式的。但是並不會保存起來,刷新之後就回到了初始狀態, **具體做法應該在vuex裏數據改變的時候把數據拷貝一份保存到localStorage裏面,刷新之後,如果 localStorage裏有保存的數據,取出來再替換store裏的state。**
let defaultCity = "上海"
try { // 用戶關閉了本地存儲功能,此時在外層加個try...catch
if (!defaultCity){
defaultCity = JSON.parse(window.localStorage.getItem('defaultCity'))
}
}catch(e){}
export default new Vuex.Store({
state: {
city: defaultCity
},
mutations: {
changeCity(state, city) {
state.city = city
try {
window.localStorage.setItem('defaultCity', JSON.stringify(state.city));
// 數據改變的時候把數據拷貝一份保存到localStorage裏面
} catch (e) {}
}
}
})
複製代碼
這裏需要注意的是:由於vuex裏,我們保存的狀態,都是數組,而localStorage只支持字符串,所以需要用JSON轉換:
JSON.stringify(state.subscribeList); // array -> string
JSON.parse(window.localStorage.getItem("subscribeList")); // string -> array
在vue中獲取DOM元素
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<script src="./node_modules/vue/dist/vue.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 組件的掛載
Vue.component('SubCom', {
template:
`
<div></div>
`
});
var App = {
template:
`
<div class = 'app'>
<button ref = 'btn'>按鈕1</button>
<button ref = 'btn2'>按鈕2</button>
<!-- 給組件綁定ref -->
<SubCom ref = 'abc'/>
</div>b
`,
created() {
<!-- 獲取所有的加上有ref屬性的集合 -->
console.log(this.$refs.btn);
},
beforeMount:function() {
<!-- 獲取所有的加上有ref屬性的集合 -->
console.log(this.$refs.btn);
},
mounted() {
<!-- 如果給標籤蚌寺那個ref = 'xxx' 屬性,使用this.$refs.xxx獲取原生的js對象 -->
<!-- ref屬性值不能重名 -->
console.log(this.$refs.btn);
console.log(this.$refs.btn2);
<!-- 如果是給自定義組件綁定ref屬性,那麼this.$refs.abc獲取的是當前的組件對象 -->
console.log(this.$refs.abc);
}
};
new Vue({
el: '#app',
data() {
return {
}
},
template: `<App></App>`,
components: {
App
}
});
</script>
</body>
</html>
給DOM元素添加事件的特殊情況
使用focus()方法,獲取焦點事件
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<script src="./node_modules/vue/dist/vue.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
var App = {
data() {
return {
isShow: false
}
},
template:
`
<div class = 'app'>
<input type = 'text' v-show = 'isShow' ref = 'input'/>
</div>
`,
mounted() {
this.isShow = true;
<!-- 能獲取到input框,但是不能使用focus()方法 -->
console.log(this.$refs.input);
<!-- 在Dom更新 -->
<!-- $nextTick()方法,在DOM更新循環之後執行回調函數,再修改數據之後可以使用此方法,在回調函數中獲取到更新之後的數據 -->
<!-- this.$ref.input.focus(); -->
this.$nextTick(function() {
console.log(this);
<!-- 窗體加載的時候input框默認觸發焦點事件 -->
this.$refs.input.focus();
});
}
};
new Vue({
el: '#app',
data() {
return {
}
},
template: `<App></App>`,
components: {
App
}
});
</script>
</body>
</html>
生命週期的圖示
核心插件
路由
路由的實現
-
傳統開發方式url改變後,立刻發生請求響應整個頁面,有可能資源過多,傳統開發會讓頁面出現白屏
-
前端路由的原理
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title></title> </head> <body> <a href="#/login">登錄</a> <a href="#/register">註冊</a> <div id="app"></div> <script type="text/javascript"> var oDiv = document.getElementById('app'); // onhashchange方法,哈希值改變後調用的方法 // a標籤中href屬性的值就是哈希值 window.onhashchange = function(){ // 訪問到用戶點擊的哈希值 console.log(location.hash); // 根據哈希值來做相對應的處理 switch (location.hash){ case '#/login': oDiv.innerHTML = '<h2>我是登錄頁面</h2>' break; case '#/register': oDiv.innerHTML = '<h2>我是註冊頁面</h2>' break; default: break; } } </script> </body> </html>
-
SPA(Single Page Application) 單頁面應用
- 錨點值改變
- 錨點值改變後,不會立刻發送請求,而是在某個合適的實際,發起的ajax請求頁面的局部渲染
- 優點:頁面不會立刻跳轉,用戶體驗好
- Vue,Angular,React這些框架都是做單頁面應用
- 錨點值改變
Vue-Router的基本使用
下載packag.json配置文件
npm init --yes
下載vue包
npm install vue --save
下載vue-router包
npm install vue-router -S
使用:
- 引包(兩個全局組件 router-link to屬性 router-view(匹配路由組件的出口))
- 創建實例化VueRouter對象
- 匹配路由規則
- 掛載new Vue()實例化對象中
- 給vue實例化對象掛在了兩個對象 this.$router(),它就是VueRouter
- this.route()獲取的是配置路由信息的對象
- 命名路由
- 綁定自定義屬性 :to = “{name:‘路由的名字’}”
- 路由的參數
- path:‘/user/id’
- to:“{name:‘user’,params:{id: 1}}”
- path:‘/user’
- to:“{name:‘user’,query:{userId: 1}}”
- path:‘/user/id’
- 嵌套路由(應用於 子路由是不同的頁面結構)
- /home/music ===> /home/movie
- 一個router-view中嵌套另外一個router-view
- /home/music ===> /home/movie
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<!-- 1引入vue模塊-->
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<!-- 2 引入vue-router模塊 -->
<!-- 引入vue-router模塊後 會拋出兩個全局組件 router-link 和 router-view -->
<!-- router-link 相當於a標籤 ,router-link中的to屬性相當於a標籤的href屬性 -->
<!-- router-view 路由匹配組件的出口 -->
<script src="./node_modules/vue-router/dist/vue-router.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 創建使用vue-router
// 3 讓Vue使用VueRouter創建
Vue.use(VueRouter);
var Login = {
template: `
<div>我是登陸頁面</div>
`
};
var Register = {
template: `
<div>我是註冊頁面</div>
`
};
<!-- // 4 創建router對象 -->
var router = new VueRouter({
<!-- //5 配置路由對象 -->
routes: [
<!-- // 路由匹配的規則 -->
<!-- 當路徑爲login時,自動匹配Login組件,然後加載組件中的內容 -->
{
path: "/login",
component: Login
},
{
path: "/register",
component: Register
},
]
});
<!-- // 聲明組件 -->
var App = {
template: `
<div>
<!-- <a href="">登錄頁面</a> -->
<router-link to="/login">登錄頁面</router-link>
<router-link to="/register">註冊頁面</router-link>
<!-- 路由匹配組件的出口 -->
<router-view></router-view>
</div>
`
}
new Vue({
el: '#app',
data() {
return {
}
},
components: {
App
},
<!-- 將 router 路由交給Vue實例化對象管理-->
router,
template: `<App></App>`
})
</script>
</body>
</html>
命名路由
綁定to屬性,匹配路由對象(通過定義的name來使用)
routes中的path屬於動態路由參數,以冒號開頭
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<!-- 1引入vue模塊-->
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<!-- 2 引入vue-router模塊 -->
<!-- 引入vue-router模塊後 會拋出兩個全局組件 router-link 和 router-view -->
<!-- router-link 相當於a標籤 ,router-link中的to屬性相當於a標籤的href屬性 -->
<!-- router-view 路由匹配組件的出口 -->
<script src="./node_modules/vue-router/dist/vue-router.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 創建使用vue-router
// 3 讓Vue使用VueRouter創建
Vue.use(VueRouter);
var Login = {
template: `
<div>我是登陸頁面</div>
`
};
var Register = {
template: `
<div>我是註冊頁面</div>
`
};
<!-- // 4 創建router對象 -->
var router = new VueRouter({
<!-- //5 配置路由對象 -->
routes: [
<!-- // 路由匹配的規則 -->
<!-- 當路徑爲login時,自動匹配Login組件,然後加載組件中的內容 -->
{
path: "/login",
name: "login", <!-- 給當前路由命名 -->
component: Login
},
{
path: "/register",
name: "register",
component: Register
},
]
});
<!-- // 聲明組件 -->
var App = {
template: `
<div>
<!-- <a href="">登錄頁面</a> -->
<!-- <router-link to="/login">登錄頁面</router-link> -->
<!-- 通過路由的命名來使用 -->
<router-link :to="{name: 'login'}">登錄頁面</router-link>
<!-- <router-link to="/register">註冊頁面</router-link> -->
<router-link :to="{name: 'register'}">登錄頁面</router-link>
<!-- 路由匹配組件的出口 -->
<router-view></router-view>
</div>
`
}
new Vue({
el: '#app',
data() {
return {
}
},
components: {
App
},
<!-- 將 router 路由交給Vue實例化對象管理-->
router,
template: `<App></App>`
})
</script>
</body>
</html>
路由參數
路由範式(規則):
- xxx.html#/user/1
- 動態參數(params)路由
- ooo.html#/user?userId = 1
- ( ?)query查詢
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<!-- 1引入vue模塊-->
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<!-- 2 引入vue-router模塊 -->
<!-- 引入vue-router模塊後 會拋出兩個全局組件 router-link 和 router-view -->
<!-- router-link 相當於a標籤 ,router-link中的to屬性相當於a標籤的href屬性 -->
<!-- router-view 路由匹配組件的出口 -->
<script src="./node_modules/vue-router/dist/vue-router.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 創建使用vue-router
// 3 讓Vue使用VueRouter創建
Vue.use(VueRouter);
var userParams = {
template: `
<div>我是用戶1</div>
`,
created() {
<!--引入vue-router時就會拋出兩個對象 -->
<!-- 這兩個對象就掛載到Vue實例化對象 -->
console.log(this.$router);
console.log(this.$route);
<!-- 獲取用戶點擊的id -->
<!-- 注意通過 :id傳遞了id參數參能獲取到id的值 -->
console.log(this.$route.params.id);
}
};
var userQuery = {
template: `
<div>我是用戶2</div>
`
};
<!-- // 4 創建router對象 -->
var router = new VueRouter({
<!-- //5 配置路由對象 -->
routes: [
<!-- // 路由匹配的規則 -->
<!-- 當路徑爲login時,自動匹配Login組件,然後加載組件中的內容 -->
{
path: "/user/:id",
<!-- params動態參數 -->
name: "userP", <!-- 給當前路由命名 -->
component: userParams
},
{
path: "/user",
<!-- query 查詢 -->
name: "userQ",
component: userQuery
},
]
});
<!-- // 聲明組件 -->
var App = {
template: `
<div>
<!-- params:{key,value} -->
<!-- 動態路由路徑 -->
<router-link :to="{name: 'userP', params:{id:1}}">用戶1</router-link>
<router-link :to="{name: 'userQ', params:{userId:2}}">用戶2</router-link>
<!-- 路由匹配組件的出口 -->
<router-view></router-view>
</div>
`
}
new Vue({
el: '#app',
data() {
return {
}
},
components: {
App
},
<!-- 將 router 路由交給Vue實例化對象管理-->
router,
template: `<App></App>`
})
</script>
</body>
</html>
嵌套路由
菜單欄的動態切換,標題欄一樣,通過小組件來實現頁面的動態切換
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<!-- 1引入vue模塊-->
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<!-- 2 引入vue-router模塊 -->
<!-- 引入vue-router模塊後 會拋出兩個全局組件 router-link 和 router-view -->
<!-- router-link 相當於a標籤 ,router-link中的to屬性相當於a標籤的href屬性 -->
<!-- router-view 路由匹配組件的出口 -->
<script src="./node_modules/vue-router/dist/vue-router.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 創建使用vue-router
// 3 讓Vue使用VueRouter創建
Vue.use(VueRouter);
<!-- 內層小組件 -->
var Song = {
template:
`
<div>歌曲列表</div>
`
};
var Movie = {
template:
`
<div>電影列表</div>
`
};
<!-- // 外層大組件 -->
<!-- 注意:每一個組件模板都是一個大的整體,需要在一個盒子裏面 -->
var Home = {
template: `
<div>首頁
<br />
<!-- 動態路由路徑 -->
<router-link to = '/home/song'>歌曲</router-link>
<router-link to = '/home/movie'>電影</router-link>
<!-- 路由匹配組件的出口 -->
<router-view></router-view>
</div>
`
};
<!-- // 4 創建router對象 -->
var router = new VueRouter({
<!-- //5 配置路由對象 -->
routes: [
<!-- // 路由匹配的規則 -->
<!-- 當路徑爲login時,自動匹配Login組件,然後加載組件中的內容 -->
{
path: "/home",
<!-- params動態參數 -->
name: "home", <!-- 給當前路由命名 -->
component: Home,
<!-- 匹配多層目錄下面的子目錄 -->
children: [
{
path: "song",
<!-- params動態參數 -->
component: Song
},
{
path: "movie",
<!-- params動態參數 -->
component: Movie
},
]
}
]
});
<!-- // 聲明組件 -->
var App = {
template: `
<div>
<!-- params:{key,value} -->
<!-- 動態路由路徑 -->
<router-link :to="{name: 'home'}">首頁</router-link>
<!-- 路由匹配組件的出口 -->
<router-view></router-view>
</div>
`
}
new Vue({
el: '#app',
data() {
return {
}
},
components: {
App
},
<!-- 將 router 路由交給Vue實例化對象管理-->
router,
template: `<App></App>`
})
</script>
</body>
</html>
動態路由匹配
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script src="./node_modules/vue-router/dist/vue-router.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 當前使用路由參數,列入/timeline/fronted導航到/timeline/backed,原來的組件實例會被複用,
// 因爲兩個路由都渲染同個組件,比起銷燬在創建,複用則顯得更高效,不過這也意味着組件的生命週期
// 不會再被調用
var ComDesc = {
data() {
return {
msg: ''
}
},
template:
`
<div>我是{{ msg }}</div>
`,
created() {
<!-- created方法只會走一次 -->
<!-- created可以發Ajax請求 -->
this.msg = '前端';
},
<!-- watch在當前組件內部監聽路由信息的變化 -->
watch: {
'$route'(to,from) {
console.log(to); <!-- to就是一個routes對象 -->
console.log(from);
<!-- 發送ajax請求,獲取到對應的參數 -->
this.msg = to.params.id;
}
}
};
var Timeline = {
template:
`
<div id = 'timeline'>
<!-- 動態路由路徑 -->
<router-link :to = "{name: 'comDesc',params:{id: 'frontend'}}">前端</router-link>
<router-link :to = "{name: 'comDesc',params:{id: 'backed'}}">後端</router-link>
<!-- 路由匹配組件的出口 -->
<router-view></router-view>
</div>
`
};
var Pins = {
template:
`
<div>
<h2>沸點</h2>
</div>
`
};
<!-- // 創建路由對象 -->
var router = new VueRouter({
<!-- mode: 'history', 哈希模式,頁面跳轉時路由不會出現# -->
routes:[
{
path: '/timeline',
component: Timeline,
children: [
{
name: 'comDesc',
<!-- 動態路由的參數 以:開頭 -->
path: '/timeline/:id',
component: ComDesc
}
]
},
{
path: '/pins',
component: Pins
}
]
});
<!-- // 實例化app組件 -->
var App = {
template:
`
<div>
<!-- 動態路由路徑 -->
<router-link to = '/timeline'>首頁</router-link>
<router-link to = '/pins'>沸點</router-link>
<!-- 路由匹配組件的出口 -->
<router-view></router-view>
</div>
`
}
<!-- // 實例化對象 -->
new Vue({
el: '#app',
router,
template: `<App></App>`,
<!-- 掛載組件 -->
components: {
App
}
})
</script>
</body>
</html>
路由元信息(meta的使用及權限控制)
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script src="./node_modules/vue-router/dist/vue-router.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<router-link to = '/home'>首頁</router-link>
<router-link to = '/blog'>我的博客</router-link>
<router-link to = '/login'>登錄</router-link>
<a href="javascript:void(0)">退出</a>
<!-- 每個路由組件都渲染到router-view裏面了 -->
<router-view></router-view>
</div>
<script type="text/javascript">
Vue.use(VueRouter);
var Home = {
template:
`
<div>首頁</div>
`
};
var Blog = {
template:
`
<div>我的博客</div>
`
};
var Login = {
data() {
return {
name: '',
pwd: ''
}
},
template:
`
<div>
<input type="text" v-model="name"/>
<input type="password" v-model="pwd"/>
<input type="button" value="登錄" @click = 'loginHandle'/>
</div>
`,
methods: {
loginHandle() {
<!-- 登錄 -->
<!-- 將用戶名 密碼保存下來 -->
localStorage.setItem('user', {name:this.name,pwd:this.pwd});
<!-- 跳轉到博客頁面 -->
<!-- 編程式導航 -->
this.$router.push({
name: 'blog'
})
}
}
};
<!-- // 創建路由對象 -->
var router = new VueRouter({
<!-- mode: 'history', 哈希模式,頁面跳轉時路由不會出現# -->
routes:[
{
path: '/',
redirect: '/home'
},
{
path: '/home',
component: Home
},
{
path: '/blog',
name: 'blog',
component: Blog,
<!-- meta給未來的路由做權限控制 -->
meta: {
<!-- 證明用戶訪問該組件的時候需要登錄 -->
auth: true
}
},
{
path: '/login',
component: Login
}
]
});
<!-- 全局路由匹配 -->
<!-- beforeEach會監測路由 -->
router.beforeEach((to, from, next) => {
console.log(to);
console.log(from);
if(to.meta.auth) { <!-- true -->
if (localStorage.getItem('user')) {
<!-- 如果localStorage有值則證明用戶登錄完成了 -->
next();
}else{
<!-- 用戶需要登錄 -->
next({
path: '/login'
});
}
} else {
<!-- false 直接放行 -->
<!-- 如果不調用 next() 方法會卡主頁面-->
next();
}
});
<!-- // 實例化對象 -->
new Vue({
el: '#app',
router, <!-- 掛載路由 -->
})
</script>
</body>
</html>
Vuex
Vue服務端渲染
Axios
Axios是一個基於promise的HTTP庫,可以在瀏覽器和node.js中使用。
作用:
- 從瀏覽器中創建
XMLHttpRequests
- 從node.js創建
http
請求 - 支持
Promise
API - 攔截請求和響應
- 轉換請求數據和響應數據
- 取消請求
- 自動轉換JSON數據
- 客戶端支持防禦
XSRF
攻擊
參考文檔鏈接:https://www.kancloud.cn/yunye/axios/234845
使用
安裝
使用npm:
npm install axios
使用bower:
bower install axios
使用cdn:
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
axios的基本使用
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<!-- 引包vue -->
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<!-- 引包axios -->
<script src="./node_modules/axios/dist/axios.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// console.log(axios);
var App = {
template:
`
<div>
<button @click = 'sendAjax'>發請求</button>
</div>
`,
methods: {
sendAjax(){
this.$axios.get('http://127.0.0.1:8888/')
.then(res => {
<!-- 拿到statusText: "OK" -->
console.log(res.data.msg); <!-- 打印輸出ok -->
})
.catch(err => {
console.log(err);
})
}
}
};
Vue.prototype.$axios = axios;
new Vue({
el: '#app',
data() {
return {
}
},
template: `<App></App>`,
components: {
App
}
});
</script>
</body>
</html>
處理併發請求
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<!-- 引包vue -->
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<!-- 引包axios -->
<script src="./node_modules/axios/dist/axios.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// console.log(axios);
var App = {
data() {
return {
res1: '',
res2: ''
}
},
template: `
<div>
響應1: {{ res1 }},
響應2: {{ res2 }},
<button @click = 'sendAjax'>併發請求</button>
</div>
`,
methods: {
sendAjax() {
<!-- 請求1 get: /-->
<!-- 請求2 post :/add -->
<!-- 配置 -->
this.$axios.defaults.baseURL = `http://127.0.0.1:8888/`;
<!-- 發請求 -->
var r1 = this.$axios.get('');
var r2 = this.$axios.post('add','a = 1');
this.$axios.all([r1, r2])
.then(this.$axios.spread((res1,res2) => {
<!-- 請求全部成功 -->
this.res1 = res1.data;
this.res2 = res2.data;
}))
.catch(err => {
<!-- 有一個失敗就失敗了 -->
console.log(err);
})
}
}
};
Vue.prototype.$axios = axios;
new Vue({
el: '#app',
data() {
return {
}
},
template: `<App></App>`,
components: {
App
}
});
</script>
</body>
</html>
請求配置
這些是創建請求時可以用的配置選項。只有url
是必需的。如果沒有指定method
,請求將使用替代get
方法。
{
// `url` 是用於請求的服務器 URL
url: '/user',
// `method` 是創建請求時使用的方法
method: 'get', // 默認是 get
// `baseURL` 將自動加在 `url` 前面,除非 `url` 是一個絕對 URL。
// 它可以通過設置一個 `baseURL` 便於爲 axios 實例的方法傳遞相對 URL
baseURL: 'https://some-domain.com/api/',
// `transformRequest` 允許在向服務器發送前,修改請求數據
// 只能用在 'PUT', 'POST' 和 'PATCH' 這幾個請求方法
// 後面數組中的函數必須返回一個字符串,或 ArrayBuffer,或 Stream
transformRequest: [function (data) {
// 對 data 進行任意轉換處理
return data;
}],
// `transformResponse` 在傳遞給 then/catch 前,允許修改響應數據
transformResponse: [function (data) {
// 對 data 進行任意轉換處理
return data;
}],
// `headers` 是即將被髮送的自定義請求頭
headers: {'X-Requested-With': 'XMLHttpRequest'},
// `params` 是即將與請求一起發送的 URL 參數
// 必須是一個無格式對象(plain object)或 URLSearchParams 對象
params: {
ID: 12345
},
// `paramsSerializer` 是一個負責 `params` 序列化的函數
// (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
paramsSerializer: function(params) {
return Qs.stringify(params, {arrayFormat: 'brackets'})
},
// `data` 是作爲請求主體被髮送的數據
// 只適用於這些請求方法 'PUT', 'POST', 和 'PATCH'
// 在沒有設置 `transformRequest` 時,必須是以下類型之一:
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
// - 瀏覽器專屬:FormData, File, Blob
// - Node 專屬: Stream
data: {
firstName: 'Fred'
},
// `timeout` 指定請求超時的毫秒數(0 表示無超時時間)
// 如果請求話費了超過 `timeout` 的時間,請求將被中斷
timeout: 1000,
// `withCredentials` 表示跨域請求時是否需要使用憑證
withCredentials: false, // 默認的
// `adapter` 允許自定義處理請求,以使測試更輕鬆
// 返回一個 promise 並應用一個有效的響應 (查閱 [response docs](#response-api)).
adapter: function (config) {
/* ... */
},
// `auth` 表示應該使用 HTTP 基礎驗證,並提供憑據
// 這將設置一個 `Authorization` 頭,覆寫掉現有的任意使用 `headers` 設置的自定義 `Authorization`頭
auth: {
username: 'janedoe',
password: 's00pers3cret'
},
// `responseType` 表示服務器響應的數據類型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
responseType: 'json', // 默認的
// `xsrfCookieName` 是用作 xsrf token 的值的cookie的名稱
xsrfCookieName: 'XSRF-TOKEN', // default
// `xsrfHeaderName` 是承載 xsrf token 的值的 HTTP 頭的名稱
xsrfHeaderName: 'X-XSRF-TOKEN', // 默認的
// `onUploadProgress` 允許爲上傳處理進度事件
onUploadProgress: function (progressEvent) {
// 對原生進度事件的處理
},
// `onDownloadProgress` 允許爲下載處理進度事件
onDownloadProgress: function (progressEvent) {
// 對原生進度事件的處理
},
// `maxContentLength` 定義允許的響應內容的最大尺寸
maxContentLength: 2000,
// `validateStatus` 定義對於給定的HTTP 響應狀態碼是 resolve 或 reject promise 。如果 `validateStatus` 返回 `true` (或者設置爲 `null` 或 `undefined`),promise 將被 resolve; 否則,promise 將被 rejecte
validateStatus: function (status) {
return status >= 200 && status < 300; // 默認的
},
// `maxRedirects` 定義在 node.js 中 follow 的最大重定向數目
// 如果設置爲0,將不會 follow 任何重定向
maxRedirects: 5, // 默認的
// `httpAgent` 和 `httpsAgent` 分別在 node.js 中用於定義在執行 http 和 https 時使用的自定義代理。允許像這樣配置選項:
// `keepAlive` 默認沒有啓用
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({ keepAlive: true }),
// 'proxy' 定義代理服務器的主機名稱和端口
// `auth` 表示 HTTP 基礎驗證應當用於連接代理,並提供憑據
// 這將會設置一個 `Proxy-Authorization` 頭,覆寫掉已有的通過使用 `header` 設置的自定義 `Proxy-Authorization` 頭。
proxy: {
host: '127.0.0.1',
port: 9000,
auth: : {
username: 'mikeymike',
password: 'rapunz3l'
}
},
// `cancelToken` 指定用於取消請求的 cancel token
// (查看後面的 Cancellation 這節瞭解更多)
cancelToken: new CancelToken(function (cancel) {
})
}
請求攔截器interceptors
在請求或響應被then
或catch
處理前攔截它們。
// 添加請求攔截器
axios.interceptors.request.use(function (config) {
// 在發送請求之前做些什麼
return config;
}, function (error) {
// 對請求錯誤做些什麼
return Promise.reject(error);
});
// 添加響應攔截器
axios.interceptors.response.use(function (response) {
// 對響應數據做點什麼
return response;
}, function (error) {
// 對響應錯誤做點什麼
return Promise.reject(error);
});
如果你想在以後可移除攔截器,可以這樣:
var myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);
可以爲自定義axios實例添加攔截器
var instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});
錯誤處理
axios.get('/user/12345')
.catch(function (error) {
if (error.response) {
// 請求已發出,但服務器響應的狀態碼不在 2xx 範圍內
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error', error.message);
}
console.log(error.config);
});
可以使用validateStatus
配置選項定義一個自定義HTTP狀態碼的錯誤範圍。
axios.get('/user/12345', {
validateStatus: function (status) {
return status < 500; // 狀態碼在大於或等於500時纔會 reject
}
})
取消
使用取消令牌取消請求
Axios的取消令牌API基於cancelable promises提議,它還處於第一階段。
可以使用CancelToken.source
工廠方法創建cancel token,像這樣:
var CancelToken = axios.CancelToken;
var source = CancelToken.source();
axios.get('/user/12345', {
cancelToken: source.token
}).catch(function(thrown) {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
// 處理錯誤
}
});
// 取消請求(message 參數是可選的)
source.cancel('Operation canceled by the user.');
還可以通過傳遞一個executor函數到CancelToken
的構造函數來創建取消令牌:
var CancelToken = axios.CancelToken;
var cancel;
axios.get('/user/12345', {
cancelToken: new CancelToken(function executor(c) {
// executor 函數接收一個 cancel 函數作爲參數
cancel = c;
})
});
// 取消請求
cancel();
注意:可以使用同一個cancel token取消多個請求
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<style type="text/css">
.spinner {
margin: 100px auto;
width: 50px;
height: 60px;
text-align: center;
font-size: 10px;
}
.spinner>div {
background-color: #67CF22;
height: 100%;
width: 6px;
display: inline-block;
-webkit-animation: stretchdelay 1.2s infinite ease-in-out;
animation: stretchdelay 1.2s infinite ease-in-out;
}
.spinner .rect2 {
-webkit-animation-delay: -1.1s;
animation-delay: -1.1s;
}
.spinner .rect3 {
-webkit-animation-delay: -1.0s;
animation-delay: -1.0s;
}
.spinner .rect4 {
-webkit-animation-delay: -0.9s;
animation-delay: -0.9s;
}
.spinner .rect5 {
-webkit-animation-delay: -0.8s;
animation-delay: -0.8s;
}
@-webkit-keyframes stretchdelay {
0%,
40%,
100% {
-webkit-transform: scaleY(0.4)
}
20% {
-webkit-transform: scaleY(1.0)
}
}
@keyframes stretchdelay {
0%,
40%,
100% {
transform: scaleY(0.4);
-webkit-transform: scaleY(0.4);
}
20% {
transform: scaleY(1.0);
-webkit-transform: scaleY(1.0);
}
}
</style>
<!-- 引包vue -->
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<!-- 引包axios -->
<script src="./node_modules/axios/dist/axios.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// console.log(axios);
var App = {
data() {
return {
isShow: false
}
},
template: `
<div>
<div class="spinner" v-show = 'isShow'>
<div class="rect1"></div>
<div class="rect2"></div>
<div class="rect3"></div>
<div class="rect4"></div>
<div class="rect5"></div>
</div>
<button @click = 'sendAjax'>發請求</button>
</div>
`,
methods: {
sendAjax() {
<!-- 模擬類似cookie的機制 -->
<!-- 添加請求攔截器 -->
this.$axios.interceptors.request.use((config) => {
console.log(config);
var token = localStorage.setItem('token');
if (token) {
config.headers['token'] = token;
}
this.isShow = true;
return config;
}, function(err) {
return Promise.reject(err);
});
<!-- // 添加響應攔截器 -->
this.$axios.interceptors.response.use(response => {
<!-- // 對響應數據做點什麼 -->
console.log(response);
this.isShow = false;
return response;
}, function(error) {
<!-- // 對響應錯誤做點什麼 -->
return Promise.reject(error);
});
this.$axios.get('http://127.0.0.1:8888')
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err);
})
}
}
};
Vue.prototype.$axios = axios;
new Vue({
el: '#app',
data() {
return {
}
},
template: `<App></App>`,
components: {
App
}
});
</script>
</body>
</html>
認識webpack
能完成所有常用的功能:
- 壓縮
- 打包
- 多種文件的編譯(比如less文件編譯成css文件)
- 腳手架
- 生成
安裝:
npm i webpack-cli -g
基本使用
index.js
//jquery存放在本地
import $ from './libs/jquery'; // 引入jquery
//jquery存放在node_modules
import $ from 'jquery';
$(function(){
alert(a);
})
webpack.config.js
model.exports{
//模式
mode: 'development',
//入口
entry: './src/js/index.js',
//輸出
output: {
path: path.resolve(__dirname,'build'),
filename: 'build.js'
}
}
webpack是一個現代JavaScript應用程序的靜態模塊打包器。當 webpack 處理應用程序時,它會遞歸地構建一個依賴關係圖(dependency graph),其中包含應用程序需要的每個模塊,然後將所有這些模塊打包成一個或多個 bundle。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Fa7einSe-1585806966684)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200331142837324.png)]
歷史介紹
- 2009年初,commonjs規範還未出來,此時前端開發人員編寫的代碼都是非模塊化的,
- 那個時候開發人員經常需要十分留意文件加載順序所帶來的依賴問題
- 與此同時 nodejs開啓了js全棧大門,而requirejs在國外也帶動着前端逐步實現模塊化
- 同時國內seajs也進行了大力推廣
- AMD 規範 ,具體實現是requirejs define(‘模塊id’,[模塊依賴1,模塊依賴2],function(){ return ;}) , ajax請求文件並加載
- Commonjs || CMD 規範seajs 淘寶玉伯
- commonjs和cmd非常相似的
- cmd require/module.exports
- commonjs是js在後端語言的規範: 模塊、文件操作、操作系統底層
- CMD 僅僅是模塊定義
- commonjs和cmd非常相似的
- UMD 通用模塊定義,一種既能兼容amd也能兼容commonjs 也能兼容瀏覽器環境運行的萬能代碼
- npm/bower集中包管理的方式備受青睞,12年browserify/webpack誕生
- npm 是可以下載前後端的js代碼475000個包
- bower 只能下載前端的js代碼,bower 在下載bootstrap的時候會自動的下載jquery
- browserify 解決讓require可以運行在瀏覽器,分析require的關係,組裝代碼
- webpack 打包工具,佔市場主流
(function (root, factory) {
if (typeof exports === 'object') {
module.exports = factory(); //commonjs環境下能拿到返回值
} else if (typeof define === 'function' ) {
define(factory); //define(function(){return 'a'}) AMD
} else {
window.eventUtil = factory();
}
})(this, function() { //this相當於傳的root
// module 返回給factory
return {
//具體模塊代碼
addEvent: function(el, type, handle) {
//...
},
removeEvent: function(el, type, handle) {
},
};
});
手動實現vue-cli腳手架工具,同時也學習webpack的使用
模塊實現
1.下載webpack爲項目開發依賴
npm install [email protected] -D
安裝全局webpack:
npm install webpack -g
2.創建main.js作爲項目的入口文件
// 整個程序的入口文件
import Vue from './vue.js'
import App from './App.js'
// 模塊整體加載
// import {num,num2,add} from './App.js'
// console.log(num);
// console.log(num2);
// add(3,5);
// import * as object from './App.js'
// console.log(object);
// console.log(object.num);
// console.log(object.num2);
// add(3,5);
new Vue({
el:'#app',
components:{
App
},
template:`<App />`
});
3.創建一個App.js
var App = {
template:`
<div>
我是一個入口組件
</div>
`
};
//1. 聲明並導出
export var num = 2; //作爲一整個對象key導出
//2. 聲明再導出
var num2 = 4;
export {num2};
//3.拋出一個函數
export function add(x,y) {
return console.log(x+y);
}
//4.拋出一個對象
export default App;
4.在package.json文件中配置如下:
{
"name": "29_module",
"version": "1.0.0",
"description": "",
"main": "main.js",
"scripts": {
"build": "webpack ./main.js ./build.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^3.12.0"
}
}
5.新建一個index.html,script腳本引入打包完成的build.js如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app"></div>
<script type="text/javascript" src="./build.js"></script>
</body>
</html>
webpack打包後文件的運行方式
- 直接運行build.js文件
- 配置build文件,然後通過run命令來運行打包後的build文件
3.上面那種方法也可以通過webpack直接運行