1.注册组件的基本步骤
(1)创建组件构造器
调用Vue.extend()方法,创建组件构造器
(2)注册组件
调用Vue.component()方法,注册组件
(3)使用组件
在Vue实例的作用范围内使用组件
<div id="app">
//3.使用组件
<my-cpn></my-cpn>
</div>
<script type="text/javascript">
//ES6 ``可换行
//1.创建组件构造器
const cpn = Vue.extend({
template:`
<div>
<h2>我是标题</h2>
<p>我是内容1</p>
<p>我是内容2</p>
</div>
`
})
//2.注册组件(全局组件)
Vue.component('my-cpn',cpn)
</script>
2.注册组件步骤解析
image.png
image.png
3.全局组件和局部组件
(1)全局组件(见如上代码)
(2)局部组件
只能在id为app的div中使用
const app = new Vue({
el:'#app',
data:{
message:'你好啊'
},
components:{
// cpn使用组件时的标签名
cpn: cpn
}
})
4.父组件与子组件
<script type="text/javascript">
// 1.创建第一个组件
const cpnC1 = Vue.extend({
template:`
<div>
<h2>我是标题1</h2>
<h2>我是标题2</h2>
</div>
`
})
// 2.创建第二个组件
const cpnC2 = Vue.extend({
template:`
<div>
<h2>我是标题3</h2>
<h2>我是标题4</h2>
<cpn1></cpn1>
</div>
`,
components:{
cpn1:cpnC1 //子组件注册
}
})
//root组件
const app = new Vue({
el:'#app',
data:{
message:'你好啊'
},
components:{
cpn2:cpnC2
}
})
</script>
5.组件的语法糖注册方式
(1)全局组件
Vue.component('cpn1',{
template:`
<div>
<h2>我是标题1</h2>
<h2>我是标题2</h2>
</div>
`
})
(2)局部组件
components:{
cpn2:{
template:`
<div>
<h2>我是标题3</h2>
<h2>我是标题4</h2>
</div>
`
}
}
6.组件模板的分离写法
(1)script标签写法
<script type="text/x-template" id="cpn1">
<div>
<h2>我是标题1</h2>
<h2>我是标题2</h2>
</div>
</script>
(2)template标签写法
<template id="cpn2">
<div>
<h2>我是标题3</h2>
<h2>我是标题4</h2>
</div>
</template>
7.组件数据的存放
注意:data为一个函数,必须有返回值
Vue.component('cpn',{
template:'#cpn',
//data写在此处,值的改变不会相互影响
data(){
return{
title:'我是标题1'
}
}
})
这样写时,data会一同改变
const obj = {
counter:0
}
Vue.component('cpn',{
template:'#cpn',
data(){
return obj
}
8.父子组件间的通信
父传子:props
子传父:自定义事件emit
image.png
1.通过props向子组件传递数据(父传子)
(1)props基本用法
在组件中,使用选项props来声明需要从父级接收到的数据。
props的值有两种方式:
方式一:字符串数组,数组中的字符串就是传递时的名称;
方式二:对象,对象可以设置传递时的类型,也可以设置默认值等。
(2)最简单的props传递
<div id="app">
<!-- 通过:cmovies="movies"将data数据传递给了props -->
<cpn :cmovies="movies" :cmessage="message"></cpn>
<!-- 省去v-bind,movies会被解析为一个字符串 -->
<!-- <cpn cmovies="movies" cmessage="message"></cpn> -->
</div>
<template id="cpn">
<div>
<ul>
<li v-for="item in cmovies">{{item}}</li>
</ul>
<h2>{{cmessage}}</h2>
</div>
</template>
<script src="../vue/vue.js" type="text/javascript"></script>
<script type="text/javascript">
const cpn = {
template:'#cpn',
//传递数组的形式
props:['cmovies','cmessage']
}
const app = new Vue({
el:'#app',
data:{
message:'你好啊',
movies:['海王','海贼王','海尔兄弟']
},
components:{cpn}
})
</script>
(3)props数据验证
除了数组之外,我们也可以使用对象,当需要对props进行类型等验证时,就需要对象写法了。
验证支持的数据类型:String、Number、Boolean、Array、Object、Data、Function、Symbol
当我们有自定义的构造函数时,验证也支持自定义的类型
image.png
(4)props的驼峰标识
数据为驼峰命名时,在引用组件时,v-bind不支持驼峰标识
<div id="app">
<cpn :cInfo="info"></cpn>
</div>
<template id="cpn">
<div>
<h2>{{cInfo}}</h2>
</div>
</template>
<script src="../vue/vue.js" type="text/javascript"></script>
<script type="text/javascript">
const cpn = {
template:'#cpn',
props:{
cInfo:{
type:Object,
default(){
return {}
}
}
}
}
const app = new Vue({
el:'#app',
data:{
info:{
name:'gjj',
age:21,
height:1.75
}
},
components:{
cpn
}
})
</script>
结果将为默认值
image.png
引用时应该将数据名改为<cpn :c-info="info"></cpn>
2.通过事件向父组件发送消息(子传父)
自定义事件流程:在子组件中,通过$emit()来触发事件,在父组件中,通过v-on来监听子组件事件
子组件:
const cpn = {
template:'#cpn',
data(){
return {
categories:[
{id:'aaa',name:'热门推荐'},
{id:'bbb',name:'手机数码'},
{id:'ccc',name:'家用家电'},
{id:'ddd',name:'电脑办公'},
]
}
},
methods:{
btnClick(item){
//发射事件:自定义事件
this.$emit('itemclick',item)
}
}
}
父组件:
const app = new Vue({
el:'#app',
data:{
info:{
name:'gjj',
age:21,
height:1.75
}
},
components:{cpn},
methods:{
cpnClick(item){
console.log(item)
}
}
})
组件模板部分
<!-- 父组件模板 -->
<div id="app">
<cpn @itemclick="cpnClick"></cpn>
</div>
<!-- 子组件模板 -->
<template id="cpn">
<div id="">
<button type="button" v-for="item in categories" @click="btnClick(item)">{{item.name}}</button>
</div>
</template>
3.父子组件双向通信(案例)
<body>
<div id="app">
<cpn :cnum1="num1" :cnum2="num2" @num1change="num1Change" @num2change="num2Change"></cpn>
</div>
<template id="cpn">
<div id="">
<h2>props:{{cnum1}}</h2>
<h2>{{dnum1}}</h2>
<input type="text" :value="dnum1" @input="num1Input"/>
<h2>props:{{cnum2}}</h2>
<h2>{{dnum2}}</h2>
<input type="text" v-model="dnum2" @input="num2Input"/>
</div>
</template>
<script src="../vue/vue.js" type="text/javascript"></script>
<script type="text/javascript">
const app = new Vue({
el:'#app',
data:{
num1:1,
num2:2
},
methods:{
num1Change(num){
this.num1 = parseInt(num)
},
num2Change(num){
this.num2 = parseInt(num)
}
},
components:{
cpn:{
template:'#cpn',
props:{
cnum1:Number,
cnum2:Number
},
data(){
return{
dnum1:this.cnum1,
dnum2:this.cnum2
}
},
methods:{
num1Input(event){
this.dnum1 = event.target.value;
console.log(this.dnum1)
this.$emit('num1change',this.dnum1) //不能使用驼峰命名
},
num2Input(){
this.$emit('num2change',this.dnum2)
}
}
}
}
})
</script>
</body>
watch实现方法
<script type="text/javascript">
const app = new Vue({
el:'#app',
data:{
num:0
},
methods:{
numChange(newValue){
this.num = parseInt(newValue)
}
},
components:{
cpn:{
template:'#cpn',
props:{
cnum:Number
},
data(){
return{
dnum:this.cnum
}
},
watch:{//v-model监听改变
//一般参数定义为newValue
dnum(newValue){
this.$emit('numchange',newValue)
}
}
}
}
})
</script>