【前端23_Vue】生命週期、常見API的使用、組件


Vue

因爲之前曾接觸過小程序的開發,所以 入手 Vue 相對爽了一些,因爲思想都是數據綁定,Vue是華人尤雨溪開發的,這可是個大佬,B站上有個關於大佬的紀律片,是 Up主:魚C-小甲魚 翻譯的,有興趣的話可以看看。

https://www.bilibili.com/video/BV1dT4y1V7Dn


M V VM

  • 他是一種架構方式、開發思想

  • M:Model 數據模型 (操作數據的類)

  • V:View 視圖界面 (HTML)

  • VM:ViewModel 視圖模型


Vue 的思想

Vue是比較重要的是用數據來驅動頁面,下面是一個簡單的用Vue實現的頁面

	<body>
		<div id="app">{{message}}</div>
	</body>
	<script src="js/vue.js"></script>
	<script>
		var app = new Vue({
			el:"#app",
			data:{
				message:"hello world"
			}
		})
	</script>

生命週期函數

需要記得有

  • beforeCreate
  • create
  • beforeMount
  • mounted
  • beforeUpdata
  • updated
  • beforeDestroy
  • destroyed

其實有規律可循,創造-掛載-更新-銷燬
在這裏插入圖片描述


Vue實例中的選項

el

  • 獲取元素,你可以用#id.類名,類似JQuery的選擇器等等,也可以用document.querySelectAll()之類的

data

  • 實例中的數據都放在這裏

computed 計算屬性

  • 計算屬性的結果是放在緩存裏的

常見API的使用

v-if 條件

	<body>
		<!-- 條件語句必須if/else緊跟着 -->
		<div id="app">
			{{message}}
			<div v-if="message == 'hello world'">if</div>
			<div v-else-if="message == 'hello world1'">else-if</div>
			<div v-else>else</div>
		</div>
	</body>
	<script src="js/vue.js"></script>
	<script>
		var app = new Vue({
			el:"#app",
			data:{
				message:"hello world"
			}
		})
	</script>

v-show

  • v-show不能搭配template ,即使條件不對也會顯示到頁面上
<template v-show="1 == 2">
	<h1>我是個標題</h1>
</template>
  • 如果v-show裏面的條件不對的話,頁面渲染的時候會使用display:none把他隱藏掉
<div v-show="1 == 2">
	<h1>我是個標題</h1>
</div>

v-for 循環

  • 比方說我要循環一個名字叫li的數組
<body>
	<div id="app">
	 	<!-- 這裏也可以寫成 (each,index) of li,借用了ES6的語法-->
		<div v-for="(each,index) in li">
			each:{{each}}-----index:{{index}}
		</div>
	</div>
</body>
<script src="../js/vue.js"></script>
<script>
	var app = new Vue({
		el:"#app",
		data:{
			li:['one','two','three','four','five']
		}
	})
</script>

在這裏插入圖片描述


v-cloak 取消抖動

用Vue渲染頁面的時候,你刷新頁面,會有頁面沒有加載數據就渲染出來的情況,一閃而過(嘗試截取動圖但是截不到),但是爲了美,這種缺點怎麼可能忍呢!!!

只需兩步輕鬆解決

  • 在標籤裏寫上 v-cloak
  • 在樣式裏寫[v-cloak]{ display: none; }

舉個小例子

<style>
	[v-cloak]{
		display: none;
	}
</style>
<body>
	<div id="app" v-cloak></div>
</body>

v-once

首次渲染之後,頁面不再隨着數據的變化而變化

	<body>
		<div id="app">
			<div v-once>
				<!--可以在控制檯上改變數值 app.message = 'nihao' -->
				{{message}}
			</div>
		</div>
	</body>
	<script src="js/vue.js"></script>
	<script>
		var app = new Vue({
			el:"#app",
			data:{
				message:"hello world"
			}
		})
	</script>

v-bind 綁定屬性 **

v-bind可以簡略寫成:,v-bind:後面接標籤的屬性,用來綁定標籤的屬性。

