Vue 学习 (三)——组件

本贴最后更新于 2029 天前,其中的信息可能已经沧海桑田

这篇文章继承上一篇继续了解 Vue 的组件机制。
参考: Vue 官方文档 https://cn.vuejs.org/v2/guide/
上一篇文章的链接:Vue 学习(二)——重要特性 http://www.honeybee.top/articles/2018/09/27/1538011046811.html


1. 什么是组件

组件就是为了拆分 Vue 实例的代码量,定义不同的组件来划分不同的功能模块,在需要组件功能的时候,去调用组件即可。
在后台会把功能模块化,模块化和组件化之间有点相似的味道,但又不是同一个东西,它们之间的区别:
组件化是从 UI 界面角度划分的,前端的组件化是为了 UI 组件的重用;
模块化是从代码逻辑的角度划分的;为了方便代码分层开发,保证功能模块的职能单一。

2. 定义全局组件

a.方式 1:

<html>
	<head>
		<meta charset="utf-8" />
		<script src="https://cdn.bootcss.com/vue/2.5.16/vue.js"></script>
	</head>
	<body>
		<div id="app">
			<!--将组件引入到页面中使用-->
			<my-com></my-com>
		</div>
		
		<script>
			//使用Vue.extend来创建全局的Vue组件
			//使用Vue.component('组件的名称', 创建出来的组件对象)注册组件
			//如果组件名称使用了 驼峰命名, 那么在引用组件的时候要把大写的驼峰改为小写的字母,同时单词之间用 '-' 连接
			Vue.component('myCom', Vue.extend({
				template: '<h3>使用Vue.extend创建的组件</h3>'
			}))
			
			var vm = new Vue({
				el: '#app'
			})
			
		</script>
	</body>
</html>

运行后的页面如下:
imagepng

b.方式 2:

<html>
	<head>
		<meta charset="utf-8" />
		<script src="https://cdn.bootcss.com/vue/2.5.16/vue.js"></script>
	</head>
	<body>
		<div id="app">
			<my-com></my-com>
		</div>
		
		<!-- 在被Vue组件控制的区域外面, 定义组件的HTML结构-->
		<template id="tmpl">
			<div>
				<h1>这是 template 元素定义的组件结构</h1>
			</div>
		</template>
		
		<script>
			Vue.component('myCom', {
				template: '#tmpl'
			})
			
			var vm = new Vue({
				el: '#app'
			})
			
		</script>
	</body>
</html>

运行后的页面如下:

imagepng

3. 定义私有组件

<html>
	<head>
		<meta charset="utf-8" />
		<script src="https://cdn.bootcss.com/vue/2.5.16/vue.js"></script>
	</head>
	<body>
		<div id="app">
			<com-private></com-private>
		</div>
		
		<div id="app2">
			<com-private></com-private>
		</div>
		
		<template id="tem2">
			<h2>vm2实例的私有组件</h2>
		</template>
		
		<script>
			
			var vm = new Vue({
				el: '#app'
			})
			
			var vm2 = new Vue({
				el: '#app2',
				components: {	//定义实例内部私有组件
					comPrivate: {
						//template: '<h2>vm2实例的私有组件</h2>'
						//上面也可在外面定义后直接引入
						template: '#tem2'
					}
				}
			})
			
		</script>
	</body>
</html>

运行后的页面如下:
imagepng

只有 id 为 app2 的 div 中的私有组件被显示出来了,app 中的组件会报如下错误:
imagepng
说明私有组件只有在定义的实例中才有效。

4. 组件中的 data 和 methods

<html>
	<head>
		<meta charset="utf-8" />
		<script src="https://cdn.bootcss.com/vue/2.5.16/vue.js"></script>
	</head>
	<body>
		<div id="app">
			<my-com></my-com>
		</div>
		
		<script>
			//组件中的data数据是一个方法,必须返回一个对象
			//组件中data数据的使用方式也是用插值表达式 {{}}
			Vue.component('myCom', {
				template: '<h1>全局组件com --- {{msg}}</h1>',
				data: function() {
					return {
						msg: '全局组件中data定义的数据'
					}
				},
				methods: {
					method1() {
						
					}
				}
			})
			
			var vm = new Vue({
				el: '#app'
			})
			
		</script>
	</body>
