包含以下几个部分
全局组件和局部组件的注册
全局组件
直接上代码,这样即注册了一个全局组件
1
2
3
4
5
6
7
8
|
Vue.component('cpn',{
template: `
<div>
<h2>我是标题</h2>
<p>我是内容,hhh</p>
<p>我是内容,hehehe</p>
</div>`
})
|
局部组件
也直接上代码了,此时相当于在app内部注册了一个组件,我们只能在该app中使用它
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
// 1.创建组件构造器
const cpnC = Vue.extend({
template: `
<div>
<h2>我是标题</h2>
<p>我是内容</p>
</div>
`
})
// 2.注册局部组件
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: { //局部组件
//cpn使用组件时的标签名,cpnC组件构造器
cpn: cpnC
}
})
|
组件模板的分离写法
有时template过于冗长,我们需要将其中包含的html代码写在组件外面,此时有两种写法
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
|
<!-- 1. script标签,注意:类型必须是text/x-template -->
<script type="text/x-template" id="cpn">
<div>
<h2>我是标题</h2>
<p>我是内容</p>
</div>
</script>
<!-- 2. template标签 -->
<template id="cpn">
<div>
<h2>{{title}}</h2>
<h2>我是标题</h2>
<p>我是内容11</p>
</div>
</template>
// 注册组件,引用template模板
Vue.component('cpn', {
template: `#cpn`,
data() {
return {
title: 'abc'
}
}
})
|
关于组件中的data为什么是函数
一句话概括:如果data不是一个函数,各个组件实例会相互影响(因为它们共同指向了一个对象),是函数的话每次都会返回一个新的对象。
组件通信
父传子
还是直接在代码中解释吧
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
|
// 1.父传子
<div id="app">
<!-- 不用v-bind的话会将movies和message当作字符串来寻找 -->
<cpn :cmovies="movies" :cmessage="message"></cpn>
</div>
<script>
const cpn = {
template: '#cpn',
// props: ['cmovies', 'cmessage']
props: {
// 1.类型限制
// cmovies: Array,
// cmessage: String
// 2.提供一些默认值
cmessage: {
type: [String, Number], //也可以是自定义类型
default: 'aaaaa',
required: true //表示必须传值,否则报错
},
cmovies: {
//类型是对象或者数组时,默认值必须是一个函数
type: Array,
default () {
return [1, 2, 3]
}
}
}
}
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
movies: ['海王', '海贼王', '海尔兄弟']
},
components: {
cpn
}
})
</script>
|
props中的驼峰标识问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<div id="app">
<cpn :c-info="info" :child-my-message="message"></cpn>
</div>
<script>
const cpn = {
template: '#cpn',
props: {
cInfo: {
type: Object,
default () {
return {}
}
},
childMyMessage: {
type: String,
default: '11'
}
}
}
</script>
|
代码如上,html标签中要传给子组件的数据必须以-
连接,而子组件props
中必须以驼峰命名的方式来写
子传父
关键词$emit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
// 在子组件的方法中定义this.$emit(事件名)
const cpn = {
template: '#cpn',
props: {
cInfo: {
type: Object,
default () {
return {}
}
},
childMyMessage: {
type: String,
default: '11'
}
}
}
// 父组件接受
<div id="app">
<h2>{{count}}</h2>
<cpn @decrement-click="add" @increment-click="increase"></cpn>
</div>
|
参数问题
来看以下一段代码,注意默认传递的参数以及this.$emit()里的不同
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
|
<!-- 父组件模板 -->
<div id="app">
<!-- 默认会把item传给cpnClick作参数,而不是一般情况下的默认传浏览器的evnt -->
<cpn @item-click="cpnClick"></cpn>
</div>
<!-- 子组件模板 -->
<template id="cpn">
<div>
<button v-for="item in categories" @click="btnClick(item)">{{item.name}}</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const cpn = {
template: '#cpn',
data() {
return {
categories: [{
id: 'aaa',
name: '热门推荐'
}, {
id: 'bbb',
name: '手机数码'
}, {
id: 'ccc',
name: '家用家电'
}]
}
},
methods: {
btnClick(item) {
this.$emit('item-click', item)
}
}
}
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
cpn
},
methods: {
cpnClick(item) {
console.log(item);
}
}
})
</script>
|
一个很纠结的父子组件通信案例
目的是实现类似v-model
的效果,父组件传递过去的值在父组件中也会同时刷新
- 常规实现,不解释了,直接看代码
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
|
<div id="app">
<h2>父组件值:{{number}}</h2>
<cpn :num="number" @num-change="numberChange"></cpn>
</div>
<template id="cpn">
<div>
<!-- 不要直接改变props里的值,会报错 -->
<h2>组件绑定值:{{num}}</h2>
<h2>组件:{{cpnNumber}}</h2>
<!-- <input type="text" v-model="cpnNumber"> -->
<input type="text" :value="cpnNumber" @input="numInput">
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const cpn = {
template: '#cpn',
props: {
num: Number
},
data() {
return {
cpnNumber: this.num
}
},
methods: {
numInput(event) {
this.cpnNumber = event.target.value
this.$emit('num-change', this.cpnNumber)
}
}
}
const app = new Vue({
el: '#app',
data: {
number: 0
},
components: {
cpn
},
methods: {
numberChange(val) {
this.number = parseFloat(val)
}
}
})
|
- watch实现,watch实现简单的多了,watch会监听数值的变化
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
|
<div id="app">
<h2>父组件值:{{number}}</h2>
<cpn :num="number" @num-change="numberChange"></cpn>
</div>
<template id="cpn">
<div>
<!-- 不要直接改变props里的值,会报错 -->
<h2>组件绑定值:{{num}}</h2>
<h2>组件:{{cpnNumber}}</h2>
<!-- <input type="text" v-model="cpnNumber"> -->
<input type="text" v-model="cpnNumber">
</div>
</template>
<script>
const cpn = {
template: '#cpn',
props: {
num: Number
},
data() {
return {
cpnNumber: this.num
}
},
watch: {
cpnNumber(newValue) {
this.$emit('num-change', newValue)
}
}
}
const app = new Vue({
el: '#app',
data: {
number: 0
},
components: {
cpn
},
methods: {
numberChange(val) {
this.number = parseFloat(val)
}
}
})
</script>
|
父子相互访问
父访问子
按照代码中的注释来看吧,自己跑一下就知道了
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
|
<div id="app">
<cpn></cpn>
<cpn></cpn>
<cpn ref="aaa"></cpn>
<button @click="btnClick">按钮</button>
</div>
<template id="cpn">
<div>我是子组件</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
methods: {
btnClick() {
// 1.$children
// 一般真实开发中 不拿$children取属性
// console.log(this.$children)
// for (let c of this.$children) {
// console.log(c.name);
// c.showMessage()
// }
// 2.$refs => 默认是一个空的对象,给子组件ref='bbb'
// 通过给cpn加ref,如aaa
console.log(this.$refs.aaa);
}
},
components: {
cpn: {
template: '#cpn',
data() {
return {
name: '我是子组件的name'
}
},
methods: {
showMessage() {
console.log('showMessage')
}
}
}
}
})
</script>
|
子访问父
参照代码注释
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
|
<div id="app">
<h2>我是cpn组件</h2>
<cpn></cpn>
</div>
<template id="cpn">
<ccpn></ccpn>
</template>
<template id="ccpn">
<div>
<h2>我是子组件</h2>
<button @click="btnClick">按钮</button>
</div>
</template>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
cpn: {
template: '#cpn',
data() {
return {
name: '我是cpn组件的name'
}
},
components: {
ccpn: {
template: '#ccpn',
methods: {
btnClick() {
// 1.访问父组件$parent
console.log(this.$parent);
console.log(this.$parent.name);
// 2.访问根组件$root
console.log(this.$root);
console.log(this.$root.message);
}
}
}
}
}
}
})
</script>
|
插槽
由于vue3会使用新的v-slot,所以这里直接写v-slot好了,以下v-slot
都可以简写成#
匿名插槽
v-slot:default
通过default默认匿名的插槽
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
|
<div id="app">
<cpn>
<template v-slot:default>
<button>按钮</button>
</template>
</cpn>
</div>
<template id="cpn">
<div>
<h2>我是组件</h2>
<p>我是组件,哈哈哈</p>
<slot></slot>
<!-- <slot><button>按钮</button></slot> 可以放默认值-->
</div>
</template>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
cpn: {
template: '#cpn'
}
}
})
</script>
|
具名插槽
在子组件中给插槽name
之后,父组件中必须声明此name
才能向插槽中插入数据
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
|
<div id="app">
<cpn>
<template v-slot:todo>
<button>按钮</button>
</template>
<template v-slot:default>没名字的</template>
</cpn>
</div>
<template id="cpn">
<div>
<slot></slot>
<h2>我是组件</h2>
<p>我是组件,哈哈哈</p>
<slot name="todo"></slot>
</div>
</template>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
cpn: {
template: '#cpn'
}
}
})
</script>
|
作用域插槽
重点是slotProps接取子组件里:clanguage="language"
类似属性的数据,slotProps 接取的是子组件标签slot上属性数据的集合所有v-bind:user=“user”
完整代码
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
|
<div id="app">
<cpn>
<!-- slotProps是任意命名的 -->
<template v-slot:default="slotProps">
<span v-for="item in slotProps.clanguage">{{item}}--</span>
</template>
</cpn>
</div>
<template id="cpn">
<div>
<slot :clanguage="language">
<!--ul里是默认值-->
<ul>
<li v-for="item in language">{{item}}</li>
</ul>
</slot>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
cpn: {
template: '#cpn',
data() {
return {
language: ['JS', 'JAVA', 'C#', 'Python', 'Go']
}
}
}
}
})
|
ok,Vue基础就到这里了,后面将学习webpack,之后就是正式上手Vue项目了