Vue.js 輕鬆上手

在瞭解vue以前,咱們先區分框架和類庫、漸進式框架等javascript

區分框架和類庫等

  1. 類庫

jQuery、Zepto、underscore... 類庫提供的是真實項目中經常使用到的方法,它是一個工具包,基於這個工具包能夠快速開發任何的項目html

  1. 插件

TAB選項卡插件、BANNER輪播圖插件、DIALOG模態框插件、DRAG拖拽插件... iscroll局部滾動插件、jquery中有不少的插件 插件是把項目中某一個具體的功能進行封裝vue

  1. UI組件

bootstrap、swiper、mui、妹子UI... UI組件庫通常是多個插件的集合體,不只提供了JS對應的功能,並且把結構、樣式等也都實現了,咱們只須要作一名CV工程師就能夠快速構建一個產品java

  1. 框架

vue、react、uni-app、react native、flutter、angular(ng)、backbone... 通常來講,框架是類庫和組件的綜合體,裏面提供了大量供咱們操做的方法,也有配套的UI組件庫供咱們快速開發;框架是具有獨立編程思想的,例如:vue是MVVM思想,讓咱們告別傳統的DOM操做,按照視圖和數據的相互渲染來完成項目開發,可是無論怎麼變,都必定會比咱們以前基於原生操做更簡單,性能更好...node

市面上經常使用的框架:vue(MVVM) / react(MVC) APP框架:uni-app / react native / flutterreact

初識vue

vue.js 是一套構建用戶界面的漸進式框架。jquery

vue只關注視圖層, 採用自底向上增量開發的設計。ios

vue的目標是經過儘量簡單的 API 實現響應的數據綁定和組合的視圖組件。vue-router

vue 咱們如今學習和使用的是第二代版本vuex

參考資料:

官方文檔:vuejs.org/v2/guide/sy…

中文文檔: cn.vuejs.org/v2/guide/sy… ---> 強烈推薦

基於 $npm i vue|$yarn add vue安裝

1.漸進式框架

漸進式:類庫或者框架都是重量級的,裏面包含不少方法,可是實際項目開發中,咱們用不到這麼多東西,因此在開發他們的時候,會把功能按照模塊進行單獨開發,使用者可根據自身狀況選擇一個模塊一個模塊的導入使用

  • vue:基礎模塊(基礎語法、核心實現、組件開發、相關指令等都在這裏)
  • vue-router:構建SPA單頁面應用的路由
  • vuex:公共狀態管理
  • vue-cli:vue腳手架
  • components:vue element、iview、vux...
  • ...

這些東西就是VUE全家桶

2.VUE是MVVM框架

MVVM是雙向數據綁定的:VUE自己實現了數據和視圖的相互監聽影響 MVC是單向數據綁定,數據更改能夠渲染視圖,可是視圖更改沒有更改數據,須要咱們本身在控制層基於change事件實現數據的更改(REACT)

img

  • m:mode 數據層
  • v:view 視圖層
  • vm:viewModel 數據和視圖的監聽層(當數據或者視圖發生改變,VM層會監聽到,同時把對應的另一層特跟着改變或者從新渲染)
    • 數據層改變:vm會幫咱們從新渲染視圖
    • 視圖層改變:vm也會幫咱們把數據從新更改

3.VUE的雙向數據綁定的原理

當初始化vue的實例時,會遍歷data中的全部的屬性,給每個屬性新增get和set方法,

當獲取這個屬性對應的屬性值,會默認執行get方法

設置屬性的屬性值時,會執行set方法;

vue的指令編譯器,對vue的指令進行解析,並初始化視圖,並訂閱觀察者來更新視圖;

並將watcher添加到Dep訂閱器中,當數據發生改變,observer的set方法會被調用,

會遍歷Dep訂閱器中全部的訂閱者,而後再更新視圖;

1.vue的簡單使用

=> new Vue 每當建立一個實例,就至關於建立一個viewModel監聽器:能夠監聽對應視圖和對應數據的相互改變

=> el:element 當前監聽器監聽的視圖(基於querySelector獲取):指定的容器不能是HTML和BODY

=> data: 當前監聽器監聽的數據(這些監聽的數據會掛載到vm1實例上,也就是vm1.msg=xxx來操做了)

=> {{msg}} 數據綁定最多見的形式就是使用 {{...}}(雙大括號 小鬍子語法)的文本插值