</html>

运行后的页面如下:
imagepng

5. 组件切换

a. 两个组件之间的切换

<html>
	<head>
		<meta charset="utf-8" />
		<script src="https://cdn.bootcss.com/vue/2.5.16/vue.js"></script>
	</head>
	<body>
		<div id="app">
			<a href="" @click.prevent="flag = true">登录</a>
			<a href="" @click.prevent="flag = false">注册</a>
			
			<!-- 利用v-if/v-else进行组件之间的切换-->
			<login v-if="flag"></login>
			<register v-else="flag"></register>
		</div>
		
		<script>
			Vue.component('login', {
				template: '<h3>登录组件</h3>'
			})
			
			Vue.component('register', {
				template: '<h3>注册组件</h3>'
			})
			
			var vm = new Vue({
				el: '#app',
				data: {
					flag: true
				}
			})
			
		</script>
	</body>
</html>

运行后的页面如下:
imagepng

b. 多个组件之间的切换

<html>
	<head>
		<meta charset="utf-8" />
		<script src="https://cdn.bootcss.com/vue/2.5.16/vue.js"></script>
	</head>
	<body>
		<div id="app">
			<a href="" @click.prevent="comName = 'login'">登录</a>
			<a href="" @click.prevent="comName = 'register'">注册</a>
			
			<!-- component 是Vue提供的一个占位符, 通过is属性值来展示对应的组件 -->
			<component :is="comName"></component>
		</div>
		
		<script>
			Vue.component('login', {
				template: '<h3>登录组件</h3>'
			})
			
			Vue.component('register', {
				template: '<h3>注册组件</h3>'
			})
			
			var vm = new Vue({
				el: '#app',
				data: {
					comName: ''
				}
			})
			
		</script>
	</body>
</html>

虽然改了切换方式,但运行的效果和上面的是一样的。

6. 组件传值

a. 父组件向子组件传值

<html>
	<head>
		<meta charset="utf-8" />
		<script src="https://cdn.bootcss.com/vue/2.5.16/vue.js"></script>
	</head>
	<body>
		<div id="app">
			<!-- 
				父组件中引用子组件时:父组件可以通过属性绑定的形式 把自身数据绑定到子组件内部,
				供子组件使用,也就是父组件向子组件传值。
			-->
			<com1 :parentmsg="msg"></com1>
		</div>
		
		<script>
			var vm = new Vue({
				el: '#app',
				data: {
					msg: '父组件中的属性值parentMsg'
				},
				components: {
					com1: {
						data() {
							return {
								content: '子组件中的属性值content'
							}
						},
						template: '<h3>子组件------{{parentmsg}}------</h3>',
						//子组件要使用父组件中的数据,需要在props中定义一下
						//注意:props中的数据,都是父组件传递给子组件的,而且都是只读的。
						props: ['parentmsg']
					}
				}
			});
			
		</script>
	</body>
</html>

运行后的页面如下:
imagepng

b. 父组件向子组件传方法

<html>
	<head>
		<meta charset="utf-8" />
		<script src="https://cdn.bootcss.com/vue/2.5.16/vue.js"></script>
	</head>
	<body>
		<div id="app">
			<!-- 
				父组件向子组件传递方法,使用的是事件绑定机制 v-on:(简写为@)
				注意:不要写方法后面的(),否则就表示把方法的结果传递给子组件了
			-->
			<com1 @click-function="show"></com1>
		</div>
		
		<template id="tmpl">
			<div>
				<h3>子组件</h3>
				<input type="button" value="点击触发父组件传递过来的方法" @click="myclick"/>
			</div>
		</template>
		
		<script>
			//定义一个组件的对象
			var com1 = {
				template: '#tmpl',
				methods: {
					myclick() {
						//调用触发父组件传递过来的方法
						this.$emit('click-function', 'limit1', 'limit2');
					}
				}
			}
			
			var vm = new Vue({
				el: '#app',
				methods: {
					show(data1, data2) {
						console.log('调用了父组件中的方法show(),参数1:' + data1 + ", 参数2:" + data2);
					}
				},
				components: {
					com1
				}
			});
			
		</script>
	</body>
