Vue框架
定義:漸進式 JavaScript 框架
漸進式:可以控制一個頁面的一個標簽,可以控制一系列標簽,也可以控制整個頁面,甚至可以控制整個前台項目。
通過對框架的了解與運用程度,來決定其在整個項目中的應用范圍,最終可以獨立以框架方式完成整個web前端項目
一、Vue基礎
1、什么是Vue
可以獨立完成前后端分離式web項目的JavaScript框架
2、為什么要學習Vue
三大主流框架之一:Angular(龐大) React(精通移動端) Vue(吸取前兩者優勢,輕量級)
先進的前端設計模式:MVVM
可以完全脫離服務器端,以前端代碼復用的方式渲染整個頁面:組件化開發
3、特點
有指令(分支結構,循環結構...),復用頁面結構等
有實例成員(過濾器,監聽),可以對渲染的數據做二次格式化
有組件(模塊的復用或組合),快速搭建頁面
單頁面web應用
數據驅動
數據的雙向綁定
虛擬DOM
4、Vue安裝
- 開發版本:vue.js
- 生產版本:vue.min.js
""" 1)cdn導入 <script src="https://cn.vuejs.org/js/vue.js"></script> 2)本地導入 <script src="js/vue.js"></script> """
注意:
掛載點介紹
el: 掛載點
1)一個掛載點只能控制一個頁面結構(優先匹配到的結構)
2)掛載點掛載的頁面標簽嚴格建議用id屬性進行匹配(一般習慣用app)
3)html標簽與body標簽不能作為掛載點(html和body標簽不可以被替換,組件中詳細介紹)
4)是否接受vue對象,是外界是否要使用vue對象的內容決定的

<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>掛載點</title> <body> <div id="app"> <div> {{ num }} </div> <div> {{ num }} </div> </div> <div id="main"> {{ n }} </div> </body> <script src="js/vue.js"></script> <script> var app = new Vue({ el: '#app', data: { num:100 } }); console.log('12345'); console.log(app.num); // console.log(app.$data.num); console.log(app.$el); new Vue({ el: '#main', data:{ n:app.num } }) </script> </html>
插值表達式
1)空插值表達式:{{ }}
2)插值表達式中渲染的變量在data中可以初始化
3)插值表達式可以進行簡單運算與簡單邏輯
4)解決插值表達式符號沖突,用delimiters自定義(了解)

<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>插值表達式</title> </head> <body> <div id="app"> <p>{{ info }}</p> <p>{{ msg }}</p> <p>{{ }}</p> <p>{{ num }}</p> <p>{{ num + 10 * 2 }}</p> <p>{{ msg + num }}</p> <p>{{ msg.length + num }}</p> <p> {{ msg[4] }}</p> <p> {{ msg.split('') }}</p> <!-- <p>[{ num }]</p>--> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', data:{ info:'信息', msg:'message', num:10 }, // 控制vue插值表達式符號 (了解) // delimiters: ['[{','}]'] }) </script> </html>
過濾器
1)用實例成員filters來定義過濾器
2)在頁面結構中,用 | 來標識使用過濾器
3)過濾方法的返回值就是過濾器過濾后的結果
4)過濾器可以對1~n個變量進行過濾,同時還可以傳入輔助的變量,
過濾器方法接受參數是按照傳入的位置先后
計算屬性
"""
計算屬性:
1)即vue中的方法屬性,就是方法名可以作為屬性來使用,屬性值為方法的返回值
2)在computed中聲明的方法屬性,不能在data中重復聲明,只是比data中聲明的屬性要多出寫邏輯的地方
3)方法屬性自帶監聽機制,在方法屬性中出現的變量都會被監聽,一旦有任何被監聽的變量值發生更新,方法屬性都會被調用,更新方法屬性的值
4)方法屬性一定要在頁面中渲染一次,方法屬性才有意義,多次渲染 方法屬性只會被調用一次
應用場景:計算器,一個變量依賴於多個變量,且需要進行一定的邏輯運算
"""