<body>
    <div id='app'>
        {{msg}}
    </div>

    <!-- IMPORT JS -->
    <script src="./node_modules/vue/dist/vue.min.js"></script>
 	/*--- 開發的時候儘量引用未壓縮版本,這樣有錯誤會拋出異常 --- */
    <script>
        let vm = new Vue({
            el:'#app',
            data:{
                msg:'hello world~'
            }
        });
    </script>
</body>
複製代碼

2.vue的基礎語法

new Vue(options)

返回值vm(viewModel)

  • el:不能掛載到html或者body上 =>querySelector

  • data

    • 數據值對於對象來講要先聲明,不然新增屬性無效(能夠基於vm.$set處理)
    • vm.arr[0]=xxx 改變數組中的某一項視圖不會渲染,須要基於內置的方法,例如:push...
    • 對象或者數組能夠總體替換值實現數據變視圖也變 ...

=> 在鬍子語法中綁定的數據值是對象類型,會基於JSON.stringify把其編譯爲字符串再呈現出來(而不是直接toString處理的)

=> 並非全部的數據更改最後都會通知視圖從新渲染

  1. 初始數據是一個對象,對象中沒有xxx鍵值對,後期新增的鍵值對是不會讓視圖從新渲染的,

    解決辦法:

​ 1) 最好在初始化數據的時候,就把視圖須要的數據提早聲明好(能夠是空值,可是要有這個屬性) =>原理:只有DATA中初始化過的屬性纔有GET/SET

​ 2) 不要修改某個屬性名,而是把對象的值總體替換(指向新的堆內存)

​ 3) 能夠基於vm.$set內置方法修改數據:vm.$set(obj,key,value)

  1. 若是數據是一個數組,咱們修改數據基於ARR[N]=xxx或者ARR.length--等操做方式,是沒法讓視圖從新渲染的;

    ​ 1) 須要基於:push/pop等內置的方法

    ​ 2) 從新把ARR的值重寫(指向新的堆內存)

    ​ 3) vm.$set

<body>
   // {{xxx}} => 小鬍子語法
	<div id="app">
		{{obj}}
		<br>
		{{arr}}
		<br>
		{{'name' in obj?'OK':'no'}}
	</div>
	<!-- IMPORT JS -->
	<script src="./node_modules/vue/dist/vue.js"></script>
	<script>
		let obj = {
			name: ''
		};
		let arr = [10];
		let vm = new Vue({
			el: '#app',
			data: {
				obj,
				arr
			}
		});
		setTimeout(() => {
            vm.arr.push(20);
			vm.$set(vm.arr, 1, 20);
            vm.obj.name = "藍藍"; // 需提早設置name屬性
			vm.$set(vm.obj, 'name', '藍藍');
		}, 1000);
	</script>
</body>
複製代碼

vue的指令

VUE指令:directive

1.都是按照v-xxx處理的,它是vue中規定給元素設置的自定義屬性

2.當vue加載成功並進行處理的時候,會按照相關的規則解析和宣傳視圖,遇到對應的指令實現對應的功能

1.v-model

通常給表單元素設置的,實現表單元素和數據之間的相互綁定

1)先把數據綁定給表單元素 ,通常把數據賦值給表單元素的value
複製代碼

​ 2)監聽表單元素的內容改變

​ 3)內容改變後,會把對應的數據也改變

​ 4)對應的數據改變,視圖中全部用到數據的地方都會從新渲染

視圖 <=> 數據
複製代碼

在vue框架中給表單元素設置value等屬性是沒有意義的

2.v-bind

給元素的內置屬性動態綁定數據,例如:給img綁定動態的圖片路徑地址

能夠簡寫成爲 :,也就是 v-bind:src 等價於 :src

3.v-html/v-text

給非表單元素設置內容,v-html支持對於標籤的自動識別,v-text會把全部內容分都當作文本

傳統的鬍子語法,在vue沒有加載完成以前,會把{{xxx}}展現在頁面中,當vue加載完纔會出現真正的內容,這樣體驗很差

4.v-once:

綁定的數據是一次性的,後面不論數據怎麼改變,視圖也都不會從新渲染

5.v-if

若是對應的值是TRUE,當前元素會在結構中顯示,若是是FALSE,當前元素會在結構中移除(它控制的是組件的加載和卸載的操做 =>DOM的增長和刪除);還有對應的 v-else-if / v-else 等指令;

6.v-show

和v-if相似,只不過它是控制元素樣式的顯示隱藏(display的操做)

​ 1)v-if是控制組件存不存在,對於結果是FALSE,不存在的組件來講,視圖渲染的時候無需渲染這部份內容;而v-show則不行,由於不論是顯示仍是隱藏,結構都在,因此視圖渲染的時候這部分也要渲染;

