Vue 学习笔记 —— 组件化开发 (三)

案例式驱动,每个案例一个小例子,带领大家领略

一、组件注册

1.1 全局组件

基本语法:

	<script>
		 Vue.component('组件名称', {
		 	data: '组件数据',
		 	template: '组件模板内容(HTML 标签)'
		 })
	</script>

示例:

我们以一个点击按钮数据累加计算来演示组件的使用

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>组件化开发</title>
	</head>
	<body>
		<div id="app">
			<!-- 每个组件的都是相互独立的 -->
			<button-counter></button-counter>
			<button-counter></button-counter>
			<button-counter></button-counter>
		</div>

		<script src="../vue.js"></script>
		<script>
			// Vue.component('button-counter'  两种方式
			Vue.component('ButtonCounter', { 
				// 使用函数,形成一个闭包的环境,保证每个数据都是独立的。
				data() {
					return {
						count: 0
					}
				},
				// template: '<button v-on:click="count++">点击了{{count}}次</button>',
				template: '<button @click="handle">点击了{{count}}次</button>',
				methods: {
					handle: function() {
						this.count++;
					},
				}
			})
			var app = new Vue({
				el: "#app",
				data: {

				}
			})
		</script>
	</body>
</html>

在这里插入图片描述

1.2 局部组件

我们在 Vue 实例中添加 components 属性,在这里我们就可以自定义自己的局部组件,使用方式和全局组件的差别不大

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>局部组件化开发</title>
	</head>
	<body>
		<div id="app">
			<component-a></component-a>
		</div>
		<!-- 
			局部组件注册
			局部组件只能在注册他的父组件中使用
		 -->
		<script src="../vue.js"></script>
		<script>
			let ComponetA = {
				data() {
					return {
						msg: 'Hello World'
					}
				},
				template: '<div>{{msg}}</div>',
				methods: {
					
				}
			}
			
			var app = new Vue({
				el:"#app",
				data:{

				},
				components: {
					'component-a': ComponetA
				}
			})
		</script>
	</body>
</html>

演示效果
在这里插入图片描述

1.3 组件注册基本注意事项

注册基本事项:

  1. data 必须是一个函数
  2. 组件模板内容必须是单个根元素
  3. 组件模板内容可以是模板字符串 ES6语法
  4. 如果使用驼峰式命名组件,要么在使用组件得时候,只能在字符串模板中用驼峰得方式使用组件

但是在普通得模板标签中,必须使用横线的方式使用组件

1.4 props 属性值类型

  • 字符串 String
  • 数值 Number
  • 布尔值 Boolean
  • 数组 Array
  • 对象 Object

二、组件之间数据交互

2.1 父组件向子组件传递数据

  • 父组件向子组件传递数据,分为静态数据 和 动态数据(属性绑定实现)
  • 子组件接收父组件传递过来的内容,要通过 props 来接收父组件的数据
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>组件数据传递</title>
	</head>
	<body>
		<div id="app">
			<!-- 
				1. 组件内部通过 props 接收传递过来的值
				2. 父组件通过属性传值给子组件
				3. props 属性名规则
					在 props 中使用驼峰形式,模板中需要使用短横线的形式
					字符串形式的模板中没有这个限制
			 -->
			<h3>父组件向子组件传递数据</h3>
			<div>
				{{pmsg}}
			</div>
			<!-- 父组件向子组件传递数据 -->
			
			<h3>二、静态数据传递</h3>
			<!-- 静态传递 -->
			<menu-item title="来自父组件的值"></menu-item>
			
			<h3>三、动态数据传递</h3>
			<!-- 动态传递 -->
			<menu-item :title="ptitle"></menu-item>
			
			<menu-item :title="pmsg" content="hello"></menu-item>
			
			<h3>四、短横线绑定</h3>
			<!-- 属性名称规则 短横线 -->
			<my-menu menu-title="Hello"></my-menu>
			
			<!-- 数组 -->
			<h3>五、数组传递</h3>
			<my-array :arr="parray"></my-array>
			
			<h3>六、对象传递</h3>
			<my-obj :person="person"></my-obj>
		</div>
		
		<script src="../vue.js"></script>
		<script type="text/javascript">
			Vue.component('menu-item', {
				// props 接收父组件传过来的内容
				props: ['title', 'content'],
				data() {
					return {
						msg: '子组件本身的数据'
					}
				},
				template: '<div>{{msg + "----" + title + "------" + content}}</div>'
			});
			
			Vue.component('my-menu', {
				props: ['menuTitle'],
				template: '<div>{{menuTitle}}</div>'
			});
			
			// 遍历数组
			Vue.component('my-array', {
				props: ['arr'],
				template: '<ul><li v-for="(item,index) of arr" :key="index">{{item}}</li></ul>'
			});
			
			Vue.component('my-obj', {
				props: ['person'],
				template: '<div>{{person.name}} {{person.age}}</div>'
			})
			var app = new Vue({
				el:"#app",
				data:{
					pmsg: '父组件的内容',
					ptitle: '动态绑定属性',
					parray: ['apple','orange','banana'],
					person: {
						name: 'coco',
						age: 18
					}
				}
			})
		</script>
	</body>