<div id="app"> <!-- type="number"表示只能寫數字 --> <input type="number" v-model="num1"> + <input type="number" v-model="num2"> = <button>{{ sum }}</button> </div> <script> new Vue({ el: '#app', data: { // sum: '', // 重復聲明 num1: '', num2: '', }, computed: { sum () { // num1和num2都在該方法屬性中,所以有一個更新值,該方法都會被調用 if (this.num1 && this.num2) { return +this.num1 + +this.num2; // +this.num1是將字符串快速轉換成數字 } return '結果'; } } }) </script>
監聽屬性
"""
1)watch中不定義屬性,只是監聽屬性,所以方法的返回值沒有任何意義,只是監聽變量值是否發生更新
2)watch中的方法名,就是被監聽的屬性(方法名同被監聽屬性名)
3)被監聽的變量值一旦發生更新,監聽方法就會被調用
應用場景:
i)k線圖:股票數據變化,頁面的k線圖重新渲染(需要邏輯將數據轉換為圖形)
ii)拆分姓名:錄入姓名,拆分為姓和名(需要邏輯將一個數據拆分為多個數據)
"""

<div id="app"> 姓名:<input type="text" v-model="full_name"> <hr> 姓:<button>{{ first_name }}</button> 名:<button>{{ last_name }}</button> </div> <script> new Vue({ el: '#app', data: { full_name: '', first_name: '未知', last_name: '未知' }, watch: { full_name () { if (this.full_name) { // 實現簡易的拆分邏輯 this.first_name = this.full_name.split('')[0]; this.last_name = this.full_name.split('')[1]; } else { this.first_name = '未知'; this.last_name = '未知'; } } } }) </script>
JS反引號變量占位
"""
1)雙引號:
"前綴" + 變量 + "后綴"
2)單引號:
'前綴' + 變量 + '后綴'
3)反引號:
`前綴${變量}后綴`
注:在反引號中可以用 ${} 來包裹變量,實現字符串拼接
"""
基礎實例成員
1)el:掛載點
2)data:提供渲染的數據
3)methods:提供綁定的方法
4)filters:提供自定義過濾器,過濾器可以同時過濾多個參數,還可以串聯過濾器
5)delimiters:插值表達式標識符,['{{','}}']
6)computed:計算(方法屬性)
7)props:屬性
8)watch:監聽
指令
1)v-* 是vue指令,會被vue解析,v-text="num"中的num是變量(指令是有限的,不可以自定義)
2)v-text是原樣輸出渲染內容,渲染控制的標簽自身內容會被替換掉(<p v-text="num">123</p>會被num替換)
3)v-html可以解析渲染html語法的內容

<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>文本指令</title> </head> <body> <div id="app"> <p>{{ num | add(300) }}</p> <p v-text="num" class="123"></p> <p v-text="num">123</p> <p v-text="info"></p> <p v-html="info"></p> <!-- js基本數據類型:字符串、數字、布爾、undefined --> <p v-text="'abc' + num + 10"></p> <!-- abc10010 --> <p>{{ 'abc' + num + 10 }}</p> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', data: { num:100, info: '<i>info內容</i>' }, filters:{ add:function (a,b) { return a + b; } } }) </script> </html>
事件指令
""" /** * 一、數據驅動 * 1)操作是一個功能,使用需要一個方法來控制 2)方法名是變量,所以控制變量就可以控制該方法 * * * 二、事件指令 * 1)在實例成員methods中聲明事件方法 * 2)標簽通過事件指令綁定聲明的方法: v-on:事件名="事件方法名" * eg: <button v-on:click="btnClick">按鈕</button> * 3)標簽通過事件指令綁定聲明的方法,且自定義傳參: v-on:事件名="事件方法名()" * eg: <button v-on:click="btnClick()">按鈕</button> 不傳任何參數 * eg: <button v-on:click="btnClick($event)">按鈕</button> 傳入事件對象,同不寫() * eg: <button v-on:click="btnClick(10)">按鈕</button> 只傳入自定義參數,當然也可以傳入事件對象 */ """
重點:v-on: 可以簡寫為 @

