Vue3-06

组件注册方式

一个组件在使用之前,必须先注册,否则会报错。而注册组件的方式有两种,分别是全局注册和局部注册。

在 Vue3 中,我们可以通过 app.component 方法来注册一个全局组件,该方法接收两个参数,第一个参数是组件的名称,第二个参数是组件的选项对象。

而局部注册则是通过 components 选项来实现的,该选项接收一个对象,对象的键是组件的名称,值是组件的选项对象。

全局注册

通过修改 main.js 文件,我们可以在全局注册一个组件。

1
2
3
4
// 全局注册
app.component('my-component', {
template: '<div>my component</div>'
})

e.g.

1
2
3
4
5
6
7
8
9
10
11
12
import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

// 全局注册
// 注册的组件要在 `app.mount()` 之前。
app.component('my-component', {
template: '<div>my component</div>'
})// 这里的 my-component 就是组件的名称,可以自定义,但是不能使用驼峰命名法,而是要使用短横线分隔命名法。

app.mount('#app')

全局注册的组件可以在任何组件中使用,但是如果组件过多,会导致全局变量过多,不利于维护。并且如果被注册的组件没有被使用,也会被打包到最终的代码中,增加了代码的体积。

局部注册

局部注册的组件只能在当前组件中使用,但是不会污染全局变量。

1
2
3
4
5
6
7
8
9
10
import { createApp } from 'vue'
import App from './App.vue'
import MyComponent from './components/MyComponent.vue'

const app = createApp(App)

// 局部注册
app.component('my-component', MyComponent)

app.mount('#app')

组件传递数据

组件与组件间并非孤立的,它们之间是可以相互通信的。

在 Vue3 中,组件之间的数据传递方式与 Vue2 中有所不同。

在 Vue2 中,我们可以通过 props 选项来实现父子组件之间的数据传递,而在 Vue3 中,我们同样可以通过 props 选项来实现父子组件之间的数据传递,但是 props 选项的使用方式与 Vue2 中有所不同。

props 使用

我们在 components 文件夹中创建一个 ParentComponent.vue 文件,该文件是父组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>
<div>
<p>父组件</p>
<p>{{ name }}</p>
<ChildComponent :name="name" />
</div>
</template>

<script>
import ChildComponent from './ChildComponent.vue'

export default {
components: {
ChildComponent
},
data() {
return {
name: 'a'
}
}
}
</script>

在父组件中,我们通过 data 选项定义了一个 name 属性,并将其绑定到了模板中。

然后我们在 components 文件夹中创建一个 ChildComponent.vue 文件,该文件是子组件。

1
2
3
4
5
6
7
8
9
10
11
12
<template>
<div>
<p>子组件</p>
<p>{{ name }}</p>
</div>
</template>

<script>
export default {
props: ['name']
}
</script>

在子组件中,我们通过 props 选项定义了一个 name 属性,该属性的值是一个数组,数组中的元素就是我们要接收的数据的名称。

组件传递多种类型数据

在上一节中,我们通过 props 选项实现了父子组件之间的数据传递,但是我们只传递了一个字符串类型的数据,那么如果我们要传递多种类型的数据,该怎么办呢?

我们在 components 文件夹中创建一个 ParentComponent.vue 文件,该文件是父组件。

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
<template>
<div>
<p>父组件</p>
<p>{{ name }}</p>
<p>{{ age }}</p>
<p>{{ height }}</p>
<p>{{ favorite }}</p>
<ChildComponent :name="name" :age="age" :height="height" :favorite="favorite" />
</div>
</template>

<script>
import ChildComponent from './ChildComponent.vue'

export default {
components: {
ChildComponent
},
data() {
return {
name: 'a',
age: 18,
height: 1.88,
favorite: ['a', 'b', 'c']
}
}
}
</script>

在父组件中,我们通过 data 选项定义了三个属性,并将其绑定到了模板中。

