Vue组件基础

基本示例

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="../lib/vue.js"></script>
	</head>
	<body>
		<!-- 第一步:定义模板 -->
		<template id="counter">
			<div>
				<button @click="count++">click me {{count}} times</button>
			</div>
		</template>
		<!-- 第三步:使用组件 -->
		<div id="app">
			<counter></counter>
		</div>
		<script type="text/javascript">
			// 第二步:定义、注册组件
			Vue.component('counter', {
				data() {
					return {
						count: 0
					}
				},
				template: '#counter'
			});
			new Vue({
				el: '#app'
			});
		</script>
	</body>
</html>

注意:定义的组件名的命名规则不能使用驼峰命名,多个单词之间要用 - 符号隔开

组件的复用

<div id="app">
    <counter></counter>
    <counter></counter>
    <counter></counter>
</div>

定义的组件后,可以任意次地复用,每个组件独立地维护着自己的 data 数据

data必须是函数

data 不能像这样直接提供一个对象,这样的话,多个相同地组件会共用同一份数据。

data: {
	count: 0
}

data 必须是一个函数,才能保证每个组件间的 data 是独立的。

通过 Prop 向子组件传递数据

prop 是你可以在组件上注册的自定义 attribute,格式为:

Vue.component('my-component', {
    props: ['title'],
    template: '<h3>{{title}}</h3>'
})

从上面代码中可以看出,在组件实例中,你可以像访问 data 中的值一样访问你自定义的 prop

在使用这个组件时,你可以像这样把数据作为一个自定义 attribute 传递进来:

<my-component title="hello"></my-component>
<my-component title="world"></my-component>

但实际地应用中往往是把 data 中的数据动态地传递给 prop。

<body>
    <div id="app">
        <my-component v-for="item in list" :key="item.id" :title="item.title"></my-component>
    </div>
    <script type="text/javascript">
        Vue.component('my-component', {
            props: ['title'],
            template: '<h3>{{title}}</h3>'
        });
        new Vue({
            el: '#app',
            data() {
                return {
                    list: [
                        { id: 1, title: 'hello' },
                        { id: 2, title: 'world' },
                        { id: 3, title: '你好,世界' },
                    ]
                }
            }
        });
    </script>
</body>

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

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="../lib/vue.js" type="text/javascript" charset="utf-8"></script>
	</head>
	<body>
		<template id="children">
			<div>
				<!-- 第二步:在子组件中可以像使用data中的数据一样使用props中的属性 -->
				<h3>父组件传过来地值:-------{{count}}</h3>
			</div>
		</template>
		<div id="app">
			<!-- 第四步:在使用子组件时,通过属性绑定的方式把父组件的 fathercount值 传递给自组件的 count属性 -->
			<my-component :count="fathercount"></my-component>
		</div>
		<script type="text/javascript">
			Vue.component('my-component', {
				// 第一步:在子组件的props数组中,定义一个count属性(这里的属性是指子组件的属性),
				// 用于接收父组件传过来的值
				props: ['count'],
				template: '#children'
			});
			new Vue({
				el: '#app',
				data() {
					return {
						// 第三步:在父组件data中定义一个值fathercount,用来传递给子组件
						fathercount: 1
					}
				}
			});
		</script>
	</body>
</html>

子组件向父组件传递数据

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="../lib/vue.js" type="text/javascript" charset="utf-8"></script>
	</head>
	<body>
		<template id="children">
			<div>
				<h3>父组件传过来地值:-------{{count}}</h3>
				<!-- 第二步:在子组件模板中定义一个按钮,给按钮添加一个点击事件,点击事件正常调用子组件的方法 -->
				<button type="button" @click="tranToFather">传值给父组件</button>
			</div>
		</template>
		<div id="app">
			<!-- 第一步:通过 v-on 给子组件添加一个自定义的事件 show-love,
			 只要子组件的自定义事件 show-love 触发了,就会调用父组件的方法 getLove -->
			<my-component :count="fathercount" v-on:show-love="getLove"></my-component>
		</div>
		<script type="text/javascript">
			Vue.component('my-component', {
				props: ['count'],
				template: '#children',
				methods: {
					tranToFather() {
						// 第三步:子组件的这个方法通过 $emit 触发自定义的事件 show-love,并把额外的参数传递出去
                        // this 指向的时当前实例 vm
						this.$emit('show-love', 'I love you!')
					}
				}
			});
			new Vue({
				el: '#app',
				data() {
					return {
						fathercount: 1
					}
				},
				methods: {
					// 第四步:父组件的 getLove 方法会接收到子组件自定义事件传出来的额外参数
					getLove(param) {
						console.log(param);
					}
				}
			});
		</script>
	</body>
