1. 组件化开发¶
1.1. 认识组件化¶
1.1.1. 什么是组件化¶
组件化是讲一个页面进行拆分为一个一个小的功能块,每个功能块完成对应的功能,如下图。
1.1.2. 组件化的思想¶
它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用。
任何的应用都会被抽象成一颗组件树。
1.2. 注册组件¶
1.2.2. 注册代码图¶
其中调用Vue.extend()创建的是一个组件构造器。
调用Vue.component()是将刚才的组件构造器注册为一个组件。
组件必须挂载在某个Vue实例下,否则它不会生效。
1.2.3. 详细代码实现¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!-- 使用-->
<demo-cpt></demo-cpt>
<demo-cpt></demo-cpt>
<demo-cpt></demo-cpt>
</div>
<script src="../js/vue.js"></script>
<script>
// 创建
const demoCpt = Vue.extend(
{
template: `
<div>
<h2> 组件标题</h2>
<p> 组件内容</p>
</div>
`
}
)
// 注册
Vue.component("demo-cpt", demoCpt)
let app = new Vue({
el: "#app",
data: {
cnt: 1,
}
})
</script>
</body>
</html>
|
1.3. 组件其他补充¶
1.3.2. 局部组件¶
如果在特定的vue下的components属性指定的组件为局部组件,只能在特定的父组件使用的。
let app = new Vue({
el: "#app",
data: {
cnt: 1,
},
components:{
"demo-cpt2": demoCpt2
}
})
1.3.3. 父子组件¶
组件和组件是有一定的层次关系的, 其中其中父子组件的是而非常重要的关系。
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!-- 使用-->
<demo-cpt2>
<demo-cpt></demo-cpt>
</demo-cpt2>
</div>
<script src="../js/vue.js"></script>
<script>
// 创建
const demoCpt = Vue.extend({
template: `
<div>
<h2> 组件标题</h2>
</div>
`
})
const demoCpt2 = Vue.extend({
template: `
<div>
<h2> 组件标题2</h2>
<p>haha</p>
<demo-cpt></demo-cpt>
<p>haha</p>
</div>
`,
components: {
"demo-cpt": demoCpt
}
})
let app = new Vue({
el: "#app",
data: {
cnt: 1,
},
components: {
"demo-cpt2": demoCpt2
}
})
</script>
</body>
</html>
|
1.3.4. 模块的分离写法¶
上面我们可以看到写一个组件内部还包含了html的代码,非常不方便管理和维护。可以通过如下方式进行改造。
2中方式在代码中体现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!-- 使用-->
<demo-cpt></demo-cpt>
<demo-cpt2></demo-cpt2>
</div>
<script src="../js/vue.js"></script>
<script type="text/x-template" id="demoCpt">
<div>
<h2> 组件标题</h2>
</div>
</script>
<template id="demoCpt2">
<div>
<h2> 组件标题</h2>
</div>
</template>
<script>
// 创建
Vue.component('demo-cpt',
{
template: '#demoCpt'
}
)
Vue.component('demo-cpt2',
{
template: '#demoCpt2'
}
)
let app = new Vue({
el: "#app",
data: {
cnt: 1,
},
})
</script>
</body>
</html>
|
1.4. 组件数据存放¶
组件内的数据有个data属性,但是这个是一个函数的,通过这个函数返回一个dict对象即可。
详细代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<demo-cpt></demo-cpt>
</div>
<script src="../js/vue.js"></script>
<template id="demoCpt">
<div>
<button @click="sub">-</button>
{{count }}
<button @click="add">+</button>
</div>
</template>
<script>
// 创建
Vue.component('demo-cpt',
{
template: '#demoCpt',
data(){
// 组件是复用的,保障每组件实例对象是有独立的数据地址空间的。使用函数解决。
return {
count: 1
}
},
methods:{
add(){
return this.count++
},
sub(){
return this.count--
}
}
}
)
let app = new Vue({
el: "#app",
data: {
cnt: 1,
},
})
</script>
</body>
</html>
|
Note
组件的data必须是一个函数的,不能是通过的字典,因为我们组件是复用的,组件复用后的数据一定是独立的。
1.5. 父子组件通信¶
官方文档中给出了父子组件的通信方式。
通过props向子组件传递数据
通过事件向父组件发送消息
1.5.1. 父级向子级传递¶
父组件向子组件创建数据,可以通过子组件提供props来传递。参考如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<label>
<input type="text" v-model="t1"> 第1个组件的值
</label>
<label>
<input type="text" v-model="t2"> 第2个组件的值
</label>
<!-- 使用-->
<label> 第一个组件实例</label>
<demo-cpt :title="t1"></demo-cpt>
<label> 第2个组件实例</label>
<demo-cpt :title="t2"></demo-cpt>
</div>
<script src="../js/vue.js"></script>
<template id="demoCpt">
<div>
<h2>{{title}}</h2>
</div>
</template>
<script>
const demoCpt = {
template: "#demoCpt",
props: {
"title": {
type: String,
default: "default title"
}
},
data() {
return {
}
},
}
let app = new Vue({
el: "#app",
data: {
t1: "abc",
t2: "def",
},
components: {
"demo-cpt": demoCpt
},
methods: {
}
})
</script>
</body>
</html>
|
1.5.2. 子级向父级传递¶
自组件向父组件传递数据,通过发射事件,然后父组件绑定事件即可。参考如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!-- 使用-->
<label> 第一个组件实例</label>
<demo-cpt @item-click="getSubInfo" ></demo-cpt>
<label >从子组件获取的值</label>
<h2> {{ subInfo}}</h2>
</div>
<script src="../js/vue.js"></script>
<template id="demoCpt">
<div>
<button v-for="item in categories" @click="bntClick(item)"> {{item.name }}</button>
</div>
</template>
<script>
const demoCpt = {
template: "#demoCpt",
props: {
"title": {
type: String,
default: "default title"
}
},
data() {
return {
categories:[
{id:"123","name":"热门推荐"},
{id:"124","name":"手机数码"},
{id:"125","name":"电脑办公"},
{id:"126","name":"家用家电"},
]
}
},
methods: {
bntClick(item) {
console.log(item)
this.$emit("item-click",item)
}
}
}
let app = new Vue({
el: "#app",
data: {
subInfo: {}
},
components: {
"demo-cpt": demoCpt
},
methods: {
getSubInfo(item){
this.subInfo= item.name
console.log(item)
}
},
})
</script>
</body>
</html>
|
1.5.3. 父访问子组件数据¶
父组件访问子组件:使用$children或$refs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<button @click="getSubInfo">点击展示子组件信息</button>
<demo-cpt ref="aaa"></demo-cpt>
</div>
<script src="../js/vue.js"></script>
<template id="demoCpt">
<div>
<h2>{{title}}</h2>
</div>
</template>
<script>
const demoCpt = {
template: "#demoCpt",
props: {
"title": {
type: String,
default: "default title"
}
},
methods: {
showMessage(){
//console.log(this.title)
alert(this.title)
}
}
}
let app = new Vue({
el: "#app",
data: {
},
components: {
"demo-cpt": demoCpt
},
methods: {
getSubInfo(){
// console.log(this.$children)
this.$refs["aaa"].showMessage()
}
},
})
</script>
</body>
</html>
|
1.5.4. 子访问父组件数据¶
子组件访问父组件:使用$parent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<button @click="getSubInfo">点击展示子组件信息</button>
<demo-cpt ref="aaa"></demo-cpt>
</div>
<script src="../js/vue.js"></script>
<template id="demoCpt">
<div>
<h2>{{title}}</h2>
</div>
</template>
<script>
const demoCpt = {
template: "#demoCpt",
props: {
"title": {
type: String,
default: "default title"
}
},
methods: {
showMessage(){
//console.log(this.title)
alert(this.title)
}
}
}
let app = new Vue({
el: "#app",
data: {
},
components: {
"demo-cpt": demoCpt
},
methods: {
getSubInfo(){
// console.log(this.$children)
this.$refs["aaa"].showMessage()
}
},
})
</script>
</body>
</html>
|
1.6. 插槽slot¶
1.6.1. 编译作用域¶
父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译。
1.6.2. 为什么使用slot¶
组件的插槽也是为了让我们封装的组件更加具有扩展性。
让使用者可以决定组件内部的一些内容到底展示什么。
1.6.3. slot的基本使用¶
在组件的模板定义中引入slot即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<demo-cpt>
<button>haha</button>
</demo-cpt>
<demo-cpt>
<h2>abc</h2>
<h2>abc</h2>
<h2>abc</h2>
</demo-cpt>
<demo-cpt></demo-cpt>
</div>
<script src="../js/vue.js"></script>
<template id="demoCpt">
<div>
<h2>测试</h2>
<slot>
<button>默认button</button>
</slot>
</div>
</template>
<script>
const demoCpt = {
template: "#demoCpt",
}
let app = new Vue({
el: "#app",
data: {
"name": "panda"
},
components: {
"demo-cpt": demoCpt
},
})
</script>
</body>
</html>
|
1.6.4. 具名slot¶
当子组件的功能复杂时,子组件的插槽可能并非是一个,怎么方便控制用户想替换哪个slot?
这就需要给slot起个名字,让用户选择给那个slot位置进行替换。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<demo-cpt>
<span slot="left">返回</span>
</demo-cpt>
</div>
<script src="../js/vue.js"></script>
<template id="demoCpt">
<div>
<slot name="left"></slot>
<slot name="center"></slot>
<slot name="right"></slot>
</div>
</template>
<script>
const demoCpt = {
template: "#demoCpt",
}
let app = new Vue({
el: "#app",
data: {
"name": "panda"
},
components: {
"demo-cpt": demoCpt
},
})
</script>
</body>
</html>
|