# 组件

组件简介 组件 (Component) 是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以表现为用  is  特性进行了扩展的原生 HTML 元素。所有的 Vue 组件同时也都是 Vue 的实例,所以可接受相同的选项对象 (除了一些根级特有的选项) 并提供相同的生命周期钩子。

# 组件注册

# 全局注册

全局注册的组件可以用在其被注册之后的任何 (通过 new Vue) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中。

<div id="app">
	<com></com>
</div>
<script>
	// 全局组件
	Vue.component("com", {
		data() {
			return {
				num: 10,
			};
		},
		template: "<h2>{{ num }}</h2>",
	});
	var vm = new Vue({
		el: "#app",
	});
</script>

# 局部注册

只能在当前页面中使用

<div id="app">
	<com></com>
	<com1></com1>
</div>
<script>
	// 局部注册组件
	var vm = new Vue({
		el: "#app",
		components: {
			com: {
				data() {
					return {
						info: "我是局部注册的组件",
					};
				},
				template: "<h3>{{ info }}</h3>",
			},
			com1: {
				data() {
					return {
						info: "我是局部注册1的组件",
					};
				},
				template: "<h3>{{ info }}</h3>",
			},
		},
	});
</script>

# 组件的大小写问题

在 dom 里面是不识别大写的 浏览器会把标签中的大写转换成小写 如果要识别的话需要用-连接 如

<div id="app">
	<h2>标题</h2>
	<is-show></is-show>
</div>
<script>
	// 局部注册组件

	var vm = new Vue({
		el: "#app",
		components: {
			isShow: {
				data() {
					return {
						info: "我是局部注册的组件",
					};
				},
				template: "<h3>{{ info }}</h3>",
			},
		},
	});
</script>

在页面里面就会渲染成 组件大小写

# 组件的特点

  • data 必须是一个函数
  • 组件是密封的 组件之间的数据是相互独立的 也就是说即使写几个组件 更改其中的某一个组件之间的值 其他的组件也不会受到影响
  • 组件模板中只能有一个根元素
  • 组件传值 组件是密封的 所有想给某个组件传值 vue 提供了 props 通过 props 传值 这个 props 是写在我们组件里面的一个属性 传值通过这个属性来传值的
<div id="app">
	<is-show prop1="父组件传递的数据" :parinfo="parinfo"></is-show>
</div>
<script>
	// 局部注册组件

	var vm = new Vue({
		el: "#app",
		data() {
			return {
				parinfo: "我是父组件的数据",
			};
		},
		components: {
			"is-show": {
				props: ["prop1", "parinfo"],
				data() {
					return {
						info: "我是局部注册的组件",
					};
				},
				template: "<h3>{{ info }} {{ prop1 }} {{ parinfo }}</h3>",
			},
		},
	});
</script>

# props 类型检测

props 类型 有八种类型作用就是对我们传递的数据进行类型检查 还会在传递数据类型遇到错误的时候从浏览器的 JavaScript 控制台提示用户

  1. String
  2. Number
  3. Boolean
  4. Array
  5. Object
  6. Date
  7. Function
  8. Symbol
<script>
	var vm = new Vue({
		el: "#app",
		components: {
			props: {
				title: String,
				likes: Number,
				isPublished: Boolean,
				commentIds: Array,
				author: Object,
				callback: Function,
				contactsPromise: Promise, // or any other constructor
			},
		},
	});
</script>

# 组件传递数据的三种方式

# 父元素传值到子元素

通过 props 传值

传值注意事项

单向数据流 父级 prop 的更新会向下流动到子组件中,但是反过来则不行 如果我们实在想改变这个传值 我们用 data 或者计算属性来代替这个传值

<div id="app">
	<is-show :parinfo="parinfo"></is-show>
</div>
<script>
	var vm = new Vue({
		el: "#app",
		data() {
			return {
				parinfo: true,
			};
		},
		components: {
			"is-show": {
				props: {
					parinfo: Boolean,
				},
				data() {
					return {
						info: "我是局部注册的组件",
						infos: this.parinfo,
					};
				},
				methods: {
					changeParent() {
						this.infos = !this.infos;
					},
				},
				template: `<div>
                    <h3> {{ infos }}</h3>
                    <button @click="changeParent">改变父元素传值</button>
                </div>`,
			},
		},
	});
</script>

# 子组件向父元素传递值

