vue組件學習

一.文章導讀

​ 前面學習了vue的基礎指令,瞭解了相關的鉤子函數,這一章學習vue的組件,組件 (Component) 是 Vue.js 最強大的功能之一,組件能夠擴展 HTML 元素,封裝可重用的代碼,組件系統讓咱們能夠用獨立可複用的小組件來構建大型應用,幾乎任意類型的應用的界面均可以抽象爲一個組件樹:javascript

菜鳥教程地址:https://www.runoob.com/vue2/vue-tutorial.htmlcss

官網學習地址:https://cn.vuejs.org/html

入門學習更加推薦菜鳥vue

二.組件定義

1.全局組件

<body>
		<!-- 建立兩個承載容器 -->
		<div id="app">
			<my-fristcomponent></my-fristcomponent>
		</div>

		<div id="app1">
			<!-- 在視圖層 直接寫組件的標籤名就能夠調用全局組件 -->
			<my-fristcomponent></my-fristcomponent>
		</div>
		<!-- 
			值得注意的點是 在js中定義了Vue全局組件在視圖層中咱們的全局組件必須在建立實例的塊中使用
		 -->
		<!-- 以下,app2咱們沒有綁定vue實例因此組件不會生效-->
		<div id="app2">
			<my-fristcomponent></my-fristcomponent>
		</div>
		<my-fristcomponent></my-fristcomponent>

		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			/* 
				自定義全局組件  my-fristcomponent是自定義組件的標籤名
				template是模板的意思,後面寫組件的內容
			 */
			Vue.component('my-fristcomponent', {
				template: "<p>個人第一個組件</p>"
			});
			/* 
				建立 兩個vue實例
			 */
			new Vue({
				el: "#app"
			});
			new Vue({
				el: "#app1"
			})
		</script>
	</body>

2.組件駝峯命名

<body>
		<div id="app">
			<!-- 
				在使用組件,若是使用駝峯命名,vue會自動解析,咱們
				調用時須要用-隔開並使用小寫,以下兩種方式是能夠
			 -->
			<Hello-world></Hello-world>
			<hello-world></hello-world>
			<!-- 錯誤 -->
			<HelloWorld></HelloWorld>
		</div>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			/* 在建立實例時,咱們遵循駝峯命名法 */
			Vue.component('HelloWorld', {
				template: "<p>HelloWorld</p>"
			})

			new Vue({
				el: "#app",
			})
		</script>
	</body>

3.組件data數據

<body>
		<div id="app">
			<data-component></data-component>
			<button @click="change">改變</button>
			{{msg}}
		</div>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			Vue.component("dataComponent", {
				/* 
					在定義組件時也能夠寫data,可是data裏面必須是一個函數
					且這個函數必須有返回值
				*/
				data: function() {
					return {
						msg: "data返回值"
					}
				},
				// 組件中的msg 只能夠在該模板中使用
				template: '<p >{{msg}}</p>'
			})

			new Vue({
				el: "#app",
				data: {
					msg: "121"
				}, 
				methods: {
					// 定義change返回沒法改變組件中的
					change: function() {
						// alert(11);
						this.msg = "1212";
					}
				}
			})
		</script>
	</body>

4.局部組件

前面已經寫個全局指令,全局過濾器,局部過濾器之類的,因此局部組件與全局組件的區別是同樣的,局部組件只能在當前實例才能使用java

<body>
		<div id="app">
			<my-component></my-component>
		</div>
		<div id="app1">
			// my-component組件註冊不正確 局部組件不能在其餘實例中使用
			<my-component></my-component> 
		</div>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			var vm = new Vue({
				el: "#app",
			/* 	data: {
					msg: "局部指令",
				}, */
				components:{
					'my-component':{
						data:function(){
							return{
								msg:"局部指令"
							}
						},
						template:"<p>{{msg}}</p>"
					}
				}
			});
				new Vue({
					el:"#app1"
				})
		</script>
	</body>

注意:組件模板中的內容只容許存在一個根標籤,多了的話只會解析第一個git

// 下面模板定義了兩個p標籤,至關於兩個根標籤,那麼第二個就不會生效
	template: '<p >{{msg}}</p> <p>{{msg}}</p>

三.組件之間的傳值

1.父組件向子組件傳值

  • 父組件發送的形式是以屬性的形式綁定值到子組件身上。
  • 而後子組件用屬性props接收
  • 在props中使用駝峯形式,模板中須要使用短橫線的形式字符串形式的模板中沒有這個限制