<body> <div id="app"> <button v-on:click="btnClick">{{ btn1 }}</button> <button v-on:click="btnClick">{{ btn2 }}</button> <hr> <!-- 直接綁定事件名:系統會在觸發事件時(點擊時)調用事件方法(fn1),傳給事件方法一個參數(事件對象) --> <button v-on:click="fn1">按鈕3</button> <!-- 綁定的事件名后跟着(),不是主動調用事件方法,而是表示在觸發事件調用時,傳入的參數全由用戶自己決定 --> <button v-on:click="fn2($event, 10, 20)">按鈕4</button> <hr> <button v-on:click="fn(btn1)">{{ btn1 }}</button> <button v-on:click="fn(btn2)">{{ btn2 }}</button> </div> </body> <script src="js/vue.js"></script> <script> // 對比DOM驅動:1)js選擇器獲取目標標簽 2)為目標標簽綁定事件 3)在事件中完成相應邏輯 // var btn = document.getElementsByTagName('button')[0]; // btn.onclick = function () { // console.log(111111111111); // }; new Vue({ el: '#app', data: { btn1: '按鈕1', btn2: '按鈕2', }, methods: { btnClick () { console.log(666) }, fn1 (ev) { console.log(ev.clientX, ev.clientY); }, fn2(ev, n1, n2) { console.log(ev, n1, n2); console.log(ev.clientX, ev.clientY); }, fn (msg) { console.log(msg); } } }) </script>

