Appearance
UniApp Vue 语法
信息
摘自原文 UniApp 官方教程 - Vue3 语法,本文仅摘选出 vue 在 UniApp 中差异的部分。
1. 基础
1.1. 在 uni-app 中使用 vue 的差异
uni-app 在发布到 H5 时支持所有 vue 的语法;发布到 App 和小程序时,由于平台限制,无法实现全部 vue 语法,但 uni-app 仍是对 vue 语法支持度最高的跨端框架。
相比 Web 平台,Vue.js 在 uni-app 中使用差异主要集中在两个方面:
uni-app 项目支持 vue 3.0 介绍,及升级指南。
uni-app 项目对 vue 3.0 的支持版本情况如下:
- Web 平台:支持;
- 小程序平台:HBuilderX 3.3.3+ 编译器改为 vite,之前版本的编译器为 webpack;
- App 平台:uni-app 3.2.5+ 支持。HBuilderX 3.3.13 起 nvue 编译器升级为 vite;
注意事项:
- vue3 响应式基于 Proxy 实现,不支持 iOS9 和 ie11;
- 暂不支持新增的
Teleport、Suspense组件; - 目前 HBuilderX 3.2 起已预置,之前的版本只能使用 cli 方式;
1.2. 模板语法
1.2.1. 指令
1.2.1.1. v-once
只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。
和前端框架中的理解不同,客户端里要实现复用的逻辑,会标记模板节点的状态,添加了 v-once 能保证节点只渲染一次,但是并不一定能优化渲染性能,反而可能会拖慢客户端复用节点时的比对效率。
警告
h5、微信小程序均不支持。
HTML
<!-- 单个元素 -->
<view v-once>This will never change: {{msg}}</view>
<!-- 有子元素 -->
<view v-once>
<text>comment</text>
<text>{{msg}}</text>
</view>1.2.1.2. v-html
更新元素的 innerHTML。
- 注意:内容按普通 HTML 插入 - 不会作为 Vue 模板进行编译;
- 如果试图使用
v-html组合模板,可以重新考虑是否通过使用组件来替代; - App 端和 H5 端支持
v-html,微信小程序会被转为rich-text,其他端不支持v-html;
跨端的富文本处理方案详见:https://ask.dcloud.net.cn/article/35772。
HTML
<template>
<view>
<view v-html="rawHtml"></view>
</view>
</template>
<script>
export default {
data() {
return {
rawHtml: '<div style="text-align:center;background-color: #007AFF;"><div >我是内容</div><img src="https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/uni@2x.png"/></div>',
};
},
};
</script>1.3. 条件渲染
1.3.1. v-show
v-show 指令用于条件性地展示一块内容:
HTML
<view v-show="ok">Hello!</view>带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS 属性的 display。
注意,v-show 不支持 template 元素,也不支持 v-else。
警告
nvue 页面不支持 v-show。
1.4. 列表渲染
1.4.1. 在 v-for 里使用对象
你也可以用 v-for 来遍历一个对象的 property。
- 第一个参数
value是被迭代的对象元素的属性值; - 第二个参数为
property名称(也就是键名); - 第三个参数作为索引;
HTML
<template>
<view>
<view v-for="(value, name, index) in object"> {{ index }}. {{ name }}: {{ value }} </view>
</view>
</template>
<script>
export default {
data() {
return {
object: {
title: "How to do lists in Vue",
author: "Jane Doe",
publishedAt: "2021-05-10",
},
};
},
};
</script>结果:
Log
0. title: How to do lists in Vue,
1. author: Jane Doe,
2. publishedAt: 2021-05-10警告
在遍历对象时,会按 Object.keys() 的结果遍历,但是不能保证它在不同 JavaScript 引擎下的结果都一致。
例如:
在 H5 平台使用
v-for循环整数时和其他平台存在差异,如v-for="(item, index) in 10"中,在 H5 平台item从1开始,其他平台item从0开始。可使用第二个参数index来保持一致;在非 H5 平台循环对象时不支持第三个参数,如
v-for="(value, name, index) in object"中,index参数是不支持的;小程序端数据为差量更新方式,由于小程序不支持删除对象属性,使用的设置值为
null的方式替代,导致遍历时可能出现不符合预期的情况,需要自行过滤一下值为null的数据(相关反馈)。
1.5. 事件处理
1.5.1. 事件修饰符
修饰符(modifier)是以半角句号 . 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。例如,.prevent 修饰符告诉 @ 事件对于触发的事件调用 event.preventDefault():
@ 事件(v-on)提供了事件修饰符:
.stop:各平台均支持,使用时会阻止事件冒泡,在非 H5 端同时也会阻止事件的默认行为;.prevent:仅在 H5 平台支持;.capture:仅在 H5 平台支持;.self:仅在 H5 平台支持;.once:仅在 H5 平台支持;.passive:仅在 H5 平台支持;
HTML
<!-- 阻止单击事件继续传播 -->
<view @click.stop="doThis"></view>使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 @click.prevent.self 会阻止所有的点击,而 @click.self.prevent 只会阻止对元素自身的点击。
注意:
为兼容各端,事件需使用
@的方式绑定,请勿使用小程序端的bind和catch进行事件绑定;也不能在 JS 中使用event.preventDefault()和event.stopPropagation()方法。若需要禁止蒙版下的页面滚动,可使用
@touchmove.stop.prevent="moveHandle",moveHandle可以用来处理touchmove的事件,也可以是一个空函数。HTML<view class="mask" @touchmove.stop.prevent="moveHandle"></view>按键修饰符:uni-app 运行在手机端,没有键盘事件,所以不支持按键修饰符。
1.5.2. 事件映射表
JSON
// 事件映射表,左侧为 WEB 事件,右侧为 uni-app 对应事件
{
"click": "tap",
"touchstart": "touchstart",
"touchmove": "touchmove",
"touchcancel": "touchcancel",
"touchend": "touchend",
"tap": "tap",
"longtap": "longtap", // 推荐使用 longpress 代替
"input": "input",
"change": "change",
"submit": "submit",
"blur": "blur",
"focus": "focus",
"reset": "reset",
"confirm": "confirm",
"columnchange": "columnchange",
"linechange": "linechange",
"error": "error",
"scrolltoupper": "scrolltoupper",
"scrolltolower": "scrolltolower",
"scroll": "scroll"
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1.6. 表单输入绑定
1.6.1. uni-app 表单组件
建议开发过程中直接使用 uni-app:表单组件。
用法示例:
H5 的
select标签用picker组件进行代替:HTML<template> <view> <picker @change="bindPickerChange" :value="index" :range="array"> <view class="picker"> 当前选择:{{array[index]}} </view> </picker> </view> </template> <script> export default { data() { return { index: 0, array: ["A", "B", "C"], }; }, methods: { bindPickerChange(e) { console.log(e); this.index = e.detail.value; }, }, }; </script>表单元素
radio用radio-group组件进行代替:HTML<template> <view> <radio-group class="radio-group" @change="radioChange"> <label class="radio" v-for="(item, index) in items" :key="item.name"> <radio :value="item.name" :checked="item.checked" /> {{item.value}} </label> </radio-group> </view> </template> <script> export default { data() { return { items: [ { name: "USA", value: "美国", }, { name: "CHN", value: "中国", checked: "true", }, { name: "BRA", value: "巴西", }, { name: "JPN", value: "日本", }, { name: "ENG", value: "英国", }, { name: "TUR", value: "法国", }, ], }; }, methods: { radioChange(e) { console.log("radio 发生 change 事件,携带 value 值为:", e.target.value); }, }, }; </script>
2. 组件
组件是视图层的基本组成单元。
组件是一个单独且可复用的功能模块的封装。
一个组件包括开始标签和结束标签,标签上可以写属性,并对属性赋值。内容则写在两个标签之内。
根节点为
<template>,这个<template>下在 App、H5 可以有多个根<view>组件,在小程序只能有一个根<view>组件。一个组件的
data选项必须是一个函数。
下面是一个基本组件示例,在根 <view> 组件下再次引入一个 <view> 组件,并给组件的 text 区绑定一个 data:
HTML
<template>
<view>
<text>{{userName}}</text>
</view>
</template>
<script>
export default {
data() {
return {
userName: "foo",
};
},
};
</script>基础组件是内置在 uni-app 框架中的,包括 view、text、input、button、video 等几十个基础组件,列表详见:uni-app 基础组件。
但仅有基础组件是不够用的,实际开发中会有很多封装的组件。
比如我们需要一个五角星点击评分的组件,在 DCloud 的插件市场里可以获取到:https://ext.dcloud.net.cn/plugin?id=33。
把这个 uni-rate 组件导入到你的 uni-app 项目下,在需要的 vue 页面里引用它,就可以在指定的地方显示出这个五角星组件:
HTML
<!-- 在 index.vue 页面引用 uni-rate 组件-->
<template>
<view>
<uni-rate></uni-rate
><!-- 这里会显示一个五角星,并且点击后会自动亮星 -->
</view>
</template>2.1. 注册
在注册一个组件的时候,我们始终需要给它一个名字。定义组件名的方式有两种:
使用 kebab-case
当使用 kebab-case(短横线分隔命名)定义一个组件时,你也必须在引用这个自定义元素时使用 kebab-case,例如
<my-component-name>。使用 PascalCase
当使用 PascalCase(首字母大写命名)定义一个组件时,你在引用这个自定义元素时两种命名法都可以使用。也就是说
<my-component-name>和<MyComponentName>都是可接受的。
在 uni-app 工程根目录下的 components 目录,创建并存放自定义组件:
Text
│─components 符合 vue 组件规范的 uni-app 组件目录
│ └─componentA 符合 ‘components/组件名称/组件名称.vue’ 目录结构,easycom 方式可直接使用组件
│ └─componentA.vue 可复用的 componentA 组件
│ └─component-a.vue 可复用的 component-a 组件2.1.1. 全局注册
uni-app 支持配置全局组件,需在 main.js 里进行全局注册,注册后就可在所有页面里使用该组件。
警告
app.component的第一个参数必须是静态的字符串;- nvue 页面暂不支持全局组件。
main.js 里进行全局导入和注册:
JavaScript
import App from "./App";
import { createSSRApp } from "vue";
// 引入组件
import myComponent from "./components/my-component/my-component.vue";
export function createApp() {
const app = createSSRApp(App);
// 调用 app.component 方法全局注册组件
app.component("my-component", myComponent);
return {
app,
};
}index.vue 里可直接使用组件:
HTML
<template>
<view>
<my-component></my-component>
</view>
</template>2.1.2. 局部注册
局部注册之前,在需要引用该组件的页面,导入你想使用的组件。
如下通过两种方式导入一个角标的组件库,详见,推荐使用 easycom 方式引入。
传统 vue 规范:在
index.vue页面中,通过import方式引入组件,在components选项中定义你想要使用的组件。HTML<!-- 在 index.vue 引入 uni-badge 组件--> <template> <view> <uni-badge text="1"></uni-badge ><!-- 3. 使用组件 --> </view> </template> <script> import uniBadge from "@/components/uni-badge/uni-badge.vue"; // 1. 导入组件(这步属于传统 vue 规范,但在 uni-app 的 easycom 下可以省略这步) export default { components: { uniBadge }, // 2. 注册组件(这步属于传统 vue 规范,但在 uni-app 的 easycom 下可以省略这步) }; </script>对于
components对象中的每个property来说,其property名就是自定义元素的名字,其property值就是这个组件的选项对象。在对象中放一个类似
uniBadge的变量名其实是uniBadge: uniBadge的缩写,即这个变量名同时是:- 用在模板中的自定义元素的名称;
- 包含了这个组件选项的变量名(仅支持驼峰法命名);
通过 uni-app 的 easycom:将组件引入精简为一步。只要组件安装在项目的
components目录下,并符合components/组件名称/组件名称.vue目录结构。就可以不用引用、注册,直接在页面中使用。HTML<!-- 在 index.vue 引入 uni-badge 组件--> <template> <view> <uni-badge text="1"></uni-badge> <!-- 3. 使用组件 --> </view> </template> <script> // 这里不用 import 引入,也不需要在 components 内注册 uni-badge 组件。template 里就可以直接用 export default { data() { return {}; }, }; </script>easycom 是自动开启的,不需要手动开启,有需求时可以在
pages.json的easycom节点进行个性化设置,详见。不管
components目录下安装了多少组件,easycom 打包后会自动剔除没有使用的组件,对组件库的使用尤为友好。
组件是 vue 技术中非常重要的部分,组件使得与 ui 相关的轮子可以方便的制造和共享,进而使得 vue 使用者的开发效率大幅提升。
uni-app 搭建了组件的插件市场,有很多现成的组件,若下载符合 components/组件名称/组件名称.vue 目录结构的组件,均可直接使用。uni-app 插件市场。
uni-app 只支持 vue 单文件组件(.vue 组件)。其他的诸如:动态组件,自定义 render,和 <script type="text/x-template"> 字符串模版等,在非 H5 端不支持。
2.2. props
2.2.1. 传递静态或动态的 prop
传入一个对象的所有
property(微信小程序暂不支持该用法)如果你想要将一个对象的所有
property都作为 prop 传入,你可以使用不带参数的v-bind(取代v-bind:prop-name)。例如,对于一个给定的对象 post:JavaScriptpost: { id: 1, title: "My Journey with Vue", }HTML<blog-post v-bind="post"></blog-post> <!-- 上面的模板等价于:--> <blog-post v-bind:id="post.id" v-bind:title="post.title"></blog-post>
2.3. 非 Prop 的 Attribute
2.3.1. 多个根节点上的 Attribute 继承
与单个根节点组件不同,具有多个根节点的组件不具有自动 attribute 回退行为(小程序不支持)。如果未显式绑定 $attrs,将发出运行时警告。
HTML
<custom-layout id="custom-layout" @click="changeValue"></custom-layout>HTML
<!-- 我是 custom-layout 组件 -->
<!-- 这将发出警告 -->
<template>
<header>...</header>
<main>...</main>
<footer>...</footer>
</template>
<!-- 没有警告,$attrs 被传递到<main>元素 -->
<template>
<header>...</header>
<main v-bind="$attrs">...</main>
<footer>...</footer>
</template>2.4. 小程序不支持列表
作用域插槽(HBuilderX 3.1.19 以下仅支持解构插槽且不可使用作用域外数据以及使用复杂的表达式);
动态组件;
异步组件;
inline-template;
X-Templates;
keep-alive(App 端也未支持);
transition(可使用animation或 CSS 动画替代);
3. API
3.1. 应用配置
config 是一个包含了 Vue 应用全局配置的对象。你可以在应用挂载前修改其以下 property:
JavaScript
const app = Vue.createApp({})
app.config = {...}| 应用配置 | 描述 | H5 | App 端 | 微信小程序 | 说明 |
|---|---|---|---|---|---|
errorHandler | 指定一个处理函数,来处理组件渲染方法执行期间以及侦听器抛出的未捕获错误。详情 | √ | √ | √ | |
warnHandler | 为 Vue 的运行时警告指定一个自定义处理函数。详情 | √ | √ | √ | |
globalProperties | 添加可以在应用程序内的任何组件实例中访问的全局 Property。详情 | √ | √ | √ | |
isCustomElement | 指定一个方法,用来识别在 Vue 之外定义的自定义元素。详情 | √ | √ | √ | |
optionMergeStrategies | 为自定义选项定义合并策略。详情 | √ | √ | √ | |
performance | 设置为 true 以在浏览器开发工具的 performance/timeline 面板中启用对组件初始化、编译、渲染和更新的性能追踪。详情 | √ | x | x | 只在 Web 环境下支持 |
3.2. 应用 API
在 Vue 3 中,改变全局 Vue 行为的 API 现在被移动到了由新的 createApp 方法所创建的应用实例上。此外,现在它们的影响仅限于该特定应用实例:
JavaScript
import { createApp } from "vue";
const app = createApp({});调用 createApp 返回一个应用实例。该实例提供了一个应用上下文。应用实例挂载的整个组件树共享相同的上下文,该上下文提供了之前在 Vue 2.x 中 “全局” 的配置。
另外,由于 createApp 方法返回应用实例本身,因此可以在其后链式调用其它方法,这些方法可以在以下部分中找到。
| 应用 API | 描述 | H5 | App 端 | 微信小程序 | 说明 |
|---|---|---|---|---|---|
component | 注册或检索全局组件。详情 | √ | √ | √ | |
config | 包含应用配置的对象。详情 | √ | √ | √ | |
directive | 注册或检索全局指令。详情 | √ | √ | x | |
mixin | 在整个应用范围内应用混入。详情 | √ | √ | √ | nvue 页面暂不支持 |
provide | 设置一个可以被注入到应用范围内所有组件中的值。详情 | √ | √ | √ | |
use | 安装 Vue.js 插件。详情 | √ | √ | √ |
3.3. 全局 API
| 全局 API | 描述 | H5 | App 端 | 微信小程序 |
|---|---|---|---|---|
createApp | 返回一个提供应用上下文的应用实例。应用实例挂载的整个组件树共享同一个上下文。详情 | √ | √ | √ |
h | 返回一个 “虚拟节点”,通常缩写为 VNode:一个普通对象,其中包含向 Vue 描述它应在页面上渲染哪种节点的信息,包括所有子节点的描述。详情 | √ | x | x |
defineComponent | 从实现上看,defineComponent 只返回传递给它的对象。但是,就类型而言,返回的值有一个合成类型的构造函数,用于手动渲染函数、TSX 和 IDE 工具支持。详情 | √ | x | x |
defineAsyncComponent | 创建一个只有在需要时才会加载的异步组件。详情 | √ | x | x |
resolveComponent | 如果在当前应用实例中可用,则允许按名称解析 component。返回一个 Component。详情 | √ | x | x |
resolveDynamicComponent | 允许使用与 component :is="" 相同的机制来解析一个 component。详情 | √ | x | x |
resolveDirective | 如果在当前应用实例中可用,则允许通过其名称解析一个 directive。返回一个 Directive。详情 | √ | x | x |
withDirectives | 允许将指令应用于 VNode。返回一个包含应用指令的 VNode。详情 | √ | x | x |
createRenderer | createRenderer 函数接受两个泛型参数:HostNode 和 HostElement,对应于宿主环境中的 Node 和 Element 类型。详情 | √ | x | x |
nextTick | 将回调推迟到下一个 DOM 更新周期之后执行。在更改了一些数据以等待 DOM 更新后立即使用它。详情 | √ | x | x |
3.4. 选项/Data
| Data | 描述 | H5 | App 端 | 微信小程序 |
|---|---|---|---|---|
data | 返回组件实例的 data 对象的函数。详情 | √ | √ | √ |
props | props 可以是数组或对象,用于接收来自父组件的数据。详情 | √ | √ | √ |
computed | 计算属性将被混入到组件实例中。所有 getter 和 setter 的 this 上下文自动地绑定为组件实例。详情 | √ | √ | √ |
methods | methods 将被混入到组件实例中。可以直接通过 VM 实例访问这些方法,或者在指令表达式中使用。方法中的 this 自动绑定为组件实例。详情 | √ | √ | √ |
watch | 一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象。详情 | √ | √ | √ |
emits | emits 可以是数组或对象,从组件触发自定义事件,emits 可以是简单的数组,或者对象作为替代,允许配置和事件验证。详情 | √ | √ | √ |
3.5. 选项/DOM
| DOM | 描述 | H5 | App 端 | 微信小程序 | 说明 |
|---|---|---|---|---|---|
template | 一个字符串模板作为 component 实例的标识使用。详情 | √ | x | x | uni-app 使用的 vue 是只包含运行时的版本 |
render | 字符串模板的另一种选择,允许你充分利用 JavaScript 的编程功能。详情 | √ | x | x | - |
3.6. 选项/生命周期钩子
| 生命周期钩子 | 描述 | H5 | App 端 | 微信小程序 |
|---|---|---|---|---|
beforeCreate | 在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。详情 | √ | √ | √ |
created | 在实例创建完成后被立即调用。详情 | √ | √ | √ |
beforeMount | 在挂载开始之前被调用:相关的 render 函数首次被调用。详情 | √ | √ | √ |
mounted | 实例被挂载后调用,这时 Vue.createApp({}).mount() 被新创建的 vm.$el 替换了。详情 | √ | √ | √ |
beforeUpdate | 数据更新时调用,发生在虚拟 DOM 打补丁之前。详情 | √ | √ | √ |
updated | 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。详情 | √ | √ | √ |
activated | 被 keep-alive 缓存的组件激活时调用。详情 | √ | √ | x |
deactivated | 被 keep-alive 缓存的组件停用时调用。详情 | √ | √ | x |
beforeUnmount | 在卸载组件实例之前调用。在这个阶段,实例仍然是完全正常的。详情 | √ | √ | √ |
unmounted | 卸载组件实例后调用。调用此钩子时,组件实例的所有指令都被解除绑定,所有事件侦听器都被移除,所有子组件实例被卸载。详情 | √ | √ | √ |
errorCaptured | 当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。详情 | √ | √ | √ |
renderTracked | 跟踪虚拟 DOM 重新渲染时调用。钩子接收 debugger event 作为参数。此事件告诉你哪个操作跟踪了组件以及该操作的目标对象和键。详情 | √ | √ | √ |
renderTriggered | 当虚拟 DOM 重新渲染为 triggered.Similarly 为 renderTracked,接收 debugger event 作为参数。此事件告诉你是什么操作触发了重新渲染,以及该操作的目标对象和键。详情 | √ | √ | √ |
3.7. 选项/资源
| 资源 | 描述 | H5 | App 端 | 微信小程序 |
|---|---|---|---|---|
directives | 包含组件实例可用指令的哈希表。详情 | √ | √ | x |
components | 包含组件实例可用组件的哈希表。详情 | √ | √ | √ |
3.8. 选项/组合
| 组合 | 描述 | H5 | App 端 | 微信小程序 |
|---|---|---|---|---|
mixins | 接收一个混入对象的数组。这些混入对象可以像正常的实例对象一样包含实例选项,这些选项将会被合并到最终的选项中,使用特定的选项合并逻辑。详情 | √ | √ | √ |
extends | 允许声明扩展另一个组件(可以是一个简单的选项对象或构造函数)。这主要是为了便于扩展单文件组件。详情 | √ | √ | √ |
provide / inject | 这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。详情 | √ | √ | √ |
setup | setup 函数是一个新的组件选项。它作为在组件内部使用组合式 API 的入口点。详情 | √ | √ | √ |
3.9. 选项/杂项
| 杂项 | 描述 | H5 | App 端 | 微信小程序 |
|---|---|---|---|---|
name | 允许组件模板递归地调用自身。注意,组件在全局用 Vue.createApp({}).component({}) 注册时,全局 ID 自动作为组件的 name。详情 | √ | √ | √ |
delimiters | 设置用于模板内文本插入的分隔符。详情 | √ | x | x |
inheritAttrs | 默认情况下父作用域的不被认作 props 的 attribute 绑定 (attribute bindings) 将会 “回退” 且作为普通的 HTML attribute 应用在子组件的根元素上。当撰写包裹一个目标元素或另一个组件的组件时,通过设置 inheritAttrs 到 false,这些默认行为将会被去掉。详情 | √ | √ | x |
3.10. 实例 property
| 实例 property | 描述 | H5 | App 端 | 微信小程序 | 说明 |
|---|---|---|---|---|---|
$data | 组件实例观察的数据对象。组件实例代理了对其 data 对象 property 的访问。详情 | √ | √ | √ | |
$props | 当前组件接收到的 props 对象。组件实例代理了对其 props 对象 property 的访问。详情 | √ | √ | √ | |
$el | 组件实例使用的根 DOM 元素。详情 | √ | x | x | |
$options | 用于当前组件实例的初始化选项。需要在选项中包含自定义 property 时会有用处。详情 | √ | √ | √ | |
$parent | 父实例,如果当前实例有的话。详情 | √ | √ | √ | H5 端 view、text 等内置标签是以 Vue 组件方式实现,$parent 会获取这些到内置组件,导致的问题是 this.$parent 与其他平台不一致,解决方式是使用 this.$parent.$parent 获取或自定义组件根节点由 view 改为 div |
$root | 当前组件树的根组件实例。如果当前实例没有父实例,此实例将会是其自己。详情 | √ | √ | √ | |
$slots | 用来访问被插槽分发的内容。每个具名插槽有其相应的 property(例如:v-slot:foo 中的内容将会在 this.$slots.foo 中被找到)。详情 | √ | √ | √ | |
$refs | 一个对象,持有注册过 ref attribute 的所有 DOM 元素和组件实例。详情 | √ | √ | √ | 非 H5 端只能用于获取自定义组件,不能用于获取内置组件实例(如:view、text),uni-app x 内置组件绑定 ref 会返回组件根节点的引用。 |
$attrs | 包含了父作用域中不作为组件 props 或自定义事件。详情 | √ | √ | x | - |
3.11. 实例方法
| 实例方法 | 描述 | H5 | App 端 | 微信小程序 |
|---|---|---|---|---|
$watch | 侦听组件实例上的响应式 property 或函数计算结果的变化。详情 | √ | √ | √ |
$emit | 触发当前实例上的事件。附加参数都会传给监听器回调。详情 | √ | √ | √ |
$forceUpdate | 迫使组件实例重新渲染。注意它仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件。详情 | √ | √ | √ |
$nextTick | 将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。详情 | √ | √ | √ |
3.12. 指令
| Vue 指令 | 描述 | H5 | App 端 | 微信小程序 | 说明 |
|---|---|---|---|---|---|
v-text | 更新元素的 textContent。详情 | √ | √ | x | |
v-html | 更新元素的 innerHTML。详情 | √ | √ | √ | 微信小程序会被转成 rich-text |
v-show | 根据表达式的真假值,切换元素的 display CSS 属性。详情 | √ | √ | √ | |
v-if | 根据表达式的真假值来有条件地渲染元素。详情 | √ | √ | √ | |
v-else | 为 v-if 或者 v-else-if 添加 “else 块”。详情 | √ | √ | √ | |
v-else-if | 表示 v-if 的 “else if 块”。可以链式调用。详情 | √ | √ | √ | |
v-for | 基于源数据多次渲染元素或模板块。详情 | √ | √ | √ | |
v-on | 绑定事件监听器。详情 | √ | √ | √ | |
v-bind | 动态地绑定一个或多个 attribute,或一个组件 prop 到表达式。详情 | √ | √ | √ | |
v-model | 在表单控件或者组件上创建双向绑定。详情 | √ | √ | √ | |
v-slot | 提供具名插槽或需要接收 prop 的插槽。详情 | √ | √ | √ | |
v-pre | 跳过这个元素和它的子元素的编译过程。详情 | √ | √ | x | |
v-cloak | 这个指令保持在元素上直到关联组件实例结束编译。详情 | √ | x | x | |
v-once | 只渲染元素和组件一次。详情 | √ | √ | x | |
v-is | 在 DOM 内模板使用时,模板受原生 HTML 解析规则的约束。详情 | √ | x | x | - |
3.13. 特殊属性
| 特殊属性 | 描述 | H5 | App 端 | 微信小程序 | 说明 |
|---|---|---|---|---|---|
key | key 的特殊 attribute 主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes。详情 | √ | √ | √ | |
ref | ref 被用来给元素或子组件注册引用信息。详情 | √ | √ | √ | 非 H5 平台只能获取 Vue 组件实例不能获取到内置组件实例 |
is | 使用动态组件。详情 | √ | √ | x | - |
3.14. 内置组件
| 内置组件 | 描述 | H5 | App 端 | 微信小程序 |
|---|---|---|---|---|
component | 渲染一个 “元组件” 为动态组件。依 is 的值,来决定哪个组件被渲染。详情 | √ | √ | x |
transition | 作为单个元素/组件的过渡效果。详情 | √ | x | x |
transition-group | 作为多个元素/组件的过渡效果。详情 | √ | x | x |
keep-alive | 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们,主要用于保留组件状态或避免重新渲染。详情 | √ | x | x |
slot | 作为组件模板之中的内容分发插槽。slot 元素自身将被替换。详情 | √ | √ | √ |
teleport | 将模板的一部分移动到 DOM 中 Vue app 之外的其他位置。详情 | √ | x | x |
3.15. 响应性 API
3.15.1. 响应性基础 API
| 响应性基础 API | 描述 | H5 | App 端 | 微信小程序 |
|---|---|---|---|---|
reactive | 返回对象的响应式副本。详情 | √ | √ | √ |
readonly | 获取一个对象(响应式或纯对象)或 ref 并返回原始代理的只读代理。详情 | √ | √ | √ |
isProxy | 检查对象是 reactive 还是 readonly 创建的代理。详情 | √ | √ | √ |
isReactive | 检查对象是否是 reactive 创建的响应式 proxy。详情 | √ | √ | √ |
isReadonly | 检查对象是否是由 readonly 创建的只读代理。详情 | √ | √ | √ |
toRaw | 返回 reactive 或 readonly 代理的原始对象。详情 | √ | √ | √ |
markRaw | 标记一个对象,使其永远不会转换为代理。返回对象本身。详情 | √ | √ | √ |
shallowReactive | 创建一个响应式代理,该代理跟踪其自身 property 的响应性,但不执行嵌套对象的深度响应式转换(暴露原始值)。详情 | √ | √ | √ |
shallowReadonly | 创建一个代理,使其自身的 property 为只读,但不执行嵌套对象的深度只读转换(暴露原始值)。详情 | √ | √ | √ |
3.15.2. Refs
| Refs | 描述 | H5 | App 端 | 微信小程序 |
|---|---|---|---|---|
ref | 接受一个内部值并返回一个响应式且可变的 ref 对象。ref 对象具有指向内部值的单个 property .value。详情 | √ | √ | √ |
unref | 如果参数为 ref,则返回内部值,否则返回参数本身。这是 val = isRef(val) ? val.value : val。详情 | √ | √ | √ |
toRef | 可以用来为源响应式对象上的 property 性创建一个 ref。然后可以将 ref 传递出去,从而保持对其源 property 的响应式连接。详情 | √ | √ | √ |
toRefs | 将响应式对象转换为普通对象,其中结果对象的每个 property 都是指向原始对象相应 property 的 ref。详情 | √ | √ | √ |
isRef | 检查值是否为 ref 对象详情 | √ | √ | √ |
customRef | 创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。详情 | √ | √ | √ |
shallowRef | 创建一个 ref,它跟踪自己的 .value 更改,但不会使其值成为响应式的。详情 | √ | √ | √ |
triggerRef | 手动执行与 shallowRef 关联的任何效果。详情 | √ | √ | √ |
3.15.3. Computed 与 watch
| Computed 与 watch | 描述 | H5 | App 端 | 微信小程序 |
|---|---|---|---|---|
computed | 使用 getter 函数,并为从 getter 返回的值返回一个不变的响应式 ref 对象。详情 | √ | √ | √ |
watchEffect | 在响应式地跟踪其依赖项时立即运行一个函数,并在更改依赖项时重新运行它。详情 | √ | √ | √ |
watch | watch API 与选项式 API this.$watch(以及相应的 watch 选项)完全等效。watch 需要侦听特定的 data 源,并在单独的回调函数中副作用。详情 | √ | √ | √ |
3.16. 组合式 API
| 组合式 API | 描述 | H5 | App 端 | 微信小程序 |
|---|---|---|---|---|
setup | 一个组件选项,在创建组件之前执行,一旦 props 被解析,并作为组合式 API 的入口点。详情 | √ | √ | √ |
| 生命周期钩子 | 可以使用直接导入的 onX 函数注册生命周期钩子。详情 | √ | √ | √ |
| Provide / Inject | provide 和 inject 启用依赖注入。只有在使用当前活动实例的 setup() 期间才能调用这两者。详情 | √ | √ | √ |
getCurrentInstance | 允许访问对高级使用或库创建者有用的内部组件实例。详情 | √ | √ | √ |
3.17. 全局变量
实现全局变量的方式需要遵循 Vue 单文件模式的开发规范。详细参考:uni-app 全局变量的几种实现方式。
3.18. 其他配置
Vue 组件编译到小程序平台的时候会编译为对应平台的组件,部分小程序平台支持 options 选项(具体选项参考对应小程序平台文档的自定义组件部分),一般情况默认即可,如有特殊需求可在 Vue 组件中增加 options 属性。
| 属性 | 类型 | 默认值 | 描述 | 平台兼容性 |
|---|---|---|---|---|
multipleSlots | Boolean | true | 在组件定义时的选项中启动多 slot 支持 | |
styleIsolation | String | apply-shared | 组件样式隔离方式,具体配置选项参见:组件样式隔离 | 微信小程序 |
addGlobalClass | Boolean | true | 微信小程序 | |
virtualHost | Boolean | false | 将自定义节点设置成虚拟的,更加接近 Vue 组件的表现。我们不希望自定义组件的这个节点本身可以设置样式、响应 flex 布局等,而是希望自定义组件内部的第一层节点能够响应 flex 布局或者样式由自定义组件本身完全决定,启用后可以通过 mergeVirtualHostAttributes 合并合并组件虚拟节点外层属性 | 支付宝小程序(默认值为 true)、微信小程序、抖音小程序(4.02+) |
JavaScript
export default {
props: ["data"],
data() {
return {};
},
options: {
virtualHost: true,
},
};3.19. 常见问题
3.19.1. 如何获取上个页面传递的数据
在 onLoad 里得到,onLoad 的参数是其他页面打开当前页面所传递的数据。
3.19.2. 如何设置全局的数据和全局的方法
uni-app 内置了 Vuex,在 app 里的使用,可参考 hello-uniapp 项目中的 store/index.js。
JavaScript
//store.js
import { createStore } from "vuex";
const store = createStore({
state: { ... },
mutations: { ... },
actions: { ... },
});
export default store;
//main.js
import App from "./App";
import { createSSRApp } from "vue";
import store from "./store";
export function createApp() {
const app = createSSRApp(App);
app.use(store);
return {
app,
};
}
//test.vue 使用时:
import { mapState, mapMutations } from "vuex";3.19.3. 如何捕获 app 的 onError
由于 onError 并不是完整意义的生命周期,所以只提供一个捕获错误的方法,在 app 的根组件上添加名为 onError 的回调函数即可。如下:
JavaScript
export default {
// 只有 app 才会有 onLaunch 的生命周期
onLaunch() {
// ...
},
// 捕获 app error
onError(err) {
console.log(err);
},
};3.19.4. 组件属性设置不生效解决办法
当重复设置某些属性为相同的值时,不会同步到 view 层。例如:每次将 scroll-view 组件的 scroll-top 属性值设置为 0,只有第一次能顺利返回顶部。这和 props 的单向数据流特性有关,组件内部 scroll-top 的实际值改动后,其绑定的属性并不会一同变化。
解决办法有两种(以 scroll-view 组件为例):
监听
scroll事件,记录组件内部变化的值,在设置新值之前先设置为记录的当前值:HTML<scroll-view scroll-y="true" :scroll-top="scrollTop" @scroll="scroll"></scroll-view>JavaScriptexport default { data() { return { scrollTop: 0, old: { scrollTop: 0, }, }; }, methods: { scroll: function (e) { this.old.scrollTop = e.detail.scrollTop; }, goTop: function (e) { this.scrollTop = this.old.scrollTop; this.$nextTick(function () { this.scrollTop = 0; }); }, }, };监听
scroll事件,获取组件内部变化的值,实时更新其绑定值:HTML<scroll-view scroll-y="true" :scroll-top="scrollTop" @scroll="scroll"></scroll-view>JavaScriptexport default { data() { return { scrollTop: 0, }; }, methods: { scroll: function (e) { // 如果使用此方法,请自行增加防抖处理 this.scrollTop = e.detail.scrollTop; }, goTop: function (e) { this.scrollTop = 0; }, }, };
第二种解决方式在某些组件可能造成抖动,推荐第一种解决方式。
4. 组合式 API
通过组合式 API,我们可以使用导入的 API 函数来描述组件逻辑。在单文件组件中,组合式 API 通常会与 <script setup> 搭配使用。这个 setup attribute 是一个标识,告诉 Vue 需要在编译时进行一些处理,让我们可以更简洁地使用组合式 API。比如,<script setup> 中的导入和顶层变量/函数都能够在模板中直接使用。
4.1. 使用组合式 API
从 vue 包内导入并使用基础的组合式 API,具体 API 可以参考:Vue 官网。从 @dcloudio/uni-app 包内导入 uni-app 应用生命周期及页面的生命周期。
JavaScript
import { defineComponent, ref } from "vue";
import { onReady } from "@dcloudio/uni-app";
export default defineComponent({
setup() {
const title = ref("Hello");
onReady(() => {
console.log("onReady");
});
return {
title,
};
},
});4.2. 使用 Script Setup
改用 Script Setup 写法导入 API。
HTML
<script setup>
import { ref } from "vue";
import { onReady } from "@dcloudio/uni-app";
const title = ref("Hello");
onReady(() => {
console.log("onReady");
});
</script>