目录
四、组件传值 1、父组件向子组件传递数据prop 2、父组件向子组件传递方法、子组件向父组件传值
组件:为了拆分Vue实例的代码量,以不同的组件划分不同的功能模块。
模块化:代码逻辑的角度,方便代码分层开发,保证每个功能模块的职能单一。
组件化:UI界面的角度,前端的组件化,方便UI组件的重用。
一、组件注册
使用组件时,直接把组件的名称,以HTML标签的形式引入到页面中。
组件名称可以是用短横线分隔或驼峰式,但是HTML标签均使用短横线分隔、字母全小写形式。推荐组件名“必须包含一个连字符”,避免和未来的HTML元素冲突。
<div id="app">
<my-com></my-com>
</div>
组件模板对象的template属性是组件要展示的HTML内容,该内容必须有且只能有一个根元素。
1、全局注册
全局注册,在注册之后可以用在任何新创建的Vue根实例的模板中,包括组件在各自内部可以互相使用。
Vue.component('my-component-name', 创建出来的组件模板对象);
(1)Vue.component
Vue.component('myCom',{
template:'<h3>模板字符串</h3>'
});
(2)组件模板对象+Vue.component
var myCom={
template:'<h3>模板字符串</h3>'
};
Vue.component('my-com',myCom);
(3)Vue.extend+Vue.component
var com=Vue.extend({
template:'<h3>模板字符串</h3>'
});
Vue.component('myCom',com);
(4)<template>+Vue.component
<!-- 在被控制的#app外面,使用template元素,定义组件的HTML模板结构,有代码提示和高亮 -->
<template id="tmp">
<h3>模板字符串</h3>
</template>
Vue.component('myCom',{
template:'#tmp'
});
(5)<script>+Vue.component
<script id="tmp" type="x-template">
<h3>模板字符串</h3>
</script>
Vue.component('myCom',{
template:'#tmp'
});
2、局部注册
局部注册的组件互相之间不可用。
局部注册的形式参考全局注册,对于(2),当组件模板对象的名称和组件名称相同时,可简化写法components:{myCom},表示该属性名和属性值相同。
var vm=new Vue({
el:'#app',
components:{
'component-a':{
template:"<div><h2>私有组件a</h2><component-sub></component-sub></div>", // 使用子组件
components:{ // 定义子组件的子组件
'component-sub':{
template:"<h3>私有组件a中的子组件c</h3>"
}
}
},
'component-b':{
template:"<h2>私有组件b</h2>"
}
}
});
二、data
组件是可复用的 Vue 实例,与new Vue接收相同的选项,如data、computed、watch、methods及生命周期钩子等。仅有的例外是像el这样根实例特有的选项。
组件的data和实例的data不同,组件的data必须是一个函数,必须返回一个对象。每个实例可以维护一份被返回对象的独立的拷贝。
Vue.component('mycom',{
template:'<h3>--{{msg}}--</h3>',
data:function(){
return {
msg:'我是组件中的data数据'
}
}
});
<counter></counter>
<counter></counter>
var obj={count:0}; //此时所有实例共享同一个对象
Vue.component('counter',{
template:'<div><button @click="increment">+1</button><h3>{{count}}</h3></div>',
data:function(){
return obj
},
methods:{
increment(){
this.count++;
}
}
});
三、组件动态切换
1、使用flag标识符结合v-if和v-else切换组件
<div id="app">
<a href="#" @click.prevent="flag=true">登录</a>
<a href="#" @click.prevent="flag=false">注册</a>
<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>
2、使用is属性来切换不同的子组件,并添加切换动画
Vue提供了<component>加is属性,来展示对应名称的组件。is可以绑定已注册组件的名称,或一个组件的选项对象。
<div id="app">
<a href="#" @click.prevent="comName='login'">登录</a>
<a href="#" @click.prevent="comName='register'">注册</a>
<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:'login'
}
});
</script>
使用<transition>实现多个组件之间的过渡。
mode属性指定过渡模式,默认进入和离开同时发生。mode的值有两个:in-out,新元素先进行过渡,完成之后当前元素过渡离开;out-in,当前元素先进行过渡,完成之后新元素过渡进入。
<transition mode="out-in">
<component :is="comName"></component>
</transition>
四、组件传值
子组件中,默认无法访问到父组件data上的数据和methods中的方法。
1、父组件向子组件传递数据prop
(1)绑定
在父组件中引用子组件时,通过属性绑定(v-bind)的形式给子组件传递数据。
可以绑定静态的值或动态的值。
任何类型的值都可以传给一个prop,包括数字、布尔值、数组、对象、对象的属性等。
HTML中的特性名是大小写不敏感的,驼峰命名的prop名需要使用其等价的短横线分隔命名。如果你使用字符串模板,那么这个限制就不存在了。
<div id="app">
<sub-com title="My journey with Vue"></sub-com> <!--绑定静态的值-->
</div>
<div id="app">
<sub-com :fathermsg="msg"></sub-com> <!--绑定动态的值,来自父组件-->
</div>
(2)prop
prop是可以在组件上注册的一些自定义特性。当一个值传递给一个prop特性时,它就变成了该组件实例的一个属性,就可以在该组件中使用该数据。
var vm=new Vue({
el:'#app',
data:{
msg:"Blogging with Vue"
},
components:{
subCom:{
template:'<h3>这是子组件 "{{fathermsg}}"是来自父组件的数据</h3>',
props:['fathermsg','title']
}
}
});
子组件的data数据是子组件私有的,如子组件通过 Ajax请求回来的数据,都可以放到 data 上,是可读可写的。组件props中的数据,是父组件传递的,都是只读的,无法重新赋值。
2、父组件向子组件传递方法、子组件向父组件传值
(1)绑定
在父组件中引用子组件时,通过事件绑定(v-on)的形式给子组件传递方法。
事件名不存在任何自动化的大小写转换,不存在驼峰和短横线命名的转换。不同于组件和 prop,事件名不会被用作一个JavaScript变量名或属性名;v-on事件监听器在DOM模板中会被自动转换为全小写,因为HTML是大小写不敏感的。推荐始终使用短横线命名的方式。
<div id="app">
<sub-com @fathershow="show"></sub-com>
</div>
(2)在子组件中触发父组件的事件$emit()
在子组件的HTML中,直接使用$emit();在子组件的方法中,使用this.$emit()。
<template id='subtmp'>
<button @click="$emit('fathershow','第二个参数');">触发父组件的show方法</button>
</template>
var vm=new Vue({
el:'#app',
methods:{
show(data){
console.log('父组件的show方法'+data);
}
},
components:{
subCom:{
template:'#subtmp'
}
}
});
(3)向父组件传值
$emit()的第二个参数及之后的参数,作为父组件事件的参数,向父组件传值。
五、插槽slot
和HTML元素一样,经常需要向一个组件传递内容。Vue自定义的<slot>元素让这变得非常简单,只要在需要的地方加入插槽。
Vue.component('alert-box', {
template: `
<div class="demo-alert-box">
<strong>Hello!</strong>
<slot></slot>
</div>
`
})
插槽内可以包含任何模板代码,包括HTML、其它组件等。
<alert-box>
Something good happened.
</alert-box>
<navigation-link url="/profile">
<!-- 添加一个图标的组件 -->
<font-awesome-icon name="user"></font-awesome-icon>
Your Profile
</navigation-link>
六、处理边界情况
(1)获取DOM元素和组件引用
通过ref特性为HTML元素或组件赋予一个ID引用。
使用this.$refs.input可操作该DOM元素,使用this.$refs.mycom可访问该组件实例,使用其中的数据和方法等。
<input ref="input">
<my-com ref="mycom"></my-com>