组件和组件通信
- 任何应用都可能会被抽象成一颗组件树
- 组件使用的步骤:
- 创建组件构造器
- 注册组件
- 使用组件
<div id="app"><!--注意这是vue的作用范围-->
<my-cpn></my-cpn><!--使用组件-->
</div>
<script src="../practice/vue.js"></script>
<script>
//1、创建组件构造器对象,与创建vue对象一样也需要传入一个对象作为参数
const cpnC = Vue.extend({
template: ` <div id="app">
<h2>蔡蔡</h2>
<p>你好</p>
<p>水果</p>
</div>`
})
//2.注册组件,Vue.component("定义的组件名字",组件构造器)
Vue.component("my-cpn",cpnC)
const app = new Vue({
el: "#app",
data: {
message: "嘿嘿"
}
})
</script>
全局组件和局部组件
- 全局组件意味着可以在多个vue实例下面使用,局部组件即在该vue实例对象中添加一个components属性,其他实例用不了
父组件和子组件
- 例子:
<body>
<div id="app">
<!-- <cpn1></cpn1> 直接输出这个会报错因为该组件不是在全局VUe注册的也不是在app这个域内注册的-->
<cpn2></cpn2>
</div>
<script src="./vue.js"></script>
<script>
//创建第一个组件构造器(子组件)
const cpnc1 = Vue.extend({
template: ` <div>
<h2>我是标题1</h2>
<p>我是内容1</p>
</div>`
})
//创建第二个组件构造器(父组件)
const cpnc2 = Vue.extend({
template: `<div>
<h2>我是标题2</h2>
<p>我是内容2</p>
<cpn1></cpn1>
</div>`,
components:{
cpn1:cpnc1
}
//组件一在组件2中注册的,组件2在vue实例中注册的
})
const app=new Vue({
el:"#app",
data:{
message:"你好"
},
components:{
cpn2:cpnc2
}
})
</script>
</body>
- 模板template的分离写法
- 使用script标签,
<script type="text/x-template" id="mycpn"> 用的时候在component属性里面的template:"#mycpn"
- 使用template标签
<template id="mycpn">
- 使用script标签,
- 组件的data(组件中的数据是分开的)
- 组件其实很像一个vue实例
- 有data属性,data(){},是一个函数,要return一个对象
<div id="app">
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>
当前计数:{{cnt}}
</h2>
<button @click=incre()>+</button>
<button @click=decre()>-</button>
</div>
</template>
<script src="../practice/vue.js"></script>
<script>
Vue.component('cpn',{
template:'#cpn',
data(){
return{
cnt:0
}
},
methods:{
incre(){
this.cnt++
},
decre(){
this.cnt--
}
}
})
const app=new Vue({
el:"#app",
data:{
message:'嘿嘿'
}
})
</script>
- 所以组件的data是一个函数(vue实例中的data就是一个对象),比如上面计数器的例子,如果是函数的话每次每个页面要调用那个计数器组件就会产生一个新的cnt对象,每个页面的计数器组件的data对象就是不同的,
但是如果这个时候的组建的data是一个对象而不是一个函数的话,一个页面点击了按钮,所有用这个组件的cnt都会变
组件是一个单独功能模块的封装组件中不能直接访问实例对象,且子组件不能直接访问父组件的内容
#####父子组件通信
-
注意:
- 在一个页面中要从服务器请求很多数据,但是有些数据是在小组件展示的,可是不会让小组件发送网络请求,而是让大组件将数据传递给小组件
- 因为发送很多次网络请求对服务器压力很大
-
props:(properties属性的缩写,父到子)可以做到类型限制,代码如下
-
$emit事件:(子到父)
-
注意点:
- vue实例其实本身可以看成是一个父组件
- 子组件不能直接引用父组件的数据
-
过程理解:子组件想给父组件传递东西的话就发射一个事件,这个事件类型需要自定义,在父组件的模板用自定义标签时进行对该事件的监听,监听后去父组件里面的methods或者其他地方进行对该事件的处理
-
案例
- 第一个小案例(但是代码结构有点乱,之后的文件以模板template、JS代码、样式构成.Vue文件更加规范)
<body>
<!--父组件的模板-->
<div id="app">
<cpn @itemclick="cpnclick"></cpn>
<!-- 浏览器默认的事件对象会传入event但是如果不是的话会自动传入自己的设置的那个参数此处即是event -->
</div>
<!--子组件的模板-->
<template id="cpn">
<div>
<button v-for="item in catego" @click="btnclick(item)">{{item.name}}</button>
<!-- 存储类别父组件根据点击的子对象去请求相对应的数据 -->
</div>
</template>
<script src="./vue.js"></script>
<script>
const cpn = {
template: "#cpn",
data() {
return {
catego: [{
id: 1,
name: "热门推荐"
}, {
id: 2,
name: "排行榜"
}, {
id: 3,
name: "歌单"
}, {
id: 4,
name: "数字专辑"
}]
}
},
methods:{
btnclick(item){
// console.log(item);
this.$emit("itemclick",item)
}//自定义事件类型点击拿到对应子对象通过发射出去给父组件该事件并且传递参数
}
}
const app = new Vue({
el: "#app",
data: {
message: "app1"
},
components:{
cpn:cpn
},
methods:{
cpnclick(item){
console.log('cpnclick',item);
}
}
})
</script>
</body>
- 第二个案例(结合双向绑定理解)
<body>
<div id="app">
<cpn :number1="num1" :number2="num2" @num1change="num1change" @num2change="num2change"/>
</div>
<template id="cpn">
<div>
<h2>props:{{number1}}</h2>
<h2>data:{{dnumber1}}</h2>
<!-- <input type="text" v-model="dnumber1"> -->
<input type="text" :value="dnumber1" @input="num1input">
<h2>props:{{number2}}</h2>
<h2>data:{{dnumber2}}</h2>
<!-- 两种进行比较,要修改的数据一定要放进data函数里面 -->
<!-- <input type="text" v-model="dnumber2"> -->
<input type="text" :value="dnumber2" @input="num2input">
</div>
</template>
<script src="./vue.js"></script>
<script>
const app=new Vue({
el:'#app',
data:{
num1:1,
num2:0//也可以改变父组件中这个值
},
methods: {
num1change(value){
this.num1=parseFloat(value)
//默认情况转换成string类型所以要进行转化用parse系列方法
},
num2change(value){
this.num2=parseFloat(value)
}
},
components:{
cpn:{
template:'#cpn',
props: {
number1:Number,
number2:Number
},
data(){
return {
dnumber1:this.number1,
dnumber2:this.number2
}//展示可以直接展示,但是如果要修改数据一定要放到data里面
},
methods:{
num1input(){
this.dnumber1=event.target.value;
this.$emit('num1change',this.dnum1)
},
num2input(){
this.dnumber2=event.target.value;
this.$emit('num1change',this.dnum1)
//将数据的改变进行传输回去给num1 num2
}
}
}
}
})
</script>
</body>