</html>

第二种写法:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="../lib/vue.js" type="text/javascript" charset="utf-8"></script>
	</head>
	<body>
		<template id="children">
			<div>
				<h3>父组件传过来地值:-------{{count}}</h3>
				<button type="button" @click="tranToFather">传值给父组件</button>
			</div>
		</template>
		<div id="app">
			<my-component :count="fathercount" ref="children"></my-component>
		</div>
		<script type="text/javascript">
			Vue.component('my-component', {
				props: ['count'],
				template: '#children',
				methods: {
					tranToFather() {
						this.$emit('show-love', 'I love you!')
					}
				}
			});
			new Vue({
				el: '#app',
				data() {
					return {
						fathercount: 1
					}
				},
				methods: {
                    // 如果子组件传过来的值有多个,可以使用 getLove(...params) 来接收
					getLove(param) {
						console.log(param);
					}
				},
                mounted() {
                    this.$refs.children.$on('show-love', this.getLove);
                }
			});
		</script>
	</body>
</html>

官方文档上放大字体的例子:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="../lib/vue.js" type="text/javascript" charset="utf-8"></script>
	</head>
	<body>
		<template id="children">
			<div>
				<p>{{item.content}}</p>
				<button @click="largeText">放大字体</button>
			</div>
		</template>
		<div id="app" :style="{ fontSize: fontSize + 'px' }">
			<my-component v-for="item in list" :key="item.id" :item="item" v-on:large-text="fatherLarge"></my-component>
		</div>
		<script type="text/javascript">
			Vue.component('my-component', {
				template: '#children',
				props: ['item'],
				methods: {
					largeText() {
						this.$emit('large-text', 4);
					}
				}
			});
			new Vue({
				el: "#app",
				data() {
					return {
						fontSize: 10,
						list: [
							{ id: 1, content: '长风破浪会有时,直挂云帆济沧海' },
							{ id: 2, content: '非淡泊无以明志,非宁静无以致远' }
						]
					}
				},
				methods: {
					fatherLarge(param) {
						this.fontSize += param;
					}
				}
			});
		</script>
	</body>
</html>

组件模板必须有一个根元素

动态组件

使用 <component> 元素再加上 is 属性可以实现在不同的组件之间切换:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="../lib/vue.js" type="text/javascript" charset="utf-8"></script>
		<style type="text/css">
			ul {
				padding: 0;
				margin: 0;
			}
			li {
				list-style: none;
				display: inline-block;
			}
			button {
				width: 50px;
				height: 30px;
				font-size: 15px;
			}
			.content {
				width: 200px;
				border-radius: 1px;
				border: 1px solid #555;
			}
		</style>
	</head>
	<body>
		<div id="app">
			<div class="container">
				<ul>
					<li v-for="item in list"><button @click="select(item)">{{item}}</button></li>
				</ul>
				<div class="content">
					<component :is="active"></component>
				</div>
			</div>
		</div>
		<script>
			Vue.component('tab1', {
				template: `
					<div>
						<h3>Java</h3>
					</div>
				`
			});
			Vue.component('tab2', {
				template: `
					<div>
						<h3>JavaScript</h3>
					</div>
				`
			});
			Vue.component('tab3', {
				template: `
					<div>
						<h3>Nodejs</h3>
					</div>
				`
			});
			new Vue({
				el: '#app',
				data() {
					return {
						active: 'tab1',
						list: ['tab1', 'tab2', 'tab3']
					}
				},
				methods: {
					select(item) {
						this.active = item;
					}
				}
			});
		</script>
	</body>
</html>