​ 2)在過於頻繁的切換操做中,v-if明顯要比v-show要低一些

7.v-for

循環動態綁定數據

​ 1) 想循環誰就給誰設置v-for

​ 2) 循環相似for/for in的語法:v-for='(item,index) in arr'

8.v-on

(簡寫 @):用來實現事件綁定的指令

​ 語法v-on:click='xxx' | @click='xxx'

1.事件觸發的時候,須要傳遞參數信息,把方法加小括號,$event是事件對象

v-on:click='sum($event,10,20)'

2.事件修飾符

常規修飾符:@click.prevent/stop = 'xxx'

按鍵修飾符:@keydown.enter/space/delete/up/right/down/left...='xxx'

鍵盤碼:@keydown.13 = 'xxx'

​ 組合按鍵:@keydown.alt.67 = 'xxx' //=>ALT+C

v-model

<body>
	<div id="app"> 人民幣:¥ <input type="text" v-model="priceRMB"> <br> 美圓:$ <span>{{priceRMB/7.1477}}</span> </div> <!-- IMPORT JS --> <script src="./node_modules/vue/dist/vue.min.js"></script> <script> //=>v-model先實現把數據綁定到視圖層(給INPUT設置VALUE值),而後監聽文本框內容的改變,一旦改變,會把數據也跟着改變;數據一變,視圖會從新的渲染; let vm = new Vue({ el: '#app', data: { priceRMB: 0 } }); </script> </body> 複製代碼

v-bind

