# 组件
我们可以对一段要复用的js/uts逻辑代码进行封装,抽出function、module等形式。
那么涉及UI的复用时,该如何抽象?
这就是vue的组件机制,把视图template、script、style都封装到独立的uvue组件文件中,在其他需要的地方使用组件的名称进行引用。
每个组件,包括如下几个部分:以组件名称为标记的开始标签和结束标签、组件内容、组件属性、组件属性值。
- 组件名称由尖括号包裹,称为标签,它有开始标签和结束标签。结束标签的`<`后面用`/`来表示结束。结束标签也称为闭合标签。如下面示例的``是开始标签,``是结束标签。
- 在开始标签和结束标签之间,称为组件内容。如下面示例的`content`
- 开始标签上可以写属性,属性可以有多个,多个属性之间用空格分割
- 每个属性通过`=`赋值
组件还可以封装方法、事件、插槽,提供了组件的生命周期,提供了组件和页面的互通信机制,满足了各种高级需求。
## 创建及引用组件 @create-and-import-component
### easycom
传统vue组件,需要安装、引用、注册,三个步骤后才能使用组件。`easycom` 将其精简为一步。
只要组件安装在项目的 `components` 目录下或 `uni_modules/插件 id/components/插件 id/插件 id.uvue` 目录下,并符合 `组件名称/组件名称.(vue|uvue)` 目录结构。就可以不用引用、注册,直接在页面中使用。
- 比如 [uni-loading](https://ext.dcloud.net.cn/plugin?id=15980),它导入到项目后,存放在了目录 /uni_modules/uni-loading/components/uni-loading/uni-loading.uvue
同时它的组件名称也叫 uni-loading,所以这样的组件,不用在 script 里注册和引用。如下:
```html
```
这里出现了`uni_module`的概念,简单说下,它是uni-app的一种包管理方案。
`uni_module`其实不止服务于组件,它可以容纳组件、script库、页面、项目等所有DCloud插件市场所支持的种类。
在HBuilderX中点右键可方便的更新插件,插件作者也可以方便的上传插件。
uni_module有详细的专项文档,请另行查阅[uni_module规范](https://uniapp.dcloud.net.cn/plugin/uni_modules.html)。
如果你的组件不满足easycom标准的目录规范,还有一种办法是在[pages.json](../collocation/pagesjson.md#pages-easycom)里声明自己的目录规则,以便编译器查找到你的组件。自定义easycom路径规则的详细教程[详见](https://uniapp.dcloud.net.cn/collocation/pages.html#easycom)
#### easycom组件的类型规范 @easycom-component-type
组件标签名首字母大写,`驼峰+ComponentPublicInstance`,如:
`` 类型为:TestComponentPublicInstance
`` 类型为:UniDataCheckboxComponentPublicInstance
### 手动引入组件 @manual-import-component
不符合 easycom 规范的组件,则需要手动引入:
```vue
Child Component
```
#### 手动引入组件的类型规范 @manual-import-component-type
类型为:ComponentPublicInstance
## 使用及通信 @use-and-communication
### 页面与页面通信 @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
示例 [详情]()
::: warning 注意
- 选项式 API:`this.$props` 是 `Map` 类型,需要使用 `this.$props["propName"]` 来访问
- 组合式 API:可以使用 `.` 点操作符来访问
:::
::: preview
> 选项式 API
> 组合式 API
:::
#### 向组件传递回调函数 @transfer-component-method
示例 [详情]()
::: preview
> 选项式 API
> 组合式 API
:::
#### 使用 `provide/inject` 来向下传递参数 @provide-inject
示例 [详情]()
::: preview
> 选项式 API
> 组合式 API
:::
#### 使用 [全局变量与状态管理](../tutorial/store.md) @global-store
> store/index.uts [文件详情](https://gitcode.net/dcloud/hello-uvue/-/blob/alpha/store/index.uts)
示例 [详情]()
::: preview
> 选项式 API
> 组合式 API
:::
#### 在 `main.uts` 中使用 `app.config.globalProperties`
如在 `main.uts` 中的 `createApp` 方法中使用:
```ts
app.config.globalProperties.globalPropertiesReactiveObj = reactive({
str: 'default reactive string',
num: 0,
bool: false,
} as UTSJSONObject)
```
示例 [详情]()
::: preview
> 选项式 API
> 组合式 API
:::
### 父组件与子组件通信 @parent-child-communication
上述 [页面与组件通信](#page-component-communication) 方法同样适用于父组件与子组件通信。
### 页面调用组件方法 @page-call-component-method
#### 调用 `easycom` 组件方法 @call-easycom-component-method
> 在调用组件方法的时候如报错 `error: Reference has a nullable type` 则需要使用 `?.` 操作符(如:a?.b?.())。
easycom组件,用法和内置组件一样。也是使用 `this.$refs` 获取组件并转换为组件的类型,通过 `.`操作符 调用组件方法或设置属性。
**语法**
```(this.$refs['组件ref属性值'] as 驼峰ComponentPublicInstance)?.foo?.();```
示例 [详情]()
::: preview
> 选项式 API
> 组合式 API
:::
##### 调用 `uni_modules easycom` 组件方法 @call-uni-modules-easycom-component-method
使用 `ref` 属性拿到组件实例,调用 `easycom` 组件方法时不需要使用 `$callMethod` 方法,直接使用点操作符即可 `.`
> 在调用组件方法的时候如报错 `error: Reference has a nullable type` 则需要使用 `?.` 操作符(如:a?.b?.())。
示例 [详情]()
::: preview
> 选项式 API
> 组合式 API
:::
#### 使用 `ref` 属性搭配 `$callMethod` 方法 @call-component-method
如果不是内置组件,也不是easycom组件,那么无法使用`.`操作符了。
此时需使用 `this.$refs` 获取组件实例,然后通过 `$callMethod` 调用组件的方法。也就是把组件的方法名、参数,当做callMethod的参数来传递。此时也就没有`.`操作符那样的代码提示和校验了。
callMethod可用于所有自定义组件,包括easycom组件也可以使用,只不过easycom组件有更简单的用法。
**语法**
```(this.$refs['组件ref属性值'] as ComponentPublicInstance)?.$callMethod('方法名', ...args)```
**组件类型**
ComponentPublicInstance
示例 [详情]()
::: preview
> 选项式 API
> 组合式 API
:::
**注意:**
- App-Android 平台 `4.0` 版本开始支持 `$callMethod` 调用 `defineExpose` 导出的方法
- Web 平台、App-iOS 平台 `4.13` 版本开始支持 `$callMethod` 调用 `defineExpose` 导出的方法
#### 内置组件的方法调用或设置属性 @call-builtin-component-method
使用 `this.$refs` 获取组件并as转换为组件对应的element类型,通过 `.`操作符 调用组件方法或设置属性。
**语法**
```(this.$refs['组件ref属性值'] as Uni[xxx]Element)?.foo?.();```
**内置组件的element类型规范**
Uni`组件名(驼峰)`Element
如:
`