</html>

运行后的页面如下:
imagepng

点击按钮后打开控制台可以看到触发了父组件中的 show 方法:
imagepng

c. 子组件向父组件传值

子组件向父组件传值的本质就是:子组件通过父组件传递过来的方法把子组件中的属性作为参数传递给这个方法,这个方法中再把传递过来的值保存到父组件的属性中。
把上面例子稍作修改:

<html>
	<head>
		<meta charset="utf-8" />
		<script src="https://cdn.bootcss.com/vue/2.5.16/vue.js"></script>
	</head>
	<body>
		<div id="app">
			<!-- 
				父组件向子组件传递方法,使用的是事件绑定机制 v-on:(简写为@)
				注意:不要写方法后面的(),否则就表示把方法的结果传递给子组件了
			-->
			{{msg}}
			<com1 @click-function="show"></com1>
		</div>
		
		<template id="tmpl">
			<div>
				<h3>子组件</h3>
				<input type="button" value="点击触发父组件传递过来的方法" @click="myclick"/>
			</div>
		</template>
		
		<script>
			//定义一个组件的对象
			var com1 = {
				template: '#tmpl',
				methods: {
					myclick() {
						//调用触发父组件传递过来的方法
						this.$emit('click-function', 'limit1', 'limit2');
					}
				}
			}
			
			var vm = new Vue({
				el: '#app',
				//新增属性
				data: {
					msg: '这是我本来的值'
				},
				methods: {
					show(data1, data2) {
						console.log('调用了父组件中的方法show(),参数1:' + data1 + ", 参数2:" + data2);
						//把属性中的msg只替换掉
						this.msg = "这是我得到子组件中传递属性后的值:" + data1 + data2;
					}
				},
				components: {
					com1
				}
			});
			
		</script>
	</body>
</html>

运行后的页面如下:
imagepng

点击按钮后:
imagepng

7. ref 获取 DOM 元素和组件引用

<html>
	<head>
		<meta charset="utf-8" />
		<script src="https://cdn.bootcss.com/vue/2.5.16/vue.js"></script>
	</head>
	<body>
		<div id="app">
			<input type="button" ref="btn" @click="getElement" value="点我触发getElement函数">
			<h3 ref="h3ele">this is a h3 element</h3>
			<hr></hr>
			<login ref="login"></login>
			<input type="button" @click="show" value="点我触发show函数">
		</div>
		
		<script>
			var login = {
				template: '<h3>登录组件</h3>',
				data() {
					return {
						loginMsg: '登录子组件的值',
					}
				},
				methods: {
					myclick() {
						console.log('子组件的方法myclick');
					}
				}
			}
			
			var vm = new Vue({
				el: '#app',
				data: {},
				methods: {
					show() {
						console.log(this.$refs.login.myclick)
					},
					getElement() {
						console.log(this.$refs.h3ele.innerText + "===" + this.$refs.btn.value)
					}
				},
				components: {
					login
				}
			});
			
		</script>
	</body>
</html>

运行后的页面如下:
imagepng

点击按钮会在控制台上显示:
imagepng

可以在控制台中输入 vm 观察 $refs 元素,确实绑定了对应的元素和组件:
imagepng

  • Vue.js

    Vue.js(读音 /vju ː/,类似于 view)是一个构建数据驱动的 Web 界面库。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。

    261 引用 • 662 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • long369

    能不能回帖 给你个赞

  • someone

    😋 三克斯