组件是可复用的 Vue 实例,且带有一个名字。因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。
组件构造器内需要一个template属性来存放组件模板
const zj=vue.extends({
template:'<div>你好,我是组件内容</div>'
})
Vue.component('组件名称',组件构造器)
Vue.component('nzj',zj)
组件的使用通过组件名称为标签来调用
<nzj></nzj>
在新版本vue中,可以直接注册组件
Vue.component('nzj2',{
template:'<div>你好,我是直接注册组件内容</div>'
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue 创建组件</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<nzj></nzj>
<nzj></nzj>
<nzj2></nzj2>
</div>
<script>
const zj=Vue.extend({
template:'<div>你好,我是组件内容</div>'
})
Vue.component('nzj',zj)
Vue.component('nzj2',{
template:'<div>你好,我是直接注册组件内容</div>'
})
let ndata={
};
const app=new Vue({
el:"#app",
data:ndata
});
</script>
</body>
</html>
在vue实例之外注册的组件,为全局组件,可以在多个vue实例内使用,在vue实例内注册的组件为局部组件,只能在当前vue实例内使用。局部组件注册使用 components 属性。
const jb={
template:'<div>你好,我是局部组件内容</div>'
}
components:{
nzj:zj,
nzj2:{template:'<div>你好,我是直接注册组件内容</div>'},
nzj3:jb
}
上面3种方式均可注册局部组件(子组件)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue 局部组件</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<nzj></nzj>
<nzj></nzj>
<nzj2></nzj2>
</div>
<script>
const zj=Vue.extend({
template:'<div>你好,我是组件内容</div>'
})
const jb={
template:'<div>你好,我是局部组件内容</div>'
}
const app=new Vue({
el:"#app",
components:{
nzj:zj,
nzj2:{template:'<div>你好,我是直接注册组件内容</div>'},
nzj3:jb
}
});
</script>
</body>
</html>
在一个组件内的 components 属性下注册另一个组件,就会形成父子组件。
TIP:全局组件独立存在,没有父组件。
Vue.component('zj1',{
template:'<div>我是组件1-<zj2></zj2></div>',
components:{
zj2:{template:'<div>我是子组件</div>'}
}
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue 父子组件</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<zj1></zj1>
</div>
<script>
Vue.component('zj1',{
template:'<div>我是组件1-<zj2></zj2></div>',
components:{
zj2:{template:'<div>我是子组件</div>'}
}
})
const app=new Vue({
el:"#app",
data:{}
});
</script>
</body>
</html>
1. 使用 script type="text/x-template" 来创建模板,然后在组件 template 里置顶模板ID来达到分离模板的目的
<script type="text/x-template" id="mb1">
<div>这里是mb1的内容</div>
</script>
Vue.component('zj1',{
template:'#mb1'
})
2. 使用 template 标签来创建模板
<template id="mb2">
<div>这里是template标签的mb2内容</div>
</template>
Vue.component('zj2',{
template:'#mb2'
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue 模板分离</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<zj1></zj1>
<zj2></zj2>
</div>
<script type="text/x-template" id="mb1">
<div>这里是mb1的内容</div>
</script>
<template id="mb2">
<div>这里是template标签的mb2内容</div>
</template>
<script>
Vue.component('zj1',{
template:'#mb1'
})
Vue.component('zj2',{
template:'#mb2'
})
const app=new Vue({
el:"#app",
data:{}
});
</script>
</body>
</html>
组件中数据存放在自己的 data 函数里,组件的 data 不能是对象,只能以函数方式出现。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue 组件数据存放</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="app">
<zj1></zj1>
</div>
<template id="mb1">
<div>{{name}}</div>
</template>
<script>
Vue.component('zj1',{
template:'#mb1',
data(){
return{
name:'你好'
}
}
})
const app=new Vue({
el:"#app",
data:{}
});
</script>
</body>
</html>
在我们开发组件时,它的一些功能可能要求我们和父级组件进行沟通。
<div id="app">
<zj1 :zname="name"></zj1>
</div>
<template id="mb1">
<div>{{zname}}</div>
</template>
const zj={
template:'#mb1',
props:['zname']
}
const app=new Vue({
el:"#app",
data:{
name:'张三'
},
components:{
zj1:zj
}
});
上面父组件vue内的数据name 被子组件内的zname绑定并输出。
父组件向子组件传递数据,在其子组件中,我们可以通过给子组件添加一个 props 属性来支持这个功能。在调用是使用 v-bind 的方式绑定父组件的数据。
1.数组方式
props:['zname']
2.对象方式
指定变量类型,如果传入参数类型不符,会有报错
props:{zname:String}
props:{zname:[String,Number]}
参数为对象,设置默认值和必选选项
props:{zname:{type:String,default:'默认值',required:true}}
props:{zname:{type:array,default(){return ['默认值']}}}
required 为 true 时,必须传值,否则报错
type 类型为 array 和 object 时,默认值必须是个函数返回。否则报错
props 中定义的变量名,尽量使用小写,如果使用驼峰命名,由于 v-bind 不支持,就必须要转换为 “-” 连接的名称。否则不识别。
props:['zName']
<div :z-name="name">{{zName}}</div>
上面代码中 props 里的 zName 驼峰命名法,在v-bind中只能使用 “z-name” 的方式绑定。
子组件可以通过调用内建的 $emit 方法并传入事件名及数据。
//zm(){
// this.$emit('事件名','子组件数据');
//}
zm(){
this.$emit('fms','子组件数据');
}
并在模板中绑定该函数
<template id="mb1">
<button @click="zm">{{zname}}</button>
</template>
最后在调用标签上将事件名绑定到父组件的函数名上即可
<zj1 :zname="name" @fms="fm"></zj1>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue 父子组件通信</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<zj1 :zname="name" @fms="fm"></zj1>
</div>
<template id="mb1">
<button @click="zm">{{zname}}</button>
</template>
<script>
const zj={
template:'#mb1',
props:['zname'],
methods:{
zm(){
this.$emit('fms','子组件数据');
}
}
}
const app=new Vue({
el:"#app",
data:{
name:'张三'
},
components:{
zj1:zj
},
methods:{
fm(value){
console.log(value);
}
}
});
</script>
</body>
</html>
尽管存在 prop 和事件,有的时候你仍可能需要在 JavaScript 里直接访问一个子组件。为了达到这个目的,你可以通过 ref 这个属性为子组件赋予一个 ID 引用。
TIP:$refs 只会在组件渲染完成之后生效,并且它们不是响应式的。这仅作为一个用于直接操作子组件的“逃生舱”——你应该避免在模板或计算属性中访问 $refs。
<div id="app">
<div>
<zj ref="zj1"></zj>
<button @click="dy">打印</button>
</div>
</div>
<script>
const app=new Vue({
el:"#app",
data:{},
components:{
zj:{
template:'#zj',
data(){
return {
zj_name:'zjname',
}
}
}
},
methods:{
dy(){
console.log(this.$refs.zj1.zj_name);
}
}
});
</script>
可以直接通过下标调用当前实例的子组件。需要注意 $children 并不保证顺序,也不是响应式的。如果你发现自己正在尝试使用 $children 来进行数据绑定,考虑使用一个数组配合 v-for 来生成子组件,并且使用 Array 作为真正的来源。一般推荐使用ref方式来调用。
<div id="app">
<div>
<zj></zj>
<zj></zj>
<button @click="dy2">打印第2个zj组件的名称</button>
</div>
</div>
<script>
const app=new Vue({
el:"#app",
data:{},
components:{
zj:{
template:'#zj',
data(){
return {
zj_name:'zjname',
}
}
}
},
methods:{
dy2(){
console.log(this.$children[1].zj_name);
}
}
});
</script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue 子组件访问</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<div>
<zj></zj>
<zj></zj>
<zj ref="zj1"></zj>
<button @click="dy">打印ref指定的子组件名称</button>
<button @click="dy2">打印第2个zj组件的名称</button>
</div>
</div>
<template id="zj">
<div>
我是子组件-{{zj_name}}
</div>
</template>
<script>
const app=new Vue({
el:"#app",
data:{},
components:{
zj:{
template:'#zj',
data(){
return {
zj_name:'zjname',
}
}
}
},
methods:{
dy(){
console.log(this.$refs.zj1.zj_name);
},
dy2(){
console.log(this.$children[1].zj_name);
}
}
});
</script>
</body>
</html>
子实例可以用 this.$parent 访问父实例,同时子实例被推入父实例的 $children 数组中。
TIP:节制地使用 $parent 和 $children - 它们的主要目的是作为访问组件的应急方法。更推荐用 props 和 events 实现父子组件通信
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue 父组件访问</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="app">
<zj></zj>
</div>
<template id="zj">
<div>
子组件的名称是:{{zj_name}} <br>
我的父组件名称是:{{fzj_name2}}
</div>
</template>
<script>
const app=new Vue({
el:"#app",
data:{
fzj_name:'叫爸爸'
},
components:{
zj:{
template:'#zj',
data(){
return {
zj_name:'子组件名称',
fzj_name2:this.$parent.fzj_name
}
}
}
}
});
</script>
</body>
</html>
使用 $root 访问当前组件树的根 Vue 实例。如果当前实例没有父实例,此实例将会是其自己。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue 根组件访问</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<zj></zj>
</div>
<template id="zj">
<div>
我是子组件我的根组件是{{rootname}}
</div>
</template>
<script>
const app=new Vue({
el:"#app",
data:{
fzj_name:'叫爸爸'
},
components:{
zj:{
template:'#zj',
data(){
return {
rootname:this.$root.fzj_name
}
}
}
}
});
</script>
</body>
</html>