<body>
		<div id="app">
			<p>實例中定義的屬性內容是: {{pmsg}}</p>
			#### 下面是組件
			<!-- 
				:content 等同於v-bind:content
				瀏覽器打印結果:
				我是定義的組件內容
				我是標題
				父組件內容
			 -->
			<!-- 
				組件定義的模板中使用的值帶有props的屬性,在視圖層使用v-bind綁定
				父組件的數據從而造成賦值,也能夠不綁定直接賦值
				eg:<menu-item title="我自動賦值" content="我自動賦值內容"></menu-item>
			 -->
			<menu-item v-bind:title="ptitle" :content="pmsg"></menu-item>
		</div>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			// menu-item 定義全局組件
			Vue.component('menu-item', {
				// 組件 用props 屬性來接受父組件傳遞的參數
				props: ['title', 'content'],
				//組件中 的data必須是函數,且有返回值
				data: function() {
					return {
						msg: "我是定義的組件內容",
						title: "我是定義的組件的標題"
					}
				},
				// 定義組件模版
				template: '<p><span>{{msg}}</span><br><span>{{title}}</span><br><span>{{content}}</span></p>'
			});
			new Vue({
				el: "#app",
				data: {
					pmsg: "父組件內容",
					ptitle: "我是標題"
				}
			});
		</script>
	</body>

2.子組件向父組件傳值

  • 子組件用$emit()觸發事件
  • $emit() 第一個參數爲 自定義的事件名稱 第二個參數爲須要傳遞的數據
  • 父組件用v-on 監聽子組件的事件
<body>
		<div id="app">
			<div :style='{fontSize: fontSize + "px"}'>{{pmsg}}</div>
			<!-- 2 父組件用v-on 監聽子組件的事件
				這裏 enlarge-text  是從 $emit 中的第一個參數對應   handle 爲對應的事件處理函數	
			-->
			<menu-item :parr='parr' @enlarge-text='handle($event)' @shrink-text='shrink($event)'
				@gain-num="gainNume($event)"
			></menu-item>
		</div>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			/*
		      子組件向父組件傳值-攜帶參數
		    */

			Vue.component('menu-item', {
				props: ['parr'],
	/* 			data: function() {
					return {
						num: 0,
					}
				}, */
				template: `
		        <div>
		          <ul>
		            <li :key='index' v-for='(item,index) in parr'>{{item}}</li>
		          </ul>
					###  一、子組件用$emit()觸發事件
					### 第一個參數爲 自定義的事件名稱   第二個參數爲須要傳遞的數據  
					<br>
				  <button @click='$emit("gain-num", 0)'>將子組件的值傳遞到父組件</button>
		          <button @click='$emit("enlarge-text", 5)'>擴大父組件中字體大小</button>
		          <button @click='$emit("shrink-text", 5)'>縮小父組件中字體大小</button>
		        </div>
		      `
			});
			var vm = new Vue({
				el: '#app',
				data: {
					pmsg: '父組件中內容',
					parr: ['apple', 'orange', 'banana'],
					fontSize: 10
				},
				methods: {
					handle: function(val) {
						alert(val)
						// 擴大字體大小
						this.fontSize += val;
					},
					shrink: function(val) {
						// 縮小 字體大小
						this.fontSize -= val;
					},
					gainNume: function(val){
						alert(val);
					}
				}
			});
		</script>
	</body>

3.兄弟組件的傳遞

  • 兄弟之間傳遞數據須要藉助於事件中心,經過事件中心傳遞數據
    • 提供事件中心 var hub = new Vue()
  • 傳遞數據方,經過一個事件觸發hub.$emit(方法名,傳遞的數據)
  • 接收數據方,經過mounted(){} 鉤子中 觸發hub.$on()方法名
  • 銷燬事件 經過hub.$off()方法名銷燬以後沒法進行傳遞數據

​ 簡單想象一下兄弟組件,在全局組件中,定義兩個全局組件那麼這兩個組件就是兄弟組件,局部組件也是同樣的,在當個實例中可定義多個局部組件組件之間就是兄弟關係瀏覽器

