提交 5a2a8eac 编写于 作者: D DCloud_LXH

wip: vue

上级 cf0701c5
......@@ -34,6 +34,11 @@ export const navbar = [
type: 'link',
link: '/uts/'
},
{
text: 'VUE',
type: 'link',
link: '/vue/'
},
{
text: '全局文件',
type: 'link',
......
......@@ -43,107 +43,142 @@ try {
pageInstanceJson = require('../utils/pageInstanceJson.json')
} catch (error) {}
function getRegExp(key) {
function getRegExp(key, text) {
return new RegExp(`<!--\\s*${key}.([\\w\\W]+[^\\s])\\s*-->`)
}
/**
*
* @param {string} text
* @returns {{match: RegExpMatchArray | null, json: {}}
* @returns {{match: RegExpMatchArray | null, json: {}, regExp: RegExp | null}
*/
const getJSON = text => {
let match = text.match(getRegExp('CSSJSON'))
const CSSJSONRegExp = getRegExp('CSSJSON')
let match = text.match(CSSJSONRegExp)
CSSJSONRegExp.lastIndex = 0
if (match) {
return {
match,
json: cssJson,
regExp: CSSJSONRegExp,
}
}
match = text.match(getRegExp('UTSJSON'))
const UTSJSONRegExp = getRegExp('UTSJSON')
match = text.match(UTSJSONRegExp)
UTSJSONRegExp.lastIndex = 0
if (match) {
return {
match,
json: utsJson,
regExp: UTSJSONRegExp,
}
}
match = text.match(getRegExp('UTSAPIJSON'))
const UTSAPIJSONRegExp = getRegExp('UTSAPIJSON')
match = text.match(UTSAPIJSONRegExp)
UTSAPIJSONRegExp.lastIndex = 0
if (match) {
return {
match,
json: utsApiJson,
regExp: UTSAPIJSONRegExp,
}
}
match = text.match(getRegExp('UTSCOMJSON'))
const UTSCOMJSONRegExp = getRegExp('UTSCOMJSON')
match = text.match(UTSCOMJSONRegExp)
UTSCOMJSONRegExp.lastIndex = 0
if (match) {
return {
match,
json: utsComJson,
regExp: UTSCOMJSONRegExp,
}
}
match = text.match(getRegExp('UTSUNICLOUDAPIJSON'))
const UTSUNICLOUDAPIJSONRegExp = getRegExp('UTSUNICLOUDAPIJSON')
match = text.match(UTSUNICLOUDAPIJSONRegExp)
UTSUNICLOUDAPIJSONRegExp.lastIndex = 0
if (match) {
return {
match,
json: utsUnicloudApiJson,
regExp: UTSUNICLOUDAPIJSONRegExp,
}
}
match = text.match(getRegExp('CUSTOMTYPEJSON'))
const CUSTOMTYPEJSONRegExp = getRegExp('CUSTOMTYPEJSON')
match = text.match(CUSTOMTYPEJSONRegExp)
CUSTOMTYPEJSONRegExp.lastIndex = 0
if (match) {
return {
match,
json: customTypeJson,
regExp: CUSTOMTYPEJSONRegExp,
}
}
match = text.match(getRegExp('VUEJSON'))
const VUEJSONRegExp = getRegExp('VUEJSON')
match = text.match(VUEJSONRegExp)
VUEJSONRegExp.lastIndex = 0
if (match) {
return {
match,
json: vueJson,
regExp: VUEJSONRegExp,
}
}
match = text.match(getRegExp('MANIFESTJSON'))
const MANIFESTJSONRegExp = getRegExp('MANIFESTJSON')
match = text.match(MANIFESTJSONRegExp)
MANIFESTJSONRegExp.lastIndex = 0
if (match) {
return {
match,
json: manifestJson,
regExp: MANIFESTJSONRegExp,
}
}
match = text.match(getRegExp('PAGESJSON'))
const PAGESJSONRegExp = getRegExp('PAGESJSON')
match = text.match(PAGESJSONRegExp)
PAGESJSONRegExp.lastIndex = 0
if (match) {
return {
match,
json: pagesJson,
regExp: PAGESJSONRegExp,
}
}
match = text.match(getRegExp('SPECIALSTRINGJSON'))
const SPECIALSTRINGJSONRegExp = getRegExp('SPECIALSTRINGJSON')
match = text.match(SPECIALSTRINGJSONRegExp)
SPECIALSTRINGJSONRegExp.lastIndex = 0
if (match) {
return {
match,
json: specialStringJson,
regExp: SPECIALSTRINGJSONRegExp,
}
}
match = text.match(getRegExp('PAGEINSTANCE'))
const PAGEINSTANCERegExp = getRegExp('PAGEINSTANCE')
match = text.match(PAGEINSTANCERegExp)
PAGEINSTANCERegExp.lastIndex = 0
if (match) {
return {
match,
json: pageInstanceJson,
regExp: PAGEINSTANCERegExp,
}
}
return {
match: null,
json: {},
regExp: null,
}
}
......@@ -157,8 +192,8 @@ module.exports = md => {
for (let index = 0; index < lines.length; index++) {
const line = lines[index]
const { match, json } = getJSON(line)
if (match) {
const { match, json, regExp } = getJSON(line)
if (match && regExp) {
const jsonPath = match[1]
const path = jsonPath.split('.')
let temp = json
......@@ -167,7 +202,7 @@ module.exports = md => {
temp = temp[key]
})
if (!temp) continue
lines[index] = temp
lines[index] = lines[index].replace(regExp, temp)
}
}
......
......@@ -7,8 +7,6 @@
* [复杂列表开发指南](tutorial/stickynestlist.md)
* [全局变量与状态管理](tutorial/store.md)
* [几种组件标记的概念澄清](tutorial/idref.md)
* vue 框架
* [概述](vue/README.md)
* [web端开发指南](web/README.md)
* 运行和调试
* [真机运行](https://uniapp.dcloud.net.cn/tutorial/run/run-app.html)
......
# uvue组件概述
uni-app x支持的组件包括:
- 内置基础组件
- 自定义vue组件
- uts组件插件
除了微信小程序,其他平台不支持的小程序wxml组件。
支持[easycom](https://uniapp.dcloud.net.cn/component/index.html#easycom)
内置组件比较简单,扩展组件的2种方式详细介绍下
- 自定义vue组件
在components目录新建一个uvue/vue文件,按vue组件规范编写代码。
组件界面通过uvue构造,script使用uts编写。
返回的类型是组件实例[ComponentPublicInstance](../vue/)。
- uts组件插件
`uts组件插件`的名称可能有点拗口,这是因为是相对于另一个分类`uts api插件`
它们同属于`uts插件`,是[uni_modules](https://uniapp.dcloud.net.cn/plugin/uni_modules.html)。api插件指能力扩展,比如蓝牙api。而组件插件指界面元素扩展,比如video、map、lottie动画等。
uts组件插件,指把原生的、需要在界面上显示的、内嵌于页面中整体排版的组件,编写uts代码调用原生sdk,通过uni_modules插件的方式集成到uni-app项目中。比如
* lottie组件,使用uts调用原生的lottie sdk来开发组件,再引入页面中。[详见](https://ext.dcloud.net.cn/plugin?name=uni-animation-view)
* video组件,其实官方的video,也是用uts组件插件实现的。[详见](https://gitcode.net/dcloud/uni-component/-/tree/master/uni_modules/uni-video)
uts组件插件,主要用于原生sdk涉及界面时,将其封装为界面组件。当然uts组件也是全端支持的。上述lottie组件也支持web端。
在app端,它的内部界面是由原生sdk绘制的,而不是uvue代码绘制的。通过封装嵌入到uvue/nvue页面中。
一个uts插件都是可以同时兼容uni-app x和uni-app js引擎版的。目前js引擎版仅支持内嵌于nvue页面中。所以上述lottie组件也是可以在app-nvue页面中使用的。
uts组件的返回类型是dom元素[Element](../dom/element.md)
uts组件插件的开发教程,[详见](https://uniapp.dcloud.net.cn/plugin/uts-component.html)
**vue组件兼容性及注意事项:**
## 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` 不支持使用自定义的构造函数。
::: preview
> 选项式 API
```ts
<script lang="uts">
export default {
// 字符串数组方式声明,所有 prop 类型均为 any | null
props: ['num', 'str', 'obj', 'arr']
}
</script>
```
> 组合式 API
```ts
<script setup lang="uts">
// 字符串数组方式声明,所有 prop 类型均为 any | null
const props = defineProps(['num', 'str', 'obj', 'arr'])
</script>
```
:::
::: preview
> 选项式 API
```ts
<script lang="uts">
type Obj = { a: number }
export default {
props: {
num: {
type: Number,
required: true
},
str: {
type: String,
default: 'str',
validator(value: string): boolean {
return value.length > 0
}
},
obj: {
type: UTSJSONObject as PropType<Obj>,
default: (): Obj => ({ a: 1 } as Obj)
},
arr: {
type: Array as PropType<number[]>,
default: (): number[] => [1, 2, 3]
}
}
}
</script>
```
> 组合式 API
```ts
<script setup lang="uts">
type Obj = { a: number }
const props = defineProps({
num: {
type: Number,
required: true
},
str: {
type: String,
default: 'str',
validator(value : string) : boolean {
return value.length > 0
}
},
obj: {
type: UTSJSONObject as PropType<Obj>,
default: () : Obj => ({ a: 1 } as Obj)
},
arr: {
type: Array as PropType<number[]>,
default: () : number[] => [1, 2, 3]
}
})
</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>
```
:::
## 作用域插槽的类型
作用域插槽需在组件中指定插槽数据类型
::: preview
> 选项式 API
```ts
// components/Foo.uvue
<template>
<slot msg="test msg" />
</template>
<script lang="uts">
import { SlotsType } from 'vue'
export default {
slots: Object as SlotsType<{
default: { msg: string }
}>
}
</script>
// page.uvue
<template>
<Foo>
<template v-slot="{ msg }">
<text>{{ msg }}</text>
</template>
</Foo>
</template>
<script lang="uts">
import Foo from './Foo.uvue'
export default {
components: { Foo },
}
</script>
```
> 组合式 API
```ts
// components/Foo.uvue
<template>
<slot msg="test msg" />
</template>
<script setup lang="uts">
defineSlots<{
default(props: { msg: string }): null
}>()
</script>
// page.uvue
<template>
<Foo>
<template v-slot="{ msg }">
<text>{{ msg }}</text>
</template>
</Foo>
</template>
<script setup lang="uts">
import Foo from './Foo.uvue'
</script>
```
:::
## ref
`uni-app js 引擎版`中,非 `Web端` 只能用于获取自定义组件,不能用于获取内置组件实例(如:`view``text`)。\
`uni-app x` 中,内置组件会返回组件根节点的引用,自定义组件会返回组件实例。
**注意事项:**
- 如果多个节点或自定义组件绑定相同 `ref` 属性,将获取到最后一个节点或组件实例的引用。
-`v-for` 循环时,绑定 `ref` 属性会获取到节点或组件实例的集合。
-`uni-app x` 中,要访问 `$refs` 中的属性,需要使用索引方式。
::: preview
> uni-app x
```ts
// 选项式 API
<template>
<view>
<text ref="textRef">text node</text>
<Foo ref="fooRef" />
</view>
</template>
<script lang="uts">
import type { ComponentPublicInstance } from 'vue'
export default {
onReady() {
const text = this.$refs["textRef"] as Element
const foo = this.$refs["fooRef"] as ComponentPublicInstance
}
}
</script>
// 组合式 API
<template>
<view>
<text ref="textRef">text node</text>
<Foo ref="fooRef" />
</view>
</template>
<script setup lang="uts">
import type { ComponentPublicInstance } from 'vue'
import Foo from './Foo.uvue'
const textRef = ref<null | Element>(null)
const fooRef = ref<null | ComponentPublicInstance>(null)
</script>
```
> uni-app js 引擎版
```ts
<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>
```
:::
## 监听页面生命周期
`4.0` 起可通过组合式 API 实现组件中监听页面生命周期,[示例代码](https://gitcode.net/dcloud/hello-uvue/-/blob/alpha/pages/composition-api/lifecycle/component-lifecycle/component-lifecycle.uvue)
`4.0` 起可通过组合式 API 实现组件中监听页面生命周期,[示例代码](../vue/component.md#component-lifecycle)
## 调用组件方法@methods
需要把组件分为 内置组件、easycom组件、非easycom组件,这3种组件有不同的方法调用方式。
需要把组件分为 内置组件、easycom组件、非easycom组件,这3种组件有不同的方法调用方式。[详情](../vue/component.md#page-call-component-method)
### 内置组件的方法调用或设置属性
> 3.93+ 支持
使用 `this.$refs` 获取组件并as转换为组件对应的element类型,通过 `.`操作符 调用组件方法或设置属性。
**语法**
```(this.$refs['组件ref属性值'] as Uni[xxx]Element).foo();```
**内置组件的element类型规范**
Uni`组件名(驼峰)`Element
如:
`<button>`: UniButtonElement
`<picker-view>`: UniPickerViewElement
**示例代码**
::: preview
> 选项式 API
```html
<template>
<slider ref="sliderRef" />
</template>
<script lang="uts">
export default {
onReady() {
// value 为属性
(this.$refs["sliderRef"] as UniSliderElement).value = 90;
//此处注意 sliderRef 必须存在,如不存在,把 null as 成 UniSliderElement 会引发崩溃
}
}
</script>
```
> 组合式 API
```html
<template>
<slider ref="sliderRef" />
</template>
<script setup lang="uts">
const sliderRef = ref<null | UniSliderElement>(null)
onReady(() => {
(sliderRef.value!).value = 90
})
</script>
```
:::
**bug&tips**
- 目前uts组件,即封装原生ui给uni-app或uni-app x的页面中使用,类型与内置组件的 Uni`组件名(驼峰)`Element 方式相同。目前没有代码提示。
使用 `this.$refs` 获取组件并as转换为组件对应的element类型,通过 `.`操作符 调用组件方法或设置属性。[详情](../vue/component.md#call-builtin-component-method)
### easycom组件调用方法或设置属性@method_easycom
> 3.97+ 支持 uni_modules 目录下的组件
easycom组件,用法和内置组件一样。也是使用 `this.$refs` 获取组件并转换为组件的类型,通过 `.`操作符 调用组件方法或设置属性。
**语法**
```(this.$refs['组件ref属性值'] as 驼峰ComponentPublicInstance).foo();```
**easycom组件的类型规范**
组件标签名首字母大写,驼峰+ComponentPublicInstance
如:
`<test/>` 类型为:TestComponentPublicInstance
`<uni-data-checkbox/>` 类型为:UniDataCheckboxComponentPublicInstance
**示例代码**
假使有一个 `Foo` 组件,其有若干方法 `foo1` 等,如下。
::: preview
> 选项式 API
```html
<script lang="uts">
export default {
methods: {
foo1() {
console.log("foo1 triggered");
},
foo2(num : number) {
console.log('foo2 triggered by num:', num);
},
foo3(callback : (() => void)) {
callback()
}
}
}
</script>
```
> 组合式 API
```html
<script setup lang="uts">
const foo1 = () => {
console.log("foo1 triggered");
}
const foo2 = (num : number) => {
console.log('foo2 triggered by num:', num);
}
const foo3 = (callback : (() => void)) => {
callback()
}
defineExpose({
foo1,
foo2,
foo3,
})
</script>
```
:::
`Foo` 组件符合[easycom规范](https://uniapp.dcloud.net.cn/component/#easycom)
那么在页面中调用 `Foo` 组件的方法如下:
::: preview
> 选项式 API
```html
<template>
<Foo ref="fooRef" />
</template>
<script lang="uts">
export default {
onReady() {
//注意组件必须存在,注意类型首字母大写
const fooRef = (this.$refs["fooRef"] as FooComponentPublicInstance)
fooRef.foo1();
fooRef.foo2(100);
fooRef.foo3(() => {console.log('foo3 triggered')});
}
}
</script>
```
> 组合式 API
```html
<template>
<Foo ref='fooRef' />
</template>
<script setup lang="uts">
const fooRef = ref<null | FooComponentPublicInstance>(null)
onReady(() => {
(fooRef.value!).foo1();
(fooRef.value!).foo2(100);
(fooRef.value!).foo3(() => {console.log('foo3 triggered')});
})
</script>
```
:::
easycom组件,用法和内置组件一样。也是使用 `this.$refs` 获取组件并转换为组件的类型,通过 `.`操作符 调用组件方法或设置属性。[详情](../vue/component.md#call-easycom-component-method)
### 其它自定义组件的方法调用使用callMethod@$callMethod
如果不是内置组件,也不是easycom组件,那么无法使用`.`操作符了。
此时需使用 `this.$refs` 获取组件实例,然后通过 `$callMethod` 调用组件的方法。也就是把组件的方法名、参数,当做callMethod的参数来传递。此时也就没有`.`操作符那样的代码提示和校验了。
callMethod可用于所有自定义组件,包括easycom组件也可以使用,只不过easycom组件有更简单的用法。
**语法**
```(this.$refs['组件ref属性值'] as ComponentPublicInstance).$callMethod('方法名', ...args)```
**组件类型**
ComponentPublicInstance
页面示例代码 `page.uvue`
::: preview
> 选项式 API
```html
<template>
<Foo ref="fooRef" />
</template>
<script lang="uts">
import Foo from './Foo.uvue'
export default {
components: {
Foo
},
onReady() {
const fooRef = this.$refs['fooRef'] as ComponentPublicInstance
fooRef.$callMethod('foo1')
const res = fooRef.$callMethod('foo2', 100, 10)
console.log('res of foo2', res)
fooRef.$callMethod('foo3', () => {
console.log('foo3 triggered')
})
}
}
</script>
```
> 组合式 API
```html
<template>
<Foo ref="fooRef" />
</template>
<script setup lang="uts">
import Foo from './Foo.uvue'
const fooRef = ref<null | ComponentPublicInstance>(null)
onReady(() => {
(fooRef.value!).$callMethod('foo1')
const res = (fooRef.value!).$callMethod('foo2', 100, 10)
console.log('res of foo2', res);
(fooRef.value!).$callMethod('foo3', () => {
console.log('foo3 triggered')
})
})
</script>
```
:::
组件示例代码 `Foo.uvue`
::: preview
> 选项式 API
```html
<script lang="uts">
export default {
methods: {
foo1() {
console.log("foo1 triggered");
},
foo2(num1 : number, num2: number){
console.log(`foo2 triggered by num1: ${num1}, num2: ${num2}`)
return num1 + num2
},
foo3(callback : (() => void)) {
callback()
}
}
}
</script>
```
> 组合式 API
```html
<script setup lang="uts">
const foo1 = () => {
console.log("foo1 triggered");
}
const foo2 = (num1 : number, num2: number): number => {
console.log(`foo2 triggered by num1: ${num1}, num2: ${num2}`)
return num1 + num2
}
const foo3 = (callback : (() => void)) => {
callback()
}
defineExpose({
foo1,
foo2,
foo3,
})
</script>
```
:::
**注意:**
- App-Android 平台 `4.0` 版本开始支持 `$callMethod` 调用 `defineExpose` 导出的方法
- Web 平台、App-iOS 平台 `4.13` 版本开始支持 `$callMethod` 调用 `defineExpose` 导出的方法
此时需使用 `this.$refs` 获取组件实例,然后通过 `$callMethod` 调用组件的方法。也就是把组件的方法名、参数,当做callMethod的参数来传递。此时也就没有`.`操作符那样的代码提示和校验了。[详情](../vue/component.md#call-component-method)
## 如何开发同时兼容 uni-app x 和 uni-app 的组件
......
......@@ -2,13 +2,13 @@
本文未包括页面生命周期的详细介绍,需另见 [页面](https://uniapp.dcloud.net.cn/tutorial/page.html)
## 页面生命周期
## 页面生命周期 @lifecycle
<!-- PAGEINSTANCE.lifeCycle.compatibility -->
示例代码, [详见](./vue/README.md#lifecycle-options)
### 页面onLoad生命周期
### 页面onLoad生命周期 @onload
页面初始化时,会触发onLoad生命周期。此时Dom还未构建渲染完毕(需要等onReady)。
......@@ -37,14 +37,17 @@ export default {
this.post_id = event["post_id"] ?? "";
// 可根据详情页id继续联网请求数据...
},
}
```
::: warning 注意
- OnLoadOptions类型,可不填。不填时可自动推导。
- OnLoadOptions类型目前在web和Android的运行时类型不统一,web是对象,Android是map。[详见issues](https://issues.dcloud.net.cn/pages/issues/detail?id=967)
* 但仍然可以通过上述示例代码跨平台的获取入参。
* 后续版本会统一类型为UTSJSONObject。
- 但仍然可以通过上述示例代码跨平台的获取入参。
- 后续版本会统一类型为UTSJSONObject。
:::
## 页面及组件生命周期流程图@lifeCycleFlow
## 页面及组件生命周期流程图 @lifecycleflow
![](./static/uni-app-lifecycle-vue3.png)#{.zooming width=1000 margin=auto}
......@@ -5,761 +5,3 @@ uni-app x的vue规范,按照vue3规范实现,从4.0起支持组合式写法
本文暂时只包括兼容性表格,vue功能详情另见 [vue3概述](https://uniapp.dcloud.net.cn/tutorial/vue3-basics.html#)[Vue3 API](https://uniapp.dcloud.net.cn/tutorial/vue3-api.html)
uni-app x中vue的用法,有单独的示例应用:[hello uvue](https://gitcode.net/dcloud/hello-uvue)。这里都是可以跑通的使用样例代码。
## 全局 API兼容性
### 应用实例 @app-instance
<!-- VUEJSON.application.compatibility -->
<!-- VUEJSON.application.example -->
**注意:**
- **app.use:** `app.use` 支持通过对象字面量、函数及 `definePlugin` 方式定义插件。\
支持传递插件参数,当传递插件参数时,`app` 的类型需要指定为 `VueApp`
```ts
// main.uts
export function createApp() {
const app = createSSRApp(App)
// 通过对象字面量方式注册插件
app.use({
install(app) {
app.config.globalProperties.plugin1 = "plugin1"
}
})
// 通过函数方式注册插件
app.use(function (app) {
app.config.globalProperties.plugin2 = "plugin2"
})
// 通过 definePlugin + 对象字面量方式注册插件
const plugin3= definePlugin({
install(app) {
app.config.globalProperties.plugin3 = "plugin3"
}
})
app.use(plugin3)
// 通过 definePlugin + 函数方式注册插件
const plugin4= definePlugin(function (app) {
app.config.globalProperties.plugin4 = "plugin4"
})
app.use(plugin4)
// 注册插件时传递参数
// 注意:当传递插件参数时,app 的类型需要指定为 VueApp
app.use(function (app: VueApp, arg1:string, arg2:string) {
app.config.globalProperties.plugin5 = `${arg1}-${arg2}`
}, "arg1", "arg2");
}
```
- **app.config.globalProperties:** 请注意,`globalProperties` 是一个保留关键字,因此在项目中请勿声明名为 `globalProperties` 的变量。\
在向 `globalProperties` 注册方法时,请使用直接函数表达式方式进行赋值。不支持先声明函数,再将其注册到 `globalProperties` 上的方式。同时,注册的函数一旦被赋值,不允许进行修改。\
`globalProperties` 在编译时处理,因此确保你的操作在编译时是可知的。例如,将变量赋值给 `globalProperties` 时,这个变量在编译时必须是已知的,而不能是在运行时才能确定的变量。
### 通用
<!-- VUEJSON.general.compatibility -->
<!-- VUEJSON.general.example -->
#### nextTick 使用注意事项
目前 nextTick 可以保证当前数据已经同步到 DOM,但是由于排版和渲染是异步的的,所以 nextTick 不能保证 DOM 排版以及渲染完毕。如果需要获取排版后的节点信息推荐使用 [uni.createSelectorQuery](../api/nodes-info.md) 不推荐直接使用 [Element](../dom/element.md) 对象。在修改 DOM 后,立刻使用 [Element](../dom/element.md) 对象的同步接口获取 DOM 状态可能获取到的是排版之前的,而 [uni.createSelectorQuery](../api/nodes-info.md) 可以保障获取到的节点信息是排版之后的。
## 组合式 API @composition-api
**注意:**
- 暂不支持 `<script setup>``<script>` 同时使用,如果需要配置 `options` 内容,比如 `name`,可以使用 `defineOptions`
- 暂不支持顶层 `await`
- 暂不支持 `<script setup>` 配置 `generic` 泛型类型参数。
- `App.uvue` 暂不支持组合式 API。
### 响应式: 核心
<!-- VUEJSON.reactivity_core.compatibility -->
<!-- VUEJSON.reactivity_core.example -->
**注意:**
- `computed` 需通过泛型指定返回值类型。
```ts
const count = ref(0)
const doubleCount = computed<number>(() : number => {
return count.value * 2
})
```
### 响应式: 工具
<!-- VUEJSON.reactivity_utilities.compatibility -->
<!-- VUEJSON.reactivity_utilities.example -->
**注意:**
- `toRefs` 仅支持 `Array``UTSJSONObject`, 不支持自定义类型。
### 响应式: 进阶
<!-- VUEJSON.reactivity_advanced.compatibility -->
<!-- VUEJSON.reactivity_advanced.example -->
### 生命周期钩子
<!-- VUEJSON.composition_lifecycle.compatibility -->
[页面及组件生命周期流程图](/page.md#lifeCycleFlow)
<!-- VUEJSON.composition_lifecycle.example -->
#### [函数 event 参数的类型](../tutorial/codegap.md#function-event-argument-type)
### 指令 @directives
<!-- VUEJSON.directives.compatibility -->
<!-- VUEJSON.directives.example -->
**注意:**
- **v-html:**`App-android` 平台,`v-html` 指令通过编译为 [rich-text](../component/rich-text.md) 组件实现。因此,`v-html` 指令的内容必须是 `rich-text` 支持的格式, 并且要遵循标签嵌套规则,例如, `swiper` 标签内只允许嵌套 `swiper-item` 标签。\
同时,受限于 `rich-text` 组件不支持 `class` 样式,`v-html` 指令中同样不支持 `class` 样式。\
绑定 `v-html` 的标签内的内容会被忽略,`v-html` 指令的内容会编译为 `rich-text` 组件渲染为该标签的子节点。
### 事件处理
- [事件修饰符](https://uniapp.dcloud.net.cn/tutorial/vue3-basics.html#%E4%BA%8B%E4%BB%B6%E4%BF%AE%E9%A5%B0%E7%AC%A6) 只支持 `stop``once`
## script
- 仅支持 `export default {}` 方式定义组件。
- `data` 仅支持函数返回对象字面量方式。
```ts
<script lang="uts">
export default {
data() {
return {
// 必须写这里
}
}
}
</script>
```
## [Class 与 Style 绑定](https://uniapp.dcloud.net.cn/tutorial/vue3-basics.html#class-%E4%B8%8E-style-%E7%BB%91%E5%AE%9A)
- `uni-app x` 支持绑定 `UTSJSONObject``Map` 类型数据。
在App-Android平台上 `Map` 的性能高于 `UTSJSONObject` 数据类型。从 `uni-app x 4.01` 起,Web平台也支持了 `Map` 类型绑定。
```html
<template>
<view>
<view :style="styleMap" :class="classMap"></view>
</view>
</template>
<script lang="uts">
export default {
data() {
return {
styleMap: new Map<string, string>([['border', '2px solid red'], ['background-color', 'green']]),
classMap: new Map<string, boolean>([['w-100', true], ['h-100', true], ['rounded', false]])
}
}
}
</script>
<style>
.w-100 {
width: 100px;
}
.h-100 {
height: 100px;
}
.rounded {
border-radius: 8px;
}
</style>
```
### 深度选择器
|App|Web|
|:-:|:-:|
|x |4.0|
处于 `scoped` 样式中的选择器如果想要做更“深度”的选择,也即:影响到子组件,可以使用 `:deep()` 这个伪类:
```html
<style scoped>
.a :deep(.b) {
/* ... */
}
</style>
```
### CSS Modules
|App|Web|
|:-:|:-:|
|x |4.0|
一个 `<style module>` 标签会被编译为 `CSS Modules` 并且将生成的 CSS class 作为 `$style` 对象暴露给组件:
```html
<template>
<text :class="$style.red">This should be red</text>
</template>
<style module>
.red {
color: red;
}
</style>
```
得出的 class 将被哈希化以避免冲突,实现了同样的将 CSS 仅作用于当前组件的效果。
**自定义注入名称**
你可以通过给 `module` attribute 一个值来自定义注入 class 对象的属性名:
```vue
<template>
<text :class="classes.red">red</text>
</template>
<style module="classes">
.red {
color: red;
}
</style>
```
**与组合式 API 一同使用**
可以通过 `useCssModule` API 在 `setup()``<script setup>` 中访问注入的 class。对于使用了自定义注入名称的 `<style module>` 块,useCssModule 接收一个匹配的 module attribute 值作为第一个参数:
```ts
import { useCssModule } from 'vue'
// 在 setup() 作用域中...
// 默认情况下, 返回 <style module> 的 class
useCssModule()
// 具名情况下, 返回 <style module="classes"> 的 class
useCssModule('classes')
```
### CSS 中的 v-bind()
|App|Web|
|:-:|:-:|
|x |4.13+ |
单文件组件的 `<style>` 标签支持使用 `v-bind` CSS 函数将 CSS 的值链接到动态的组件状态:
```html
<template>
<text class="text">hello</text>
</template>
<script>
export default {
data() {
return {
color: 'red'
}
}
}
</script>
<style>
.text {
color: v-bind(color);
}
</style>
```
这个语法同样也适用于 `<script setup>`,且支持 UTS 表达式 (需要用引号包裹起来):
```html
<script setup>
const theme = {
color: 'red'
}
</script>
<template>
<text class="view">hello</text>
</template>
<style scoped>
.text {
color: v-bind('theme.color');
}
</style>
```
## 应用生命周期
uni-app x 新增了 [onLastPageBackPress](../collocation/App.md#applifecycle)[onExit](../collocation/App.md#applifecycle) 应用级生命周期,Android退出应用逻辑写在app.uvue里,新建项目的模板自动包含相关代码。如需修改退出逻辑,请直接修改相关代码。
## 组件 @component
- [props](../component/README.md#props)
- [自定义事件](../component/README.md#自定义事件)
- [计算属性和侦听器](../component/README.md#计算属性和侦听器)
- [作用域插槽的类型](../component/README.md#作用域插槽的类型)
- [监听页面生命周期](../component/README.md#监听页面生命周期)
- [vue 与 uvue 不同文件后缀的优先级](../component/README.md#priority)
::: warning 注意
1. App 端,如需页面级滚动,根节点必须是 `scroll-view` 标签。
:::
<!-- VUEJSON.components.compatibility -->
<!-- VUEJSON.components.example -->
### 特殊元素 @special-elements
#### script
<!-- VUEJSON.script.description -->
<!-- VUEJSON.script.attribute -->
<!-- VUEJSON.script.event -->
<!-- VUEJSON.script.example -->
<!-- VUEJSON.script.compatibility -->
<!-- VUEJSON.script.children -->
<!-- VUEJSON.script.reference -->
#### template
<!-- VUEJSON.template.description -->
<!-- VUEJSON.template.attribute -->
<!-- VUEJSON.template.event -->
<!-- VUEJSON.template.example -->
<!-- VUEJSON.template.compatibility -->
<!-- VUEJSON.template.children -->
<!-- VUEJSON.template.reference -->
#### slot
<!-- VUEJSON.slot.description -->
<!-- VUEJSON.slot.attribute -->
<!-- VUEJSON.slot.event -->
<!-- VUEJSON.slot.example -->
<!-- VUEJSON.slot.compatibility -->
<!-- VUEJSON.slot.children -->
<!-- VUEJSON.slot.reference -->
#### style
<!-- VUEJSON.style.description -->
<!-- VUEJSON.style.attribute -->
<!-- VUEJSON.style.event -->
<!-- VUEJSON.style.example -->
<!-- VUEJSON.style.compatibility -->
<!-- VUEJSON.style.children -->
<!-- VUEJSON.style.reference -->
#### keep-alive
<!-- VUEJSON.keep-alive.description -->
<!-- VUEJSON.keep-alive.attribute -->
<!-- VUEJSON.keep-alive.event -->
<!-- VUEJSON.keep-alive.example -->
<!-- VUEJSON.keep-alive.compatibility -->
<!-- VUEJSON.keep-alive.children -->
<!-- VUEJSON.keep-alive.reference -->
#### component
<!-- VUEJSON.component.description -->
<!-- VUEJSON.component.attribute -->
<!-- VUEJSON.component.event -->
<!-- VUEJSON.component.example -->
<!-- VUEJSON.component.compatibility -->
<!-- VUEJSON.component.children -->
<!-- VUEJSON.component.reference -->
#### transition
<!-- VUEJSON.transition.description -->
<!-- VUEJSON.transition.attribute -->
<!-- VUEJSON.transition.event -->
<!-- VUEJSON.transition.example -->
<!-- VUEJSON.transition.compatibility -->
<!-- VUEJSON.transition.children -->
<!-- VUEJSON.transition.reference -->
#### transition-group
<!-- VUEJSON.transition-group.description -->
<!-- VUEJSON.transition-group.attribute -->
<!-- VUEJSON.transition-group.event -->
<!-- VUEJSON.transition-group.example -->
<!-- VUEJSON.transition-group.compatibility -->
<!-- VUEJSON.transition-group.children -->
<!-- VUEJSON.transition-group.reference -->
#### teleport
<!-- VUEJSON.teleport.description -->
<!-- VUEJSON.teleport.attribute -->
**注意:**
- App-Android 平台暂不支持动态修改 `to` 属性。
<!-- VUEJSON.teleport.event -->
<!-- VUEJSON.teleport.example -->
<!-- VUEJSON.teleport.compatibility -->
<!-- VUEJSON.teleport.children -->
<!-- VUEJSON.teleport.reference -->
### 特殊 Attributes @special-attributes
<!-- VUEJSON.special_attributes.compatibility -->
<!-- VUEJSON.special_attributes.example -->
### 生命周期选项 @lifecycle-options
<!-- VUEJSON.options_lifecycle.compatibility -->
<!-- VUEJSON.options_lifecycle.example -->
#### mounted、unmounted 使用注意事项
目前 mounted、unmounted 可以保证当前数据已经同步到 DOM,但是由于排版和渲染是异步的的,所以 mounted、unmounted 不能保证 DOM 排版以及渲染完毕。如果需要获取排版后的节点信息推荐使用 [uni.createSelectorQuery](../api/nodes-info.md) 不推荐直接使用 [Element](../dom/element.md) 对象。在修改 DOM 后,立刻使用 [Element](../dom/element.md) 对象的同步接口获取 DOM 状态可能获取到的是排版之前的,而 [uni.createSelectorQuery](../api/nodes-info.md) 可以保障获取到的节点信息是排版之后的。
## 插件
暂不支持vue插件,比如pinia、vuex、i18n、router。简单的状态管理可以参考文档[全局变量和状态管理](../tutorial/store.md)
## 选项式 API兼容性 @options-api-compatibility
### 状态选项
<!-- VUEJSON.options_state.compatibility -->
**注意:**
- `watch immediate` 第一次调用时,App-Android 平台旧值为初始值,web 平台为 null。
<!-- VUEJSON.options_state.example -->
### 渲染选项 @rendering-options
<!-- VUEJSON.options_rendering.compatibility -->
<!-- VUEJSON.options_rendering.example -->
### 组合选项 @composition-options
<!-- VUEJSON.options_composition.compatibility -->
<!-- VUEJSON.options_composition.example -->
**注意:**
- **inject:** 当使用 `inject` 声明从上层提供方注入的属性时,支持两种写法:字符串数组和对象。推荐使用对象写法,因为当使用数组方法时,类型会被推导为 `any | null` 类型。\
使用对象写法时,额外增加 `type` 属性用于标记类型。如果注入的属性类型不是基础数据类型,需要通过 `PropType` 来标记类型。
```ts
export default {
inject: {
provideString: {
type: String,
default: 'default provide string value'
},
provideObject: {
type: Object as PropType<UTSJSONObject>
},
provideMap: {
type: Object as PropType<Map<string, string>>,
default: (): Map<string, string> => {
return new Map<string, string>([['key', 'default provide map value']])
}
}
}
}
```
- **mixins:** `mixins` 仅支持通过字面量对象方式和 `defineMixin` 函数方式定义。
```ts
const mixin1 = defineMixin({
onLoad() {
console.log('mixin1 onLoad')
}
})
export default {
mixins: [
mixin1,
{
data() {
return {
mixin2: 'mixin2'
}
}
}
]
}
```
同名属性会被覆盖,同名生命周期会依次执行。
同名属性的优先级如下:
-`app.mixin` 内嵌入的 mixin < 在 `app.mixin` 中声明的 mixin < 在 `page.mixin` 内嵌入的 mixin < 在 `page.mixin` 中声明的 mixin < 在 `component.mixin` 内嵌入的 mixin < 在 `component.mixin` 中声明的 mixin
同名生命周期的执行顺序如下:
1.`app.mixin` 内嵌入的 mixin
2.`app.mixin` 中声明的 mixin
3.`page.mixin` 内嵌入的 mixin
4.`page.mixin` 中声明的 mixin
5.`component.mixin` 内嵌入的 mixin
6.`component.mixin` 中声明的 mixin
### 其他杂项
<!-- VUEJSON.options_misc.compatibility -->
<!-- VUEJSON.options_misc.example -->
### 组件实例 @component-instance
<!-- VUEJSON.component_instance.compatibility -->
<!-- VUEJSON.component_instance.example -->
#### $nextTick 使用注意事项
目前 $nextTick 可以保证当前数据已经同步到 DOM,但是由于排版和渲染是异步的的,所以 $nextTick 不能保证 DOM 排版以及渲染完毕。如果需要获取排版后的节点信息推荐使用 [uni.createSelectorQuery](../api/nodes-info.md) 不推荐直接使用 [Element](../dom/element.md) 对象。在修改 DOM 后,立刻使用 [Element](../dom/element.md) 对象的同步接口获取 DOM 状态可能获取到的是排版之前的,而 [uni.createSelectorQuery](../api/nodes-info.md) 可以保障获取到的节点信息是排版之后的。
#### $data 使用注意事项
data内$开头的属性不可直接使用`this.$xxx`访问,需要使用`this.$data['$xxx']`,这是vue的规范。目前安卓端可以使用this.$xxx访问是Bug而非特性,请勿使用此特性。
示例
```vue
<template>
<view></view>
</template>
<script>
export default {
data() {
return {
$a: 1
}
},
onReady() {
console.log(this.$data['$a'] as number) // 1
}
}
</script>
```
## 进阶 API兼容性
### 渲染函数
<!-- VUEJSON.render_function.compatibility -->
<!-- VUEJSON.render_function.example -->
## 单文件组件兼容性
### \<script setup>
<!-- VUEJSON.single_file_component_script.compatibility -->
<!-- VUEJSON.single_file_component_script.example -->
**注意:**
- `defineProps` 仅支持数组字面量、对象字面量定义(等同于 `options` 中的 `props`规则)及使用纯类型参数的方式来声明。
```ts
// 数组字面量
defineProps(['str', 'num', 'bool', 'arr', 'obj', 'fn'])
// 对象字面量
defineProps({
str: String,
num: Number,
bool: {
type: Boolean,
default: true
},
arr: {
type: Array as PropType<string[]>,
default: () : string[] => [] as string[]
},
obj: {
type: Object as PropType<UTSJSONObject>,
default: () : UTSJSONObject => ({ a: 1 })
},
fn: {
type: Function as PropType<() => string>,
default: () : string => ''
}
})
// 纯类型参数
defineProps<{
str : String,
num : Number,
bool : Boolean,
arr : PropType<string[]>,
obj : PropType<UTSJSONObject>,
fn : PropType<() => string>
}>()
```
- `defineEmits` 仅支持数组字面量和纯类型参数的方式来声明。
```ts
// 数组字面量
const emit = defineEmits(['change'])
// 纯类型参数
const emit = defineEmits<{
(e : 'change', id : number) : void
}>()
const emit = defineEmits<{
// 具名元组语法
change : [id: number]
}>()
```
- `defineOptions` 仅支持对象字面量方式定义。
```ts
defineOptions({
data() {
return {
count: 0,
price: 10,
total: 0
}
},
computed: {
doubleCount() : number {
return this.count * 2
},
},
watch: {
count() {
this.total = this.price * this.count
},
},
methods: {
increment() {
this.count++
}
}
})
```
- `defineExpose` 仅支持对象字面量方式定义,导出的变量或方法,必须是 `setup` 中定义的,暂不支持外部定义。
```ts
<script setup>
const str = 'str'
const num = ref(0)
const increment = () => {
num.value++
}
defineExpose({
str,
num,
increment
})
</script>
```
## 其他vue特性
### 递归组件
实现递归组件时不要使用组件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>
```
## 其他示例
- [嵌套组件通讯](https://gitcode.net/dcloud/hello-uvue/-/tree/master/pages/examples/nested-component-communication)
- [自定义组件中使用 class 定制另一个自定义组件根节点样式](https://gitcode.net/dcloud/hello-uvue/-/tree/master/pages/examples/set-custom-child-component-root-node-class)
<!-- ## Bug & Tips@tips -->
- [概述](./README.md)
- [数据绑定模型](./data-bind.md)
- [组件模型](./component.md)
- [全局 API](./global-api.md)
- [组合式 API](./composition-api.md)
- [选项式 API](./options-api.md)
- [内置内容](./built-in.md)
- [单文件](./single-file-component.md)
- [进阶 API](./advanced-api.md)
- [其他vue特性](./others.md)
# 进阶 API
### 渲染函数
<!-- VUEJSON.render_function.compatibility -->
<!-- VUEJSON.render_function.example -->
# 内置内容
## 指令 @directives
<!-- VUEJSON.directives.compatibility -->
<!-- VUEJSON.directives.example -->
::: warning 注意
- **v-html:**`App-android` 平台,`v-html` 指令通过编译为 [rich-text](../component/rich-text.md) 组件实现。因此,`v-html` 指令的内容必须是 `rich-text` 支持的格式, 并且要遵循标签嵌套规则,例如, `swiper` 标签内只允许嵌套 `swiper-item` 标签。\
同时,受限于 `rich-text` 组件不支持 `class` 样式,`v-html` 指令中同样不支持 `class` 样式。\
绑定 `v-html` 的标签内的内容会被忽略,`v-html` 指令的内容会编译为 `rich-text` 组件渲染为该标签的子节点。
:::
## 事件处理
- [事件修饰符](https://uniapp.dcloud.net.cn/tutorial/vue3-basics.html#%E4%BA%8B%E4%BB%B6%E4%BF%AE%E9%A5%B0%E7%AC%A6) 只支持 `stop``once`
## 组件 @component
- [props](../component/README.md#props)
- [自定义事件](../component/README.md#自定义事件)
- [计算属性和侦听器](../component/README.md#计算属性和侦听器)
- [作用域插槽的类型](../component/README.md#作用域插槽的类型)
- [监听页面生命周期](../component/README.md#监听页面生命周期)
- [vue 与 uvue 不同文件后缀的优先级](../component/README.md#priority)
::: warning 注意
- App 端,如需页面级滚动,根节点必须是 `scroll-view` 标签。
:::
### \<KeepAlive> @keep-alive
<!-- VUEJSON.keep-alive.description -->
<!-- VUEJSON.keep-alive.attribute -->
<!-- VUEJSON.keep-alive.event -->
<!-- VUEJSON.keep-alive.example -->
<!-- VUEJSON.keep-alive.compatibility -->
<!-- VUEJSON.keep-alive.children -->
<!-- VUEJSON.keep-alive.reference -->
### \<Transition> @transition
<!-- VUEJSON.transition.description -->
<!-- VUEJSON.transition.attribute -->
<!-- VUEJSON.transition.event -->
<!-- VUEJSON.transition.example -->
<!-- VUEJSON.transition.compatibility -->
<!-- VUEJSON.transition.children -->
<!-- VUEJSON.transition.reference -->
### \<TransitionGroup> @transition-group
<!-- VUEJSON.transition-group.description -->
<!-- VUEJSON.transition-group.attribute -->
<!-- VUEJSON.transition-group.event -->
<!-- VUEJSON.transition-group.example -->
<!-- VUEJSON.transition-group.compatibility -->
<!-- VUEJSON.transition-group.children -->
<!-- VUEJSON.transition-group.reference -->
### \<Teleport> @teleport
<!-- VUEJSON.teleport.description -->
<!-- VUEJSON.teleport.attribute -->
**注意:**
- App-Android 平台暂不支持动态修改 `to` 属性。
<!-- VUEJSON.teleport.event -->
<!-- VUEJSON.teleport.example -->
<!-- VUEJSON.teleport.compatibility -->
<!-- VUEJSON.teleport.children -->
<!-- VUEJSON.teleport.reference -->
## 特殊元素 @special-elements
### \<template> @template
<!-- VUEJSON.template.description -->
<!-- VUEJSON.template.attribute -->
<!-- VUEJSON.template.event -->
<!-- VUEJSON.template.example -->
<!-- VUEJSON.template.compatibility -->
<!-- VUEJSON.template.children -->
<!-- VUEJSON.template.reference -->
### \<slot> @slot
<!-- VUEJSON.slot.description -->
<!-- VUEJSON.slot.attribute -->
<!-- VUEJSON.slot.event -->
<!-- VUEJSON.slot.example -->
<!-- VUEJSON.slot.compatibility -->
<!-- VUEJSON.slot.children -->
<!-- VUEJSON.slot.reference -->
### \<component> @component
<!-- VUEJSON.component.description -->
<!-- VUEJSON.component.attribute -->
<!-- VUEJSON.component.event -->
<!-- VUEJSON.component.example -->
<!-- VUEJSON.component.compatibility -->
<!-- VUEJSON.component.children -->
<!-- VUEJSON.component.reference -->
## 特殊 Attributes @special-attributes
<!-- VUEJSON.special_attributes.compatibility -->
<!-- VUEJSON.special_attributes.example -->
# 组件
## 定义
- 组件是视图层的基本组成单元。
- 组件是一个单独且可复用的功能模块的封装。
每个组件,包括如下几个部分:以组件名称为标记的开始标签和结束标签、组件内容、组件属性、组件属性值。
- 组件名称由尖括号包裹,称为标签,它有开始标签和结束标签。结束标签的`<`后面用`/`来表示结束。结束标签也称为闭合标签。如下面示例的`<component-name>`是开始标签,`</component-name>`是结束标签。
- 在开始标签和结束标签之间,称为组件内容。如下面示例的`content`
- 开始标签上可以写属性,属性可以有多个,多个属性之间用空格分割
- 每个属性通过`=`赋值
## 使用入门教程
uni-app x 支持的组件包括:
- 内置基础组件
- 自定义 vue 组件
- uts 组件插件
> 除了微信小程序,其他平台不支持的小程序wxml组件。
内置组件比较简单,扩展组件的2种方式详细介绍下
### 自定义组件 @custom-component
在 components 目录新建一个 uvue/vue 文件,按 vue 组件规范编写代码。
组件界面通过 uvue 构造,script 使用 [uts](../uts/README.md) 编写。
返回的类型是组件实例 ComponentPublicInstance
### uts 组件插件 @uts-component
> uts组件插件,指把原生的、需要在界面上显示的、内嵌于页面中整体排版的组件,编写uts代码调用原生sdk,通过uni_modules插件的方式集成到uni-app项目中。
`uts 组件插件`的名称可能有点拗口,这是因为是相对于另一个分类`uts api 插件`\
它们同属于`uts 插件`,是 [uni_modules](https://uniapp.dcloud.net.cn/plugin/uni_modules.html)。api 插件指能力扩展,比如蓝牙 api。而组件插件指界面元素扩展,比如 video、map、lottie 动画等。
在 app 端,它的内部界面是由原生 SDK 绘制的,而不是 uvue 代码绘制的。通过封装嵌入到 uvue/nvue 页面中。比如
> * lottie组件,使用uts调用原生的lottie sdk来开发组件,再引入页面中。[详见](https://ext.dcloud.net.cn/plugin?name=uni-animation-view)
> * video组件,其实官方的video,也是用uts组件插件实现的。[详见](https://gitcode.net/dcloud/uni-component/-/tree/master/uni_modules/uni-video)
>
> uts组件插件,主要用于原生sdk涉及界面时,将其封装为界面组件。当然uts组件也是全端支持的。上述lottie组件也支持web端。
一个 uts 插件都是可以同时兼容 uni-app x 和 uni-app js 引擎版的。目前js引擎版仅支持内嵌于nvue页面中。所以上述lottie组件也是可以在app-nvue页面中使用的。
uts 组件的返回类型是dom元素[Element](../dom/element.md)
uts 组件插件的开发教程,[详见](https://uniapp.dcloud.net.cn/plugin/uts-component.html)
## 在页面使用组件
### 内置组件 @builtin-component
内置组件可以直接在页面中使用,不需要引入。如:[view](../component/view.md),组件文档中都有相应示例供查看使用
### easycom
传统vue组件,需要安装、引用、注册,三个步骤后才能使用组件。`easycom` 将其精简为一步。
只要组件安装在项目的 `components` 目录下或 `uni_modules/插件 id/components` 目录下,并符合 `组件名称/组件名称.(vue|uvue)` 目录结构。就可以不用引用、注册,直接在页面中使用。
- 比如 [uni-rate组件](https://ext.dcloud.net.cn/plugin?id=33),它导入到项目后,存放在了目录 /uni_modules/uni-rate/uni-rate.vue
同时它的组件名称也叫 uni-rate,所以这样的组件,不用在 script 里注册和引用。
如下:
```html
<template>
<view>
<uni-rate></uni-rate><!-- 这里会显示一个五角星,并且点击后会自动亮星 -->
</view>
</template>
<script>
// 这里不用import引入,也不需要在components内注册uni-list组件。template里就可以直接用
export default {
data() {
return {
}
}
}
</script>
```
#### uni_modules 组件规范
uni_module其实不止服务于组件,它可以服务于组件、js库、页面、项目等所有DCloud插件市场所支持的种类。
符合uni_module规范的组件都在项目的`uni_modules`目录下,以插件id为目录存放。(项目模板不放在`uni_modules`目录下)
在HBuilderX中点右键可方便的更新插件,插件作者也可以方便的上传插件。
uni_module还支持云端一体的插件。
uni_module有详细的专项文档,请另行查阅[uni_module规范](/plugin/uni_modules.md)
### 手动 import 组件
在新建一个组件后,如果不符合 easycom 规范,则需要手动引入:
```vue
<!-- 组件 child.vue -->
<template>
<view>Child Component</view>
</template>
<!-- 页面(与 child.vue 组件在同级目录 -->
<template>
<view>
<child></child>
</view>
</template>
<script>
// 引入 child 组件
import child from './child.vue'
export default {
components: {
child
}
}
</script>
```
## 通信
### 页面与页面通信 @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
#### 在 `main.uts` 中使用 `app.config.globalProperties`
如在 `main.uts` 中的 `createApp` 方法中使用:
```ts
app.config.globalProperties.globalPropertiesReactiveObj = reactive({
str: 'default reactive string',
num: 0,
bool: false,
} as UTSJSONObject)
```
示例 [详情](<!-- VUEJSON.E_app-instance.globalProperties_globalProperties-options.gitUrl -->)
::: preview <!-- VUEJSON.E_app-instance.globalProperties_globalProperties-options.webUrl -->
> 选项式 API
<!-- VUEJSON.E_app-instance.globalProperties_globalProperties-options.code -->
> 组合式 API
<!-- VUEJSON.E_app-instance.globalProperties_globalProperties-composition.code -->
:::
#### 向组件传递 `props` @transfer-component-props
示例 [详情](<!-- 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 -->
:::
#### 向组件传递回调函数 @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 -->
> 选项式 API(1)
<!-- VUEJSON.E_component-instance.provide_provide-options-1.code -->
> 选项式 API(2)
<!-- VUEJSON.E_component-instance.provide_provide-options-2.code -->
> 组合式 API
<!-- VUEJSON.E_component-instance.provide_provide-composition.code -->
:::
#### 使用 [全局变量与状态管理](../tutorial/store.md) @global-store
示例 [详情](<!-- 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 -->
:::
### 父组件与子组件通信 @parent-child-communication
上述 [页面与组件通信](#page-component-communication) 方法同样适用于父组件与子组件通信。
### 页面调用组件方法 @page-call-component-method
#### 使用 `ref` 属性搭配 `$callMethod` 方法 @call-component-method
如果不是内置组件,也不是easycom组件,那么无法使用`.`操作符了。
此时需使用 `this.$refs` 获取组件实例,然后通过 `$callMethod` 调用组件的方法。也就是把组件的方法名、参数,当做callMethod的参数来传递。此时也就没有`.`操作符那样的代码提示和校验了。
callMethod可用于所有自定义组件,包括easycom组件也可以使用,只不过easycom组件有更简单的用法。
**语法**
```(this.$refs['组件ref属性值'] as ComponentPublicInstance).$callMethod('方法名', ...args)```
**组件类型**
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` 导出的方法
#### 调用 `easycom` 组件方法 @call-easycom-component-method
> 3.97+ 支持 uni_modules 目录下的组件
>
> 在调用组件方法的时候如报错 `error: Reference has a nullable type` 则需要使用 `?.` 操作符,如:a?.b?.()。
easycom组件,用法和内置组件一样。也是使用 `this.$refs` 获取组件并转换为组件的类型,通过 `.`操作符 调用组件方法或设置属性。
**语法**
```(this.$refs['组件ref属性值'] as 驼峰ComponentPublicInstance).foo();```
**easycom组件的类型规范**
组件标签名首字母大写,驼峰+ComponentPublicInstance
如:
`<test/>` 类型为:TestComponentPublicInstance
`<uni-data-checkbox/>` 类型为:UniDataCheckboxComponentPublicInstance
示例 [详情](<!-- 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 -->
:::
#### 调用 `uni_modules easycom` 组件方法 <Badge text="HBuilderX 3.97+"> @call-uni-modules-easycom-component-method
使用 `ref` 属性拿到组件实例,调用 `easycom` 组件方法时不需要使用 `$callMethod` 方法,直接使用点操作符即可 `.`
> 在调用组件方法的时候如报错 `error: Reference has a nullable type` 则需要使用 `?.` 操作符,如:a?.b?.()。
> 与 ts 不同,在 `()` 前也需要使用 `?.` 操作符。
示例 [详情](<!-- 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 -->
:::
#### 内置组件的方法调用或设置属性 <Badge text="HBuilderX 3.93+"> @call-builtin-component-method
使用 `this.$refs` 获取组件并as转换为组件对应的element类型,通过 `.`操作符 调用组件方法或设置属性。
**语法**
```(this.$refs['组件ref属性值'] as Uni[xxx]Element).foo();```
**内置组件的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 方式相同。目前没有代码提示。
## 组件的生命周期 @component-lifecycle
> 选项式 API 和 组件式 API 的组件生命周期使用时有所不同
>
> 比如选项式 API 中的 `onShow`、`onHide` 生命周期在组合式 API 中分别对应 `onPageShow`、`onPageHide`(在组合式 API 时会和 App 的生命周期冲突)
>
> 具体请查看 [组件生命周期](../page.md#lifecycle)
示例 [详情](<!-- VUEJSON.E_lifecycle.component_ChildComponentOptions.gitUrl -->)
::: preview <!-- VUEJSON.E_lifecycle.component_ChildComponentOptions.webUrl -->
> 选项式 API
<!-- VUEJSON.E_lifecycle.component_ChildComponentOptions.code -->
> 组合式 API
<!-- VUEJSON.E_lifecycle.component_ChildComponentComposition.code -->
:::
## 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
示例 [详情](<!-- VUEJSON.E_built-in.component_slots_child-options.gitUrl -->)
作用域插槽需在组件中指定插槽数据类型
::: preview <!-- VUEJSON.E_built-in.component_slots_child-options.webUrl -->
> 选项式 API
<!-- VUEJSON.E_built-in.component_slots_child-options.code -->
> 组合式 API
<!-- VUEJSON.E_built-in.component_slots_child-composition.code -->
:::
## 递归组件
实现递归组件时不要使用组件 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>
```
# 组合式 API
::: warning 注意
- 暂不支持 `<script setup>``<script>` 同时使用,如果需要配置 `options` 内容,比如 `name`,可以使用 `defineOptions`
- 暂不支持顶层 `await`
- 暂不支持 `<script setup>` 配置 `generic` 泛型类型参数。
- `App.uvue` 暂不支持组合式 API。
:::
## 响应式: 核心
<!-- VUEJSON.reactivity_core.compatibility -->
<!-- VUEJSON.reactivity_core.example -->
::: warning 注意
- `computed()` 需通过泛型指定返回值类型。
```ts
const count = ref(0)
const doubleCount = computed<number>(() : number => {
return count.value * 2
})
```
:::
### 示例代码
#### ref
- 定义相应式数据
示例 [详情](<!-- VUEJSON.E_reactivity.core_ref_ref.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.core_ref_ref.webUrl -->
<!-- VUEJSON.E_reactivity.core_ref_ref.code -->
:::
- 使用 `<template ref>`
示例 [详情](<!-- VUEJSON.E_component-instance.refs_refs-composition.gitUrl -->)
::: preview <!-- VUEJSON.E_component-instance.refs_refs-composition.webUrl -->
<!-- VUEJSON.E_component-instance.refs_refs-composition.code -->
:::
#### watch
示例 [详情](<!-- VUEJSON.E_reactivity.core_watch_watch-composition.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.core_watch_watch-composition.webUrl -->
<!-- VUEJSON.E_reactivity.core_watch_watch-composition.code -->
:::
#### computed
示例 [详情](<!-- VUEJSON.E_reactivity.core_computed_computed-composition.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.core_computed_computed-composition.webUrl -->
<!-- VUEJSON.E_reactivity.core_computed_computed-composition.code -->
:::
#### reactive
示例 [详情](<!-- VUEJSON.E_reactivity.core_reactive_reactive.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.core_reactive_reactive.webUrl -->
<!-- VUEJSON.E_reactivity.core_reactive_reactive.code -->
:::
#### readonly
示例 [详情](<!-- VUEJSON.E_reactivity.core_readonly_readonly.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.core_readonly_readonly.webUrl -->
<!-- VUEJSON.E_reactivity.core_readonly_readonly.code -->
:::
#### watchEffect
示例 [详情](<!-- VUEJSON.E_reactivity.core_watch-effect_watch-effect.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.core_watch-effect_watch-effect.webUrl -->
<!-- VUEJSON.E_reactivity.core_watch-effect_watch-effect.code -->
:::
#### watchPostEffect
示例 [详情](<!-- VUEJSON.E_reactivity.core_watch-post-effect_watch-post-effect.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.core_watch-post-effect_watch-post-effect.webUrl -->
<!-- VUEJSON.E_reactivity.core_watch-post-effect_watch-post-effect.code -->
:::
#### watchSyncEffect
示例 [详情](<!-- VUEJSON.E_reactivity.core_watch-sync-effect_watch-sync-effect.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.core_watch-sync-effect_watch-sync-effect.webUrl -->
<!-- VUEJSON.E_reactivity.core_watch-sync-effect_watch-sync-effect.code -->
:::
## 响应式: 工具
<!-- VUEJSON.reactivity_utilities.compatibility -->
<!-- VUEJSON.reactivity_utilities.example -->
::: warning 注意
- `toRefs()` 仅支持 `Array``UTSJSONObject`, 不支持自定义类型。
:::
### 示例代码
#### isRef
示例 [详情](<!-- VUEJSON.E_reactivity.utilities_is-ref_is-ref.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.utilities_is-ref_is-ref.webUrl -->
<!-- VUEJSON.E_reactivity.utilities_is-ref_is-ref.code -->
:::
#### unref
示例 [详情](<!-- VUEJSON.E_reactivity.utilities_un-ref_un-ref.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.utilities_un-ref_un-ref.webUrl -->
<!-- VUEJSON.E_reactivity.utilities_un-ref_un-ref.code -->
:::
#### toRef
示例 [详情](<!-- VUEJSON.E_reactivity.utilities_to-ref_to-ref.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.utilities_to-ref_to-ref.webUrl -->
<!-- VUEJSON.E_reactivity.utilities_to-ref_to-ref.code -->
:::
#### toValue
示例 [详情](<!-- VUEJSON.E_reactivity.utilities_to-value_to-value.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.utilities_to-value_to-value.webUrl -->
<!-- VUEJSON.E_reactivity.utilities_to-value_to-value.code -->
:::
#### toRefs
示例 [详情](<!-- VUEJSON.E_reactivity.utilities_to-refs_to-refs.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.utilities_to-refs_to-refs.webUrl -->
<!-- VUEJSON.E_reactivity.utilities_to-refs_to-refs.code -->
:::
#### isProxy
示例 [详情](<!-- VUEJSON.E_reactivity.utilities_is-proxy_is-proxy.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.utilities_is-proxy_is-proxy.webUrl -->
<!-- VUEJSON.E_reactivity.utilities_is-proxy_is-proxy.code -->
:::
#### isReactive
示例 [详情](<!-- VUEJSON.E_reactivity.utilities_is-reactive_is-reactive.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.utilities_is-reactive_is-reactive.webUrl -->
<!-- VUEJSON.E_reactivity.utilities_is-reactive_is-reactive.code -->
:::
#### isReadonly
示例 [详情](<!-- VUEJSON.E_reactivity.utilities_is-readonly_is-readonly.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.utilities_is-readonly_is-readonly.webUrl -->
<!-- VUEJSON.E_reactivity.utilities_is-readonly_is-readonly.code -->
:::
## 响应式: 进阶
<!-- VUEJSON.reactivity_advanced.compatibility -->
<!-- VUEJSON.reactivity_advanced.example -->
### 示例代码
#### customRef
示例 [详情](<!-- VUEJSON.E_reactivity.advanced_custom-ref_custom-ref.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.advanced_custom-ref_custom-ref.webUrl -->
<!-- VUEJSON.E_reactivity.advanced_custom-ref_custom-ref.code -->
:::
#### effectScope
示例 [详情](<!-- VUEJSON.E_reactivity.advanced_effect-scope_effect-scope.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.advanced_effect-scope_effect-scope.webUrl -->
<!-- VUEJSON.E_reactivity.advanced_effect-scope_effect-scope.code -->
:::
#### getCurrentScope
示例 [详情](<!-- VUEJSON.E_reactivity.advanced_get-current-scope_get-current-scope.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.advanced_get-current-scope_get-current-scope.webUrl -->
<!-- VUEJSON.E_reactivity.advanced_get-current-scope_get-current-scope.code -->
:::
#### onScopeDispose
示例 [详情](<!-- VUEJSON.E_reactivity.advanced_on-scope-dispose_on-scope-dispose.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.advanced_on-scope-dispose_on-scope-dispose.webUrl -->
<!-- VUEJSON.E_reactivity.advanced_on-scope-dispose_on-scope-dispose.code -->
:::
#### shallowReactive
示例 [详情](<!-- VUEJSON.E_reactivity.advanced_shallow-reactive_shallow-reactive.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.advanced_shallow-reactive_shallow-reactive.webUrl -->
<!-- VUEJSON.E_reactivity.advanced_shallow-reactive_shallow-reactive.code -->
:::
#### shallowReadonly
示例 [详情](<!-- VUEJSON.E_reactivity.advanced_shallow-readonly_shallow-readonly.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.advanced_shallow-readonly_shallow-readonly.webUrl -->
<!-- VUEJSON.E_reactivity.advanced_shallow-readonly_shallow-readonly.code -->
:::
#### shallowRef
示例 [详情](<!-- VUEJSON.E_reactivity.advanced_shallow-ref_shallow-ref.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.advanced_shallow-ref_shallow-ref.webUrl -->
<!-- VUEJSON.E_reactivity.advanced_shallow-ref_shallow-ref.code -->
:::
#### toRaw
示例 [详情](<!-- VUEJSON.E_reactivity.advanced_to-raw_to-raw.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.advanced_to-raw_to-raw.webUrl -->
<!-- VUEJSON.E_reactivity.advanced_to-raw_to-raw.code -->
:::
#### triggerRef
示例 [详情](<!-- VUEJSON.E_reactivity.advanced_trigger-ref_trigger-ref.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.advanced_trigger-ref_trigger-ref.webUrl -->
<!-- VUEJSON.E_reactivity.advanced_trigger-ref_trigger-ref.code -->
:::
## 生命周期钩子 @page-lifecycle
<!-- VUEJSON.composition_lifecycle.compatibility -->
示例 [详情](<!-- VUEJSON.E_lifecycle.page_page-composition.gitUrl -->)
::: preview <!-- VUEJSON.E_lifecycle.page_page-composition.webUrl -->
<!-- VUEJSON.E_lifecycle.page_page-composition.code -->
:::
[页面及组件生命周期流程图](../page.md#lifecycleflow)
# 数据绑定模型
## 声明响应式状态 @declaring-reactive-state
### 选项式 API @options-api
选用选项式 API 时,会用 `data` 选项来声明组件的响应式状态。此选项的值应为返回一个对象的函数。Vue 将在创建新组件实例的时候调用此函数,并将函数返回的对象用响应式系统进行包装。此对象的所有顶层属性都会被代理到组件实例 (即方法和生命周期钩子中的 `this`) 上。
示例 [详情](<!-- VUEJSON.E_component-instance.data_data-options.gitUrl -->)
::: preview <!-- VUEJSON.E_component-instance.data_data-options.webUrl -->
<!-- VUEJSON.E_component-instance.data_data-options.code -->
:::
### 组合式 API @composition-api
选用组合式 API 时,会用 `ref``reactive` 来声明组件的响应式状态。使用组合式 API定义的变量,需要通过 [defineExpose](#defineexpose) 导出,才能在模板中使用。
#### ref
在组合式 API 中,推荐使用 `ref()` 函数来声明响应式状态。需要给 `ref` 标注类型,如:`ref<string>()`
`ref()` 接收参数,并将其包裹在一个带有 `.value` 属性的 `ref` 对象中返回
**注意**,在模板中使用 ref 时,我们不需要附加 `.value`。为了方便起见,当在模板中使用时,ref 会自动解包。
示例 [详情](<!-- VUEJSON.E_reactivity.core_ref_ref.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.core_ref_ref.webUrl -->
<!-- VUEJSON.E_reactivity.core_ref_ref.code -->
:::
#### reactive
还有另一种声明响应式状态的方式,即使用 reactive() API。与将内部值包装在特殊对象中的 ref 不同,reactive() 将使对象本身具有响应性,还可以使用 `readOnly` 来禁止修改
值得注意的是,reactive() 返回的是一个原始对象的 Proxy,它和原始对象是不相等的
只有代理对象是响应式的,更改原始对象不会触发更新。因此,使用 Vue 的响应式系统的最佳实践是仅使用你声明对象的代理版本。
示例 [详情](<!-- VUEJSON.E_reactivity.core_readonly_readonly.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.core_readonly_readonly.webUrl -->
<!-- VUEJSON.E_reactivity.core_readonly_readonly.code -->
:::
#### defineExpose
使用 `<script setup>` 的组件是**默认关闭**的——即通过模板引用或者 `$parent` 链获取到的组件的公开实例,**不会**暴露任何在 `<script setup>` 中声明的绑定。
可以通过 `defineExpose` 编译器宏来显式指定在 `<script setup>` 组件中要暴露出去的属性:
> 在示例中,使用 `defineExpose` 导出一个方法供自动化测试使用
示例 [详情](<!-- VUEJSON.E_component-instance.define-expose_define-expose.gitUrl -->)
::: preview <!-- VUEJSON.E_component-instance.define-expose_define-expose.webUrl -->
<!-- VUEJSON.E_component-instance.define-expose_define-expose.code -->
:::
## 绑定变量 @bind-data
### 在模板里绑定 @bind-template-data
当使用 `Options API` `data``Composition API``ref``reactive` 定义了响应式数据后,可以在模板中使用 `{{}}` 语法绑定数据
可以在模板中使用以下任一指令一起:
- `v-bind``:`(简写)
- `v-if``v-else-if``v-else`
- `v-for`
示例 [详情](<!-- VUEJSON.E_built-in.component_template_template-options.gitUrl -->)
::: preview <!-- VUEJSON.E_built-in.component_template_template-options.webUrl -->
> 选项式 API
<!-- VUEJSON.E_built-in.component_template_template-options.code -->
> 组合式 API
<!-- VUEJSON.E_built-in.component_template_template-composition.code -->
:::
### 使用 `v-bind` 在样式里绑定 @v-bind-css-data
`v-bind` 也可在样式中使用,可以很方便的在 uts 中改变样式,如下所示:
示例 [详情](<!-- VUEJSON.E_directive.v-bind_v-bind-options.gitUrl -->)
::: preview <!-- VUEJSON.E_directive.v-bind_v-bind-options.webUrl -->
> 选项式 API
<!-- VUEJSON.E_directive.v-bind_v-bind-options.code -->
> 组合式 API
<!-- VUEJSON.E_directive.v-bind_v-bind-composition.code -->
:::
## 定义方法 @methods
使用选项式 API 时可以在 `methods` 选项中定义方法,这些方法可以在模板中使用\
而使用组合式 API 时,可以直接在 `<script setup lang="uts">` 中定义方法
定义方法之后,可以传递给子组件,子组件使用 `emit` 调用,也可以在 `script` 中直接使用
::: 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 -->
:::
# 全局 API
## 应用实例 @app-instance
### 兼容性 @compatibility
<!-- VUEJSON.application.compatibility -->
### app.use
`app.use` 支持通过对象字面量、函数及 `definePlugin` 方式定义插件。
支持传递插件参数,当传递插件参数时,`app` 的类型需要指定为 `VueApp`
示例 [详情](<!-- VUEJSON.E_app-instance.use_use-options.gitUrl -->)
::: preview <!-- VUEJSON.E_app-instance.use_use-options.webUrl -->
> 选项式 API
<!-- VUEJSON.E_app-instance.use_use-options.code -->
> 组合式 API
<!-- VUEJSON.E_app-instance.use_use-composition.code -->
:::
### app.config.globalProperties
请注意,`globalProperties` 是一个保留关键字,因此在项目中请勿声明名为 `globalProperties` 的变量。
在向 `globalProperties` 注册方法时,请使用直接函数表达式方式进行赋值。不支持先声明函数,再将其注册到 `globalProperties` 上的方式。同时,注册的函数一旦被赋值,不允许进行修改。
`globalProperties` 在编译时处理,因此确保你的操作在编译时是可知的。例如,将变量赋值给 `globalProperties` 时,这个变量在编译时必须是已知的,而不能是在运行时才能确定的变量。
件参数,当传递插件参数时,`app` 的类型需要指定为 `VueApp`
示例 [详情](<!-- VUEJSON.E_app-instance.globalProperties_globalProperties-options.gitUrl -->)
::: preview <!-- VUEJSON.E_app-instance.globalProperties_globalProperties-options.webUrl -->
> 选项式 API
<!-- VUEJSON.E_app-instance.globalProperties_globalProperties-options.code -->
> 组合式 API
<!-- VUEJSON.E_app-instance.globalProperties_globalProperties-composition.code -->
:::
## 应用生命周期 @app-lifecycle
uni-app x 新增了 [onLastPageBackPress](../collocation/App.md#applifecycle)[onExit](../collocation/App.md#applifecycle) 应用级生命周期,Android退出应用逻辑写在app.uvue里,新建项目的模板自动包含相关代码。如需修改退出逻辑,请直接修改相关代码。
示例 [详情](<!-- VUEJSON.E_App.example.gitUrl -->)
::: preview <!-- VUEJSON.E_App.example.webUrl -->
<!-- VUEJSON.E_App.example.code -->
:::
## 通用 @general
<!-- VUEJSON.general.compatibility -->
<!-- VUEJSON.general.example -->
### nextTick 使用注意事项 @nexttick
目前 nextTick 可以保证当前数据已经同步到 DOM,但是由于排版和渲染是异步的的,所以 nextTick 不能保证 DOM 排版以及渲染完毕。如果需要获取排版后的节点信息推荐使用 [uni.createSelectorQuery](../api/nodes-info.md) 不推荐直接使用 [Element](../dom/element.md) 对象。在修改 DOM 后,立刻使用 [Element](../dom/element.md) 对象的同步接口获取 DOM 状态可能获取到的是排版之前的,而 [uni.createSelectorQuery](../api/nodes-info.md) 可以保障获取到的节点信息是排版之后的。
# 选项式 API @options-api
## 状态选项
::: warning 注意
- `watch immediate` 第一次调用时,App-Android 平台旧值为初始值,web 平台为 null。
:::
<!-- VUEJSON.options_state.compatibility -->
### 示例代码
#### data
示例 [详情](<!-- VUEJSON.E_component-instance.data_data-options.gitUrl -->)
::: preview <!-- VUEJSON.E_component-instance.data_data-options.webUrl -->
<!-- VUEJSON.E_component-instance.data_data-options.code -->
:::
### props
示例 [详情](<!-- VUEJSON.E_component-instance.props_props-options.gitUrl -->)
::: preview <!-- VUEJSON.E_component-instance.props_props-options.webUrl -->
<!-- VUEJSON.E_component-instance.props_props-options.code -->
:::
#### computed
示例 [详情](<!-- VUEJSON.E_reactivity.core_computed_computed-options.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.core_computed_computed-options.webUrl -->
<!-- VUEJSON.E_reactivity.core_computed_computed-options.code -->
:::
#### methods
[详情点击查看](./component.md#page-call-component-method)
#### watch
示例 [详情](<!-- VUEJSON.E_reactivity.core_watch_watch-options.gitUrl -->)
::: preview <!-- VUEJSON.E_reactivity.core_watch_watch-options.webUrl -->
<!-- VUEJSON.E_reactivity.core_watch_watch-options.code -->
:::
#### emits
示例 [详情](<!-- VUEJSON.E_component-instance.emit-function_child-options.gitUrl -->)
::: preview <!-- VUEJSON.E_component-instance.emit-function_child-options.webUrl -->
<!-- VUEJSON.E_component-instance.emit-function_child-options.code -->
:::
## 渲染选项 @rendering-options
<!-- VUEJSON.options_rendering.compatibility -->
### 示例代码
#### template
示例 [详情](<!-- VUEJSON.E_built-in.component_template_template-options.gitUrl -->)
::: preview <!-- VUEJSON.E_built-in.component_template_template-options.webUrl -->
<!-- VUEJSON.E_built-in.component_template_template-options.code -->
:::
#### render
- 选项式 API
示例 [详情](<!-- VUEJSON.E_rendering.render_render.gitUrl -->)
::: preview <!-- VUEJSON.E_rendering.render_render.webUrl -->
<!-- VUEJSON.E_rendering.render_render.code -->
:::
- \<script setup>
示例 [详情](<!-- VUEJSON.E_component-instance.setup-function_RenderFunction.gitUrl -->)
::: preview <!-- VUEJSON.E_component-instance.setup-function_RenderFunction.webUrl -->
<!-- VUEJSON.E_component-instance.setup-function_RenderFunction.code -->
:::
#### slots
示例 [详情](<!-- VUEJSON.E_component-instance.slots_slots-options.gitUrl -->)
作用域插槽需在组件中指定插槽数据类型
::: preview <!-- VUEJSON.E_component-instance.slots_slots-options.webUrl -->
<!-- VUEJSON.E_component-instance.slots_slots-options.code -->
:::
## 生命周期选项 @lifecycle-options
<!-- VUEJSON.options_lifecycle.compatibility -->
### mounted、unmounted 使用注意事项
目前 mounted、unmounted 可以保证当前数据已经同步到 DOM,但是由于排版和渲染是异步的的,所以 mounted、unmounted 不能保证 DOM 排版以及渲染完毕。\
如果需要获取排版后的节点信息推荐使用 [uni.createSelectorQuery](../api/nodes-info.md) 不推荐直接使用 [Element](../dom/unielement.md) 对象。\
在修改 DOM 后,立刻使用 [Element](../dom/unielement.md) 对象的同步接口获取 DOM 状态可能获取到的是排版之前的,而 [uni.createSelectorQuery](../api/nodes-info.md) 可以保障获取到的节点信息是排版之后的。
示例 [详情](<!-- VUEJSON.E_lifecycle.page_page-options.gitUrl -->)
::: preview <!-- VUEJSON.E_lifecycle.page_page-options.webUrl -->
<!-- VUEJSON.E_lifecycle.page_page-options.code -->
:::
## 组合选项 @options-composition
<!-- VUEJSON.options_composition.compatibility -->
### inject
当使用 `inject` 声明从上层提供方注入的属性时,支持两种写法:字符串数组和对象。推荐使用对象写法,因为当使用数组方法时,类型会被推导为 `any | null` 类型。\
使用对象写法时,额外增加 `type` 属性用于标记类型。如果注入的属性类型不是基础数据类型,需要通过 `PropType` 来标记类型:
示例 [详情](<!-- VUEJSON.E_component-instance.inject_inject-options-1.gitUrl -->)
::: preview <!-- VUEJSON.E_component-instance.inject_inject-options-1.webUrl -->
> inject 1
<!-- VUEJSON.E_component-instance.inject_inject-options-1.code -->
> inject 2
<!-- VUEJSON.E_component-instance.inject_inject-options-2.code -->
:::
### mixins
- `mixins` 仅支持通过字面量对象方式和 `defineMixin` 函数方式定义。\
```ts
const mixin1 = defineMixin({
onLoad() {
console.log('mixin1 onLoad')
}
})
export default {
mixins: [
mixin1,
{
data() {
return {
mixin2: 'mixin2'
}
}
}
]
}
```
- 同名属性会被覆盖,同名生命周期会依次执行。同名属性的优先级如下:
-`app.mixin` 内嵌入的 mixin `<``app.mixin` 中声明的 mixin `<``page.mixin` 内嵌入的 mixin `<``page.mixin` 中声明的 mixin `<``component.mixin` 内嵌入的 mixin `<``component.mixin` 中声明的 mixin
- 同名生命周期的执行顺序如下:
1.`app.mixin` 内嵌入的 mixin
2.`app.mixin` 中声明的 mixin
3.`page.mixin` 内嵌入的 mixin
4.`page.mixin` 中声明的 mixin
5.`component.mixin` 内嵌入的 mixin
6.`component.mixin` 中声明的 mixin
::: preview <!-- VUEJSON.E_component-instance.mixins-app-page-namesake.webUrl -->
示例 [详情](<!-- VUEJSON.E_component-instance.mixins-app-page-namesake.gitUrl -->)
> mixins-app-page-namesake
<!-- VUEJSON.E_component-instance.mixins-app-page-namesake.code -->
> mixins-app
<!-- VUEJSON.E_component-instance.mixins-app.code -->
> mixins-web
<!-- VUEJSON.E_component-instance.mixins-web.code -->
:::
## 其他杂项
<!-- VUEJSON.options_misc.compatibility -->
<!-- VUEJSON.options_misc.example -->
### 示例代码
#### name
示例 [详情](<!-- VUEJSON.E_component-instance.circular-reference_ChildB-options.gitUrl -->)
::: preview <!-- VUEJSON.E_component-instance.circular-reference_ChildB-options.webUrl -->
> 选项式 API
<!-- VUEJSON.E_component-instance.circular-reference_ChildB-options.code -->
> 组合式 API
<!-- VUEJSON.E_component-instance.circular-reference_ChildC-composition.code -->
:::
#### inheritAttrs
示例 [详情](<!-- VUEJSON.E_component-instance.mixins_components_Comp1.gitUrl -->)
::: preview <!-- VUEJSON.E_component-instance.mixins_components_Comp1.webUrl -->
> inheritAttrs: true
<!-- VUEJSON.E_component-instance.mixins_components_Comp1.code -->
> inheritAttrs: false
<!-- VUEJSON.E_component-instance.mixins_components_Comp2.code -->
:::
#### components
示例 [详情](<!-- VUEJSON.E_component-instance.circular-reference_ChildB-options.gitUrl -->)
::: preview <!-- VUEJSON.E_component-instance.circular-reference_ChildB-options.webUrl -->
> 选项式 API
<!-- VUEJSON.E_component-instance.circular-reference_ChildB-options.code -->
> 组合式 API
<!-- VUEJSON.E_component-instance.circular-reference_ChildB-composition.code -->
:::
## 组件实例 @component-instance
<!-- VUEJSON.component_instance.compatibility -->
<!-- VUEJSON.component_instance.example -->
### $nextTick 使用注意事项 @options-nextTick
目前 $nextTick 可以保证当前数据已经同步到 DOM,但是由于排版和渲染是异步的,所以 $nextTick 不能保证 DOM 排版以及渲染完毕。\
如果需要获取排版后的节点信息推荐使用 [uni.createSelectorQuery](../api/nodes-info.md) 不推荐直接使用 [Element](../dom/unielement.md) 对象。\
在修改 DOM 后,立刻使用 [Element](../dom/unielement.md) 对象的同步接口获取 DOM 状态可能获取到的是排版之前的,而 [uni.createSelectorQuery](../api/nodes-info.md) 可以保障获取到的节点信息是排版之后的。
### $data 使用注意事项 @options-data
data内 $ 开头的属性不可直接使用 `this.$xxx`访问,需要使用 `this.$data['$xxx']` ,这是vue的规范
> 目前安卓端可以使用 this.$xxx 访问是Bug而非特性,请勿使用此特性。
示例
```vue
<template>
<view></view>
</template>
<script>
export default {
data() {
return {
$a: 1
}
},
onReady() {
console.log(this.$data['$a'] as number) // 1
}
}
</script>
```
# 其他vue事项
## 插件
暂不支持vue插件,比如pinia、vuex、i18n、router。简单的状态管理可以参考文档[全局变量和状态管理](../tutorial/store.md)
# 单文件组件 @single-file-component
## \<script setup> @script_setup
### 基本语法 @basic-syntax
- 仅支持 `export default {}` 方式定义组件。
- `data` 仅支持函数返回对象字面量方式。
```ts
<script lang="uts">
export default {
data() {
return {
// 必须写这里
}
}
}
</script>
```
<!-- VUEJSON.script.description -->
<!-- VUEJSON.script.attribute -->
<!-- VUEJSON.script.event -->
<!-- VUEJSON.script.example -->
<!-- VUEJSON.script.compatibility -->
<!-- VUEJSON.script.children -->
<!-- VUEJSON.script.reference -->
### 单文件组件中方法兼容性 @single-file-component-script-methods
<!-- VUEJSON.single_file_component_script.compatibility -->
#### defineProps
仅支持数组字面量、对象字面量定义(等同于 `options` 中的 `props`规则)及使用纯类型参数的方式来声明。
```ts
// 数组字面量
defineProps(['str', 'num', 'bool', 'arr', 'obj', 'fn'])
// 对象字面量
defineProps({
str: String,
num: Number,
bool: {
type: Boolean,
default: true
},
arr: {
type: Array as PropType<string[]>,
default: () : string[] => [] as string[]
},
obj: {
type: Object as PropType<UTSJSONObject>,
default: () : UTSJSONObject => ({ a: 1 })
},
fn: {
type: Function as PropType<() => string>,
default: () : string => ''
}
})
// 纯类型参数
defineProps<{
str : String,
num : Number,
bool : Boolean,
arr : PropType<string[]>,
obj : PropType<UTSJSONObject>,
fn : PropType<() => string>
}>()
```
- `defineEmits` 仅支持数组字面量和纯类型参数的方式来声明。
```ts
// 数组字面量
const emit = defineEmits(['change'])
// 纯类型参数
const emit = defineEmits<{
(e : 'change', id : number) : void
}>()
const emit = defineEmits<{
// 具名元组语法
change : [id: number]
}>()
```
#### defineOptions
仅支持对象字面量方式定义。
```ts
defineOptions({
data() {
return {
count: 0,
price: 10,
total: 0
}
},
computed: {
doubleCount() : number {
return this.count * 2
},
},
watch: {
count() {
this.total = this.price * this.count
},
},
methods: {
increment() {
this.count++
}
}
})
```
#### defineExpose
仅支持对象字面量方式定义,导出的变量或方法,必须是 `setup` 中定义的,暂不支持外部定义。
```ts
<script setup>
const str = 'str'
const num = ref(0)
const increment = () => {
num.value++
}
defineExpose({
str,
num,
increment
})
</script>
```
<!-- VUEJSON.single_file_component_script.example -->
## CSS 功能 @css
### style 标签 @style
<!-- VUEJSON.style.description -->
<!-- VUEJSON.style.attribute -->
<!-- VUEJSON.style.event -->
<!-- VUEJSON.style.example -->
<!-- VUEJSON.style.compatibility -->
<!-- VUEJSON.style.children -->
<!-- VUEJSON.style.reference -->
```vue
<template>
<view>
<view :style="styleMap" :class="classMap"></view>
</view>
</template>
<script lang="uts">
export default {
data() {
return {
styleMap: new Map<string, string>([['border', '2px solid red'], ['background-color', 'green']]),
classMap: new Map<string, boolean>([['w-100', true], ['h-100', true], ['rounded', false]])
}
}
}
</script>
<style lang="scss" scoped>
.w-100 {
width: 100px;
}
.h-100 {
height: 100px;
}
.rounded {
border-radius: 8px;
}
</style>
```
### Class 与 Style 绑定 @class-style
- [参见](https://uniapp.dcloud.net.cn/tutorial/vue3-basics.html#class-%E4%B8%8E-style-%E7%BB%91%E5%AE%9A)
- `uni-app x` 支持绑定 `UTSJSONObject``Map` 类型数据。
- 在App-Android平台上 `Map` 的性能高于 `UTSJSONObject` 数据类型。从 `uni-app x 4.01` 起,Web平台也支持了 `Map` 类型绑定。
### 深度选择器 @scoped
> 处于 `scoped` 样式中的选择器如果想要做更“深度”的选择,也即:影响到子组件,可以使用 `:deep()` 这个伪类:
```vue
<style scoped>
.a :deep(.b) {
/* ... */
}
</style>
```
### CSS Modules @css-module
一个 `<style module>` 标签会被编译为 `CSS Modules` 并且将生成的 CSS class 作为 `$style` 对象暴露给组件:
```vue
<template>
<text :class="$style.red">This should be red</text>
</template>
<style module>
.red {
color: red;
}
</style>
```
得出的 class 将被哈希化以避免冲突,实现了同样的将 CSS 仅作用于当前组件的效果。
#### CSS Modules 自定义注入名称 @css-module-custom-injection
你可以通过给 `module` attribute 一个值来自定义注入 class 对象的属性名:
```vue
<template>
<text :class="classes.red">red</text>
</template>
<style module="classes">
.red {
color: red;
}
</style>
```
#### CSS Modules 与组合式 API 一同使用 @css-module-composition-api
可以通过 `useCssModule` API 在 `setup()``<script setup>` 中访问注入的 class。对于使用了自定义注入名称的 `<style module>` 块,useCssModule 接收一个匹配的 module attribute 值作为第一个参数:
```ts
import { useCssModule } from 'vue'
// 在 setup() 作用域中...
// 默认情况下, 返回 <style module> 的 class
useCssModule()
// 具名情况下, 返回 <style module="classes"> 的 class
useCssModule('classes')
```
### CSS 中的 v-bind() @css-v-bind
|App|Web|
|:-:|:-:|
|x |4.13+ |
单文件组件的 `<style>` 标签支持使用 `v-bind` CSS 函数将 CSS 的值链接到动态的组件状态:
```vue
<template>
<text class="text">hello</text>
</template>
<script>
export default {
data() {
return {
color: 'red'
}
}
}
</script>
<style>
.text {
color: v-bind(color);
}
</style>
```
这个语法同样也适用于 `<script setup>`,且支持 UTS 表达式 (需要用引号包裹起来):
```vue
<script setup>
const theme = {
color: 'red'
}
</script>
<template>
<text class="view">hello</text>
</template>
<style scoped>
.text {
color: v-bind('theme.color');
}
</style>
```
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册