component.md 18.5 KB
Newer Older
D
DCloud_LXH 已提交
1 2
# 组件

W
wanganxp 已提交
3
我们可以对一段要复用的js/uts逻辑代码进行封装,抽出function、module等形式。
D
DCloud_LXH 已提交
4

W
wanganxp 已提交
5 6 7
那么涉及UI的复用时,该如何抽象?

这就是vue的组件机制,把视图template、script、style都封装到独立的uvue组件文件中,在其他需要的地方使用组件的名称进行引用。
D
DCloud_LXH 已提交
8 9 10

每个组件,包括如下几个部分:以组件名称为标记的开始标签和结束标签、组件内容、组件属性、组件属性值。

D
DCloud_LXH 已提交
11 12
- 组件名称由尖括号包裹,称为标签,它有开始标签和结束标签。结束标签的`<`后面用`/`来表示结束。结束标签也称为闭合标签。如`<component-name>`是开始标签,`</component-name>`是结束标签
- 在开始标签和结束标签之间,称为组件内容
D
DCloud_LXH 已提交
13 14 15
- 开始标签上可以写属性,属性可以有多个,多个属性之间用空格分割
- 每个属性通过`=`赋值

D
DCloud_LXH 已提交
16
组件还可以封装方法、事件、插槽,提供了[组件的生命周期](#component-lifecycle),提供了组件和页面的[互通信机制](#use-and-communication),满足了各种高级需求。
W
wanganxp 已提交
17

D
DCloud_LXH 已提交
18 19 20 21 22 23 24 25 26 27
## 组件内容构成 @component-structure

uni-app x 组件基于 vue 单文件组件规范,一个组件内,有 3 个根节点标签:

- `<template>`:组件的模板内容
- `<script>`:组件的脚本代码
- `<style>`:组件的样式

### 和页面的区别 @component-page-difference

W
wanganxp 已提交
28
组件的内容构成和页面大体上一致,都符合vue的sfc规范。
D
DCloud_LXH 已提交
29

W
wanganxp 已提交
30 31 32 33 34 35
事实上,一个在pages.json注册的页面uvue文件,也可以被当做一个组件引入到其他页面。

组件和页面的差别有:
1. 组件中不支持页面相关的生命周期和API,比如 `onLoad``onShow`[页面生命周期](../page.md#lifecycle),比如$setPageStyle等API。
2. 组件中有一批组件独有的生命周期和API,比如 `mounted``unmounted`[组件生命周期](#component-lifecycle),比如页面和组件通信的API。
3. 组件文件不需要在pages.json中注册
D
DCloud_LXH 已提交
36

W
wanganxp 已提交
37 38 39

## 创建及引用组件 @create-and-import-component
<!-- TODO:此处需要重写 -->
D
DCloud_LXH 已提交
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
### 创建组件 @create-component

#### easycom

1.`项目根目录/components` 目录上右键(如果没有,在根目录新建一个 `components` 目录即可),选择 `新建组件`,输入组件名称,选择一个模板;可勾选创建同名目录,将组件放在同名目录下。
2.`项目根目录/uni_modules` 目录上右键(如果没有,在根目录新建一个 `uni_modules` 目录即可),选择 `新建uni_modules插件`,输入`插件ID`,分类选择`前端组件-通用组件`;将组件放在和插件ID同名的目录下。

#### 创建自定义组件 @create-custom-component

3. 在项目 `pages 目录` 下的任意地方创建 `.uvue/.vue` 文件并编写组件代码

::: warning 注意事项
uni-app x 项目支持使用 `.vue``.uvue` 文件作为组件使用,但同文件名的两个文件同时存在,`.uvue` 文件会优先编译。
:::

### 引用组件 @import-component
#### easycom
D
DCloud_LXH 已提交
57 58 59

传统vue组件,需要安装、引用、注册,三个步骤后才能使用组件。`easycom` 将其精简为一步。

60
只要组件安装在项目的 `components` 目录下或 `uni_modules/插件 id/components/插件 id/插件 id.uvue` 目录下,并符合 `组件名称/组件名称.(vue|uvue)` 目录结构。就可以不用引用、注册,直接在页面中使用。
D
DCloud_LXH 已提交
61

62
- 比如 [uni-loading](https://ext.dcloud.net.cn/plugin?id=15980),它导入到项目后,存放在了目录 /uni_modules/uni-loading/components/uni-loading/uni-loading.uvue
D
DCloud_LXH 已提交
63

64
  同时它的组件名称也叫 uni-loading,所以这样的组件,不用在 script 里注册和引用。如下:
D
DCloud_LXH 已提交
65 66 67 68

  ```html
  <template>
      <view>
69
        <uni-loading></uni-loading><!-- 这里会显示一个loading -->
D
DCloud_LXH 已提交
70 71 72
      </view>
    </template>
  <script>
73
    // 这里不用import引入,也不需要在components内注册组件。template里就可以直接用
D
DCloud_LXH 已提交
74
    // ...
D
DCloud_LXH 已提交
75 76 77
  </script>
  ```

78
这里出现了`uni_module`的概念,简单说下,它是uni-app的一种包管理方案。
D
DCloud_LXH 已提交
79

80
`uni_module`其实不止服务于组件,它可以容纳组件、script库、页面、项目等所有DCloud插件市场所支持的种类。
D
DCloud_LXH 已提交
81 82 83 84 85

在HBuilderX中点右键可方便的更新插件,插件作者也可以方便的上传插件。

uni_module有详细的专项文档,请另行查阅[uni_module规范](https://uniapp.dcloud.net.cn/plugin/uni_modules.html)

W
wanganxp 已提交
86 87
如果你的组件不满足easycom标准的目录规范,还有一种办法是在[pages.json](../collocation/pagesjson.md#pages-easycom)里声明自己的目录规则,以便编译器查找到你的组件。自定义easycom路径规则的详细教程[详见](https://uniapp.dcloud.net.cn/collocation/pages.html#easycom)

D
DCloud_LXH 已提交
88
##### easycom组件的类型规范 @easycom-component-type
D
DCloud_LXH 已提交
89 90 91 92 93 94

组件标签名首字母大写,`驼峰+ComponentPublicInstance`,如:

`<test/>` 类型为:TestComponentPublicInstance
`<uni-data-checkbox/>` 类型为:UniDataCheckboxComponentPublicInstance

D
DCloud_LXH 已提交
95
#### 手动引入组件 @manual-import-component
D
DCloud_LXH 已提交
96

97
不符合 easycom 规范的组件,则需要手动引入:
D
DCloud_LXH 已提交
98 99 100 101 102 103 104 105 106 107

```vue
<!-- 组件 child.vue -->
<template>
  <view>Child Component</view>
</template>

<!-- 页面(与 child.vue 组件在同级目录 -->
<template>
  <view>
D
DCloud_LXH 已提交
108
    <child ref="component1"></child>
D
DCloud_LXH 已提交
109 110 111 112 113 114 115 116
  </view>
</template>
<script>
// 引入 child 组件
import child from './child.vue'
export default {
  components: {
    child
D
DCloud_LXH 已提交
117 118 119 120 121
  },
  data() {
    return {
      component1: null as ComponentPublicInstance | null // 手动引入组件时的类型
    }
D
DCloud_LXH 已提交
122 123 124 125 126
  }
}
</script>
```

D
DCloud_LXH 已提交
127
##### 手动引入组件的类型规范 @manual-import-component-type
D
DCloud_LXH 已提交
128 129 130 131 132

类型为:ComponentPublicInstance


## 使用及通信 @use-and-communication
D
DCloud_LXH 已提交
133 134 135 136 137 138 139 140 141 142 143 144

### 页面与页面通信 @page-page-communication

1. 使用 [navigateTo](https://doc.dcloud.net.cn/uni-app-x/api/navigator.html#navigateto)`url` 地址中携带参数
2. 使用 [event-bus](https://doc.dcloud.net.cn/uni-app-x/api/event-bus.html)

### 页面与组件通信 @page-component-communication

#### 向组件传递 `props` @transfer-component-props

示例 [详情](<!-- VUEJSON.E_component-instance.props_props-options.gitUrl -->)

D
DCloud_LXH 已提交
145 146 147 148 149
::: warning 注意
- 选项式 API:`this.$props``Map` 类型,需要使用 `this.$props["propName"]` 来访问
- 组合式 API:可以使用 `.` 点操作符来访问
:::

D
DCloud_LXH 已提交
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
::: preview <!-- VUEJSON.E_component-instance.props_props-options.webUrl -->

> 选项式 API

<!-- VUEJSON.E_component-instance.props_props-options.code -->

> 组合式 API

<!-- VUEJSON.E_component-instance.props_props-composition.code -->

:::

#### 向组件传递回调函数 @transfer-component-method

示例 [详情](<!-- VUEJSON.E_component-instance.emit-function_emit-function-options.gitUrl -->)

::: preview <!-- VUEJSON.E_component-instance.emit-function_emit-function-options.webUrl -->

> 选项式 API

<!-- VUEJSON.E_component-instance.emit-function_emit-function-options.code -->

> 组合式 API

<!-- VUEJSON.E_component-instance.emit-function_emit-function-composition.code -->

:::

#### 使用 `provide/inject` 来向下传递参数 @provide-inject

示例 [详情](<!-- VUEJSON.E_component-instance.provide_provide-options-1.gitUrl -->)

::: preview <!-- VUEJSON.E_component-instance.provide_provide-options-1.webUrl -->

D
DCloud_LXH 已提交
184
> 选项式 API
D
DCloud_LXH 已提交
185 186 187 188 189 190 191 192 193 194 195

<!-- VUEJSON.E_component-instance.provide_provide-options-1.code -->

> 组合式 API

<!-- VUEJSON.E_component-instance.provide_provide-composition.code -->

:::

#### 使用 [全局变量与状态管理](../tutorial/store.md) @global-store

D
DCloud_LXH 已提交
196 197
> store/index.uts [文件详情](https://gitcode.net/dcloud/hello-uvue/-/blob/alpha/store/index.uts)

D
DCloud_LXH 已提交
198 199 200 201 202 203 204 205 206 207 208 209 210 211
示例 [详情](<!-- VUEJSON.E_examples.nested-component-communication_nested-component-communication-options.gitUrl -->)

::: preview <!-- VUEJSON.E_examples.nested-component-communication_nested-component-communication-options.webUrl -->

> 选项式 API

<!-- VUEJSON.E_examples.nested-component-communication_nested-component-communication-options.code -->

> 组合式 API

<!-- VUEJSON.E_examples.nested-component-communication_nested-component-communication-composition.code -->

:::

D
DCloud_LXH 已提交
212
#### 在 `main.uts` 中使用 `app.config.globalProperties`
D
DCloud_LXH 已提交
213

D
DCloud_LXH 已提交
214 215 216 217 218 219 220 221
如在 `main.uts` 中的 `createApp` 方法中使用:
```ts
app.config.globalProperties.globalPropertiesReactiveObj = reactive({
  str: 'default reactive string',
  num: 0,
  bool: false,
} as UTSJSONObject)
```
D
DCloud_LXH 已提交
222

D
DCloud_LXH 已提交
223
示例 [详情](<!-- VUEJSON.E_app-instance.globalProperties_globalProperties-options.gitUrl -->)
D
DCloud_LXH 已提交
224

D
DCloud_LXH 已提交
225
::: preview <!-- VUEJSON.E_app-instance.globalProperties_globalProperties-options.webUrl -->
D
DCloud_LXH 已提交
226 227 228

> 选项式 API

D
DCloud_LXH 已提交
229
<!-- VUEJSON.E_app-instance.globalProperties_globalProperties-options.code -->
D
DCloud_LXH 已提交
230 231 232

> 组合式 API

D
DCloud_LXH 已提交
233
<!-- VUEJSON.E_app-instance.globalProperties_globalProperties-composition.code -->
D
DCloud_LXH 已提交
234 235 236

:::

D
DCloud_LXH 已提交
237 238 239 240 241 242

### 父组件与子组件通信 @parent-child-communication

上述 [页面与组件通信](#page-component-communication) 方法同样适用于父组件与子组件通信。

### 页面调用组件方法 @page-call-component-method
D
DCloud_LXH 已提交
243 244 245

#### 调用 `easycom` 组件方法 @call-easycom-component-method

D
DCloud_LXH 已提交
246
> 在调用组件方法的时候如报错 `error: Reference has a nullable type` 则需要使用 `?.` 操作符(如:a?.b?.())。
D
DCloud_LXH 已提交
247 248 249 250 251

easycom组件,用法和内置组件一样。也是使用 `this.$refs` 获取组件并转换为组件的类型,通过 `.`操作符 调用组件方法或设置属性。

**语法**

D
DCloud_LXH 已提交
252
```(this.$refs['组件ref属性值'] as 驼峰ComponentPublicInstance)?.foo?.();```
D
DCloud_LXH 已提交
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267

示例 [详情](<!-- VUEJSON.E_component-instance.methods_call-method-easycom-options.gitUrl -->)

::: preview <!-- VUEJSON.E_component-instance.methods_call-method-easycom-options.webUrl -->

> 选项式 API

<!-- VUEJSON.E_component-instance.methods_call-method-easycom-options.code -->

> 组合式 API

<!-- VUEJSON.E_component-instance.methods_call-method-easycom-composition.code -->

:::

D
DCloud_LXH 已提交
268
##### 调用 `uni_modules easycom` 组件方法 <Badge text="HBuilderX 3.97+"> @call-uni-modules-easycom-component-method
D
DCloud_LXH 已提交
269 270 271

使用 `ref` 属性拿到组件实例,调用 `easycom` 组件方法时不需要使用 `$callMethod` 方法,直接使用点操作符即可 `.`

D
DCloud_LXH 已提交
272
> 在调用组件方法的时候如报错 `error: Reference has a nullable type` 则需要使用 `?.` 操作符(如:a?.b?.())。
D
DCloud_LXH 已提交
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287

示例 [详情](<!-- VUEJSON.E_component-instance.methods_call-method-easycom-uni-modules-options.gitUrl -->)

::: preview <!-- VUEJSON.E_component-instance.methods_call-method-easycom-uni-modules-options.webUrl -->

> 选项式 API

<!-- VUEJSON.E_component-instance.methods_call-method-easycom-uni-modules-options.code -->

> 组合式 API

<!-- VUEJSON.E_component-instance.methods_call-method-easycom-uni-modules-composition.code -->

:::

D
DCloud_LXH 已提交
288 289 290 291 292 293 294 295 296 297
#### 使用 `ref` 属性搭配 `$callMethod` 方法 @call-component-method

如果不是内置组件,也不是easycom组件,那么无法使用`.`操作符了。

此时需使用 `this.$refs` 获取组件实例,然后通过 `$callMethod` 调用组件的方法。也就是把组件的方法名、参数,当做callMethod的参数来传递。此时也就没有`.`操作符那样的代码提示和校验了。

callMethod可用于所有自定义组件,包括easycom组件也可以使用,只不过easycom组件有更简单的用法。

**语法**

D
DCloud_LXH 已提交
298
```(this.$refs['组件ref属性值'] as ComponentPublicInstance)?.$callMethod('方法名', ...args)```
D
DCloud_LXH 已提交
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322

**组件类型**

ComponentPublicInstance

示例 [详情](<!-- VUEJSON.E_component-instance.parent_parent-options.gitUrl -->)

::: preview <!-- VUEJSON.E_component-instance.parent_parent-options.webUrl -->

> 选项式 API

<!-- VUEJSON.E_component-instance.parent_parent-options.code -->

> 组合式 API

<!-- VUEJSON.E_component-instance.parent_parent-composition.code -->

:::

**注意:**
- App-Android 平台 `4.0` 版本开始支持 `$callMethod` 调用 `defineExpose` 导出的方法
- Web 平台、App-iOS 平台 `4.13` 版本开始支持 `$callMethod` 调用 `defineExpose` 导出的方法


D
DCloud_LXH 已提交
323 324 325 326 327 328
#### 内置组件的方法调用或设置属性 <Badge text="HBuilderX 3.93+"> @call-builtin-component-method

使用 `this.$refs` 获取组件并as转换为组件对应的element类型,通过 `.`操作符 调用组件方法或设置属性。

**语法**

D
DCloud_LXH 已提交
329
```(this.$refs['组件ref属性值'] as Uni[xxx]Element)?.foo?.();```
D
DCloud_LXH 已提交
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358

**内置组件的element类型规范**

Uni`组件名(驼峰)`Element

如:

`<button>`: UniButtonElement
`<picker-view>`: UniPickerViewElement


示例 [详情](<!-- VUEJSON.E_component-instance.methods_call-method-uni-element-options.gitUrl -->)

::: preview <!-- VUEJSON.E_component-instance.methods_call-method-uni-element-options.webUrl -->

> 选项式 API

<!-- VUEJSON.E_component-instance.methods_call-method-uni-element-options.code -->

> 组合式 API

<!-- VUEJSON.E_component-instance.methods_call-method-uni-element-composition.code -->

:::

**bug&tips**

- 目前uts组件,即封装原生ui给uni-app或uni-app x的页面中使用,类型与内置组件的 Uni`组件名(驼峰)`Element 方式相同。目前没有代码提示。

D
DCloud_LXH 已提交
359
### 组件监听应用、页面生命周期 @component-page-lifecycle
D
DCloud_LXH 已提交
360

D
DCloud_LXH 已提交
361
> 选项式 API 和 组件式 API 在监听页面生命周期时有所不同
D
DCloud_LXH 已提交
362
>
D
DCloud_LXH 已提交
363
> 比如选项式 API 中的 `onShow`、`onHide` 监听页面生命周期在组合式 API 中分别对应 `onPageShow`、`onPageHide`(在组合式 API 时会和 App 的生命周期冲突)
D
DCloud_LXH 已提交
364
>
D
DCloud_LXH 已提交
365
> 具体请查看 [页面生命周期](../page.md#lifecycle)
D
DCloud_LXH 已提交
366

D
DCloud_LXH 已提交
367 368 369 370 371
::: warning 注意
1. onAppHide、onAppShow 目前只有 Android 支持
2. onPageHide、onPageShow 需要写在 setup 函数或者 `<script setup>` 中才能生效
:::

D
DCloud_LXH 已提交
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
示例 [详情](<!-- VUEJSON.E_lifecycle.page_monitor-page-lifecycle-options.gitUrl -->)

::: preview <!-- VUEJSON.E_lifecycle.page_page-options.webUrl -->

> 选项式 API

<!-- VUEJSON.E_lifecycle.page_monitor-page-lifecycle-options.code -->

> 组合式 API

<!-- VUEJSON.E_lifecycle.page_monitor-page-lifecycle-composition.code -->

:::

## 组件的生命周期 @component-lifecycle

388 389 390 391 392 393 394 395
#### 组件生命周期(选项式 API)兼容性 @component-lifecycle-options-compatibility

<!-- VUEJSON.options_lifecycle.compatibility -->

### 组件生命周期(组合式 API)兼容性 @component-lifecycle-composition-compatibility

<!-- VUEJSON.composition_lifecycle.compatibility -->

D
DCloud_LXH 已提交
396 397
示例 [详情](<!-- VUEJSON.E_lifecycle.component_ChildComponentOptions.gitUrl -->)

D
DCloud_LXH 已提交
398
::: preview <!-- VUEJSON.E_lifecycle.component_component-options.webUrl -->
D
DCloud_LXH 已提交
399 400 401 402 403 404 405 406 407 408 409

> 选项式 API

<!-- VUEJSON.E_lifecycle.component_ChildComponentOptions.code -->

> 组合式 API

<!-- VUEJSON.E_lifecycle.component_ChildComponentComposition.code -->

:::

D
DCloud_LXH 已提交
410 411 412
## 全局组件 @global-component

[详情见 app.component](./global-api.md#app-component)
D
DCloud_LXH 已提交
413

D
DCloud_LXH 已提交
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
## props

- 支持[对象方式](https://cn.vuejs.org/guide/components/props.html#props-declaration)声明。从 4.0+ 支持字符串数组方式声明。使用字符串数组方式声明时,所有 prop 类型均为 any | null。
- 仅支持直接在 `export default` 内部声明,不支持其他位置定义后,在 `export default` 中引用。
- 复杂数据类型需要通过 `PropType` 标记类型,[详见](https://cn.vuejs.org/guide/typescript/options-api.html#typing-component-props)
- `type` 不支持使用自定义的构造函数。

示例 [详情](<!-- VUEJSON.E_component-instance.props_props-options.gitUrl -->)

::: preview <!-- VUEJSON.E_component-instance.props_props-options.webUrl -->
> 选项式 API

<!-- VUEJSON.E_component-instance.props_props-options.code -->

> 组合式 API

<!-- VUEJSON.E_component-instance.props_props-composition.code -->

:::

## ref

`uni-app js 引擎版`中,非 `Web端` 只能用于获取自定义组件,不能用于获取内置组件实例(如:`view``text`)。\
`uni-app x` 中,内置组件会返回组件根节点的引用,自定义组件会返回组件实例。

**注意事项:**
- 如果多个节点或自定义组件绑定相同 `ref` 属性,将获取到最后一个节点或组件实例的引用。
-`v-for` 循环时,绑定 `ref` 属性会获取到节点或组件实例的集合。
-`uni-app x` 中,要访问 `$refs` 中的属性,需要使用索引方式。

示例 [详情](<!-- VUEJSON.E_component-instance.refs_refs-options.gitUrl -->)

::: preview <!-- VUEJSON.E_component-instance.refs_refs-options.webUrl -->
> uni-app x(选项式)

<!-- VUEJSON.E_component-instance.refs_refs-options.code -->

> uni-app x(组合式)

<!-- VUEJSON.E_component-instance.refs_refs-composition.code -->

> uni-app js 引擎版

```vue
<template>
	<view>
		<text ref="textRef">text node</text>
		<Foo ref="fooRef" />
	</view>
</template>

<script lang="ts">
  import type { ComponentPublicInstance } from 'vue'

	export default {
		onReady() {
			const text = this.$refs.textRef as Element // 仅H5端支持
			const foo = this.$refs.fooRef as ComponentPublicInstance
		}
	}
</script>
```
:::

## 自定义组件 v-model 绑定复杂表达式 @v-model-complex-expression

自定义组件 `v-model` 绑定复杂表达式时,需要通过 `as` 指定类型(仅App-Android 平台)。

::: preview
> 选项式 API
```ts
<template>
  <input v-model="obj.str as string" />
</template>

<script lang="uts">
	type Obj = {
		str : string
	}
	export default {
		data() {
			return {
				obj: {
					str: "str"
				} as Obj
			}
		}
	}
</script>
```
> 组合式 API
```ts
<template>
  <input v-model="obj.str as string" />
</template>

<script setup lang="uts">
  type Obj = {
    str: string
  }
  const obj = reactive({
      str: "str"
    } as Obj)
</script>
```
:::


## 作用域插槽的类型 @scoped-slot-type

D
DCloud_LXH 已提交
524
示例 [详情](<!-- VUEJSON.E_built-in.special-elements_slots_child-options.gitUrl -->)
D
DCloud_LXH 已提交
525 526

作用域插槽需在组件中指定插槽数据类型
D
DCloud_LXH 已提交
527
::: preview <!-- VUEJSON.E_built-in.special-elements_slots_child-options.webUrl -->
D
DCloud_LXH 已提交
528 529
> 选项式 API

D
DCloud_LXH 已提交
530
<!-- VUEJSON.E_built-in.special-elements_slots_child-options.code -->
D
DCloud_LXH 已提交
531 532 533

> 组合式 API

D
DCloud_LXH 已提交
534
<!-- VUEJSON.E_built-in.special-elements_slots_child-composition.code -->
D
DCloud_LXH 已提交
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572

:::

## 递归组件

实现递归组件时不要使用组件 import 自身的写法,直接在模板内使用组件名即可。

```vue
// component-a.uvue
<template>
  <view>
    <text>component-a::{{text}}</text>
    <component-a v-if="!end" :text="text" :limit="limit-1"></component-a>
  </view>
</template>

<script>
  // import componentA from './component-a' // 错误用法
  export default {
    name: "component-a",
    props: {
      text: {
        type: String,
        default: ''
      },
      limit: {
        type: Number,
        default: 2
      }
    },
    computed: {
      end() : boolean {
        return this.limit <= 0
      }
    }
  }
</script>
```