子组件向父元素传递值是通过自定义事件来完成的

  • 原理:父组件将方法的引用,传递到子组件内部,子组件在内部调用父组件传递过来的方法,同时把要发送给父组件的数据,在调用方法的时候当作参数传递进去;
  • 父组件将方法的引用传递给子组件,其中,getMsg 是父组件中 methods 中定义的方法名称,func 是子组件调用传递过来方法时候的方法名称
<son @func="getMsg"></son>
  • 子组件内部通过 this.$emit('方法名', 要传递的数据)方式,来调用父组件中的方法,同时把数据传递给父组件使用
<div id="app">
	<!-- 引用父组件 -->
	<son @func="getMsg"></son>

	<!-- 组件模板定义 -->
	<script type="x-template" id="son">
		<div>
		  <input type="button" value="向父组件传值" @click="sendMsg" />
		</div>
	</script>
</div>

<script>
	// 子组件的定义方式
	Vue.component("son", {
		template: "#son", // 组件模板Id
		methods: {
			sendMsg() {
				// 按钮的点击事件
				this.$emit("func", "OK"); // 调用父组件传递过来的方法,同时把数据传递出去
			},
		},
	});

	// 创建 Vue 实例,得到 ViewModel
	var vm = new Vue({
		el: "#app",
		data: {},
		methods: {
			getMsg(val) {
				// 子组件中,通过 this.$emit() 实际调用的方法,在此进行定义
				alert(val);
			},
		},
	});
</script>

# 非父子组件传值

非父子组件之间传值,需要定义个bus,作为中间仓库来传值,不然路由组件之间达不到传值的效果。

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<meta http-equiv="X-UA-Compatible" content="ie=edge" />
		<title>Document</title>
		<script src="lib/vue.js"></script>
	</head>
	<body>
		<div id="app">
			<zujian1 :mes="childInfo"></zujian1>
			<zujian2 @event="parEvents"></zujian2>
		</div>
		<script>
			// 局部注册组件   bus
			var bus = new Vue();
			var vm = new Vue({
				el: "#app",
				data() {
					return {
						parinfo: "我是父组件的数据",
						childInfo: "",
					};
				},
				methods: {
					parEvents(val) {
						this.childInfo = val;
						console.log("我是子组件传递过来的数据", val);
					},
				},
				components: {
					zujian1: {
						props: ["mes"],
						data() {
							return {
								get1: "",
							};
						},
						created() {
							var that = this;
							var mess = bus.$on("busevent", (val) => {
								console.log(that, this);
								this.get1 = val;
								//return val
							});
						},
						template: "<h3>组件 传递过来的值是{{ mes }} {{ get1 }}</h3>",
					},
					zujian2: {
						data() {
							return {};
						},
						methods: {
							post2() {
								//this.$emit("event",1)
								bus.$emit("busevent", 1);
							},
						},
						template: "<h3 @click='post2'>组件2传递数据</h3>",
					},
				},
			});
		</script>
	</body>
</html>

# sync 修饰符

在 vue 的组件通信 props 中,一般情况下,数据都是单向的,即父组件数据的更改会下传到子组件(用了.once 除外),子组件对数据无法做出更改(当传递的数据是引用数据类型时,可以更改父组件数据,比如,数组的破坏性方法,push 等)。sync 可以实现数据的双向绑定

示例代码如下

<comp :foo.sync="bar"></comp>

会被扩展为

<comp :foo="bar" @update:foo="val => bar = val"></comp>

当子组件需要更新 foo 的值时,它需要显式地触发一个更新事件:

this.$emit('update:foo', newValue)

完整示例

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<meta http-equiv="X-UA-Compatible" content="ie=edge" />
		<title>Document</title>
		<script src="lib/vue.js"></script>
	</head>
	<body>
		<div id="app">
			<com :message.sync="mes"></com>
		</div>
		<script>
			var vm = new Vue({
				el: "#app",
				methods: {},
				data() {
					return {
						mes: "父元素里面的值",
					};
				},
				components: {
					com: {
						props: ["message"],
						template: "<h3 @click='changeProp'>子组件 {{message}}</h3>",
						methods: {
							changeProp() {
								this.$emit("update:message", "改变之后的");
							},
						},
					},
				},
			});
		</script>
	</body>
</html>
上次更新: 11/26/2019, 10:43:50 AM