<body>
	<div id="app"> <button v-html='msg' @click='handle'></button> <br> <img :src="pic" alt="" v-if='show'> </div> <!-- IMPORT JS --> <script src="./node_modules/vue/dist/vue.js"></script> <script> let vm = new Vue({ el: '#app', data: { //=>這裏的數據最後都會做爲實例的屬性掛載到實例上vm.show... msg: '隱藏圖片', show: true, pic: '1.png' }, methods: { //=>這裏的方法最後也會掛載到實例的私有屬性上 handle() { //=>this:vm this.show = !this.show; this.msg = this.show ? '隱藏圖片' : '顯示圖片'; } } }); </script> </body> 複製代碼

v-for

<body>
	<div id="app">
		<table>
			<thead>
				<tr>
					<th>編號</th>
					<th>姓名</th>
					<th>年齡</th>
				</tr>
			</thead>
			<tbody>
				<tr v-for='(item,index) in arr'>
					<td v-html='item.id'></td>
					<td v-html='item.name'></td>
					<td v-html='item.age'></td>
				</tr>
			</tbody>
		</table>
	</div>
	<!-- IMPORT JS -->
	<script src="./node_modules/vue/dist/vue.js"></script>
	<script>
		let vm = new Vue({
			el: '#app',
			data: {
				arr: [{
					id: 1,
					name: '張三',
					age: 25
				}, {
					id: 2,
					name: '李四',
					age: 24
				}, {
					id: 3,
					name: '王五',
					age: 26
				}]
			}
		});
	</script>

	<script>
		//JS中循環的幾種方式:for循環、while循環、do while循環 | for in循環 | for of循環
		let arr = [10, 20, 30, 40],
			obj = {
				name: '',
				year: 10,
				1: 100
			};
		Object.prototype.AA = 12;

/*=>ES6新增for of循環
*1.獲取的不是屬性名是屬性值
*2.不會遍歷原型上公有的屬性方法(哪怕是自定義的)
*3.只能遍歷可被迭代的數據類型值(Symbol.iteratoer):Array、String、Arguments、NodeList、Set、Map等,可是普通對象是不可被迭代的數據,因此不能用for of循環
*/
for (let item of obj) {
    console.log(item);
} 

for (let key in arr) {
    if (!arr.hasOwnProperty(key)) break;
    console.log(key, arr[key]);
} 

for (let key in obj) {
    //=>KEY遍歷的屬性名
    //=>OBJ[KEY]屬性值
    //=>優先遍歷屬性名爲數字的
    //=>會把所屬類原型上自定義的屬性方法也遍歷到
    if (!obj.hasOwnProperty(key)) break;
    console.log(key);
} 
	</script>
</body>
複製代碼

v-on

<body>
	<div id="app"> <a href="http://www.baidu.com/" @click.prevent.stop='func'> 百度</a> <button v-on:click='func'></button> <button v-on:click='sum($event,10,20)'></button> <input type="text" placeholder="請輸入搜索內容" v-model='text' @keydown.alt.67='func'> </div> <!-- IMPORT JS --> <script src="./node_modules/vue/dist/vue.js"></script> <script> let vm = new Vue({ el: '#app', data: { text: '' }, methods: { func(ev) { alert('是我了~'); }, sum(ev, n, m) { console.log(arguments); } } }); </script> </body>
複製代碼

表單元素的處理

單選或者複選按鈕

​ 1.按照 v-model 進行分組,單選框裝備的數據是一個值,複選框準備的數據是一個數組

​ 2.每個框都有本身的value,誰被選中,數據值就是被選中元素的value值;相反,值是多少,對應value的元素也會被默認選中;

<body>
	<div id="app">
		<input type="checkbox" value="OK" v-model='all' @click='handle'>全選/全不選
		<br>
		<div @change='delegate'>
			<input type="checkbox" value="song" v-model='hobby'>唱歌
			<input type="checkbox" value="dance" v-model='hobby'>跳舞
			<input type="checkbox" value="read" v-model='hobby'>讀書
			<input type="checkbox" value="javascript" v-model='hobby'>編程
		</div>
		<br>
		<button @click='submit'>提交</button>
	</div>
	<!-- IMPORT JS -->
	<script src="./node_modules/vue/dist/vue.js"></script>
	<script>
		let vm = new Vue({
			el: '#app',
			data: {
				sex: 0,
				hobby: ['javascript'],
				all: []
			},
			methods: {
				submit() {
					console.log(this.sex);
				},
				handle() {
					//=>CLICK事件處理比視圖更新後數據的更改要先去作
					if (!this.all.includes('OK')) {
						this.hobby = ['song', 'dance', 'read', 'javascript'];
					} else {
						this.hobby = [];
					}
				},
				delegate() {
					//=>CHANGE事件處理,要晚於數據更新
					this.all = this.hobby.length >= 4 ? ['OK'] : [];
				}
			}
		});
	</script>
</body>
複製代碼

1.vue - filter 過濾器

濾器的語法:按照豎線分隔,把豎線左側的值傳遞給右側的過濾器方法,通過方法的處理,把處理後的結果展現在視圖中

過濾器方法只能在鬍子語法{{}}和v-bind中使用(過濾器中的方法沒有掛載到實例上)

/*如下 methods && filters 中各有方法*/
<body>
<div id="app">
	<input type="text" v-model='text'>
	<br>
	/*<span v-text='text.replace(/\b[a-zA-Z]+\b/g,item=>{
		return item.charAt(0).toUpperCase()+item.substring(1);
	})'></span>
	<span v-text='toUP(text)'></span>*/

	<span>{{text|toUP|filterB}}</span>
	<img :src="pic|picHandle" alt="">
</div>
<!-- IMPORT JS -->
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
	let vm = new Vue({
		el: '#app',
		data: {
			//=>響應式數據:DATA中準備的要在視圖中渲染的數據(MODEL)
			text: ''
		},
		methods: {
			//=>都會掛載到實例上(不能和DATA中的屬性名衝突):這裏的制定的方法是普通方法,能夠在視圖中調取使用,也能夠在其它方法中調取使用
			toUP(value) {
				return value.replace(/\b[a-zA-Z]+\b/g, item => {
					return item.charAt(0).toUpperCase() + item.substring(1);
				});
			}
		},
		filters: {
			//=>設置過濾器:把須要在視圖中渲染的數據進行二次或者屢次的處理
			toUP(value) {
				//=>value:須要過濾的數據 return返回的是過濾後的結果
				return value.replace(/\b[a-zA-Z]+\b/g, item => {
					return item.charAt(0).toUpperCase() + item.substring(1);
				});
			},
			filterB(value) {
				return value.split('').reverse().join('');
			},
			picHandle(value){
				return value.length===0?'http://www.baidu.com/static/1.png':value;
			}
		}
	});
</script>
</body>
複製代碼

2.vue-computed

計算屬性:它不是方法是一個屬性,因此在視圖中調取的時候不能加括號執行,toUP和DATA中的TEXT同樣,都會掛載到實例上,它存儲的值是對應方法返回的結果(getter函數處理的結果)

計算屬性有本身的緩存處理:第一次獲取toUP屬性值,會關聯某個響應式數據(text),當第一次結果獲取後,會把這個結果緩存下來;後期視圖從新渲染,首先看text值是否發生更改,若是發生更改,會從新計算toUP屬性值,若是沒有更改,則還會拿上次緩存的結果進行渲染;

<body>
	<div id="app"> <input type="text" v-model='text'> <br> <span v-text='toUP'></span> </div> <!-- IMPORT JS --> <script src="./node_modules/vue/dist/vue.js"></script> <script> let vm = new Vue({ el: '#app', data: { text: '' }, computed: { toUP() { return this.text.replace(/\b[a-zA-Z]+\b/g, item => { return item.charAt(0).toUpperCase() + item.substring(1); }); } }, methods: { /* toUP(value) { return value.replace(/\b[a-zA-Z]+\b/g, item => { return item.charAt(0).toUpperCase() + item.substring(1); }); } */ } }); </script> </body> 複製代碼
  • 真實項目中:咱們通常用一個計算屬性和某些響應式數據進行關聯,響應式數據發生改變,計算屬性的GETTER函數會從新執行,不然使用的是上一次計算出來的緩存結果
  • methods:無論數據是否改變,只要視圖更新就會執行
<body>
	<div id="app">
		<p>正常結果:{{text}}</p>
		<p>反轉結果:{{reverseMethod()}}</p>
		<p>反轉結果:{{reverseComputed}}</p>
		<p>{{now2()}}</p>
	</div>
	<!-- IMPORT JS -->
	<script src="./node_modules/vue/dist/vue.js"></script>
	<script>
		let vm = new Vue({
			el: '#app',
			data: {
				text: 'MY NAME IS LANLAN'
			},
			computed: {
				//=>GETTER函數
				reverseComputed() {
					return this.text.split('').reverse().join('');
				},
				now1() {
			//=>計算屬性中必需要關聯一個響應式數據,不然GETTER函數只執行一次
           // 咱們也能夠 =>強制更新視圖的從新渲染
					return new Date();  
				}
			},
			methods: {
				reverseMethod() {
					return this.text.split('').reverse().join('');
				},
				now2() {
					return new Date();
				}
			}
		});

		let n = 0;
		let timer = setInterval(() => {
			n++;
			if (n > 5) {
				clearInterval(timer);
				return;
			}
			if (n === 3) {
				vm.text = 'WELCOME TO china;
				return;
			}
			//=>強制更新視圖的從新渲染
			vm.$forceUpdate();
		}, 1000);
	</script>
</body>
複製代碼
  • get/set
<body>
	<div id="app"> <p>正常結果:{{text}}</p> <p>反轉結果:{{reverseComputed}}</p> <input type="text" v-model='reverseComputed'> </div> <!-- IMPORT JS --> <script src="./node_modules/vue/dist/vue.js"></script> <script> let vm = new Vue({ el: '#app', data: { text: 'MY NAME IS LANLAN' }, computed: { //=>GETTER函數 /* reverseComputed() { return this.text.split('').reverse().join(''); } */ reverseComputed: { get() { //=>GETTER:只要獲取這個屬性值就會觸發GET函數執行 return this.text.split('').reverse().join(''); }, set(value) { //=>SETTER:給屬性設置值的時候會觸發SET函數,VALUE是給這個屬性設置的值 console.log('OK', value); } } } }); let n = 0; let timer = setInterval(() => { n++; if (n > 5) { clearInterval(timer); return; } if (n === 3) { vm.text = 'WELCOME TO CHINA'; return; } //=>強制更新視圖的從新渲染 vm.$forceUpdate(); }, 1000); </script> </body>
複製代碼
  • 全選/非全選例子
<body>
	<div id="app">
		<input type="checkbox" name="" id="check" v-model='slected'>
		<label for="check" v-text='text'></label>
		<br>
		<span v-for='item in hobbyList'>
			<input type="checkbox" name="" :id="item.id|handle" :value='item.value' v-model='checkList'>
			<label :for="item.id|handle" v-text='item.name'></label>
		</span>
	</div>
	<script src="./node_modules/vue/dist/vue.js"></script>

	<script>
		/*
		* 1.手動點擊全選按鈕的時候會觸發set,根據value控制checkList=>視圖從新渲染=> 觸發get;
		* 2.點擊每一個按鈕的時候,v-model='checkList'監聽改變 => 觸發視圖從新渲染,都會從新觸發get=>判斷是否全選
		*/ 
		let vm = new Vue({
			el: '#app',
			data: {
				text: '全選/非全選',
				hobbyList: [{
					id: 1,
					name: '唱歌',
					value: 'song'
				}, {
					id: 2,
					name: '跳舞',
					value: 'dance'
				}, {
					id: 3,
					name: '閱讀',
					value: 'read'
				}, {
					id: 4,
					name: '睡覺',
					value: 'sleep'
				}],
				//存儲選中的興趣愛好
				checkList: [],
			},
			computed: {
				// 存儲選中按鈕的選中狀態
				slected: {
					// get:獲取時觸發;
					get() {
						return this.hobbyList.length === this.checkList.length;
					},
					// 點擊全選按鈕的時候會修改slected的值
					set(value) {
						// value:存儲的是選中的狀態 true|false
						if (value) {
							this.hobbyList.forEach(item => {
								this.checkList.push(item.value)
							});
							return;
						}
						this.checkList = [];
					}
				}
			},
			filters: {
				handle(value) {
					return 'hobby' + value;
				}
			}
		});
	</script>
</body>
複製代碼

3.vue-watch

watch監聽響應式數據的改變(watch中監聽的響應式數據必須在data中初始化) 和 computed中的setter相似

  • 只不過computed是本身單獨設置的計算屬性(不能和DATA中的衝突),而watch只能監聽DATA中有的屬性

  • 監聽器支持異步操做 computed的getter不支持異步獲取數據

<body>
<div id="app">
	<input type="checkbox" v-model='slected' @change='handle'>全選/非全選
	<br>
	<span v-for='item in hobbyList'>
		<input type="checkbox" :id="item.id|handleID" :value="item.value" v-model='checkList'>
		<label :for="item.id|handleID" v-text='item.name'></label>
	</span>
</div>
<!-- IMPORT JS -->
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
	let vm = new Vue({
		el: '#app',
		data: {
			hobbyList: [{
				id: 1,
				name: '唱歌',
				value: 'song'
			}, {
				id: 2,
				name: '跳舞',
				value: 'dance'
			}, {
				id: 3,
				name: '閱讀',
				value: 'read'
			}, {
				id: 4,
				name: '睡覺',
				value: 'sleep'
			}],
			//存儲選中的興趣愛好
			checkList: [],
			//存儲全選狀態
			slected: false
		},
    watch: {
       checkList() {
           this.slected = this.checkList.length === this.hobbyList.length ? true : false;
            }
		},
	methods: {
		handle() {
			if (this.slected) {
				 this.hobbyList.forEach(item => {
					 this.checkList.push(item.value);
				});
				return;
			}
			this.checkList = [];
		}
	},
	filters: {
		handleID(value) {
			return 'hobby' + value;
		}
	}
});
</script>
複製代碼

4.vue-class

  • 對象方式處理動態的樣式

    *  `:class="{樣式類名:響應式數據,...}"`
    複製代碼

​ * 響應式數據爲TRUE則有這個樣式類,反之則沒有

  • 數組控制樣式類

​ * :class="[響應式數據1,....]"

* 控制響應式數據的值是對應的樣式類或者沒有值,來控制是否有這個樣式
複製代碼
/*=== CSS ===*/ 
<style>
    .active {
    color: red;
    }

    .big {
    font-size: 40px;
    }
</style>

<body>
	<div id="app">
		<!-- 對象方式處理動態的樣式 -->
		<p :class="{active:a,big:true}">你好哇~</p>
		<button @click='handle'>切換樣式</button> 
		<button @click='a=!a'>切換樣式</button> 

		<!-- 數組控制樣式類 -->
		<p :class="[active,big]">你好哇~~</p>
		<button @click='handle'>切換樣式</button>
	</div>
	<!-- IMPORT JS -->
	<script src="./node_modules/vue/dist/vue.js"></script>
	<script>
		let vm = new Vue({
			el: '#app',
			data: {
				// a: false
				active: '',
				big: 'big'
			},
			methods: {
				handle() {
					this.active = this.active === '' ? 'active' : '';
					// this.a = !this.a;
				}
			}
		});
	</script>
</body>
複製代碼

5.vue-ref

VUE框架開發的時候,咱們應該儘量減小直接去操做DOM

基於REF能夠把當前元素放置到this.$refs對象中,從而實現對DOM的直接操做(只有在mounted及以後才能夠獲取到)

<body>
	<div id="app">
		<h3 v-html='msg' ref='titleBox'></h3>
		<p ref='pBox'></p>
	</div>
	<!-- IMPORT JS -->
	<script src="./node_modules/vue/dist/vue.js"></script>
	<script>
		let vm = new Vue({
			el: '#app',
			data: {
				msg: '你好世界'
			},
			mounted() {
				console.log(this.$refs); //=>{titleBox:H3,pBox:P}
			}
		});
	console.log(vm.$refs.titleBox)   // <h3>你好世界</h3> 
	</script>
</body>
複製代碼

3. vue生命週期函數

  1. beforeCreate 建立vue實例以前

  2. created 建立實例成功(通常在這裏實現數據的異步請求)

  3. beforeMount 渲染DOM以前(加載組件第一次渲染)

  4. mounted 渲染DOM完成(加載組件第一次渲染)

  5. beforeUpdate 從新渲染以前(數據更新等操做控制DOM從新渲染)

  6. updated 重現渲染完成

  7. beforeDestroy 銷燬以前

  8. destroyed 銷燬完成 => 銷燬以後,再去修改響應式數據值,視圖也不會在從新的渲染了

選項卡案例

/*---CSS---*/
<style>
    *{
        margin: 0;
        padding: 0;
    }
    .tabBox {
        box-sizing: border-box;
        margin: 50px auto;
        width: 500px;
    }

    .tabBox .tab {
        display: flex;
        position: relative;
        top: 1px;
    }

    .tabBox .tab li {
        list-style: none;
        margin-right: 10px;
        padding: 0 20px;
        line-height: 35px;
        border: 1px solid #AAA;
        background: #EEE;
        cursor: pointer;
    }

    .tabBox .tab li.active {
        background: #FFF;
        border-bottom-color: #FFF;
    }

    .tabBox .content {
        display: none;
        box-sizing: border-box;
        padding: 10px;
        height: 100px;
        border: 1px solid #AAA;
    }

    .tabBox .content.active {
        display: block;
    }
</style>

/*--- JS ---*/
<body>
<div id="app">
    <div class="tabBox">
        <ul class="tab">
            <li v-for='(item,index) in TAB_DATA' v-html='item.name' :class='{
                active:index===curIdex}' @click='curIdex=index'></li>
        </ul>
        <div v-for='(item,index) in TAB_DATA' v-html='item.children' :class='{
            content:true,active:index===curIdex}'></div>
    </div>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
    let TAB_DATA = [{
        id: 1,
        name: '音樂',
        children: '音樂的內容'
    },
    {
        id: 2,
        name: '動漫',
        children: '二次元的世界'
    }, {
        id: 3,
        name: '讀書',
        children: '知識的芬芳'
    }, {
        id: 4,
        name: '視頻',
        children: '視頻的內容'
    }, {
        id: 5,
        name: '新聞',
        children: '最新報道'
    }]
    let em = new Vue({
        el: '#app',
        data: {
            TAB_DATA,
            curIdex: 0 // 默認顯示選項卡的索引 
        }
    })
</script>
</body>
複製代碼
  • 事件委託版
<body>
<div id="app">
	<div class="tabBox">
		<ul class="tab" @click='handle($event)'>
			<li v-for='(item,index) in TAB_DATA' v-html='item.name' :class="{active:index===curIndex}"
				:index='index'>
				<!-- @click='curIndex=index' -->
			</li>
		</ul>
		<div v-for='(item,index) in TAB_DATA' v-html='item.children'
			:class="{content:true,active:index===curIndex}"></div>
	</div>
</div>
<!-- IMPORT JS -->
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
	let TAB_DATA = [{
		id: 1,
		name: '音樂',
		children: '音樂的內容'
	}, {
		id: 2,
		name: '影視',
		children: '影視的內容'
	}, {
		id: 3,
		name: '動漫',
		children: '動漫的內容'
	}, {
		id: 4,
		name: '紀錄片',
		children: '紀錄片的內容'
	}];

	let vm = new Vue({
		el: '#app',
		data: {
			//選項卡數據
			TAB_DATA,
			//展現選項卡的索引
			curIndex: 0
		},
		methods: {
			handle(ev) {
				let target = ev.target,
					tarTag = target.tagName;
				if (tarTag === 'LI') {
					this.curIndex = parseInt(target.getAttribute('index'));
				}
			}
		}
	});
</script>
</body>
複製代碼
  • 點擊Tab再請求不一樣的數據
<style>
   .tabBox {
   	box-sizing: border-box;
   	margin: 20px auto;
   	width: 600px;
   }
   .tabBox .tab {
   	display: flex;
   	position: relative;
   	top: 1px;
   }
   .tabBox .tab li {
   	margin-right: 10px;
   	padding: 0 20px;
   	line-height: 35px;
   	border: 1px solid #AAA;
   	background: #EEE;
   	cursor: pointer;
   }
   .tabBox .tab li.active {
   	background: #FFF;
   	border-bottom-color: #FFF;
   }
   .tabBox .content {
   	box-sizing: border-box;
   	padding: 10px;
   	height: 300px;
   	border: 1px solid #AAA;
   }
</style>
</head>

<body>
<div id="app">
   <div class="tabBox">
   	<ul class="tab">
   		<li v-for='(item,index) in TAB_DATA' v-html='item.name' :class="{active:index===curIndex}"
   			@click='handle($event,index,item.id)'>
   		</li>
   	</ul>
   	<div class="content" v-html='content'></div>
   </div>
</div>
<!-- IMPORT JS -->
<script src="./node_modules/vue/dist/vue.js"></script>
<script src="./node_modules/axios/dist/axios.min.js"></script>
<script>
   let TAB_DATA = [{
   	id: 1,
   	name: '音樂'
   }, {
   	id: 2,
   	name: '影視'
   }, {
   	id: 3,
   	name: '動漫'
   }, {
   	id: 4,
   	name: '紀錄片'
   }];

   let vm = new Vue({
   	el: '#app',
   	data: {
   		//選項卡數據
   		TAB_DATA,
   		//展現選項卡的索引
   		curIndex: 0,
   		//內容區域的數據
   		content: ''
   	},
   	created() {
   		//=>生命週期函數(VUE實例建立成功)
   		this.queryDATA(TAB_DATA[this.curIndex]['id']);
   	},
   	methods: {
   		queryDATA(curID) {
   			axios.get('./data.json').then(response => {
   				return response.data;
   			}).then(result => {
   				let itemDATA = result.find(item => parseInt(item.id) === parseInt(curID));
   				if (itemDATA) {
   					this.content = itemDATA.content;
   					return;
   				}
   				return Promise.reject();
   			}).catch(reason => {
   				this.content = '查無此信息';
   			});
   		},
   		handle(ev, index, id) {
   			if (this.curIndex === index) return;
   			this.curIndex = index;
   			this.queryDATA(id);
   		}
   	}
   });
</script>
</body>

/*---data.json---*/
[{
   "id": 1,
   "content": "音樂的內容"
}, {
   "id": 2,
   "content": "影視的內容"
}, {
   "id": 3,
   "content": "動漫的內容"
}, {
   "id": 4,
   "content": "紀錄片的內容"
}]
複製代碼

商城計算器案例

<body>
    <div class="wrap" id="wrap">
        <div class="box">
            <ul class="list">
                <li v-for='(item,index) in DATA'>
                    <i @click='handle($event,"minus",index)'></i>
                    <em v-html='item.count'></em>
                    <i @click='handle($event,"plus",index)'></i>
                    <span>
                        單價:<strong v-html='item.price+"元"'></strong>
                        小計:<strong v-html='computedTotal(item.price,item.count)'></strong>
                    </span>
                </li>
            </ul>
            <div class="info">
                <span>商品公合計:<em v-html='total'></em>件</span>
                <span>共花費了:<em v-html='totalPrice'></em>元</span>
                <span>其中最貴的商品單價是:<em v-html='maxPrice'></em>元</span>
            </div>
        </div>
    </div>

<!-- IMPORT JS -->
    <script src="../node_modules/vue/dist/vue.js"></script>
<script>
        //數據
    let DATA = [{
         id: 1,
         count: 0,
         price: 12.5
    },
    {
        id: 2,
        count: 0,
        price: 8.5
    },
    {
        id: 3,
        count: 0,
        price: 4.5
    },
    {
        id: 4,
        count: 0,
        price: 10.5
    },
    {
        id: 3,
        count: 0,
        price: 20.0
    }];

let vm = new Vue({
    el: '#wrap',
    data: {
        DATA
    },
    methods: {
        computedTotal(price, count) {
            return price * count + '元'
        },
        handle(ev, type, activeIndex) {
            this.DATA = this.DATA.map((item, index) => {
                if (activeIndex === index) {
                    if (type === 'minus') {
                        item.count--;
                        item.count <= 0 ? item.count = 0 : null;
                    } else if (type === 'plus') {
                        item.count++;
                        item.count > 10 ? (item.count = 10,alert('不能太貪心哦~')) : null;
                    }
                }
                return item;
            })
        }
    },
    computed: {
        // 總計
        total() {
            return this.DATA.reduce((accumulator, item, index) => {
                return accumulator + item.count;
            }, 0)
        },
        // 總價格
        totalPrice() {
            return this.DATA.reduce((accumulator, item, index) => {
                return accumulator + item.count * item.price;
            }, 0)
        },
        // 最貴
        maxPrice() {
            //找到count不爲0的數據,返回最大價錢
            let arr = this.DATA.filter(item => {
                return item.count >= 1;
            }).map(item => {
                return item.price;
            });
            // 初始count都爲0,因此arr爲空
            return arr.length === 0 ? 0 : Math.max(...arr);
        }
    }
})
    </script>
</body>
複製代碼
相關文章
相關標籤/搜索