<body>
		<div id="app">
			<!-- 下面兩個div的綁定類是一樣的,都是name1 -->
			<div v-bind:class="className"> v-bind:class="className"</div>
			<div :class="className">:class</div>
		</div>
	</body>
	<script src="js/vue.js"></script>
	<script>
		var app = new Vue({
			el:"#app",
			data:{
				className:"name1"
			}
		})
	</script>

在這裏插入圖片描述


v-on 綁定事件

  • v-on 也可以寫成 @
  • 可以傳遞參數,如果向添加事件因子,可以@click="函數名($event)這樣傳遞
<!-- 下面兩個div都綁定了click點擊事件,效果一樣 -->
<div v-on:click=""></div>
<div @click=""></div>
<button @click="hand2(10,$event)">btn2---$event</button>

修飾符

.這個點就是修飾符,能修飾什麼呢?下面就是例子

冒泡與捕獲

  • 阻止冒泡:.stop
<div @click="fa">fa
	<div @click.stop="son">son</div>
	<!-- 這樣,點擊son,就不會出發fa的點擊事件了 -->
</div>
  • 捕獲:.capture
<div @click.capture="fa">fa
	<div @click="son">son</div>
</div>
<!-- 這樣,點擊son,就會先觸發fa,然後son -->

按鍵觸發事件

  • 37是鍵盤上的左方向鍵
  • 如果向要組合按鍵,觸發連招的話,可以連着修飾符寫,如下
<input type="text" @keydown.37="key1Handler">
<input type="text" @keydown.space="key1Handler1" placeholder="space">
<!-- 組合按鍵 -->
<input type="text" @keydown.shift.83="key1Handler2" placeholder="shift+S">

v-html 編譯 & v-pre 跳過

注意 v-html 的一些細節

	<body>
		<div id="app">
			<span v-html="tar">span1</span>
			<span v-pre="tar1">span2</span>
		</div>
	</body>
	<script src="js/vue.js"></script>
	<script>
		// v-html 轉化成html
		// 注意轉化後的頁面格式,是插入此標籤內了,標籤內原有的內容將被覆蓋
		
		// v-pre 跳過這個元素和它的子元素的編譯過程。
		// 可以用來顯示原始 Mustache 標籤。跳過大量沒有指令的節點會加快編譯。
		var app = new Vue({	
			el:'#app',
			data:{
				tar:"<a href='#'>11</a>",
				tar1:"<a href='#'>11</a>"
			}
		})
	</script>

圖片展示在這裏插入圖片描述


v-model 綁定輸入

  • v-model可以綁定inputtextarea的文本
<body>
	<div id="app" v-cloak> 
		<input type="text" v-model="message">
		{{message}}
		<textarea rows="" cols="" v-model="message">
			
		</textarea>
	</div>
</body>
<script src="../js/vue.js"></script>
<script>
	var app = new Vue({
		el:"#app",
		data:{
			message:"hello world"
		}
	})
</script>
  • input失焦時在改變data,把輸入框中的值變爲number、去掉輸入框中值的首尾空格
<body>
	<div id="app">
		<!-- .lazy 是change事件,當失去焦點的時候會改變 -->
		<input type="text" v-model.lazy="mes">
		
		<!-- .number 把輸入數據變成類型爲number -->
		<input type="text" v-model.number="mes">
		
		<!-- .trim 去首和尾空格 -->
		<input type="text" v-model.trim="mes">
		
		<h1>{{mes}}</h1>
	</div>
</body>
<script src="../js/vue.js"></script>
<script>
	var app = new Vue({
		el:"#app",
		data:{
			mes:"hello world"
		}
	})
</script>

單選框、複選框、下拉框

  • 都是通過v-model來分組,相當於校服,不同學校相當於不同的組。校服一樣說明是一個學校的
  • 單選框
<body>
	<div id="app">
		<!-- 單選:多個互斥 -->
		<input type="radio" v-model="pick" value="male">	<label></label>
		<input type="radio" v-model="pick" value="female">	<label></label>
		<input type="radio" v-model="pick" value="???">		<label>男女男</label>
	</div>