然后我们在 components 文件夹中创建一个 ChildComponent.vue 文件,该文件是子组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<template>
<div>
<p>子组件</p>
<p>{{ name }}</p>
<p>{{ age }}</p>
<p>{{ height }}</p>
<ul>
<li v-for="(item, index) in favorite" :key="index">{{ item }}</li>
</ul>
</div>
</template>

<script>
export default {
props: ['name', 'age', 'height', 'favorite']
}
</script>

在子组件中,我们通过 props 选项定义了四个属性,该属性的值是一个数组,数组中的元素就是我们要接收的数据的名称。

上面的例子中,我们传递了字符串、数字、浮点数和数组四种类型的数据,但是如果我们要传递对象类型的数据,该怎么办呢?

修改 ParentComponent.vue 文件,如下所示。

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
<template>
<div>
<p>父组件</p>
<p>{{ info }}</p>
<ChildComponent :info="info" />
</div>
</template>

<script>
import ChildComponent from './ChildComponent.vue'

export default {
components: {
ChildComponent
},
data() {
return {
info: {
name: 'b',
age: 19,
height: 1.77
}
}
}
}
</script>

修改 ChildComponent.vue 文件,如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
<div>
<p>子组件</p>
<p>{{ info.name }}</p>
<p>{{ info.age }}</p>
<p>{{ info.height }}</p>
</div>
</template>

<script>
export default {
props: ['info']
}
</script>

我们还可以通过 type 选项来指定接收的数据的类型。

使用上面例子的 ParentComponent.vue 文件。修改 ChildComponent.vue 文件,如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<div>
<p>子组件</p>
<p>{{ info.name }}</p>
<p>{{ info.age }}</p>
<p>{{ info.height }}</p>
</div>
</template>

<script>
export default {
props: {
info: {
type: Object
}
}
}
</script>

传递的数据类型不是对象,那么就会报错。

我们还可传递 boolean 类型的数据。

修改 ParentComponent.vue 文件,如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>
<div>
<p>父组件</p>
<p>{{ isShow }}</p>
<ChildComponent :isShow="isShow" />
</div>
</template>

<script>
import ChildComponent from './ChildComponent.vue'

export default {
components: {
ChildComponent
},
data() {
return {
isShow: true
}
}
}
</script>

修改 ChildComponent.vue 文件,如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<div>
<p>子组件</p>
<p>{{ isShow }}</p>
</div>
</template>

<script>
export default {
props: {
isShow: {
type: Boolean
//default: false
default() {
return false
}// 这里的 default 选项可以是一个函数,函数的返回值就是默认值。
}
}
}
</script>

props 验证

上面我们通过 type 选项来指定接收的数据的类型,其实可以用做简单的验证,但是还有更强大的验证方式。

我们可以通过 required 选项来指定接收的数据是否必须传递。

修改 ParentComponent.vue 文件,如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>
<div>
<p>父组件</p>
<p>{{ name }}</p>
<ChildComponent :name="name" />
</div>
</template>

<script>
import ChildComponent from './ChildComponent.vue'

export default {
components: {
ChildComponent
},
data() {
return {
name: 'a'
}
}
}
</script>

修改 ChildComponent.vue 文件,如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<template>
<div>
<p>子组件</p>
<p>{{ name }}</p>
</div>
</template>

<script>
export default {
props: {
name: {
type: String,
required: true
}
}
}
</script>

添加 required: true 选项后,如果父组件没有传递 name 属性,那么就会报错。

props 是只读的,我们不能在子组件中修改 props 中的数据。

此外,我们还可以通过 validator 选项来指定自定义验证函数。

保持 ParentComponent.vue 文件不变。修改 ChildComponent.vue 文件,如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<div>
<p>子组件</p>
<p>{{ name }}</p>
</div>
</template>

<script>
export default {
props: {
name: {
type: String,
required: true,
validator(value) {
return value.length > 0
}
}
}
}
</script>