【一】初識Vue
【1】什麼是Vue
Vue 是一套用於構建使用者介面的漸(逐漸)進(遞進)式 JavaScript 框架
Vue 可以自底向上逐層應用,由國人尤雨溪開發
採用元件化模式,提高程式碼的複用率、讓程式碼更好維護
宣告式編碼方式,讓編碼人員無需直接操作 DOM,提高開發效率
使用虛擬DOM + 優秀的 Diff 演算法,儘量複用 DOM 節點
Vue.js 的核心是一個允許採用簡潔的模板語法來宣告式地將資料渲染進 DOM 的系統:
【2】引入Vue
本地方式引入
<script src="../js/vue.js"></script>
網路CDN方式引入
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
【3】Vue基本結構
在初學階段,Vue 的結構由 容器 + 物件 兩大部分構成
<body>
<div id="app">
{{name}}
{{age}}
</div>
</body>
<script>
var vm = new Vue({
el: '#app', // 這是Vue物件所繫結的容器物件,一般使用css選擇器繫結
data: { // data用於儲存資料
name: 'green',
age: 18
}
})
</script>
【二】基礎知識
【1】模板語法
插值語法
<body>
<div id="app">
{{name}}
<br>
{{age}}
<br>
{{hobby}}|{{hobby[0]}} // 陣列只能用中括號取值
<br>
{{obj}}|{{obj.name}}|{{obj["name"]}} // 物件可以用中括號或者點屬性取值
<br>
{{link}}
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
name: 'green',
age: 18,
hobby: ['洗衣服', '做飯', '打遊戲'],
obj: {name: "hqq", age: 22, hobby: ['抽菸', '喝酒', '洗腳']},
link: '<a href="https://meizi5.com">點選看美女</a>'
}
})
</script>
</body>
指令語法
<div id="root">
<!-- v-bind 可以簡寫為 : -->
<a v-bind:href="url">點我去百度 - 完整寫法</a>
<a :href="url">點我去百度 - 簡略寫法</a>
</div>
<script>
new Vue({
el: '#root',
data: {
url: 'https://www.baidu.com'
}
})
</script>
總結
插值語法
功能:用於解析標籤體中的內容
寫法:{{xxxx}},其中 xxxx 是 js 表示式,且可以直接讀取到 data 中的所有屬性
指令語法
功能:用於解析標籤(包括:標籤屬性,標籤體內容,繫結事件)
【2】資料繫結
單向繫結:str變---》input框變,input框變---》str不變
單向繫結:str變---》input框變,input框變---》str也變
<div id="app">
單向繫結 <input type="text" :value="str">
雙向繫結 <input type="text" v-model:value="str">
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
str: '炎帝蕭炎'
}
})
</script>
</body>
總結
總結:
單向繫結(v-bind):資料只能由 data 流向頁面
雙向繫結(v-model)
資料既能從 data 流向頁面,也能從頁面流向 data
雙向繫結一般都應用在表單類元素上(input、select...)
v-model:value 可以簡寫為 v-model,因為 v-model 預設繫結的就是 value 屬性
【3】事件指令
es6的物件寫法
// es6 的物件寫法
var hobby=['抽菸','燙頭']
var obj={
'name':'hqq',
age:19, // 鍵值可以不帶引號
hobby, // 可以直接省略鍵名,在有定義的情況下
showName() {
console.log(this.name)
// 函式可以省略:function
}
}
函式傳引數問題
<body>
<div id="app">
<button v-on:click="showFunc1">不傳引數,函式有引數(會自動把當前事件傳入)</button>
<button v-on:click="showFunc2(name)">傳引數,函式有引數(正常輸出)</button>
<button v-on:click="showFunc3($event)">傳引數,函式有引數,把事件物件傳入(正常輸出)</button>
<button v-on:click="showFunc4()">傳引數,函式有多個引數,少傳引數(少傳就輸出傳入的,多傳就不關多出來的)</button>
</div>
</body>
<script>
let vm = new Vue({
el: '#app',
data: {
name: 'green'
},
methods: {
showFunc1(event) {
console.log(event)
},
showFunc2(param) {
console.log(param)
},
showFunc3(event) {
console.log(event)
},
showFunc4(a,b,c) {
console.log(a,b,c)
}
}
})
</script>
【4】屬性指令
1. 標籤上有屬性 如:
img的src屬性,a標籤的href屬性
2. 屬性指令的作用就是使用變數動態的設定屬性的值
3. 使用方法
v-bind:屬性名='變數'
簡寫
:屬性名='變數'
動態切換美女圖片案例
<body>
<div id="app">
<button @click="handleClick">點選切換自動切換美女</button>
<img :src="src" alt="">
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
list: ['/img/1.jpg', '/img/2.jpg', '/img/3.jpg'],
src: '',
index: 0,
flag: false,
t: null
},
methods: {
handleChange() {
console.log(this.index)
this.src = this.list[this.index]
this.index += 1
if (this.index === 3) {
this.index = 0
}
},
handleClick() {
if (this.flag === false) {
this.t = setInterval(this.handleChange, 1000)
this.flag = true
} else {
clearInterval(this.t)
this.flag = false
}
}
}
})
</script>
</body>
補充:js中的計時器
js 定時器有以下兩個方法:
setInterval() :按照指定的週期(以毫秒計)來呼叫函式或計算表示式。方法會不停地呼叫函式,直到 clearInterval() 被呼叫或視窗被關閉。
setTimeout() :在指定的毫秒數後呼叫函式或計算表示式。
語法
setInterval(code,millisec,lang)
code 必需。要呼叫的函式或要執行的程式碼串。
millisec 必須。週期性執行或呼叫 code 之間的時間間隔,以毫秒計。
lang 可選。 JScript | VBScript | JavaScript
【5】style和class
# 1 class 可以繫結 字串,陣列,物件
字串: 'div1 div2'---》字串替換控制樣式
陣列:['div1','div2']--->追加陣列,刪除陣列控制樣式
物件:{div1: true, div2: true, div3: true, div4: false}--》透過true和false控制樣式
# 2 style 可以繫結 字串,陣列,物件
字串'background-color: green;height: 300px;width: 300px'---》字串替換控制樣式
陣列:[{'background-color': 'green'}, {height: '300px'}, {width: '300px'}]--->追加陣列,刪除陣列控制樣式
物件:{backgroundColor: 'green', height: '330px', width: '300px'} --》透過根據key修改value控制樣式
# 3 坑:以後如果改了物件,或陣列,發現頁面沒有變化,實際上值被真正的改了
Vue.set(this.style_list,3,{'margin':'auto'})
【6】條件渲染
v-if v-else-if v-else
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./vue/vue.js"></script>
<style>
</style>
</head>
<body>
<div id="app">
<h1>條件判斷</h1>
<h2>分數是:{{score}}</h2>
<h3 v-if="score>=90&&score<=100">優秀</h3>
<h3 v-else-if="score>=80&&score<90">良好</h3>
<h3 v-else-if="score>=60&&score<80">及格</h3>
<h3 v-else>不及格</h3>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
score: 99
}
})
</script>
</html>
【7】列表渲染
透過使用v-for迴圈顯示多條資料
購物車案例
<body>
<div class="container text-center" id="app">
<div class="row">
<div class="col-6 offset-3">
<h1 class="text-center">購物車</h1>
<button class="btn btn-success" @click="showGood">載入購物車</button>
<div v-if="!good_list">空空如也</div>
<table class="table table-info">
<thead>
<tr>
<th scope="col">商品ID</th>
<th scope="col">商品名稱</th>
<th scope="col">商品數量</th>
<th scope="col">商品價格</th>
<th scope="col">商品圖片</th>
</tr>
</thead>
<tbody>
<tr v-for="good in good_list">
<th scope="row">{{good.id}}</th>
<td>{{good.name}}</td>
<td>{{good.number}}</td>
<td>{{good.price}}</td>
<td><img v-bind:src="good_img" alt="" v-bind:style="style_dic"></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
good_list: null,
good_img: null,
style_dic: {}
},
methods: {
showGood() {
this.good_list = [
{'id': 1, 'name': '短裙', 'number': 20, 'price': 22},
{'id': 2, 'name': '黑絲', 'number': 34, 'price': 43},
{'id': 3, 'name': '白絲', 'number': 55, 'price': 12},
{'id': 4, 'name': '過膝襪', 'number': 19, 'price': 5},
{'id': 5, 'name': '馬油襪', 'number': 39, 'price': 3},
]
this.good_img = '/img/1.jpg'
Vue.set(this.style_dic, 'width', '30px')
Vue.set(this.style_dic, 'height', '30px')
}
}
})
</script>
</body>
for迴圈不同資料型別
<body>
<div id="app">
<h1>for迴圈字串</h1>
<p>預設迴圈字元,還可以加入第二個引數,迴圈索引</p>
<p v-for="(item,index) in str">字元--->{{item}} 索引--->{{index}}</p>
<h1>for迴圈數字</h1>
<p>從1開始迴圈到最後一個數字(包括最後一個數字)也可以迴圈索引</p>
<p v-for="(item,index) in num">數字--->{{item}} 索引--->{{index}}</p>
<h1>迴圈陣列</h1>
<p>預設迴圈元素,還可以加入第二個引數,迴圈索引</p>
<p v-for="(item,index) in list">元素--->{{item}} 索引--->{{index}}</p>
<h1>迴圈物件</h1>
<p>預設迴圈value值,還可以加入第二個引數,迴圈鍵值</p>
<p v-for="(value,key) in obj">值--->{{value}} 鍵--->{{key}}</p>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
list: ['張雪峰', '暴叔', '吉田'],
str: 'hello word',
obj: {name: 'green', age: 18},
num: 10
}
})
</script>
</body>
標籤內加入key屬性
#1 以後寫v-for,都要在標籤上加 :key="key" ,key必須唯一
# 2 這樣做可以提高虛擬dom的替換效率
【8】事件處理
# 1 input 標籤的事件處理
input 當輸入框進行輸入的時候 觸發的事件
change 當元素的值發生改變時 觸發的事件
blur 當輸入框失去焦點的時候 觸發的事件
focus 當獲得焦點的時候 觸發的事件
<body>
<div id="app">
<input type="text" @input="handleInput($event)" value="當輸入框進行輸入的時候 觸發的事件"><br>
<input type="text" @change="handleChange" value="當元素的值發生改變時 觸發的事件"><br>
<input type="text" @blur="handleBlur" :value="inputValue"><br>
<input type="text" @focus="handleFocus" :value="inputValue"><br>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
inputValue: ''
},
methods: {
handleInput(event) {
console.log(event.data)
},
handleChange() {
alert('發生改變了')
},
handleBlur() {
this.inputValue = '失去焦點了'
},
handleFocus(){
this.inputValue = '得到焦點了'
}
}
})
</script>
</body>
過濾小案例
<body>
<div id="app" class="container-fluid">
<div class="row">
<div class="col-6 offset-3">
<h1 class="text-center">過濾小案例</h1>
<p class="text-center">搜尋框</p>
<input type="email" class="form-control" v-model:value="kewWord" @input="handleInput">
<table class="table">
<tr v-for="item in list">
<td class="text-center">{{item}}</td>
</tr>
</table>
</div>
</div>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
dataList: ['黑絲', '黑絲襪', '黑絲連體襪', '吊帶', '吊帶蝴蝶結', 'black', 'blac', 'bla'],
kewWord: 'hahah',
list: null
},
methods: {
handleInput() {
let _this = this
this.list = this.dataList.filter(function (item) {
return item.indexOf(_this.kewWord) >= 0
})
}
}
})
</script>
</body>
# 箭頭函式最佳化程式碼寫法
methods: {
handleInput() {
this.list = this.dataList.filter((item)=> item.indexOf(this.kewWord) >= 0
)
}
}
// 流程
核心是 要透過輸入框的內容過濾資料列表
輸入框的內容可以透過雙向繫結得到
透過filter函式過濾,它可以將陣列裡的一個個元素分別進行校驗,如果不透過返回flase,透過返回true
透過 indexOf 方法校驗當前輸入框的內容和資料陣列裡的元素是否匹配 如果匹配返回大於0的數,不匹配返回-1
補充:js中的filter函式
filter() 方法建立一個新的陣列,新陣列中的元素是透過檢查指定陣列中符合條件的所有元素。
注意: filter() 不會對空陣列進行檢測。
注意: filter() 不會改變原始陣列。
語法
array.filter(function(currentValue,index,arr), thisValue)
currentValue 當前從array取出校驗的元素
index 當前取出的元素的索引
arr 當前元素的來源
補充:es6語法箭頭函式
<!-- 初始匿名函式寫法-->
let name = 'green'
let f = function (name){
return name + 'nb'
}
console.log(f(name))
// 箭頭函式寫法,去掉function,在括號和大括號中間加上=>
let f = (name) => {
return name + 'nb'
}
console.log(f(name))
// 當函式只需要傳一個引數時,可以不用 用括號把引數括起來
let f = name => {
return name + 'nb'
}
console.log(f(name))
// 當返回值只有一行程式碼時,可以不用寫return 和 大括號
let f = name => name + 'nb'
console.log(f(name))
為什麼要寫箭頭函式?
箭頭函式是為了解決function函式的this指向問題,
箭頭函式體內的this物件,就是定義該函式時所在的作用域指向的物件,而不是使用時所在的作用域指向的物件。
【9】事件修飾符
在Vue中,事件修飾符處理了許多DOM事件的細節,讓我們不再需要花大量的時間去處理這些煩惱的事情,而能有更多的精力專注於程式的邏輯處理。
在Vue中事件修飾符主要有:
.stop:等同於JavaScript中的event.stopPropagation(),防止事件冒泡
.prevent:等同於JavaScript中的event.preventDefault(),防止執行預設的行為(如果事件可取消,則取消該事件,而不停止事件的進一步傳播)
.capture:與事件冒泡的方向相反,事件捕獲由外到內
.self:只會觸發自己範圍內的事件,不包含子元素
.once:只會觸發一次
【10】jsfor迴圈的方式
普通的索引迴圈
<script>
<!-- 普通的索引迴圈-->
let arr = [18, 'green', {name: 'hqq', age: 22}]
for(let i=0 ;i<arr.length;i++){
console.log(arr[i])
}
</script>
基於迭代的off迴圈
<script>
<!-- 迭代off迴圈-->
let arr = [18, 'green', {name: 'hqq', age: 22}]
for (let item of arr) { // item就是陣列裡面的一個個元素
console.log(item)
}
</script>
基於迭代的in迴圈
<script>
<!-- 迭代in迴圈-->
let arr = [18, 'green', {name: 'hqq', age: 22}]
for (let index in arr) { // index是索引
console.log(arr[index])
}
</script>
陣列的forEach方法迴圈
<script>
<!-- 陣列的forEach方法迴圈-->
let arr = [18, 'green', {name: 'hqq', age: 22}]
arr.forEach((value,index,array)=>{ // 分別是元素,索引,資料來源陣列
console.log(value,index,array)
})
</script>
【11】按鍵修飾符
#1 按下某個鍵盤,觸發事件,透過修飾控制只有按下某個鍵,才觸發事件
#2 keyCode對應表--》按鍵修飾符
https://www.cnblogs.com/841019rossi/p/16808455.html
<body>
<div id="app">
<button @keyup.enter="handleEnter">按回車有驚喜</button>
</div>
<script>
let vm = new Vue({
el: '#app',
data:{},
methods:{
handleEnter(){
alert('回車被按了')
}
}
})
</script>
</body>
【12】表單控制
# 1 checkbox v-model 繫結
-布林 :選中沒選中
-陣列:多選
# 2 radio:
-字串:value的值
購物車小案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-/mhDoLbDldZc3qpsJHpLogda//BVZbgYuw6kof4u2FrCedxOtgRZDTHgHUhOCVim"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app" class="container">
<div class="row">
<div class="col-6 offset-3">
<h1 class="text-center">圖書商城</h1>
<p class="text-center">
<button class="btn btn-success" @click.once="handleLoad">載入購物車</button>
</p>
<div class="input-group mb-3">
<input type="text" class="form-control" placeholder="搜尋書名"
aria-label="Recipient's username" aria-describedby="button-addon2" v-model="searchText">
<button class="btn btn-outline-secondary" type="button" id="button-addon2" @click="handleSearch" >搜尋
</button>
</div>
<table class="table table-bordered">
<thead>
<tr>
<th scope="col">id</th>
<th scope="col">書名</th>
<th scope="col">作者</th>
<th scope="col">價格</th>
<th scope="col">數量</th>
<th scope="col"><p>全選/全不選 <input type="checkbox" v-model="checkAll" @change="handleChange"></p>
</th>
</tr>
</thead>
<tbody>
<tr v-for="(book,index) in showList">
<th scope="row">{{index + 1}}</th>
<td>{{book.title}}</td>
<td>{{book.author}}</td>
<td>{{book.Price}}</td>
<td>
<button class="btn" @click="handleSub(book)">-</button>
{{book.num}}
<button class="btn" @click="handleAdd(book)">+</button>
</td>
<td><input type="checkbox" v-model="checkList" @change="handleSum" :value="book"></td>
</tr>
</tbody>
</table>
<p>總價格</p>
<input type="text" class="form-control" readonly :value="getSum">
</div>
</div>
</div>
</body>
<script>
let vm = new Vue({
el: '#app',
data: {
bookList: [],
checkList: [],
checkAll: null,
searchText: '',
showList: []
},
methods: {
handleLoad() {
axios.get('http://127.0.0.1:8000/api/v1/book/')
.then((response) => {
for (const responseElement of response.data.results) {
responseElement.num = 0
}
this.bookList = response.data.results
})
},
handleAdd(book) {
book.num += 1
this.handleSum()
},
handleSub(book) {
if (!book.num) {
return
}
book.num -= 1
this.handleSum()
},
handleSum() {
this.checkAll = (this.checkList.length === this.bookList.length)
},
handleChange() {
if (this.checkAll) {
this.checkList = this.bookList
} else {
this.checkList = []
}
},
handleSearch() {
this.showList = this.bookList.filter((book) => book.title.indexOf(this.searchText) >= 0)
}
},
computed: {
getSum() {
let total = 0
for (let book of this.checkList) {
total += book.num * book.Price
}
return total
}
}
})
</script>
</html>
【13】v-model進階
v-model 之 lazy、number、trim
lazy:等待input框的資料繫結失去焦點之後再變化
number:數字開頭,只保留數字,後面的字母不保留;字母開頭,都保留
trim:去除首位的空格
【14】vue與ajax
vue的資料與後端進行互動的ajax方式有:
原生js的ajax(不常用)
jquery封裝的ajax(不常用)
H5自帶的fetch (可能用)
vue的axios(Vue作者推薦用)
原生js的ajax
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
<script>
/* ajax */
//post資料傳遞,一般需要介面文件,自己用node寫也是可以的
//建立ajax
var xhr = new XMLHttpRequest;
//請求地址
xhr.open('post', 'url');
//請求頭
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
//因為ajax非同步send還是寫這裡比較好
xhr.send('name=zhangsan&age=18')
xhr.onreadystatechange = function(){
if (xhr.readyState === 4){
if (xhr.status>=200 && xhr.status<300){
var res = xhr.responseText;
console.log(res);
}
}
}
</script>
</html>
jquery封裝的ajax
因為jquery有比較完整的ajax封裝,但它主要是操作DOM和Bom,所以一般也不怎麼用,作為擴充吧
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- bootcdn的映象也可以自己下載jquery庫-->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
<title>Document</title>
</head>
<body>
</body>
<script>
/* jquery */
$.ajax({
method:'post',
url:'url',
// // dataType:"",
data:{
name:'zhangsan',
age:18
},
success:res=>{
console.log(res);
},
// // error:err=>{
// // }
})
</script>
</html>
H5自帶的fetch
H5自帶的fetch封裝的ajax也是比較好的,現在市面上還有些公司在用
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
<script>
/* fetch */
//get,返回值是物件所以需要呼叫then()方法,呼叫出來
fetch('url?name=zhangsan&age=18').then(res=>res.text()).then(res=>{
console.log(res);
})
//post,body裡還是不能用物件
fetch('url',{
method:'post',
body:'name=zhangsan&age=14',
headers: {
"content-type": 'application/x-www-form-urlencoded'
}
//轉json資料格式
}).then(res=>res.json()).then(res=>{
console.log(res);
})
</script>
</html>
axios庫
主要使用的資料請求方式,因為作者推薦,作者都推薦了嘛,最後還得是看公司,沒要求最好還是axios
使用需要下載axios外掛,使用方法詳見官網:axios官網
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
<script src="./node_modules/axios/dist/axios.js"></script>
<script>
/* axios */
//設定全域性令牌,傳送請求就不用特地帶令牌了
axios.defaults.headers['authorization'] = 'token'
//get,可以設定全域性地址提高程式碼複用率,減少自己寫程式碼,就不用每個都寫這麼長的地址,嘿嘿
axios.defaults.baseURL='url'
axios.get('third', {
params: {
name: 'lisi',
age: 20
}
}).then(res => {
console.log(res.data);
})
//post
axios.post('/fourth', 'name=a&age=12').then(res => {
console.log(res);
})
</script>
</html>
【15】計算屬性
# 1 計算屬性是基於它們的依賴進行快取的
# 2 計算屬性只有在它的相關依賴發生改變時才會重新求值
# 3 計算屬性就像Python中的property,可以把方法/函式偽裝成屬性
# 4 寫在computed中,必須返回值--》返回值才是屬性
-以後把他當屬性用
-可以被for迴圈
透過計算屬性實現名字首字母大寫
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<input type="text" v-model="nameText"> ---> {{upperFirst}}
</div>
<script>
let vm = new Vue({
el: '#app',
data:{
nameText:'',
},
methods:{},
computed:{
upperFirst(){
return this.nameText.substring(0, 1).toUpperCase() + this.nameText.substring(1)
}
}
})
</script>
</body>
</html>
【16】監聽屬性
雖然計算屬性在大多數情況下更合適,但有時也需要一個自定義的偵聽器。這就是為什麼 Vue 透過 watch
選項提供了一個更通用的方法,來響應資料的變化。當需要在資料變化時執行非同步或開銷較大的操作時,這個方式是最有用的。
需要監聽哪個屬性,就在watch裡面寫哪個屬性,只要這個屬性傳送改變,就會自動執行這個方法
小案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-/mhDoLbDldZc3qpsJHpLogda//BVZbgYuw6kof4u2FrCedxOtgRZDTHgHUhOCVim"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<button class="btn btn-success" @click="res='python'">python</button>
<button class="btn btn-info" @click="res='java'">java</button>
<button class="btn btn-danger" @click="res='go'">go</button>
result --->{{res}}
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
res: ''
},
watch:{ // 想要監聽哪個引數就在watch裡面寫哪個引數,當這個引數發生變化就會自動執行
// before改變前,back改變後 這兩引數可填可不填
res(before,back){
console.log(back,before)
}
}
})
</script>
</body>
</html>
【17】生命週期
vue生命週期分別有建立、初始化資料、編譯模板、掛在DOM、渲染-更新-渲染、解除安裝利用鉤子函式完成對應的專案效果
beforeCreate( 建立前 )
在例項化之後,資料的觀測和事件的配置之前的時候呼叫,此時元件的選項物件還未建立,el 和 data 並未初始化,因此無法訪問methods, data, computed等上的方法和資料
created ( 建立後)
在建立之後使用,主要用於資料觀測、屬性和方法的運算,watch/event事件回撥,完成了data 資料的初始化,el沒有。 然而,掛在階段還沒有開始.
beforeMount (掛載前)
用於在掛載之前使用,在這個階段是獲取不到dom操作的,把data裡面的資料和模板生成html,完成了data等初始化,注意此時還沒有掛在html到頁面上
mount (掛載後)
用於掛載之後使用,在這個時候可以獲取到dom操作,比如可以獲取到ref等,操作的dom, 在這個時候只能呼叫一次ajax,在這個時候el和data都可以獲取的到
beforeUpdate (更新前)
在資料更新之前被呼叫,發生在虛擬DOM重新渲染,可以在該鉤子中進一步地更改狀態,不會觸發重複渲染過程
updated (更新後)
在由於資料更改導致地虛擬DOM重新渲染會呼叫,呼叫時,元件DOM已經更新,所以可以執行依賴於DOM的操作,然後在大多是情況下,應該避免在此期間更改狀態,因為這可能會導致更新無限迴圈,但是在伺服器端渲染期間不被呼叫,可以用於監聽某些資料的時候使用鉤子
beforeDestroy(銷燬前)
在這個時候還是可以用this來獲取,可以用於銷燬計時器時候使用,為了防止跳轉到其它頁面該事件還在執行,還可以清除dom事件等
destroy(銷燬後)
在例項銷燬之後呼叫,呼叫後,所以的事件監聽器會被移出,所有的子例項也會被銷燬.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<child v-if="showChild"></child>
<button @click="showChild=!showChild">點我消失</button>
</div>
</body>
<script>
Vue.component('Child', {
template: `
<div>
<button @click="handleClick">{{ title }}</button>
</div>`,
data() {
return {
title: 'hello word'
}
},
methods: {
handleClick() {
alert(this.title)
this.title = '你好世界'
},
},
// 在建立例項之前執行 this.title不會有值 this.$el不會有值
beforeCreate() {
console.log('beforeCreate')
console.log(this.title)
console.log(this.$el)
},
// 建立例項時執行 this.$el不會有值
created() {
console.log('Create')
console.log(this.title)
console.log(this.$el)
},
// 掛載之前執行 this.$el不會有值
beforeMount() {
console.log('beforeMount')
console.log(this.title)
console.log(this.$el)
},
mounted() {
console.log('mounted')
console.log(this.title)
console.log(this.$el)
},
// 在沒有更新資料就不會執行, 有更新的話會在更新之前執行
beforeUpdate() {
console.log('beforeUpdate')
console.log(this.title)
console.log(this.$el)
},
// // 在沒有更新資料就不會執行, 有更新的話會在更新之後執行
updated() {
console.log('Updated')
console.log(this.title)
console.log(this.$el)
},
// 在沒有執行刪除就不會執行, 有刪除操作的話會在刪除之前執行
beforeDestroy() {
console.log('beforeDestroy')
console.log(this.title)
console.log(this.$el)
},
// 在沒有執行刪除就不會執行, 有刪除操作的話會在刪除之後執行
destroyed() {
console.log('destroyed')
console.log(this.title)
console.log(this.$el)
}
})
let vm = new Vue({
el: '#app',
data: {
showChild: true
},
methods: {}
})
</script>
</html>
【18】元件的使用
元件分為區域性元件和全域性元件,全域性元件可以在根元件的任意位置使用,區域性元件只能使用在父元件裡面
元件中的資料,事件都是獨立的
全域性元件的書寫
<body>
<div id="app">
<Child></Child>
</div>
</body>
<script>
// 全域性元件的書寫
Vue.component('Child', {
// 需要透過template掛載
template: `
<div><h1>我是全域性元件</h1>
<p>{{ message }}</p>
<button @click="handleClick">點我顯示名字</button>
</div>`,
// data需要寫成一個函式 然後把值寫在函式的返回值裡
data() {
return {
message: '需要寫在根元件裡'
}
},
// 方法的寫法和根元件的寫法一致
methods: {
handleClick() {
this.message = 'green'
}
}
})
let vm = new Vue({
el: '#app',
})
</script>
區域性元件的書寫
<body>
<div id="app">
<p>{{message}}</p>
<button @click="handleClick">點選顯示根元件名字</button>
<Child></Child>
</div>
</body>
<script>
let vm = new Vue({
el: '#app',
data: {
message: '我是根元件'
},
methods: {
handleClick() {
this.message = 'green'
}
},
// 在根元件中定義區域性元件,這裡以根元件為例子,定義在哪裡的區域性元件,就只能在哪裡使用
components:{
Child:{
template:`<div><h1>我是區域性元件,根元件的子元件</h1><button @click="handleClick">點我彈窗</button></div>`,
data(){
return{
message:'我是子元件Child'
}
},
methods: {
handleClick(){
alert(this.message)
}
}
}
}
})
</script>
【19】元件中通訊
各個元件的資料都是獨立的,要想實現各個元件的資料互通,需要用到一些特定的方法
父傳子
<body>
<div id="app">
<button @click="handleClick">點選給在子元件發訊息</button>
<!-- 1.在子元件標籤中繫結資料屬性-->
<Child :message="message"></Child>
</div>
</body>
<script>
let vm = new Vue({
el: '#app',
data: {
message: ''
},
methods: {
handleClick() {
this.message = '我是來自父元件的訊息--->你好'
}
},
// 定義子元件
components: {
Child: {
template: `
<div><h1>我是子元件Child</h1>
<p>來自父元件的訊息---->{{ message }}</p></div>`,
// 2.在子元件中定義props,將子元件標籤中定義的資料屬性鍵值填入props的陣列
props: ['message']
}
}
})
</script>
子傳父
<body>
<div id="app">
<h1>我是父元件</h1>
<img :src="src" width="250px" height="300px" alt="" v-if="src">
<!-- 子元件給父元件傳引數,需要給子元件標籤繫結一個自定義事件-->
<Child @event="handleEvent"></Child>
</div>
</body>
<script>
let em = new Vue({
el: '#app',
data: {
src: ''
},
methods: {
handleEvent(src) {
this.src = src
}
},
components: {
Child: {
template: `
<div><h1>我是子元件</h1><img :src="src" alt="" width="250px" height="300px" v-if="src">
<button @click="handleClick">點選把圖片傳到父元件</button>
</div>`,
data() {
return {
src: './img/1.jpg'
}
},
methods: {
handleClick() {
// 透過this.$emit('event', this.src),第一個引數就是自定義事件的名稱,第二個引數就是傳遞的引數
this.$emit('event', this.src)
this.src = ''
}
}
}
}
})
</script>
【20】ref屬性
ref是Vue2中一個重要的屬性,用於在元件中對DOM元素或者子元件的引用。透過ref,可以在某個元件的內部直接訪問DOM元素或者它的子元件。
在Vue2中可以將ref新增到元素,元件或者子元件的標籤上,然後可以透過元件例項的$refs物件來訪問這些引用
<body>
<div id="app">
<h1>我是父元件</h1>
<button @click="handleClick" ref="button">點我看控制檯</button>
<Child ref="child"></Child>
</div>
</body>
<script>
let vm = new Vue({
el: '#app',
data: {},
methods: {
handleClick() {
// this是當前Vue的例項
// this.$refs是一個物件,裡面包含了所有的有ref屬性的標籤的dom物件或者元件物件
// 1.拿到子元件的屬性
console.log(this.$refs.child.message)
// 2.修改子元件的屬性
this.$refs.child.message = '我是修改後的訊息'
// 3.呼叫子元件的函式
this.$refs.child.handleClick('我是來自父元件的引數')
// 4.給子元件的函式傳引數
}
},
components: {
Child: {
template: `
<div ><h1>我是子元件</h1> <button @click="handleClick">點我看看</button><p>{{message}}</p></div>`,
data() {
return {
message: '我是來自子元件的訊息'
}
},
methods: {
handleClick(name){
console.log('我被父元件的事件呼叫了')
console.log(name)
}
}
}
}
})
</script>
【21】動態元件
動態元件,就是實現動態切換的元件
記住以下三點,就能掌握動態元件
① 利用 <component/>
元素的 is
屬性
② is
屬性應該用 v-bind
修飾(可以簡寫為 :
)
③ is
屬性應該傳入註冊的元件名
<body>
<div id="app">
<button @click="name='Girl1'">美女1</button>
<button @click="name='Girl2'">美女2</button>
<button @click="name='Girl3'">美女3</button>
<!-- component是一個萬能元件,他的is屬性就決定了它是哪一個元件 -->
<component :is="name"></component>
</div>
</body>
<script>
let vm = new Vue({
el: '#app',
data: {
name:''
}
})
Vue.component('Girl1', {
template: `<div><h1>美女1</h1><img src="./img/1.jpg" alt=""></div>`
})
Vue.component('Girl2', {
template: `<div><h1>美女2</h1><img src="./img/2.jpg" alt=""></div>`
})
Vue.component('Girl3', {
template: `<div><h1>美女3</h1><img src="./img/3.jpg" alt=""></div>`
})
</script>
【22】keep-alive
在平常開發中,有部分元件沒有必要多次初始化,這時,我們需要將元件進行持久化,使元件的狀態維持不變,在下一次展示時,也不會進行重新初始化元件。
也就是說,keepalive
是 Vue
內建的一個元件,可以使被包含的元件保留狀態,或避免重新渲染 。也就是所謂的元件快取
<keep-alive>
是Vue的內建元件,能在元件切換過程中將狀態保留在記憶體中,防止重複渲染DOM。
<!--被keepalive包含的元件會被快取-->
<keep-alive>
<component><component />
</keep-alive>
【23】插槽
正常情況下,如果已經寫好了一個元件,並且想要往元件裡面新增別的東西,就只能修改元件內容,擴充性很差
所以就出現了插槽的概念,只需要在模板中可能需要更改的地方加上<slot></slot>
,後續想要更新內容的時候直接在html裡面加就行