</body>
<script src="../js/vue.js"></script>
<script>
	// 單選框
	// 頁面上選擇哪一項,pick的值就是哪一個value值
	var app = new Vue({
		el:"#app",
		data:{
			pick:"male"
		}
	})
</script>
  • 多選框
<body>
	<div id="app">
		<!-- 複選框多選 -->
		<input type="checkbox" v-model="check" value="checkBox1">		<label>複選框1</label>
		<input type="checkbox" v-model="check" value="checkBox2">		<label>複選框2</label>
	</div>
</body>
<script src="../js/vue.js"></script>
<script>
	var app = new Vue({
		el:"#app",
		data:{
			// check裏存儲誰被選中了
			check:[]
		}
	})
</script>
  • 下拉框
<body>
	<div id="app">
		<!-- select如果想添加多個屬性,加multiple -->
		<select v-model="select">
			<!-- 默認是個option中的文本進行匹配
			 如果用了value的話優先value
			 -->
			<option>1</option>
			<option>2</option>
			<option value='你好'>3</option>
		</select>
	</div>
</body>
<script src="../js/vue.js"></script>
<script>
	var app = new Vue({
		el:"#app",
		data:{
			select:"你好"
		}
	})
</script>

組件

組件命名要求

  • 短橫線分隔命名
  • 首字母大寫命名

全局/局部組件定義

顧名思義,組件的使用範圍不一樣

  • 需要注意的是,全局組件要在實例化對象之前就要註冊,說人話,就是
    在這裏插入圖片描述
  • 爲什麼要先註冊在實例化呢?反過來行不行呢?我反過來會報如下的錯誤
[Vue warn]: Unknown custom element: <card> -
 did you register the component correctly? 
 For recursive components, make sure to provide the "name" option.

報錯信息提示說:不知道的元素card,是否正確註冊組件?,看一下生命週期那張流程圖:創建完Vue實例之後就已經渲染完template了,這時候在註冊帶有template的組件的話,Vue是不認識的

<body>
	<div id="app">
		{{message}}
		<else-name></else-name>
	</div>
</body>
<script src="../js/vue.js"></script>
<script>
	// 全局組件:
	// else-name 是我自定義的標籤名稱
	// 命名規範:不能用駝峯命名,推薦都用小寫 	
	Vue.component('else-name',{
		template:'<div>這是組件中</div>'
	})
</script>

局部的組件,這裏寫了兩種寫法

  • 直接把模板放到組件裏
  • 把模板放到外邊:方便修改
// 局部:只在當前vue中有效
	var child = {
		template:'<div>這是組件局部,內部中2</div>'
	}
	var app = new Vue({
		el:"#app",
		data:{
			message:'hello world'
		},
		components:{
			'demo1':{
				template:'<div>這是組件局部,內部中1</div>'
			},
			'demo2':child
		}
	})

組件中的模板

  • 模板裏只能由只能有一個根元素,不能有兩個以上的根元素

意思是說可以這樣:<div> <div></div> </div> 不可以<div></div> <div></div>
前者兩個div是父子關係,後者兩個div是同級的哥們關係

組件中的變量

組件中的變量可以這樣定義和使用

Vue.component('else-name',{
	template:'<div>這是組件全局-外部中{{mess1}} {{mess2}}</div>',
	data:function(){
		return {
			mess1:'<<這是組件中的data1>>',
			mess2:'<<這是組件中的data2>>'
		}
	}
})

組件的通信

  • 先來個簡單的,Vue的實例對象和組件的通信
    在這裏插入圖片描述

  • 假如我設Vue實例是爸爸,實例中的組件是兒子,兒子裏又有個組件叫孫子,那麼,爸爸和孫子之間怎麼交流?

<body>
	<div id="app">
		<son :msgson=msgfa></son>
	</div>
