组件是什么?有什么作用?
这几天一直在看《vue.js实战》这本书,一直卡在组件这一章节,的确像作者说的那样,组件是vue.js的核心知识,同时也是最难的地方,从书中暂时只是了解到组件可以实现模板的复用,但是具体的用处还不是很理解。
今天终于看懂了一些知识,先记下来!!!
在vue中声明的组件,需要注册才能被使用,在vue中组件有两种注册方式,分为全局注册和局部注册。
那么,全局注册和局部注册有什么区别呢?
在全局注册的组件可以被所有的实例访问,但是局部注册的组件只能被在注册的实例中使用,所以作用域不同!
如何来实现全局注册和局部注册?
假设已有:
<div id="app">
<my-component></my-component>
</div>
(1)全局注册:
Vue.component('my-component',{
template:'<div>这是my-component组件</div>'
});
var app=new Vue({
el:'#app'
})
全局注册通过Vue.component()来实现
(2)局部注册:
var app=new Vue({
el:'#app',
components:{
'my-component':{
template:'<div>这是通过局部注册的组件</div>'
}
}
})
上面也可改成下列的写法:
myComponent={
template:'<div>这是局部注册组件的另一种写法</div>'
}
var app=new Vue({
el:'#app',
components:{
'my-component':myComponent
}
})
注意局部注册的组件中是components,需要加上"s"
以上两种注册方式都会被vue渲染成下列的形式:
<div id="app">
<div>...(组件中的内容)</div>
</div>
注意在模板中,如果不止有一个标签,那么外部需要通过一个<div></div>标签将其包裹起来!
如:
//组件的全局声明
Vue.component('my-component',{
template:'<div><div>{{count}}</div><button @click="up">点击加1</button></div>',
data:function(){
return {
count:0
}
},
methods:{
up:function(){
this.count++;
}
}
});
这种会被渲染为:
<div id="app">
<div>
<div></div>
<button></button>
</div>
</div>
如果写成下列的形式,则不会被渲染:
//组件的全局声明
Vue.component('my-component',{
template:'<div>{{count}}</div><button @click="up">点击加1</button>',
data:function(){
return {
count:0
}
},
methods:{
up:function(){
this.count++;
}
}
});
那么如何理解全局注册和局部注册的区别呢?下面来讲一下我的理解,先贴出代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<my-component></my-component>
</div>
<div id="app2">
<my-component></my-component>
</div>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script>
Vue.component('my-component',{
template:'<div>这是通过全局注册的组件</div>'
})
var app=new Vue({
el:'#app'
});
var app=new Vue({
el:'#app2'
})
</script>
</body>
</html>
上面的代码中,通过全局注册的组件,在app和app2都可以使用,这里只是通过全局注册了一次!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<my-component></my-component>
</div>
<div id="app2">
<my-component></my-component>
</div>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script>
var myComponent={
template:'<div>这是通过局部注册的组件</div>'
};
var app=new Vue({
el:'#app',
components:{
'my-component':myComponent
}
});
var app2=new Vue({
el:'#app2',
components:{
'my-component':myComponent
}
})
</script>
</body>
</html>
以上的局部注册中可以看出,要在app和app2中使用组件,需要通过components分别在各自的实例中进行声明!每使用一次需要声明一次!
其实到最后才开始发现在组件里的写法和vue实例的写法有些相似,在书本中作者也提到了,但是却没有一开始就发现,这个就是看书的时候不用心吧,怪不得要多读几遍才能知道!!!
所以之后可以通过对比来理解组件的知识
在这里还需要注意的是:
在组件中声明的data需要通过函数来实现,如下:
//组件的全局声明
Vue.component('my-component',{
template:'<div><div>{{count}}</div><button @click="up">点击加1</button></div>',
data:function(){
return {
count:0
}
},
methods:{
up:function(){
this.count++;
}
}
});
这里再加点关于父子组件通信的一些知识,关于组件通信,这部分估计还需要再写一篇博文,因为通信部分有点复杂
刚刚还在想能不能通过vue实例中的data属性来给组件中模板的{{msg}}来赋值,结果不行,但是还未弄懂是什么原因,现在好像有点眉目了,实例可以看作是里面组件的父组件,data选项不能直接操作组件的数据,只能通过props来传递,而组件中的data选项可以直接操作自己数据(可能自己的理解不是很对,如果错了,希望大家能指正以下)
下面开始举例来讲解:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<my-component></my-component>
</div>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
var app=new Vue({
el:'#app',
components:{
'my-component':{
template:'<div>{{message}}</div>',
data:function(){
return {
message:'这是来自组件中的数据'
}
}
}
}
})
</script>
</body>
</html>
这里组件可以通过自己的data选项传输数据
如果直接通过实例传递,则会出现以下情况,这里不知道有没有直接联系(如果大家知道也麻烦告知一下)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<my-component></my-component>
</div>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
var app=new Vue({
el:'#app',
components:{
'my-component':{
template:'<div>{{message}}</div>'
}
},
data:{
message:'这是来自实例的数据'
}
})
</script>
</body>
</html>
那么如果要将这个msg从实例中传递过来要如何做呢?就要通过props来实现了,如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<my-component :message="msg"></my-component>
</div>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
var app=new Vue({
el:'#app',
components: {
'my-component': {
template: '<div>{{message}}</div>',
props: ['message']
}
},
data:{
msg:'这是来自实例的数据'
}
})
</script>
</body>
</html>
这里是通过动态渲染数据,通过v-bind来动态绑定props的值,可以实时根据父级的数据动态渲染。
如果只是静态渲染父级的数据的话,就可以借鉴下面的写法:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<my-component warning-text="提示信息"></my-component>
</div>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
var app=new Vue({
el:"#app",
components:{
'my-component':{
template:'<div>{{warningText}}</div>',
props:['warningText']
}
}
});
</script>
</body>
</html>
这里需要注意的是:在html中,不区分大小写,如果在props中采用驼峰命名法,则在组件中需要使用"-"来相应改变。
这里还需要注意的是:如果要直接传递数字、布尔值、数组、对象,如果不使用v-bind,传递的仅是字符串,这里举书中例子:
<div id="app">
<my-component message="[1,2,3]"></my-component>
<my-component :message="[1,2,3]"></my-component>
</div>
<script>
Vue.component('my-component',{
template:'<div>{{message.length}}</div>',
props:['message']
});
var app=new Vue({
el:'#app'
})
</script>
第一个没有使用v-bind,所以渲染后是7(字符串的长度),第二个由于使用了v-bind,所以渲染后是3(数组的长度)
这里再加一点props的知识,props有两种值,一种是字符串数组,一种是对象,可以通过书中的数据验正例子来了解下:
对于书中数据验证的使用我还不是很清楚,这里改天遇到了再来补充!
Vue.component('my-component',{
props:{
//必须是数字类型
propA:Number,
//必须是字符串或数字类型
propB:[String,Number],
//布尔值,如果没有定义,默认值是true
propC:{
type:Boolean,
default:true
},
//数字,且必传
propD:{
type:Number,
required:true
},
//如果是数组,默认值必须返回一个函数
propE:{
type:Array,
default:function(){
return [];
}
},
//自定义一个验证函数
propF:{
validator:function(value){
return value>10;
}
}
}
})
书中作者提到当自己的组件需要提供给别人使用的时候,推荐进行数据验证。
验证的类型有:String、Number、Boolean、Object、Array、Function或者自定义构造器
注意:通过props传递的数据是单向的,即父组件数据变化时会传递给子组件,但是反过来不行,但是在业务中会需要改变props的情况,作者举了两个常见的情况:
1)父组件传递初始值进来后,子组件将其作为初始值保存,然后在自己的作用域下随意使用和修改
2)props作为需要被转变的原始值传入
这里就不再写作者的例子了,等自己做项目遇到再另写一篇。
为什么子组件修改数据会改变父组件呢?这个是因为props是数组或对象,这两种在js中是引用类型,这里如果不知道引用类型是什么或者其特点,就自行百度吧,暂时写到这里了~