vue.js组件
为什么使用组件?
组件就是一个个的Vue实例,可以重复使用。
组件的构成?
//tagName:是组件名 //options:是组件的配置 Vue.component(tagName, options)
如Vue.filter(参数1,参数2)过滤器本质也是一个组件,参数一是组件的标签(即名字);参数二:是组件的构造器。
组件的基础知识:
- 组件分为:全局组件Vue.component()
和 局部组件Vue.components(); -
因为组件是Vue实例,因此组件中也可以包含data、method、watch等标签;
-
组件的data标签与往常的Vue中的data使用不同,组件中的data必须是一个函数,该函数返回一个对象,
如:data:function(){return msg:"我是一个组件!"}
-
Vue.extend():组件构造器,无法直接使用,相当于vue.component()中的第二个参数。如:
// 创建构造器 var au = Vue.extend({ template: "<p><a :href='url'>{{ author }}</a></p>", data : function() { return { author : 'Li', url : 'http://www.baidu.com' } } }); // 创建组件 Vue.component('au',au); // 注册 new Vue({ el:"#app" })
//也可以创建构造器实例,并将其挂载到一个元素上
new au().$mount('#app'); -
在component组件中可以定义子组件components();
-
在Vue中组件实例的作用域是独立的,默认情况下,父子组件之间的数据是不共享的。
-
子组件获取父组件数据:在子组件中声明props,然后在子组件的模板中进行数据绑定:
<div id="app"> <div> <input v-model="parentMsg"> //将子组件中props声明的message与父组件中的属性parentMsg绑定 <child v-bind:message="parentMsg"></child> </div> </div> <script> // 注册 Vue.component('child', { // 声明 props props: ['message'], // 同样也可以在 vm 实例中像 "this.message" 这样使用 template: '<span>{{ message }}</span>' }) // 创建根实例 new Vue({ el: '#app', data: { parentMsg: '父组件内容' } }) </script>
- props中可以传入任意数量的prop,props可以是数组也可以是对象
<div id="app"> <ol> <todo-item v-for="item in sites" v-bind:todo="item"></todo-item> </ol> </div> <script> Vue.component('todo-item', { props: ['todo'], template: '<li>{{ todo.text }}</li>' }) new Vue({ el: '#app', data: { sites: [ { text: 'Runoob' }, { text: 'Google' }, { text: 'Taobao' } ] } }) </script>
注意:这种传递方式是单向的,使用prosps子组件只能接收父组件的信息,而不能反过来传递给父组件。
-
父组件获取子组件的数据,需要子组件定义一个发送数据的事件,例如:
//准备一个空的实例对象
var Event=new Vue();
//定义A组件 var A={ template:` <div> <span>我是A组件</span> -> {{a}} <input type="button" value="把A数据给父组件" @click="send"> </div> `, methods:{ send(){ Event.$emit('a-msg',this.a); } }, data(){ return { a:'我是a数据' } } }; //父组件接收A组件数据 { template:` <div> <span>接收过来的A的数据为: {{a}}</span> </div> `, data(){ return { a:'' } }, mounted(){ var _this = this; //接收A组件的数据 Event.$on('a-msg',function(a){ _this.a=a; }); //另一种方式接收 Event.$on('a-msg',function(a){ this.a=a; }.bind(this)); } };
//步骤总结:- 准备一个空的实例对象 var Event=new Vue();
- 发送数据 Event.$emit(事件名称, 数据)
- 接收数据 Event.$on(事件名称,function(data){ }.bind(this));
- 父子组件之间数据传递结论:父向子组件传递数据,是通过属性绑定的形式,父数据改变,子也会随之改变;
而子向父传递数据是通过emit的方法,需要事件驱动,若没有触发事件,则子数据改变,父组件的数据并不会有变化(事件驱动的通信方式适合爷孙、兄弟组件之间的通信)。
- 通过对象引用的方式,也可以实现子组件的改变同步到父组件
<body> <template id="child"> <div> <span>我是子组件</span> <input type="button" value="按钮" @click="change"> <strong>{{msg.a}}</strong> </div> </template> <div id="box"> 父级: ->{{giveData.a}} <child-com :msg="giveData"></child-com> </div> <script> new Vue({ el:'#box', data:{ giveData:{ a:'我是父组件数据' } }, components:{ 'child-com':{
//这里msg与父组件的giveData对象完成了绑定 props:['msg'], template:'#child', methods:{ change(){ this.msg.a='被改了'; } } } } }); </script> </body> - 父组件访问子组件使用 $children或$ref
//$children返回所有子组件的实例,是一个数组 new Vue({ el: '#count', data: {}, methods: { showmsg () { for(var i = 0; i < this.$children.length; i++) { alert(this.$children[i].msg) } } } })
$ref :有时候组件过多的话,就很记清各个组件的顺序与位置,所以通过给子组件一个索引ID
<div id="count"> <button @click="showmsg"> 显示两个组件的信息 </button> //给组件加索引 <child1 ref='c1'></child1> <child2 ref='c2'></child2> </div> new Vue({ el: '#count', data: {}, methods: { showmsg () { alert(this.$refs.c1.msg) alert(this.$refs.c2.msg) } } })
-
子组件访问父组件 $parent
Vue.component('child1', { template: '#child1', data () { return { msg: '这是子组件1的信息' } }, methods: { showpmsg () { //访问父组件的msg属性 alert(this.$parent.msg) } } })
-
子组件访问根组件 $root
methods: { showroot () { //访问跟组件的msg属性 alert(this.$root.msg) } } })
-
当在父组件的template中编写子组件的数据时,该内容是默认消失的,例如;
<template id="aaa"> <div class="parent"> <p>父组件</p> <bbb> <p>测试内容1</p> <p>测试内容2</p> <p>测试内容3</p> </bbb> </div> </template> //bbb组件中的内容是不会显示的
要想保存该部分内容,需要使用插槽标签slot,这样在父组件中的子组件信息都想插入到子组件中定义插槽的位置。
注意:该匿名slot标签只能使用有一次,多个slot会导致程序错误。
- 除了匿名slot,还有实名slot
<template id="aaa"> <div class="parent"> <p>父组件</p> <bbb> <p slot="my-header">我是头部</p> <p slot="my-footer">我是尾部</p> <p>我是主体</p> </bbb> </div> </template> //可以在子组件中定义实名slot <slot name="my-header">头部默认值</slot> <slot name="my-body">主体默认值</slot> <slot name="my-footer">尾部默认值</slot>