</body>
<script src="../js/vue.js"></script>
<script>
	// props單項傳遞,父向子傳
	var app = new Vue({
		el: '#app',
		data: {
			msgfa: '我是你爸爸'
		},
		components:{
			'son': {
				props:["msgson"],
				template:`<div>
							介紹:{{msgson}}
							<grandson :msggrandson='sonData'></grandson>
						  </div>`,
				components:{
					'grandson':{
						props:['msggrandson'],
						template:`<div>{{msggrandson}}</div>`
					}
				},
				data:function(){
					return {
						sonData:'兒子'
					}
				}
			}
		}
	})
</script>
  • 兒子如何向爸爸傳遞信息呢,也就是子向父傳遞,這時候用到了自定義函數
<body>
	<div id="app">
		<show @myevent="showVal"></show>
	</div>
</body>
<script src="../js/vue.js"></script>
<script>
	// 子向父親 $emit()觸發事件,只是爲了傳值 v-on
	Vue.component('show', {
		data: function(){
			return {
				str: '我是組件中的string'
			}
		},
		methods: {
			sendMsgToFa: function(){
				// 這裏的this指向組件
				// 自定義事件
				this.$emit('myevent',this.str);
			}
		},
		template: `<button @click="sendMsgToFa">點擊彈出組件傳遞的數據</button>`
	})
	var app = new Vue({
		el:"#app",
		data:{
			message:"hello world"
		},
		methods:{
			showVal: function(a){
				alert(a)
			}
		}
	})
</script>
  • 如果我的孫子向給兒子傳遞信息呢?(就是組件中的組件組件 傳遞信息)
<body>
	<div id="app">
		我有三個階級關係,分別是父親--兒子--孫子
		<son :msgson=msgfa></son>
		
	</div>
</body>
<script src="../js/vue.js"></script>
<script>
	// props單項傳遞,父向子傳
	var app = new Vue({
		el: '#app',
		data: {
			msgfa: '我是你爸爸'
		},
		components:{
			'son': {
				props:["msgson"],
				template:`<div>
							介紹:{{msgson}}
							<grandson :msggrandson='sonData' @myevent='showVal'></grandson>
							
						  </div>`,
				components:{
					'grandson':{
						props:['msggrandson'],
						template:`<div>
										{{msggrandson}}
										<button @click="sendMsgToFa">孫子給兒子傳值</button>
								  </div>`,
						methods:{
							sendMsgToFa: function(){
								// 傳值不是自發的,而是事件驅動的,所以需要個綁定事件
								// 自定義事件確定了,父親的接收函數名,和想要傳遞給父親的數據,
								this.$emit('myevent','我是孫子裏面的消息')
							}
						}
					}
				},
				data:function(){
					return {
						sonData:'兒子'
					}
				},
				methods:{
					showVal: function(val){
						console.log(val);
					}
				}
			}
		}
	})
</script>

中央事件總線bus:數據的中介

如果我現在還是有三層關係,分別是父親,兒子,和孫子,父親是Vue實例,兒子是實例中的組件,孫子是組件中的組件
如果這三個人,兩兩之間可以互相通信,那麼就不向上面那樣麻煩了,如何做到呢?

我們需要藉助一箇中介:中央事件總線
在這裏插入圖片描述

父鏈/子鏈

  • 子組件可以通過父鏈拿到父組件的所有,也可以修改父組件的數據
  • 取父組件中的數據可以,但是如果是修改的話,那麼父子組件的關係就會更緊,這是解耦合的操作,不太推薦(組件之間的關係應該儘量獨立,不要太過親暱)在這裏插入圖片描述

給組件起名字,並通過名字獲得組件

  • 給組件起名字 ref
  • 取值的話通過this.$refs.組件名字
    在這裏插入圖片描述

組件的插槽

  • 插槽的作用在於內容的分發
    在這裏插入圖片描述
<body>
	<!-- 編譯的作用域 -->
	<!-- 父組件的模板的內容實在父組件的作用域編譯 -->
	<!-- 插槽 -->
	<div id="app">
		<comp>
			<p>父親模板的內容</p>
		</comp>
	</div>
</body>
<script src="../js/vue.js"></script>
<script>
	// slot是插槽
	Vue.component('comp',{
		template:`<div>
					<slot>如果父模板沒有內容,就顯示我</slot>
				</div>`
	})
	var app = new Vue({
		el:"#app",
		data:{
			message:"hello world"
		}
	})
