组件化
组件化
在大型应用开发的时候,页面可以划分成很多部分。往往不同的页面,也会有相同的部分。例如可能会有相同的头部导航。
但是如果每个页面都独自开发,这无疑增加了我们开发的成本。所以我们会把页面的不同部分拆分成独立的组件,然后在不同页面就可以共享这些组件,避免重复开发。
在 vue 里,所有的 vue 实例都是组件
组件的基本使用
简单的组件示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Title</title>
</head>
<body>
<div id="app">
<!-- 3.使用组件 -->
<my-cpn></my-cpn>
<my-cpn></my-cpn>
<my-cpn></my-cpn>
<cpnc></cpnc>
</div>
<script src="../js/vue.js"></script>
<script>
// 1.创建组件构造器对象
const cpnc = Vue.extend({
template: `
<div>
<h2>标题</h2>
<p>内容1...<p>
<p>内容2...<p>
</div>`,
})
// 2.全局注册组件
Vue.component('my-cpn', cpnc)
const app = new Vue({
el: '#app',
data: {},
components: {
//局部组件创建
cpnc: cpnc,
},
})
</script>
</body>
</html>
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
组件是可复用的 Vue 实例,且带有一个名字:在这个例子中是 my-cpn
。我们可以在一个通过 new Vue
创建的 Vue 根实例中,把这个组件作为自定义元素来使用: <my-cpn></my-cpn>
。
创建组件构造器对象
template
中是组件的 DOM 元素内容。
注册组件
- 全局注册,通过
Vue.component
。 - 局部注册,通过
components:{cpnc:cpnc}
。
使用组件
像使用 html 标签一样使用。
<div id="app">
<!-- 3.使用组件 -->
<my-cpn></my-cpn>
<my-cpn></my-cpn>
<my-cpn></my-cpn>
<cpnc></cpnc>
</div>
2
3
4
5
6
7
全局组件和局部组件
组件的注册方式有两种,一种是全局组件一种是局部组件。
<div id="app">
<h2>全局组件</h2>
<my-cpn></my-cpn>
<h2>局部组件</h2>
<cpnc></cpnc>
</div>
<script src="../js/vue.js"></script>
<script>
// 1.创建组件构造器对象
const cpnc = Vue.extend({
template: `
<div>
<h2>标题</h2>
<p>内容1</p>
<p>内容2</p>
</div>`,
})
// 2.注册组件(全局组件,可以在多个vue实例中使用)
Vue.component('my-cpn', cpnc)
const app = new Vue({
el: '#app',
components: {
//局部组件创建
cpnc: cpnc,
},
})
</script>
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
全局组件
全局组件,可以在多个 vue 实例中使用,类似于全局变量。
使用Vue.component('my-cpn', cpnc)
方式注册,直接使用<my-cpn></my-cpn>
调用。my-cpn
是全局组件的名字,cpnc
是定义的组件对象。
局部组件
局部组件,只能在当前 vue 实例挂载的对象中使用,类似于局部变量,有块级作用域。
注册方式
const app = new Vue({
el: '#app',
components: {
//局部组件创建
cpnc: cpnc,
},
})
2
3
4
5
6
7
使用方式与全局变量一样,直接使用<cpnc></cpnc>
调用。cpnc:cpnc
第一个 cpnc 是给组件命名的名字,第二个是定义的组件对象。如果俩个同名也可以直接使用 es6 语法:
components: {
//局部组件创建
cpnc
}
2
3
4
父组件和子组件的区别
<div id="app">
<cpn2></cpn2>
</div>
<script src="../js/vue.js"></script>
<script>
// 1.创建组件构造器对象
const cpn1 = Vue.extend({
template: `
<div>
<h2>标题1</h2>
<p>组件1</p>
</div>`,
})
// 组件2中使用组件1
const cpn2 = Vue.extend({
template: `
<div>
<h2>标题2</h2>
<p>组件2</p>
<cpn1></cpn1>
</div>`,
components: {
cpn1: cpn1,
},
})
const app = new Vue({
el: '#app',
components: {
//局部组件创建
cpn2: cpn2,
},
})
</script>
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
上述代码中定义了两个组件对象cpn1
和cpn2
,在组件cpn2
中使用局部组件注册了cpn1
,并在template
中使用了注册的cpn1
,然后在 vue 实例中使用注册了局部组件cpn2
,在 vue 实例挂载的 div 中调用了cpn2
,cpn2
与cpn1
形成父子组件关系。
注意:组件就是一个 vue 实例,vue 实例的属性,组件也可以有,例如 data、methods、computed 等。
注册组件的语法糖
<div id="app">
<cpn1></cpn1>
<cpn2></cpn2>
</div>
<script src="../js/vue.js"></script>
<script>
// 1.注册全局组件语法糖
Vue.component('cpn1', {
template: `
<div>
<h2>全局组件语法糖</h2>
<p>全局组件语法糖</p>
</div>`,
})
const app = new Vue({
el: '#app',
components: {
//局部组件创建
cpn2: {
template: `
<div>
<h2>局部组件语法糖</h2>
<p>局部组件语法糖</p>
</div>`,
},
},
})
</script>
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
注册组件时候可以不实例化组件对象,直接在注册的时候实例化。{}
就是一个组件对象。
组件模板的分离写法
script 标签
使用script
标签定义组件的模板,script
标签注意类型是text/x-template
。
<!-- 1.script标签注意类型是text/x-template -->
<script type="text/x-template" id="cpn1">
<div>
<h2>组件模板的分离写法</h2>
<p>script标签注意类型是text/x-template</p>
</div>
</script>
2
3
4
5
6
7
template 标签
使用template
标签,将内容写在标签内。
<!-- 2.template标签 -->
<template id="cpn2">
<div>
<h2>组件模板的分离写法</h2>
<p>template标签</p>
</div>
</template>
2
3
4
5
6
7
调用分离的模板,使用 template:'#cpn1'
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
components: {
//局部组件创建
cpn1: {
template: '#cpn1',
},
cpn2: {
template: '#cpn2',
},
},
})
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
组件的数据
存放问题
前面说过 vue 组件就是一个 vue 实例,相应的 vue 组件也有data
属性来存放数据。
<div id="app">
<cpn1></cpn1>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
components: {
//局部组件创建
cpn1: {
template: '<div>{{msg}}</div>',
data() {
return {
msg: '组件的数据存放必须要是一个函数',
}
},
},
},
})
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
在template
中使用组件内部的数据msg
。
组件的 data 为什么必须要是函数
组件的思想是复用,定义组件当然是把通用的公共的东西抽出来复用。
<div id="app">
<h2>data不使用函数</h2>
<cpn1></cpn1>
<cpn1></cpn1>
<hr />
<h2>data使用函数</h2>
<cpn2></cpn2>
<cpn2></cpn2>
<hr />
</div>
<script src="../js/vue.js"></script>
<template id="cpn1">
<div>
<button @click="count--">-</button>
当前计数:{{count}}
<button @click="count++">+</button>
</div>
</template>
<template id="cpn2">
<div>
<button @click="count--">-</button>
当前计数:{{count}}
<button @click="count++">+</button>
</div>
</template>
<script>
const obj = {
count: 0,
}
const app = new Vue({
el: '#app',
components: {
//局部组件创建
cpn1: {
template: '#cpn1',
data() {
return obj
},
},
cpn2: {
template: '#cpn2',
data() {
return {
count: 0,
}
},
},
},
})
</script>
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
上述代码中定义了两个组件cpn1
和cpn2
,都是定义了两个计数器,con1
的 data 虽然使用了函数,但是为了模拟data:{count:0}
,使用了常量obj
来返回 count。
图中可以看到,不使用函数data
的好像共用一个count
属性,而使用函数的data
的 count 是各自用各自的,像局部变量一样有块级作用域,这个块级就是 vue 组件的作用域。
我们在复用组件的时候肯定希望,各自组件用各自的变量,如果确实需要都用一样的,可以全局组件注册,也可以是用 vuex 来进行状态管理。
父组件给子组件传递数据
使用props
属性,父组件向子组件传递数据
使用组件的 props 属性
const cpn = {
template: '#cpn',
props: {
cmessage: {
type: String,
default: 'zzzzz',
required: true, //在使用组件必传值
},
},
}
2
3
4
5
6
7
8
9
10
向 cmessage 对象传值
<div id="app">
<cpn :cMessage="message"></cpn>
</div>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好',
movies: ['复仇者联盟', '钢铁侠', '星际穿越', '哪吒传奇'],
},
components: {
cpn,
},
})
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
props 属性使用
数组写法
props: ['cmovies', 'cmessage']
对象写法
props: {
cmessage: {
type: String,
default: 'zzzzz',
required: true //在使用组件必传值
}
}
2
3
4
5
6
7
props 属性的类型限制
//1.类型限制(多个类使用数组)
cmovies:Array,//限制为数组类型
cmessage:String,//限制为Strin类型
cmessage:['String','Number']//限制为String或Number类型
2
3
4
props 属性的默认值
// 2.提供一些默认值,以及必传值
cmessage: {
type: String,
default: 'zzzzz',//默认值
}
2
3
4
5
props 属性的必传值
cmessage: {
type: String,
default: 'zzzzz',
required: true //在使用组件必传值
}
2
3
4
5
类型是 Object/Array,默认值必须是一个函数
//类型是Object/Array,默认值必须是一个函数
cmovies: {
type: Array,
default () {
return [1, 2, 3, 4]
}
},
2
3
4
5
6
7
自定义验证函数
vaildator: function (value) {
//这个传递的值必须匹配下列字符串中的一个
return ['zzzzz', 'ttttt', 'yyy'].indexOf(value) !== -1
}
2
3
4
自定义类型
function Person(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
cmessage: Person //限定了cmeessage必须是Person类型
2
3
4
5
综合使用
<div id="app">
<cpn :cMovies="movies" :cMessage="message"></cpn>
</div>
<template id="cpn">
<div>
<ul>
<li v-for="(item, index) in cmovies" :key="index">{{item}}</li>
</ul>
<h2>{{cmessage}}</h2>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
function Person(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
// 父传子:props
const cpn = {
template: '#cpn',
// props: ['cmovies', 'cmessage'],//数组写法
props: {
//对象写法
// 1.类型限制(多个类使用数组)
// cmovies:Array,
// cmessage:String,
// cmessage:['String','Number'],
// 2.提供一些默认值,以及必传值
cmessage: {
type: String,
default: 'zzzzz',
required: true, //在使用组件必传值
},
//类型是Object/Array,默认值必须是一个函数
cmovies: {
type: Array,
default() {
return [1, 2, 3, 4]
},
},
// 3.自定义验证函数
// vaildator: function (value) {
// //这个传递的值必须匹配下列字符串中的一个
// return ['zzzzz', 'ttttt', 'yyy'].indexOf(value) !== -1
// }
// 4.自定义类型
// cmessage:Person,
},
data() {
return {}
},
methods: {},
}
const app = new Vue({
el: '#app',
data: {
message: '你好',
movies: ['复仇者联盟', '钢铁侠', '星际穿越', '哪吒传奇'],
},
components: {
cpn,
},
})
</script>
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
props 的驼峰标识
v-bind 是不支持使用驼峰标识的,例如cUser
要改成c-User
。
<div id="app">
<!-- v-bind不支持驼峰 :cUser改成 :c-User-->
<!-- <cpn :cUser="user"></cpn> -->
<cpn :c-User="user"></cpn>
<cpn :cuser="user"></cpn>
</div>
<template id="cpn">
<div>
<!-- 使用驼峰 -->
<h2>{{cUser}}</h2>
<!-- 不使用 -->
<h2>{{cuser}}</h2>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
// 父传子:props
const cpn = {
template: '#cpn',
props: {
//对象写法
//驼峰
cUser: Object,
//未使用驼峰
cuser: Object,
},
data() {
return {}
},
methods: {},
}
const app = new Vue({
el: '#app',
data: {
user: {
name: 'zzz',
age: 18,
height: 175,
},
},
components: {
cpn,
},
})
</script>
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
子传父$emit
子组件向父组件传值,使用自定义事件$emit
。
<!-- 父组件 -->
<div id="app">
<!-- 不写参数默认传递btnClick的item -->
<cpn @itemclick="cpnClcik"></cpn>
</div>
<!-- 子组件 -->
<template id="cpn">
<div>
<button v-for="(item, index) in categoties" :key="index" @click="btnClick(item)">
{{item.name}}
</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const cpn = {
template: '#cpn',
data() {
return {
categoties: [
{
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() {
return {}
},
methods: {
cpnClcik(item) {
console.log('cpnClick' + item.name)
},
},
components: {
cpn,
},
})
</script>
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
1.在子组件中定义一个方法btnClick(item)
,使用$emit
,’itemclick’是事件名,item
是传过去的值。
methods: {
btnClick(item) {
this.$emit('itemclick', item)
}
},
2
3
4
5
2.在子组件中监听点击事件并回调此方法
<div>
<button v-for="(item, index) in categoties" :key="index" @click="btnClick(item)">
{{item.name}}
</button>
</div>
2
3
4
5
3.在父组件中定义一个方法 cpnClcik(item)
methods: {
cpnClcik(item) {
console.log('cpnClick'+item.name);
}
},
2
3
4
5
4.并在父组件(vue 实例)中调用<cpn @itemclick="cpnClcik"></cpn>
(不写参数默认传递 btnClick 的 item ),父组件监听事件名为itemclick
的子组件传过来的事件。
<cpn @itemclick="cpnClcik"></cpn>
父子组件通信案例
实现父子组件的值双向绑定。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>组件通信-父子通信案例</title>
</head>
<body>
<!-- 父组件 -->
<div id="app">
<h2>子组件</h2>
<cpn :number1="num1" :number2="num2" @num1change="num1Change" @num2change="num2Change"></cpn>
<h2>--------------</h2>
<h2>父组件{{num1}}</h2>
<input type="text" v-model="num1" />
<h2>父组件{{num2}}</h2>
<input type="text" v-model="num2" />
</div>
<!-- 子组件 -->
<template id="cpn">
<div>
<h2>number1:{{number1}}</h2>
<h2>dnumber1:{{dnumber1}}</h2>
<input type="text" :value="dnumber1" @input="num1input" />
<h2>number2:{{number2}}</h2>
<h2>dnumber2:{{dnumber2}}</h2>
<input type="text" :value="dnumber2" @input="num2input" />
</div>
</template>
<script src="../js/vue.js"></script>
<script>
// 父传子:props
const cpn = {
template: '#cpn',
data() {
return {
dnumber1: this.number1,
dnumber2: this.number2,
}
},
props: {
number1: [Number, String],
number2: [Number, String],
},
methods: {
num1input(event) {
this.dnumber1 = event.target.value
this.$emit('num1change', this.dnumber1)
},
num2input(event) {
this.dnumber2 = event.target.value
this.$emit('num2change', this.dnumber2)
},
},
}
const app = new Vue({
el: '#app',
data: {
num1: 1,
num2: 2,
},
methods: {
num1Change(value) {
this.num1 = value
},
num2Change(value) {
this.num1 = value
},
},
components: {
cpn,
},
})
</script>
</body>
</html>
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
79
80
81
82
使用 watch 实现。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>组件通信-父子通信案例(watch实现)</title>
</head>
<body>
<!-- 父组件 -->
<div id="app">
<cpn :number1="num1" :number2="num2" @num1change="num1Change" @num2change="num2Change"></cpn>
<h2>父组件{{num1}}</h2>
<input type="text" v-model="num1" />
<h2>父组件{{num2}}</h2>
<input type="text" v-model="num2" />
</div>
<!-- 子组件 -->
<template id="cpn">
<div>
<h2>{{number1}}</h2>
<input type="text" v-model="dnumber1" />
<h2>{{number2}}</h2>
<input type="text" v-model="dnumber2" />
</div>
</template>
<script src="../js/vue.js"></script>
<script>
// 父传子:props
const cpn = {
template: '#cpn',
data() {
return {
dnumber1: this.number1,
dnumber2: this.number2,
}
},
props: {
number1: [Number, String],
number2: [Number, String],
},
watch: {
dnumber1(newValue) {
this.dnumber1 = newValue * 100
this.$emit('num1change', newValue)
},
dnumber2(newValue) {
this.dnumber1 = newValue * 100
this.$emit('num2change', newValue)
},
},
}
const app = new Vue({
el: '#app',
data() {
return {
num1: 1,
num2: 2,
}
},
methods: {
num1Change(value) {
this.num1 = value
},
num2Change(value) {
this.num1 = value
},
},
components: {
cpn,
},
})
</script>
</body>
</html>
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
79
80
父访问子(children-ref)
父组件访问子组件,有时候需要直接操作子组件的方法,或是属性,此时需要用到$children
和$ref
。
<!-- 父组件 -->
<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>
// 父传子:props
const cpn = {
template: '#cpn',
data() {
return {
name: '我是子组件的name',
}
},
methods: {
showMessage() {
console.log('showMessage')
},
},
}
const app = new Vue({
el: '#app',
data() {
return {
message: 'hello',
}
},
methods: {
btnClick() {
// 1.children
// console.log(this.$children[0].showMessage)
// for (let cpn of this.$children) {
// console.log(cpn.showMessage)
// }
// 2.$ref
console.log(this.$refs.aaa.name)
},
},
components: {
cpn,
},
})
</script>
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
$children 方式
// 1.children
console.log(this.$children[0].showMessage)
for (let cpn of this.$children) {
console.log(cpn.showMessage)
}
2
3
4
5
使用this.$children
直接获取**当前实例的直接子组件,需要注意 $children
并不保证顺序,也不是响应式的。**如果你发现自己正在尝试使用 $children
来进行数据绑定,考虑使用一个数组配合 v-for
来生成子组件,并且使用 Array 作为真正的来源。
$refs 方式
先定义子组件
<cpn ref="aaa"></cpn>
直接调用
slot-插槽的基本使用
我们在使用组件的时候有时候希望,在组件内部定制化内容,例如京东这样。
这两个都是导航栏,组件的思想是可以复用的,把这个导航栏看做一个组件。
这个组件都可以分成三个部分,左边中间右边,如果可以分割组件,就可以定制化组件内容了。
<!-- 父组件 -->
<div id="app">
<cpn></cpn>
<cpn>
<span style="color:red;">这是插槽内容222</span>
</cpn>
<cpn>
<i style="color:red;">这是插槽内容333</i>
</cpn>
<cpn></cpn>
</div>
<!-- 插槽的基本使用<slot></slot> -->
<!-- 子组件 -->
<template id="cpn">
<div>
<div>{{message}}</div>
<!-- 插槽默认值 -->
<slot><button>button</button></slot>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const cpn = {
template: '#cpn',
data() {
return {
message: '我是子组件',
}
},
}
const app = new Vue({
el: '#app',
data() {
return {
message: '我是父组件消息',
}
},
components: {
cpn,
},
})
</script>
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
简单使用插槽,定义 template 时候使用 slot
<!-- 子组件 -->
<template id="cpn">
<div>
<div>{{message}}</div>
<!-- 插槽默认值 -->
<slot><button>button</button></slot>
</div>
</template>
2
3
4
5
6
7
8
插槽可以使用默认值,就是插槽的默认值。
<cpn></cpn>
<cpn><span style="color:red;">这是插槽内容222</span></cpn>
2
使用插槽,这是插槽内容 222将替换插槽的默认值
上述代码结果如图所示
替换了两次插槽,两次未替换显示默认的 button。
如果想实现组件分成三部分就可以使用三个
<slot></slot>
来填充插槽了。
slot-具名插槽的使用
具名插槽,就是可以让插槽按指定的顺序填充,而没有具名的插槽是按照你填充的顺序排列的,而具名插槽可以自定义排列。
<!-- 父组件 -->
<div id="app">
<cpn>
<span>具名插槽</span>
<span slot="left">这是左边具名插槽</span>
<!-- 新语法 -->
<template v-slot:center>这是中间具名插槽</template>
<!-- 新语法缩写 -->
<template #right>这是右边具名插槽</template>
</cpn>
</div>
<!-- 插槽的基本使用使用<slot></slot> -->
<!-- 子组件 -->
<template id="cpn">
<div>
<slot name="left">左边</slot>
<slot name="center">中间</slot>
<slot name="right">右边</slot>
<slot>没有具名的插槽</slot>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const cpn = {
template: '#cpn',
data() {
return {
message: '我是子组件',
}
},
}
const app = new Vue({
el: '#app',
data() {
return {
message: '我是父组件消息',
}
},
components: {
cpn,
},
})
</script>
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
如图所示
没有具名的插槽排在最后,因为在定义组件的时候,排在了最后,如果有多个按顺序排列。具名插槽按照自定义的顺序排列。
定义具名插槽,使用 name 属性,给插槽定义一个名字。
<!-- 插槽的基本使用使用<slot></slot> -->
<!-- 子组件模板 -->
<template id="cpn">
<div>
<slot name="left">左边</slot>
<slot name="center">中间</slot>
<slot name="right">右边</slot>
<slot>没有具名的插槽</slot>
</div>
</template>
2
3
4
5
6
7
8
9
10
使用具名插槽,在自定义组件标签内使用 slot="left",插入指定插槽
<!-- 父组件 -->
<div id="app">
<cpn>
<span>具名插槽</span>
<span slot="left">这是左边具名插槽</span>
<!-- 新语法 -->
<template v-slot:center>这是中间具名插槽</template>
<!-- 新语法缩写 -->
<template #right>这是右边具名插槽</template>
</cpn>
</div>
2
3
4
5
6
7
8
9
10
11
注意:此处有是三种写法,获取指定插槽。
编译的作用域
前面说过组件都有自己的作用域,自己组件的作用在自己组件内。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>编译的作用域</title>
</head>
<body>
<!-- 父组件 -->
<div id="app">
<!-- 使用的vue实例作用域的isShow -->
<cpn v-show="isShow"></cpn>
</div>
<!-- 子组件 -->
<template id="cpn">
<div>
<h2>我是子组件</h2>
<p>哈哈哈</p>
<!-- 组件作用域,使用的子组件的作用域 -->
<button v-show="isShow"></button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const cpn = {
template: '#cpn',
data() {
return {
isShow: false,
}
},
}
const app = new Vue({
el: '#app',
data() {
return {
message: '我是父组件消息',
isShow: true,
}
},
components: {
cpn,
},
})
</script>
</body>
</html>
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
结果如下
子组件使用的是子组件的 isShow,子组件为 false,所以 button 没显示,被隐藏。
作用域插槽案例
父组件替换插槽的标签,但是内容是由子组件来提供。
当组件需要在多个父组件多个界面展示的时候,将内容放在子组件插槽中,父组件只需要告诉子组件使用什么方式展示界面。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>作用域插槽案例</title>
</head>
<body>
<!-- 父组件 -->
<div id="app">
<cpn></cpn>
<!-- 目的是获取子组件数据 -->
<cpn>
<!-- 2.5以下必须使用template -->
<template slot-scope="slot">
<!-- <span v-for="(item, index) in slot.data" :key="index">{{item}}-</span> -->
<span>{{slot.data.join(' - ')}}</span>
</template>
</cpn>
<cpn>
<!-- 2.5以下必须使用template -->
<template slot-scope="slot">
<!-- <span v-for="(item, index) in slot.data" :key="index">{{item}}*</span> -->
<span>{{slot.data.join(' * ')}}</span>
</template>
</cpn>
</div>
<!-- 插槽的基本使用使用<slot></slot> -->
<!-- 子组件 -->
<template id="cpn">
<div>
<slot :data="pLanguage">
<ul>
<li v-for="(item, index) in pLanguage" :key="index">{{item}}</li>
</ul>
</slot>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const cpn = {
template: '#cpn',
data() {
return {
isShwo: false,
pLanguage: ['JavaScript', 'Java', 'C++', 'C'],
}
},
}
const app = new Vue({
el: '#app',
data() {
return {
isShow: true,
}
},
components: {
cpn,
},
})
</script>
</body>
</html>
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
组件中使用 slot-scope="slot"(2.6.0 已经废弃)给插槽属性命名,在通过 slot 调用绑定在插槽上的属性。也可以使用 v-slot="slot"。