组件的介绍
全局组件
使用Vue.component进行全局注册,所有vue实例都会共享此组件
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
1 <div id="app">
2 {{msg}}
3 <const-comp></const-comp>
4
5 </div>
6 <script>
7
8 Vue.component('constComp', {
9 template: "<h3>我是全局组件</h3>"
10
11 });
12
13 new Vue({
14 el: "#app",
15 data: {
16 msg: "hello component"
17 }
18 });
19
20 </script>
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
局部组件
局部组件只能在引入当前的vue实例中有效,在当前vue实例中components属性加上引入进来的组件实例即可
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
<div id="app">
{{msg}}
<!-- <const-comp></const-comp> -->
<local-comp></local-comp>
</div>
<script>
/*Vue.component('constComp', {
template: "<h3>我是全局组件</h3>"
});*/
let localComp = {
template: "<div>我是局部组件</div>"
};
new Vue({
el: "#app",
data: {
msg: "hello component"
},
components: {
localComp
}
});
</script>
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
单文件组件(xxx.vue)
其实就是将写在js中的组件提出到一个vue文件中写而已,这样组件更加的好维护以及阅读性也会好,提取出来了相应的引入即可,不会显得文件很多行很长。
其主要有<template></template><script></script><style></style>这三个标签,每个标签做自己的事。template就像我们在html中写dom,script写js代码当前的组件实例,style写组件样式,注意:加上scoped即可使当前样式只在当前组件生效,组件渲染的时候此组件的dom会加上data-v-xxx属性来选择当前组件样式。如果没加上scoped的话当前组件的样式就会在引入这个组件的实例中造成影响
如我写的一个found.vue文件demo
View Code
组件的通信
vue组件的通信是vue组件的核心,组件不仅仅是要把模板的内容进行复用;更主要的是组件间要进行通信;组件之间的通信数据传递是组件的生命力之一。
props单向数据流,父组件向子组件传递数据
props可以是一个数据类型也可以是一个数组,也可以是对象,对象下的数据有3个属性type,default,require。其中default,require值都是布尔类型值。type有Number,String,Boolean,Array,Object,Function,Symbol。如果props数据是对象或数组时默认值default必须是一个函数来返回初始化数据。而且因为对象或数据是引用类型,指向的是同一个内存空间所以当props数据是这两个类型时,数据改变时子组件内改变是会影响父组件的。
props数据类型及相关样例
View Code
这里稍微改动一下局部组件的代码,父组件向子组件传递数据;
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
1 <div id="app">
2 {{msg}}
3 <!-- <const-comp></const-comp> -->
4 <local-comp :props-a="info"></local-comp>
5 </div>
6 <script>
7
8 /*Vue.component('constComp', {
9 template: "<h3>我是全局组件</h3>"
10
11 });*/
12 let localComp = {
13 template: "<div>我是局部组件<p>父组件传过来的数据为-->{{propsA}}</p></div>",
14 props: {
15 propsA: {
16 type: String,
17 default: "",
18 require: true
19 }
20 }
21 };
22 new Vue({
23 el: "#app",
24 data: {
25 msg: "hello component",
26 info: "hello props"
27 },
28 components: {
29 localComp
30 }
31 });
32
33 </script>
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
自定义事件$emit,子组件向父组件通信
这里还是在原来的基础上改,子组件使用$emit自定义一个send事件向父组件发送数据
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
1 <div id="app">
2 {{msg}}
3 <!-- <const-comp></const-comp> -->
4 <div>子组件数据为---->{{fromChildData}}</div>
5 <local-comp :props-a="info" @send="getChildData"></local-comp>
6 </div>
7 <script>
8
9 /*Vue.component('constComp', {
10 template: "<h3>我是全局组件</h3>"
11
12 });*/
13 let localComp = {
14 template: "<div>我是局部组件\
15 <p>父组件传过来的数据为-->{{propsA}}</p>\
16 <button @click='sendMsg'>使用$emit子组件向父组件传递事件</button>\
17 </div>",
18 props: {
19 propsA: {
20 type: String,
21 default: "",
22 require: true
23 }
24 },
25 data() {
26 return {
27 msg: "子组件数据"
28 }
29 },
30 methods: {
31 sendMsg(evt) {
32 this.$emit('send', this.msg);
33 }
34 }
35 };
36 new Vue({
37 el: "#app",
38 data: {
39 msg: "hello component",
40 info: "hello props",
41 fromChildData: ""
42 },
43 components: {
44 localComp
45 },
46 methods: {
47 getChildData(val) {
48 this.fromChildData = val
49 }
50 }
51 });
52
53 </script>
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
非子父组件通信,使用一个空的Vue实例作为一个事件总线监听数据变化
这种场景用于组件之间不为子父层级关系的时候相关通信,我们使用的那个空vue实例里也可以放vue的属性。用这个空的vue实例来$emit自定义一个事件然后再用这个实例来$on监听自定义事件,从而达到非子父组件之间的通信。(PS:这里暂时不讨论vuex),看demo代码。demo例子使用了ref组件索引。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
<div id="app">
{{message}}
<component-a ref="a"></component-a>
<component-a ref="b"></component-a>
</div>
<script>
const bus = new Vue({});
Vue.component('component-a', {
data () {
return {
msg: 1
}
},
template: '<button @click="handleEvent">传递事件</button>',
methods: {
handleEvent () {
bus.$emit('on-message', '来自组件 com-a 的内容');
}
}
});
const app = new Vue({
el: '#app',
data: {
message: ''
},
mounted () {
bus.$on('on-message', (msg) => {
this.message = msg;
});
this.$children.msg = 2;
}
})
</script>
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
slot组件内容分发
单个就默认slot,多个使用具名slot,$slots访问对应slot,vue2.0新增;因为vue2使用render函数来渲染,所以需要使用this.$slots来访问slot。this.$slots.xxx访问具体的slot,即slot中name指定的值 值类型{ [name: string]: ?Array<VNode> }
如果需要给slot添加默认内容的时候直接在slot上写就可以了,这个时候默认的slot内容所在的作用域就是其所在的组件实例,可以根据其所在的组件来控制slot默认的内容展示如:<slot>{{msg}}</slot>。如果没有指定默认数据的话slot内容根据其父组件所在的作用域。
当 vue 组件中当需要组件混合使用的时候需要用到内容分发,内容不确定的时候需要用到slot内容分发。
看demo代码;
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
1 <div id="app">
2 <com-out>
3 <div slot="b">{{msgB}}</div>
4 <div slot="a">{{msgA}}</div>
5
6 </com-out>
7 </div>
8 <template id="co">
9 <div>
10 hello
11 <slot name="a"></slot>
12 <slot name="b"></slot>
13 </div>
14 </template>
15 <script>
16 Vue.component('com-out', {
17 template: "#co",
18 mounted() {
19 console.log("com-out slot" + this.$slots.a[0]);
20 }
21 });
22 new Vue({
23 el: "#app",
24 data: {
25 msgA: '父组件数据a',
26 msgB: '父组件数据b'
27 }
28 })
29 </script>
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
递归组件
递归组件要记住两点:
1.递归组件必须要给组件设置name。
2.要在一个合适的时间(条件)跳出递归否则会报栈溢出异常。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
1 <div id="app">
2 <com :count="1"></com>
3 </div>
4 <template id="cr">
5 <div><com :count="count + 1" v-if="count < 3"></com>{{count}}</div>
6 </template>
7 <script>
8 Vue.component('com', {
9 name: 'comr',
10 template: "#cr",
11 props: {
12 count: {
13 type: Number,
14 default: 1
15 }
16 }
17 })
18 new Vue({
19 el: '#app'
20 })
21
22
23 </script>
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
动态组件
vue动态组件其实就是在组件中使用:is属性根据值来判断显示哪个组件。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
1 <div id="app">
2 <button @click="changeCom">点击让子组件显示</button>
3 <com v-bind:is="activeCom"></com>
4 </div>
5 <script>
6 new Vue({
7 el: '#app',
8 data: {
9 activeCom: "comA"
10 },
11 methods: {
12 changeCom: function () {
13 let arr = ["comA", "comB", "comC"], index;
14 index = Math.ceil(Math.random()*arr.length);
15 this.activeCom = arr[index];
16 }
17 },
18 components: {
19 comA: {
20 template: "<div>组件comA</div>"
21 },
22 comB: {
23 template: "<div>组件comB</div>"
24 },
25 comC: {
26 template: "<div>组件comC</div>"
27 },
28 }
29 });
30 </script>
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
异步组件
异步组件在性能上有一定的优势,不仅加快了渲染时间也减少了不必要的加载;在路由中经常用到
看demo;
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
<div id="app">
<child-component></child-component>
</div>
<script>
Vue.component('child-component', function (resolve, reject) {
window.setTimeout(function () {
resolve({
template: '<div>异步组件的内容</div>'
})
}, 2000)
});
new Vue({
el: '#app'
})
</script>
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
在路由中异步组件可以这样用:
1 {
2 path:"/路由地址",
3 name:"routeName",
4 component: resolve => require(["../components/xxx.vue"], resolve)
5 }