<body>
		<div id="app">
			<div>父組件</div>
			<div>
				<button @click='handle'>銷燬事件</button>
			</div>
			<test-tom></test-tom>
			<test-jerry></test-jerry>
		</div>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			/*
		      兄弟組件之間數據傳遞
		    */
			//一、 提供事件中心
			var hub = new Vue();

			Vue.component('test-tom', {
				data: function() {
					return {
						num: 0
					}
				},
				template: `
		        <div>
		          <div>TOM:{{num}}</div>
		          <div>
		            <button @click='handle'>點擊</button>
		          </div>
		        </div>
		      `,
				methods: {
					handle: function() {
						//二、傳遞數據方,經過一個事件觸發hub.$emit(方法名,傳遞的數據)   觸發兄弟組件的事件
						hub.$emit('jerry-event', 2);
					}
				},
				mounted: function() {
					// 三、接收數據方,經過mounted(){} 鉤子中  觸發hub.$on(方法名
					hub.$on('tom-event', (val) => {
						this.num += val;
					});
				}
			});
			Vue.component('test-jerry', {
				data: function() {
					return {
						num: 0
					}
				},
				template: `
		        <div>
		          <div>JERRY:{{num}}</div>
		          <div>
		            <button @click='handle'>點擊</button>
		          </div>
		        </div>
		      `,
				methods: {
					handle: function() {
						//二、傳遞數據方,經過一個事件觸發hub.$emit(方法名,傳遞的數據)   觸發兄弟組件的事件
						hub.$emit('tom-event', 1);
					}
				},
				mounted: function() {
					// 三、接收數據方,經過mounted(){} 鉤子中  觸發hub.$on()方法名
					hub.$on('jerry-event', (val) => {
						this.num += val;
					});
				}
			});
			
			var vm = new Vue({
				el: '#app',
				data: {

				},
				methods: {
					handle: function() {
						//四、銷燬事件 經過hub.$off()方法名銷燬以後沒法進行傳遞數據  
						hub.$off('tom-event');
						hub.$off('jerry-event');
					}
				}
			});
		</script>
	</body>

4.自定義輪播組件

四.組件插槽

  • 組件的最大特性就是複用性,而用好插槽能大大提升組件的可複用能力
  • 插槽標籤指令
  • 在組件的基礎上的一個標籤

1.匿名插槽

  • 沒有被name屬性修飾的插槽叫匿名插槽
<body>
		<div id="app">
			<alert-box></alert-box>
			<!-- 插槽至關於一個默認的佔位符,若是沒有去修飾值修飾它,它會以默認值展示 -->
			<alert-box1>{{msg}}</alert-box1>
		</div>

		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			Vue.component("alert-box", {
				template: `
					<div>
						###在組件模板中定一個插槽<br>
						<slot>我是一個插槽</slot>
					</div>
				`
			})
			Vue.component("alert-box1", {
				template: `
					<div>
						###雖然我也是一個插槽可是我被佔用了<br>
						<slot>我是一個插槽</slot>
					</div>
				`
			})

			new Vue({
				el: "#app",
				data: {
					msg:"我要佔用插槽"
				}
			});
		</script>
	</body>

2.具名插槽

  • 被name屬性修飾的插槽叫具名插槽
<body>
		<div id="app">
			<table-list>
				<!-- 在模板內分別爲兩個插槽填充數據 達到表格效果 -->
				<template slot='heands'>
					<th>ID</th>
					<th>名稱</th>
				</template>
				<template slot='tablebody'>
					<tr v-for="l in list">
						<td>{{l.id}}</td>
						<td>{{l.name}}</td>
					</tr>
				</template>
			</table-list>
		</div>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			// 定義一個 table 組件 
			Vue.component('table-list', {
				// 定義一個模板,定義兩個插槽heands 和 tablebody
				template: `
					<table>
						<tr>
						   <slot name='heands'></slot> 
						</tr>
						<tbody>
							 <slot name="tablebody"></slot> 
						</tbody>
					</table>
				`
			})
			new Vue({
				el: "#app",
				data: {
					// 準備初始化數據
					list: [{
							id: 1,
							name: '李四'
						},
						{
							id: 2,
							name: '張三'
						},
						{
							id: 3,
							name: '張飛'
						},
					]
				}
			})
		</script>
	</body>

3.做用域插槽

  • 父組件對子組件加工處理
  • 既能夠複用子組件的slot,又能夠使slot內容不一致
