2020年12月1日星期二

vue组件学习

一.文章导读

​ 前面学习了vue的基础指令,了解了相关的钩子函数,这一章学习vue的组件,组件 (Component) 是 Vue.js 最强大的功能之一,组件可以扩展 HTML 元素,封装可重用的代码,组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树:

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

官网学习地址:https://cn.vuejs.org/

入门学习更加推荐菜鸟

二.组件定义

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.局部组件

前面已经写个全局指令,全局过滤器,局部过滤器之类的,所以局部组件与全局组件的区别是一样的,局部组件只能在当前实例才能使用

<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>

注意:组件模板中的内容只允许存在一个根标签,多了的话只会解析第一个

	// 下面模板定义了两个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>					### 1、子组件用$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">			/*		  兄弟组件之间数据传递		 */			//1、 提供事件中心			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() {						//2、传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据) 触发兄弟组件的事件						hub.$emit('jerry-event', 2);					}				},				mounted: function() {					// 3、接收数据方,通过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() {						//2、传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据) 触发兄弟组件的事件						hub.$emit('tom-event', 1);					}				},				mounted: function() {					// 3、接收数据方,通过mounted(){} 钩子中 触发hub.$on()方法名					hub.$on('jerry-event', (val) => {						this.num += val;					});				}			});						var vm = new Vue({				el: '#app',				data: {				},				methods: {					handle: function() {						//4、销毁事件 通过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">			<!-- 				1、当我们希望li 的样式由外部使用组件的地方定义,因为可能有多种地方要使用该组件,				但样式希望不一样 这个时候我们需要使用作用域插槽 							-->			<fruit-list :list='list'>				<!-- 2、 父组件中使用了<template>元素,而且包含scope="slotProps",					slotProps在这里只是临时变量 				--->				<template slot-scope='slotProps'>					<strong v-if='slotProps.info.id==3' >						{{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'],				/* 				 3、 在子组件模板中,<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- :show="show" :hide="hide" :prepagestye="prepagestye"			 :nextpagestye="nextpagestye" :slideshow			 @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 :>					<ul v-for="imgs in images" >						<li v-if="index === imgs.id" :>							<img :src="imgs.path" :>						</li>						<li v-else :>							<img :src="imgs.path" >						</li>					</ul>					<span : @click='$emit("prepage")'>						<img src = "img/上一页.png" width="30px">					</span>					<span : @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-dmeo









原文转载:http://www.shaoqun.com/a/494501.html

万国邮政联盟:https://www.ikjzd.com/w/861

acca是什么:https://www.ikjzd.com/w/1370

upc:https://www.ikjzd.com/w/111


一.文章导读​ 前面学习了vue的基础指令,了解了相关的钩子函数,这一章学习vue的组件,组件(Component)是Vue.js最强大的功能之一,组件可以扩展HTML元素,封装可重用的代码,组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树:菜鸟教程地址:https://www.runoob.com/vue2/vue-tutorial.htm
kk馆:kk馆
乐一番:乐一番
世园会或迎游客高峰_景点服务受赞 :世园会或迎游客高峰_景点服务受赞
你还在发自嗨式的开发信吗?:你还在发自嗨式的开发信吗?
Wish商家如何申请加入FBW物流(FBW US和FBW EU):Wish商家如何申请加入FBW物流(FBW US和FBW EU)

没有评论:

发表评论