<style> body { /* 不允許文本選中 */ user-select: none; } .d1:hover { color: orange; /* 鼠標樣式 */ cursor: pointer; } /* 只有按下采用樣式,抬起就沒了 */ .d1:active { color: red; } /* div標簽壓根不支持 :visited 偽類 */ .d1:visited { color: pink; } .d2.c1 { color: orange; } .d2.c2 { color: red; } .d2.c3 { color: pink; } </style> <div id="app"> <div class="d1">偽類操作</div> <br><br><br> <!-- click: 單擊 dblclick:雙擊 mouseover:懸浮 mouseout:離開 mousedown:按下 mouseup:抬起 --> <div :class="['d2', c]" @click="hFn('c1')" @mouseover="hFn('c2')" @mousedown="hFn('c3')">事件處理</div> </div> <script> new Vue({ el: '#app', data: { c: '', }, methods: { hFn (c) { this.c = c } } }) </script>
斗篷指令
v-cloak:避免屏幕閃爍
1)屬性選擇器,會將v-cloak屬性所在的標簽隱藏
2)當vue環境加載后,會將v-cloak屬性解析移除,所以內容{{ num }}就會顯示出來
3)而現在vue已經准備完畢,所以用戶會直接看到數值10,而不會看到 頁面從{{ num }}閃爍成數值10 """

<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title></title> <style> [v-cloak] { display: none; } </style> </head> <body> <div id="app" v-cloak> <p>{{ num }}</p> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', data:{ num:10 }, }) </script> </html>
屬性指令
屬性指令 1)語法:v-bind:屬性名="變量" 2)針對不同屬性,使用方式稍微有區別 i)自定義屬性以及title這些,直接賦值的,使用方式如下(t是變量,'o'是常量) <p v-bind:title="t" v-bind:owen="'o'">段落</p> ii)class屬性(重點): 綁定的變量:值可以為一個類名 "p1",也可以為多個類名 "p1 p2" 綁定的數組:數組的每一個成員都是一個變量 綁定的字典:key就是類名,value是決定該類名是否起作用的
iii)style屬性(了解):
綁定的變量:值是一個字典
重點:
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>屬性指令</title> <style> .b1 { width: 100px; height: 100px; background-color: red; } .b2 { border-radius: 50%; } </style> </head> <body> <!--1) 標簽的屬性沒有被v-bind綁定,就是同原來一樣基本使用--> <!--2)標簽的屬性被v-bind綁定,就會被vue控制,值就會變為變量--> <!-- 換而言之,如果一個屬性要被vue控制,填寫變量就要用v-bind來處理--> <div id="app"> <p v-bind:class="a" style="color: red;background-color:orange " v-bind:title="t" v-bind:owen="'o'">段落</p> <p v-bind:class="b"></p> <p class="b1 b2"></p> <p v-bind:class="[c,d]"></p> <p v-bind:class="{b1:0}"></p> <!-- a是變量,值就是類名 b1就是類名,不是變量 e是變量,值為布爾,決定b1類是否起作用 --> <p v-bind:class="[a,{b1:e}]"></p> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', data:{ t:'懸浮提示', a:'a1', b:'b1 b2', c:'b1', d:'b2', e:true, } }) </script> </html>
<p v-bind:style="myStyle"></p> <script> let app = new Vue({ el: '#app', data: { myStyle: { width: '50px', height: '50px', backgroundColor: 'pink', borderRadius: '50%' } }, }) </script>
案例:

<style> .live{ background-colorL:yellowgreen } </style> <button v-bind:class="{live: isLive == 1}" v-on:click="changeLive(1)">1</button> <button v-bind:class="{live: isLive == 2}" v-on:click="changeLive(2)">2</button> <button v-bind:class="{live: isLive == 3}" v-on:click="changeLive(3)">3</button> <script> let app = new Vue({ el: '#app', data: { isLive: 0, }, methods: { changeLive (index) { // this就代表當前vue對象,和app變量等價 // app.isLive = index; this.isLive = index; } } }) </script>
表單指令
1)語法:v-model="變量"
2)v-model綁定的變量控制的是表單元素標簽的value屬性值
3)v-model要比v-bind:value要多一個監聽機制
4)數據的雙向綁定:
v-model可以將綁定的變量值映射給表單元素的value
v-model還可以將表單元素的新value映射給表單的變量
<!-- 兩個輸入框內容會同時變化 --> <div id="app"> <form action="" method=""> <input name="n1" type="text" v-model="v1"> <input name="n2" type="text" v-model="v1"> <button type="submit">提交</button> </form> </div> <script> new Vue({ el: '#app', data: { v1: '' } }) </script>
條件指令
1)語法:v-show="變量" | v-if="變量"
2)兩者區別:
v-show在隱藏標簽時,采用display:none渲染標簽,標簽通過css隱藏
v-if在隱藏標簽時,不會渲染到頁面上
3)v-if有家族:v-if | v-else-if | v-else
v-if是必須的,必須設置條件
v-else-if可以為0~n個,必須設置條件
v-else可以為0~1個
上方分支成立會屏蔽下方所有分支,從上到下依次類推
<div id="app"> <div> <p v-show="isShow">show控制顯隱</p> <p v-if="isShow">if控制顯隱</p> </div> <div> <p v-if="1">你是第一個p</p> <p v-else-if="2">你是第二個p</p> <p v-else>你是第三個p</p> </div> </div> <script> new Vue({ el: '#app', data:{ isShow:false, } }) </script>
案例:

<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>案例</title> <style> body { margin: 0 } button { width: 60px; line-height: 40px; float: right; } .bGroup:after { display: block; content: ''; clear: both; } .box { /* vw: view width vh: view height*/ width: 100vw; height: 200px; } .red { background-color: red; } .green { background-color: green; } .blue { background-color: blue; } button.active { background-color: cyan; } </style> </head> <body> <div id="app"> <div class="bGroup"> <button :class="{active: isShow === 'red'}" @click="isShow = 'red'">紅</button> <button :class="{active: isShow === 'green'}" @click="isShow = 'green'">綠</button> <button :class="{active: isShow === 'blue'}" @click="isShow = 'blue'">藍</button> </div> <div> <div v-if="isShow === 'red'" class="box red"></div> <div v-else-if="isShow === 'green'" class="box green"></div> <div v-else class="box blue"></div> </div> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', data: { isShow: 'red' } }) </script> </html>
循環指令
"""
1)語法:v-for="ele in obj" obj是被遍歷的對象,ele是遍歷得到的每一次結果
2)遍歷可迭代對象的首要結果,都是可迭代對象容器中的值,其次還可以遍歷得到索引及鍵等數據
字符串:v-for="v in str" | v-for="(v, i) in str"
數組:v-for="v in arr" | v-for="(v, i) in arr"
對象:v-for="v in obj" | v-for="(v, k) in obj" | v-for="(v, k, i) in obj"
注:v-for遍歷要依賴於一個所屬標簽,該標簽及內部所有內容會被遍歷復用
"""
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>循環指令</title> </head> <body> <div id="app"> <!-- 遍歷數字 5 【1】【2】【3】【4】【5】 --> <p>{{ d1 }}</p> <i v-for="e in d1">【{{ e }}】</i> <hr> <!-- 遍歷字符串 abc 【a】【b】【c】 【0a】【1b】【2c】 --> <p>{{ d2 }}</p> <i v-for="e in d2">【{{ e }}】</i> <i v-for="(e, i) in d2">【{{ i }}{{ e }}】</i> <hr> <!-- 遍歷數組 [ 1, 3, 5 ] 【1】【3】【5】 【01】【13】【25】 --> <p>{{ d3 }}</p> <i v-for="e in d3">【{{ e }}】</i> <i v-for="(e, i) in d3">【{{ i }}{{ e }}】</i> <hr> <!-- 遍歷對象 { "name": "Bob", "age": 17.5, "gender": "男" } 【Bob】【17.5】【男】 【name-Bob】【age-17.5】【gender-男】 【name-Bob-0】【age-17.5-1】【gender-男-2】 --> <p>{{ d4 }}</p> <i v-for="e in d4">【{{ e }}】</i> <i v-for="(e, k) in d4">【{{ k }}-{{ e }}】</i> <i v-for="(e, k, i) in d4">【{{ k }}-{{ e }}-{{ i }}】</i> <hr> </div> </body> <script> new Vue({ el: '#app', data: { d1: 5, d2: 'abc', d3: [1, 3, 5], d4: { name: "Bob", age: 17.5, gender: "男" } } }) </script>
案例:

<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title></title> <style> .box { width: 280px; border: 1px solid #eee; border-radius: 5px; overflow: hidden; /* 隱藏超出父級顯示范圍外的內容 */ text-align: center; /* 文本相關的屬性大多默認值是inherit */ float: left; margin: 10px; } .box img { width: 100%; } </style> </head> <body> <div id="app"> <div class="box" v-for="obj in goods"> <img :src="obj.img" alt=""> <p>{{ obj.title }}</p> </div> </div> </body> <script src="js/vue.js"></script> <script> let goods = [ { "img":"https://***1.jpg", "title": "商品1" }, { "img":"https://***2.jpg", "title": "商品2" } ]; new Vue({ el:"#app", data:{ goods, } }) </script> </html>
todolist
補充知識點:
js的Array操作
"""
尾增:arr.push(ele)
首增:arr.unshift(ele)
尾刪:arr.pop()
首刪:arr.shift()
增刪改插:arr.splice(begin_index, count, args)
"""
前台數據庫
"""
// 存
// 持久化化存儲,永遠保存
localStorage.name = "Bob";
// 持久化化存儲,生命周期同所屬標簽(頁面),頁面關閉,重新打開就會丟失
sessionStorage.name = "Tom";
// 取
console.log(localStorage.name);
console.log(sessionStorage.name);
// 清空
localStorage.clear();
sessionStorage.clear();
// 短板:只能存儲字符串,所以對象和數組需要轉換為json類型字符串,再進行存儲
let a = [1, 2, 3];
localStorage.arr = JSON.stringify(a);
let b = JSON.parse(localStorage.arr);
console.log(b);
"""
splice:
案例:留言板

<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>todolist</title> <style> li:hover { color: red; cursor: pointer; } </style> </head> <body> <div id="app"> <form action=""> <input type="text" v-model="info"> <button type="button" @click="sendInfo">留言</button> </form> <ul> <li v-for="(info,index) in info_arr" @click="deleteInfo(index)">{{ info }}</li> </ul> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', data:{ info:'', // 三元運算符: 條件 ? 結果1 : 結果2 info_arr:localStorage.info_arr ? JSON.parse(localStorage.info_arr) : [] }, methods: { sendInfo() { //完成留言,將info添加到info_arr // 增 push unshift | 刪 pop shift if(this.info){ //留言 this.info_arr.push(this.info); //清空輸入框 this.info = ''; //前台數據持久化(緩存) localStorage.info_arr = JSON.stringify(this.info_arr); } }, deleteInfo(index){ // 刪留言 this.info_arr.splice(index,1) // 同步給數據庫 localStorage.info_arr = JSON.stringify(this.info_arr); } } }) </script> </html>
"""1)雙引號:"前綴" + 變量 + "后綴"2)單引號:'前綴' + 變量 + '后綴'
3)反引號:`前綴${變量}后綴`注:在反引號中可以用 ${} 來包裹變量,實現字符串拼接"""