<body>
		<div id="app">
			<!-- 
				一、當咱們但願li 的樣式由外部使用組件的地方定義,由於可能有多種地方要使用該組件,
				但樣式但願不同 這個時候咱們須要使用做用域插槽 
				
			-->
			<fruit-list :list='list'>
				<!-- 二、 父組件中使用了<template>元素,並且包含scope="slotProps",
					slotProps在這裏只是臨時變量   
				--->
				<template slot-scope='slotProps'>
					<strong v-if='slotProps.info.id==3' class="current">
						{{slotProps.info.name}}
					</strong>
					<span v-else>{{slotProps.info.name}}</span>
				</template>
			</fruit-list>
		</div>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			/*
		      做用域插槽
		    */
			Vue.component('fruit-list', {
				props: ['list'],
				/* 
				   三、 在子組件模板中,<slot>元素上有一個相似props傳遞數據給組件的寫法msg="xxx",
				   插槽能夠提供一個默認內容,若是若是父組件沒有爲這個插槽提供了內容,會顯示默認的內容。
				 		若是父組件爲這個插槽提供了內容,則默認的內容會被替換掉
				 */
				template: `
		        <div>
		          <li :key='item.id' v-for='item in list'>
		            <slot :info='item'>{{item.name}}</slot>
		          </li>
		        </div>
		      `
			});
			var vm = new Vue({
				el: '#app',
				data: {
					list: [{
						id: 1,
						name: 'apple'
					}, {
						id: 2,
						name: 'orange'
					}, {
						id: 3,
						name: 'banana'
					}]
				}
			});
		</script>
	</body>

五.習題練習

1.定義輪播組件

<html>
	<head>
		<meta charset="utf-8">
		<title>自定義輪播組件</title>
	</head>
	<style type="text/css">
		* {
			padding: 0;
			margin: 0;
		}

		#slideshow {
			width: 800px;
			height: 400px;
			margin: 50px auto;
			border: 1px solid black;
			position: relative;
		}
	</style>
	<body>
		<div id="slideshow">
			<slides-show :images="images" :index="index" :img-style="imgStyle" :show="show" :hide="hide" :prepagestye="prepagestye"
			 :nextpagestye="nextpagestye" :slideshowstyle="slideshowstyle"
			 @prepage='prepage' @nextpage='nextpage'
			 >

			</slides-show>
		</div>

		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			Vue.component("slides-show", {
				props: ['images', 'index', 'slideshowstyle', 'imgStyle', 'show', 'hide',
					'prepagestye', 'nextpagestye'
				],
				template: `
				<div :style="[slideshowstyle]">
					<ul v-for="imgs in images" class="slideTable">
						<li v-if="index === imgs.id" :style="[show]">
							<img :src="imgs.path" :style="[imgStyle]">
						</li>
						<li v-else :style="[hide]">
							<img :src="imgs.path" >
						</li>
					</ul>
					<span :style="[prepagestye]" @click='$emit("prepage")'>
						<img src = "img/上一頁.png" width="30px">
					</span>
					<span :style="[nextpagestye]"  @click='$emit("nextpage")'>
						<img src = "img/上一頁.png" width="30px">
					</span>
				</div>
				`
			})
			new Vue({
				// 綁定父元素
				el: "#slideshow",
				data: {
					// 定義輪播圖片數據
					index: 1,
					images: [{
							id: 1,
							path: 'img/3Dbg01.jpg'
						},
						{
							id: 2,
							path: 'img/3Dbg02.jpg'
						},
						{
							id: 3,
							path: 'img/3Dbg03.jpg'
						},
						{
							id: 4,
							path: 'img/3Dbg04.jpg'
						}
					],
					// 隱藏顯現
					hide: {
						display: 'none'
					},
					show: {
						display: 'inline'
					},
					//定義圖片大小
					imgStyle: {
						width: '100%',
						height: '400px'
					},
					// 上一頁
					prepagestye: {
						width: '35px',
						position: 'absolute',
						top: '190px',
						display: 'inline-block',
						left: '8px',
						cursor: 'pointer',
					},
					// 下一頁
					nextpagestye: {
						width: '35px',
						position: 'absolute',
						top: '190px',
						right: '8px',
						cursor: 'pointer',
						display: 'inline-block',
						transform: ' rotate(180deg)',
					},
					slideshowstyle: {
						position: 'relative',
						width: '100%',
						height: '400px'
					}
				},
				methods: {
					prepage: function() {
						console.log('11')
						if(this.index <= 1){
							this.index = this.images.length;
						}else{
							this.index = this.index-1;
						}
					},
					nextpage: function() {
						console.log('2')
						if (this.index >= this.images.length) {
							this.index = 1;
						} else {
							this.index = this.index + 1;
						}
					}
				}
			})
		</script>
		<!-- <style type="text/css">
			.slideshowStyele {
				position: relative;
				text-align: center;
				background-color: #fff;
				list-style: none;
				width: 100%;
				height: auto;
				width: 30px;
				height: 30px;
				transform: rotate(180deg);
				cursor: pointer;
				display: inline-block;
			}
		</style> -->
	</body>
</html>

2.dmoe下載

https://gitee.com/li_shang_shan/vue-component-learning-dmeoapp

相關文章
相關標籤/搜索