1.什么是组件化?
将一个页面拆分成许多个组件,每一个组件用于实现页面的一个功能,每一个组件也可以进行细分为更小的组件
2.Vue组件化思想
任何一个应用都会被抽象成一颗组件树,Vue.js提供了一种抽象,我们可以开发出一个个小的可复用的独立的组件来构造一个大的页面或应用。
3.组件化开发
1.组件的基本使用
- 创建组件构造器
- 注册组件
- 使用组件
<body>
<div id='app'>
<!-- 3.使用组件(在Vue实例的作用范围内使用组件) -->
<my-cpn></my-cpn>
</div>
<script src='../js/vue.js'></script>
<script>
//1. 创建组件构造器对象
// 调用Vue.extend()创建一个组件构造器
const cpnConstructor = Vue.extend({
// 传入template作为自定义组件的模板,但事实上此写法现在已经比较少见,会使用新的语法糖
template:`
<div>
<h2>short poetry</h2>
<p>我们静静地坐在湖滨,
听燕子给我们讲南方的静夜。
南方的静夜已经被它们带来,
夜的芦苇蒸发着浓郁的情热——
我已经感到了南方的夜间的陶醉,
请你也嗅一嗅吧这芦苇中的浓味。
你说大熊星总象是寒带的白熊,
望去使你的全身都感到凄冷。
这时的燕子轻轻地掠过水面,
零乱了满湖的星影—— 。</p>
</div>`
})
// 2.注册组件
// 传递两个参数,组件标签名,组件构造器
Vue.component('my-cpn',cpnConstructor);
const app = new Vue ({
el: '#app',
data: {
message:'hello'
}
})
</script>
</body>
1.Vue.extend():
- 调用Vue.extend创建组件构造器
- 在创建组件构造器时,传入template为自定义组件模板
- 这个模板是在使用该组件的地方要显示的HTML代码
- 但这种方法在Vue2、3已经不再使用,而使用的是语法糖,这种方式可以更好理解新的方法
2.Vue.coomponent():
- 调用其是将创建的组件构造器注册为组件,并且起一个组件的标签名称
- 需要传递连个参数:1.注册组件的标签名 2.组件构造器
3.组件必须挂载在某个Vue实例下,否则不生效
2.全局组件与局部组件
调用Vue.component()注册的组件是全局组件,意味着这个组件在任何Vue实例下都可以使用,在实例内注册的组件为局部组件
<body>
<div id='app'>
<!-- 使用组件 -->
<cpn></cpn>
</div>
<!-- 全局组件在其他实例上也可以使用 -->
<div id="app2">
<cpn></cpn>
</div>
<script src='../js/vue.js'></script>
<script>
// 创建组件构造器
const cpnC = Vue.extend({
template:`
<div>
<p>stone</p>
</div>`
})
// 1.注册组件(全局组件,意味着可以在多个Vue实例下使用)
// Vue.component ('cpn',cpnC);
const app = new Vue ({
el: '#app',
data: {
message:'hello'
},
// 2.局部注册组件,可以注册多个组件
components:{
// cpn为使用组件时的标签名
cpn:cpnC,
}
})
// Vue的第二个实例,但一般在项目开发只用一个实例
const app2 = new Vue({
el:'#app2'
})
</script>
</body>
3.父组件与子组件
通过前面的组件树,可以看出组件与组件之间存在层级关系,其中一种关系就是父子关系
<body>
<div id='app'>
<!-- 若要在此用父组件内的子组件,必须再到root组件中注册子组件 -->
<!-- <cpna></cpna> -->
<cpnb></cpnb>
</div>
<script src='../js/vue.js'></script>
<script>
// 创建第一个组件构造器:子组件
const cpnCa = Vue.extend({
template:`
<div>
<p>small stone</p>
</div>`
});
// 创建第二个组件构造器:父组件
const cpnCb = Vue.extend({
template:`
<div>
<p>big stone</p>
<cpna></cpna>
</div>`,
components: {
cpna: cpnCa
}
})
// root组件
const app = new Vue ({
el: '#app',
data: {
message:'hello'
},
components: {
cpnb: cpnCb,
// cpna: cpnCa
}
})
</script>
</body>
4.注册组件语法糖
Vue为了简化此过程,提供了注册语法糖,,主要省去了Vue.extend()步骤,直接使用一个对象代替。
<body>
<div id='app'>
<cpna></cpna>
<cpnb></cpnb>
</div>
<script src='../js/vue.js'></script>
<script>
// 全局组件注册语法糖
Vue.component ('cpna',{
template:`
<div>
<p>hh</p>
</div>`
})
const app = new Vue ({
el: '#app',
data: {
message:'hello'
},
// 局部组件注册语法糖
components: {
'cpnb':{
template:`
<div>
<p>lalalalala</p>
</div>`
}
}
})
</script>
</body>
5.模板的分离写法
通过语法糖来简化组件的注册,Vue还提供了两种方案来定义HTML模块内容
- 使用< script >标签
- 使用< template >标签
将HTML分离开写,然后挂载到对应组件上,结构会更加清晰
<body>
<div id='app'>
<cpna></cpna>
</div>
<!-- 1.script标签,类型必须是text/x-template -->
<!-- <script type="text/x-template" id="cpn">
<div>
<p>hhhhhhhh</p>
</div>
</script> -->
<!-- 2.template标签 -->
<template id="cpn">
<div>
<p>hhhhhhhh</p>
</div>
</template>
<script src='../js/vue.js'></script>
<script>
// 注册一个全局组件
Vue.component('cpna',{
template:'#cpn'
})
const app = new Vue ({
el: '#app',
data: {
message:'hello'
}
})
</script>
</body>
6.组件数据存放
组件是一个有单独功能的模块封装,有属于自己的HTML模板,也应该有属于自己的数据 组件的数据存放在组件对象的data中,组件无法获取到Vue实例中data内的数据
<body>
<div id='app'>
<cpna></cpna>
</div>
<template id="cpn">
<div>
<h4>{{title}}</h4>
<p>{{text}}</p>
</div>
</template>
<script src='../js/vue.js'></script>
<script>
Vue.component('cpna',{
template:'#cpn',
data(){
return{
title:'poetry',
text:2022
}
}
})
const app = new Vue ({
el: '#app',
data: {
message:'hello'
}
})
</script>
</body>
7.组件中的数据为什么必须是函数?
对象是一个引用数据类型,当多次使用同一个组件时,引用的是同一个地址,这样的话某个组件的数据改变,会影响到其他组件的数据,不利于组件的复用,而函数可以避免,函数每次都会返回一个全新的对象多次使用组件时,每次都是全新的对象地址,不会发生数据同步问题
<body>
<div id='app'>
<cpna></cpna>
<cpna></cpna>
</div>
<template id="cpn">
<div>
<p>{{title}}</p>
<p>{{text}}</p>
<p>当前计数为:{{counter}}</p>
<button @click="incre">+</button>
<button @click="decre">-</button>
</div>
</template>
<script src='../js/vue.js'></script>
<script>
Vue.component('cpna',{
template:'#cpn',
data(){
return{
` title:'poetry',
` text:`我们静静地坐在湖滨,
听燕子给我们讲南方的静夜`,
counter:0
}
},
methods:{
incre(){
this.counter++;
},
decre(){
this.counter--;
}
}
})
const app = new Vue ({
el: '#app',
data: {
message:'hello'
}
})
</script>
</body>