</html>

在这里插入图片描述

2.2 子组件向父组件传递数据

子组件向父组件传值

props 传递数据原则,单向数据流

  1. 子组件通过自定义事件向父组件传递信息 $emit 向父组件传递数据
  2. 父组件监听子组件的事件

接下来我们以一个改变字体大小 以及 传递数组的实例来给给大家演示子组件向父最贱传递数据的流程

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>子组件向父组件传递数据</title>
	</head>
	<body>

		<div id="app">
			<!-- style 属性绑定 -->
			<div :style="{fontSize: fontSize + 'px'}">{{pmsg}}</div>
			<!-- 这个监听事件的名称必须和子组件的事件完全一致 -->
			<menu-item :parr="parr" @enlarge-text="handle"></menu-item>
		</div>

		<script src="../vue.js"></script>
		<script>
			// 子组件向父组件传值 —— 基本用法
			 Vue.component('menu-item', {
				 props: ['parr'],
				 template:`
					<div>
						<ul>
							<li :key="index" v-for="(item, index) of parr">{{item}}</li>
						</ul>
					<button @click="parr.push('lemon')">点击</button>
					<button @click="$emit('enlarge-text')">扩大父组件中字体大小</button>
					</div>
				 `
			 })
			 
			var app = new Vue({
				el: "#app",
				data: {
					pmsg: '我是父组件的信息',
					parr: ['orange','apple','banana','watermelen'],
					fontSize: 10
				},
				methods: {
					handle: function() {
						// 扩大字体大小
						this.fontSize += 5;
					}
				}
			})
		</script>
	</body>
</html>

在这里插入图片描述
在这里插入图片描述

2.3 子组件通过自定义事件向父组件传递信息

基本和上面一致

子组件传递的数据,在父组件中要通过 $event 来接收数据

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>子组件向父组件传递数据</title>
	</head>
	<body>

		<div id="app">
			<div :style="{fontSize: fontSize + 'px'}">{{pmsg}}</div>
			<menu-item :parr="parr" @enlarge-text="handle($event)"></menu-item>
		</div>

		<script src="../vue.js"></script>
		<script>
			// 子组件自定义向父组件传值 —— 基本用法
			/**
			 * props 传递数据原则,单向数据流
			 * 1. 子组件通过自定义事件向父组件传递信息  $emit
			 * 2. 父组件监听子组件的事件
			 * 3. 父组件通过 $event 获取值
			 * */
			 Vue.component('menu-item', {
				 props: ['parr'],
				 template:`
					<div>
						<ul>
							<li :key="index" v-for="(item, index) of parr">{{item}}</li>
						</ul>
					<button @click="parr.push('lemon')">点击</button>
					<button @click="$emit('enlarge-text',5)">扩大父组件中字体大小</button>
					<button @click="$emit('enlarge-text',10)">扩大父组件中字体大小</button>
					</div>
				 `
			 })
			 
			var app = new Vue({
				el: "#app",
				data: {
					pmsg: '我是父组件的信息',
					parr: ['orange','apple','banana','watermelen'],
					fontSize: 10
				},
				methods: {
					handle: function(val) {
						// 扩大字体大小
						this.fontSize += val;
					}
				}
			})
		</script>
	</body>
</html>

在这里插入图片描述

2.4 非父子组件间传值 (兄弟组件之间数据交互)

通过事件中心完成交互

在这里插入图片描述
使用方式:

  1. 单独创建一个 Vue 实例
  2. 然后处理事件的监听 和 销毁
// 单独创建时间中心管理组件间的通信
var eventHub = new Vue();

// 监听事件和销毁事件
eventHub.$on('add-todo',addTodo); // 自定义事件名称  事件函数
eventHub.$off('add-tod');

// 触发事件
eventHub.$emit('add-todo',id);

示例

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>组件化开发</title>
	</head>
	<body>
		<div id="app">
			<div>事件销毁</div>
			<div>
				<button @click="handle">点击</button>
			</div>
			<!-- 每个组件的都是相互独立的 -->
			<test-tom></test-tom>
			<test-jerry></test-jerry>
		</div>

		<script src="../vue.js"></script>
		<script>
			/**
			 * 兄弟组件传值
			 * */
			 // 提供事件中心
			var eventHub = new Vue();
			 
			Vue.component('test-tom', {
				data() {
					return {
						num: 0
					}
				},
				template: `
					<div>
						<div>TOM:{{num}}</div>
						<div>
							<button @click='handle'>点击</button>
						</div>
					</div>
				 `,
				methods: {
					handle: function() {
						// 触发兄弟组件的事件
						eventHub.$emit('jerry-event',2);
					}
				},
				mounted() {
					// 监听事件, 使用箭头函数,使用 this
					eventHub.$on('tom-event', (val)=> {
						this.num+=val;
					})
				}
			})

			Vue.component('test-jerry', {
				data() {
					return {
						num: 0
					}
				},
				template: `
					<div>
						<div>JERRY:{{num}}</div>
						<div>
							<button @click='handle'>点击</button>
						</div>
					</div>
				 `,
				methods: {
					handle: function() {
						// 触发兄弟组件的事件
						eventHub.$emit('tom-event',1);
					}
				},
				mounted() {
					// 监听事件, 使用箭头函数,使用 this
					eventHub.$on('jerry-event', (val)=> {
						this.num+=val;
					})
				}
			})
			

			var app = new Vue({
				el: "#app",
				data: {

				},
				methods: {
					// 事件销毁
					handle: function() {
						eventHub.$off('tom-event');
						eventHub.$off('jerry-event');
					}
				}
			})
		</script>
	</body>