</script>
  • 指定插槽的內容分發,我們可以給每個插槽起個名字
    在這裏插入圖片描述
<body>
	<!-- 插槽: 具名的插槽分發-->
	<div id="app">
		<comp>
			<!-- 注意這裏不是v-slot -->
			<p slot="top">top</p>
			<p slot="foot">foot</p>
			<p>我沒有名字1</p>
			<p>我沒有名字2</p>
		</comp>
	</div>
</body>
<script src="../js/vue.js"></script>
<script>
	// slot是插槽
	Vue.component('comp',{
		template:`<div>
					 <slot name="top"></slot>
					 <slot name="foot"></slot>
					 <div>
						<slot></slot>
					 </div>
				  </div>`
	})
	var app = new Vue({
		el:"#app",
		data:{
			message:"hello world"
		}
	})
</script>

動態切換組件

  • component 標籤上有個屬性is,裏面填寫組件的名字
    在這裏插入圖片描述

路由

簡單路由

在這裏插入圖片描述

<script src="./node_modules/vue/dist/vue.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<body>
	<div id="app">
		<router-link to="/shangcheng">商城</router-link>
		<router-link to="/shuma">數碼</router-link>
		<router-link to="/jiaju">傢俱</router-link>
		<router-view></router-view>
	</div>
</body>
<script>
	var sc = { template:`<h1>商城組件</h1>` }
	var sm = { template:`<h1>數碼組件</h1>` }
	var jj = { template:`<h1>傢俱組件</h1>` }
	var router = new VueRouter({
		routes:[
			// redirect 重定向
			{ path: '/',redirect: '/shuma' },
			{ path: '/shangcheng',component: sc},
			{ path: '/shuma',component: sm},
			{ path: '/jiaju',component: jj}
		]
	})
	var app = new Vue({
		el:"#app",
		router,
	})
</script>

動態路由

  • 動態路由可以
<body>
	<div id="app">
		<router-link to="hello/65">點擊</router-link>
		<router-view></router-view>
	</div>
</body>
<script>
	// 動態路由
	var Hello = {
		template: `<h1>你好 {{$route.params.id}} </h1>`
	}
	var router = new VueRouter({
		routes:[
			{ path:'/hello/:id', component: Hello }
		]
	})
	var app = new Vue({
		el:"#app",
		router
	})
</script>

路由前進/後退

<body>
	<div id="app">
		<router-link to="hello">點擊</router-link>
		<router-view></router-view>
		<button v-on:click="back">後退</button>
		<button v-on:click="go">前進</button>
	</div>
</body>

<script>
	// 組件
	var Hello = {
		template: `<h1>名字{{name}},年齡{{age}} </h1>`,
		props:['name', 'age']
	}
	// 路由傳參
	var router = new VueRouter({
		routes:[
			{ 
				path: '/hello', 
				component: Hello ,
				props: { name:'張三', age:11 }
			}
		]
	})
	var app = new Vue({
		el:"#app",
		router,
		methods:{
			// 路由的前進和後退
			go(){
				this.$router.go(1)
			},
			back(){
				this.$router.go(-1)
			}
		}
	})
</script>

監聽路由

  • 我想點擊登錄的時候在右上角更改信息,就是把原先的登錄註冊按鈕改成用戶名和註銷
  • 然而我的登錄寫成了組件,在組件中更改App.vue的一個data信息,奈何學術不精,百度了好久,想到通過監聽路由來出發事件
  • 主要的是watch()這個API,只要路由變化就會觸發,但是瀏覽器的後退是不會觸發的
export default{
	data:function(){
		return{
			isLogin: false,
			userName:''
		}
	},
	methods:{
		zhuxiao(){
			window.sessionStorage.setItem('isLogin', false)
			this.isLogin = false
			this.$router.push({
				path: `/login`
			})
		}
	},
	watch:{
		$route(to){
			if(to.path === '/view'){
				this.isLogin = true
				this.userName = window.sessionStorage.getItem('userName')
			}
		}
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章