</html>

在这里插入图片描述

2.5 组件插槽

  • 父组件向子组件传递模板内容
  • 子组件通过插槽 slot 显示父组件中模板的数据

slot 是 vue 提供的 API,使用 slot 在子组件,我们可以在模板中插入我们想要的数据,我们还可以在 slot 中添加默认的数据

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>组件化开发</title>
	</head>
	<body>
		<div id="app">
			<test-box>
				<h3>我没有通过 slot,我进不来</h3>
			</test-box>
			<hr>
			<alert-box>
				<h3>我通过 slot 插入进来了</h3>
			</alert-box>
		</div>

		<script src="../vue.js"></script>
		<script>
			Vue.component('test-box',{
				template: `
					<div>
						<strong>没插槽的时候</strong>
					<div>
					`,
			})
			
			Vue.component('alert-box', { 
				template: `
					<div>
						<strong>有插槽的时候</strong>
						<slot></slot>
					<div>
					`,
			})
			var app = new Vue({
				el: "#app",
				data: {

				}
			})
		</script>
	</body>
</html>

在这里插入图片描述

2.6 具名插槽

在一个组件中,我们可以指定多个插槽插入数据,但是为了区分这些数据,我们会设置一个 name 值来标识唯一的插槽

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>组件化开发</title>
	</head>
	<body>
		<div id="app">
			<!-- slot 根据名称匹配
				匹配的到的就会进入指定插槽
				匹配不到的就会进入默认插槽
				使用 template 可以包含多个标签,不使用它只能包含一个标签
			 -->
			<base-layout>
				<p slot="header">标题信息</p>
				<p>我是主要内容</p>
				<p>我是主要内容</p>
				<p slot="footer">底部信息</p>
			</base-layout>
				<hr />
					
			<base-layout>
				<template slot="header">
					<p>标题信息1</p>
					<p>标题信息2</p>
				</template>
				<p>我是主要内容</p>
				<p>我是主要内容</p>
				<template slot="footer">
					<p>底部信息1</p>
					<p>底部信息2</p>
				</template>
			</base-layout>
		</div>

		<script src="../vue.js"></script>
		<script>
			Vue.component('base-layout', { 
				template: `
					<div>
						<header>
							<slot name="header"></slot>
						</header>
						<main>
							<slot></slot>
						</main>
						<footer>
							<slot name="footer"></slot>
						</footer>
					</div>
				`
			})
			var app = new Vue({
				el: "#app"
			})
		</script>
	</body>
</html>

在这里插入图片描述

2.7 作用域插槽

应用场景: 父组件对子组件的内容进行加工处理。

使用方式:

  1. 在子组件中设置 slot,并自定义一个属性,接收父组件的内容
  2. 父组件创建 template,通过设置 slot-scope 就可以接收到子组件的内容
  3. 然后得到数据,就可以对数据进行显示了。
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>作用域插槽</title>
	</head>
	<style>
		.current {
			color: orange;
		}
	</style>
	<body>
		<!-- 父组件对子组件的内容加工处理 -->
		<div id="app">
			<first-fruit :list="list">
				<!-- 得到子组件通过 slot 传过来的数据, 并对数据加工处理 -->
				<template slot-scope="slotProps">
					<strong v-if="slotProps.info.id == 2" class="current">
						{{slotProps.info.name}}
					</strong>
					<span v-else> 
						{{slotProps.info.name}}
					</span>
				</template>
			</first-fruit>
		</div>
		<script src="../vue.js"></script>
		<script type="text/javascript">
			Vue.component('first-fruit',{
				props: ['list'],
				template: `
					<div>
						<ul>
							<li v-for="item of list" :key="item.id">
								<slot :info='item'>
									{{item.name}}
								</slot>
							</li>
						</ul>
					</div>
				`
			})
			var vm = new Vue({
				el:"#app",
				data: {
					list: [{
						id: 1,
						name: 'apple'
					},{
						id: 2,
						name: 'banana'
					},{
						id: 3,
						name: 'orange'
					}]
				}
			})
		</script>
	</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值