use.md 17.4 KB
Newer Older
M
mehaotian 已提交
1 2 3 4 5

``uni-app`` 在发布到H5时支持所有vue的语法;发布到App和小程序时,由于平台限制,无法实现全部vue语法,但``uni-app``仍是是对vue语法支持度最高的跨端框架。本文将详细讲解差异。

相比Web平台, ``Vue.js````uni-app`` 中使用差异主要集中在两个方面:
- 新增:uni-app除了支持Vue实例的生命周期,还支持应用启动、页面显示等生命周期
雪洛's avatar
雪洛 已提交
6 7
- 受限:相比web平台,在小程序和App端部分功能受限,具体见下。
- v3版本App端可以使用更多的vue特性,[详见](https://ask.dcloud.net.cn/article/36599)
M
mehaotian 已提交
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213

## 生命周期

``uni-app`` 完整支持 ``Vue`` 实例的生命周期,同时还新增 [应用生命周期](/frame?id=应用生命周期)[页面生命周期](/frame?id=页面生命周期)

详见Vue官方文档:[生命周期钩子](https://cn.vuejs.org/v2/api/#%E9%80%89%E9%A1%B9-%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E9%92%A9%E5%AD%90)


## 模板语法

``uni-app`` 完整支持 ``Vue`` 模板语法。

详见Vue官方文档:[模板语法](https://cn.vuejs.org/v2/guide/syntax.html)

**注意**
如果使用**老版**的非自定义组件模式,即manifest中`"usingComponents":false`,部分模版语法不支持,但此模式已不再推荐使用,[详见](https://ask.dcloud.net.cn/article/35699)

**老版**非自定义组件模式不支持情况(**新版自定义组件模式已不存在此情况**):
- 不支持部分复杂的 JavaScript 渲染表达式
- 不支持过滤器

## data 属性

``data`` 必须声明为返回一个初始数据对象的函数;否则页面关闭时,数据不会自动销毁,再次打开该页面时,会显示上次数据。

```javascript
//正确用法,使用函数返回对象
data() {
	return {
		title: 'Hello'
	}
}

//错误写法,会导致再次打开页面时,显示上次数据
data: {
	title: 'Hello'
}
```

## 全局变量

实现全局变量的方式需要遵循 Vue 单文件模式的开发规范。详细参考:[uni-app全局变量的几种实现方式](https://ask.dcloud.net.cn/article/35021)

## Class 与 Style 绑定

为节约性能,我们将 ``Class````Style`` 的表达式通过 ``compiler`` 硬编码到 ``uni-app`` 中,支持语法和转换效果如下:

class 支持的语法:

```html
<view :class="{ active: isActive }">111</view>
<view class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }">222</view>
<view class="static" :class="[activeClass, errorClass]">333</view>
<view class="static" v-bind:class="[isActive ? activeClass : '', errorClass]">444</view>
<view class="static" v-bind:class="[{ active: isActive }, errorClass]">555</view>
```

style 支持的语法:

```html
<view v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }">666</view>
<view v-bind:style="[{ color: activeColor, fontSize: fontSize + 'px' }]">777</view>
```

非H5端不支持 [Vue官方文档:Class 与 Style 绑定](https://cn.vuejs.org/v2/guide/class-and-style.html) 中的 ``classObject````styleObject`` 语法。

不支持示例:

```html
<template>
	<view :class="[activeClass]" :style="[baseStyles,overridingStyles]"></view>
</template>

<script>
	export default {
		data() {
			return {
                activeClass: {
                    'active': true,
                    'text-danger': false
                },
                baseStyles: {
                    color: 'green',
                    fontSize: '30px'
                },
                overridingStyles: {
                    'font-weight': 'bold'
                }
			}
		}
	}
</script>
```

**注意:以``:style=""``这样的方式设置px像素值,其值为实际像素,不会被编译器转换。**

此外还可以用 ``computed`` 方法生成 ``class`` 或者 ``style`` 字符串,插入到页面中,举例说明:

```html
<template>
    <!-- 支持 -->
    <view class="container" :class="computedClassStr"></view>
    <view class="container" :class="{active: isActive}"></view>

    <!-- 不支持 -->
    <view class="container" :class="computedClassObject"></view>
</template>
<script>
    export default {
        data () {
            return {
                isActive: true
            }
        },
        computed: {
            computedClassStr () {
                return this.isActive ? 'active' : ''
            },
            computedClassObject () {
                return { active: this.isActive }
            }
        }
    }
</script>
```

**用在组件上**

非H5端暂不支持在自定义组件上使用 ``Class````Style`` 绑定

## 计算属性

完整支持 [Vue官方文档:计算属性](https://cn.vuejs.org/v2/guide/computed.html)

## 条件渲染

完整支持 [Vue官方文档:条件渲染](https://cn.vuejs.org/v2/guide/conditional.html)

## 列表渲染

完整vue列表渲染 [Vue官方文档:列表渲染](https://cn.vuejs.org/v2/guide/list.html)

### key
 
如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 ``<input>`` 中的输入内容,``<switch>`` 的选中状态),需要使用 ``:key`` 来指定列表中项目的唯一的标识符。

``:key`` 的值以两种形式提供

- 使用 ``v-for`` 循环 ``array````item`` 的某个 ``property``,该 ``property`` 的值需要是列表中唯一的字符串或数字,且不能动态改变。
- 使用 ``v-for`` 循环中 ``item`` 本身,这时需要 ``item`` 本身是一个唯一的字符串或者数字

当数据改变触发渲染层重新渲染的时候,会校正带有 ``key`` 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。

**如不提供 ``:key``,会报一个 ``warning``, 如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略。**

**示例:**

```html
<template>
	<view>
		<!-- array 中 item 的某个 property -->
		<view v-for="(item,index) in objectArray" :key="item.id">
			{{index +':'+ item.name}}
		</view>
		<!-- item 本身是一个唯一的字符串或者数字时,可以使用 item 本身 -->
		<view v-for="(item,index) in stringArray" :key="item">
			{{index +':'+ item}}
		</view>
	</view>
</template>
<script>
export default {
  data () {
    return {
      objectArray:[{
		  id:0,
		  name:'li ming'
	  },{
		  id:1,
		  name:'wang peng'
	  }],
	  stringArray:['a','b','c']
    }
  }
}

</script>
```

### 注意事项
* 在H5平台 使用 v-for 循环整数时和其他平台存在差异,如 `v-for="(item, index) in 10"` 中,在H5平台 item 从 1 开始,其他平台 item 从 0 开始,可使用第二个参数 index 来保持一致。
* 在非H5平台 循环对象时不支持第三个参数,如 `v-for="(value, name, index) in object"` 中,index 参数是不支持的。

## 事件处理器

几乎全支持 [Vue官方文档:事件处理器](https://cn.vuejs.org/v2/guide/events.html)

```javascript
// 事件映射表,左侧为 WEB 事件,右侧为 ``uni-app`` 对应事件
{
    click: 'tap',
    touchstart: 'touchstart',
    touchmove: 'touchmove',
    touchcancel: 'touchcancel',
    touchend: 'touchend',
    tap: 'tap',
雪洛's avatar
雪洛 已提交
214
    longtap: 'longtap', //推荐使用longpress代替
M
mehaotian 已提交
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
    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'
}
```

**注意:**

<!-- * 事件映射表中没有的原生事件也可以使用,例如``map``组件的``regionchange`` 事件直接在组件上写成 ``@regionchange``,同时这个事件也非常特殊,它的 ``event`` ``type````begin````end`` 两个,导致我们无法在``handleProxy`` 中区分到底是什么事件,所以你在监听此类事件的时候同时监听事件名和事件类型既 
``<map @regionchange="functionName" @end="functionName" @begin="functionName"><map>``。 -->
* 为兼容各端,事件需使用 ``v-on````@`` 的方式绑定,请勿使用小程序端的``bind````catch`` 进行事件绑定。
* 事件修饰符
 * ``.stop``:各平台均支持, 使用时会阻止事件冒泡,在非 H5 端同时也会阻止事件的默认行为
 * ``.prevent`` 仅在 H5 平台支持
 * ``.self``:仅在 H5 平台支持
 * ``.once``:仅在 H5 平台支持
 * ``.capture``:仅在 H5 平台支持
 * ``.passive``:仅在 H5 平台支持 
* 若需要禁止蒙版下的页面滚动,可使用 ``@touchmove.stop.prevent="moveHandle"``,moveHandle 可以用来处理 touchmove 的事件,也可以是一个空函数。
  ```html
  <view class="mask" @touchmove.stop.prevent="moveHandle"></view>
  ```
* 按键修饰符:``uni-app``运行在手机端,没有键盘事件,所以不支持按键修饰符。


## 表单控件绑定

支持 [Vue官方文档:表单控件绑定](https://cn.vuejs.org/v2/guide/forms.html)

建议开发过程中直接使用  [uni-app:表单组件](component/button)。用法示例:

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)
    }
  }
}

</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>

```

## v-html指令

由于非H5端,不支持dom和普通html元素,所以自然非H5端也不支持v-html。

跨端的富文本处理方案详见:[https://ask.dcloud.net.cn/article/35772](https://ask.dcloud.net.cn/article/35772)

## 组件   

### Vue 组件

组件是 ``vue`` 技术中非常重要的部分,组件使得与ui相关的轮子可以方便的制造和共享,进而使得vue使用者的开发效率大幅提升。

uni-app搭建了组件的插件市场,可大幅提升开发者的效率。[https://ext.dcloud.net.cn/](https://ext.dcloud.net.cn/)

在项目的/component目录下存放组件,在要显示组件的页面中则分为3步:导入、注册和使用。

可以这个[评分组件](https://ext.dcloud.net.cn/plugin?id=33)的使用为例,了解vue组件的使用方式。

```html
<template>
	<view>
		<uni-rate value="2"></uni-rate> <!-- 第三步,使用组件。并传值点亮2颗星 -->
	</view>
</template>
<script>
import uniRate from "@/components/uni-rate/uni-rate.vue" //第一步,导入组件
export default {
    components: {
		uniRate //第二步,注册组件
	}
}
</script>
```
雪洛's avatar
雪洛 已提交
358 359 360

- `2.5.0+`版本支持在pages.json内引入组件,[详见](/collocation/pages?id=easycom)
- **uni-app只支持vue单文件组件(.vue 组件)**。其他的诸如:动态组件,自定义 ``render``,和``<script type="text/x-template">`` 字符串模版等,在非H5端不支持。
M
mehaotian 已提交
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394


详细的非H5端不支持列表:

* ``Slot````scoped`` 暂时还没做支持)
* 动态组件
* 异步组件
* ``inline-template``
* ``X-Templates``
* ``keep-alive``
* ``transition`` (可使用 [animation](/api/ui/animation) 或 CSS 动画替代)
* [老的非自定义组件编译模式](https://ask.dcloud.net.cn/article/35843)不支持在组件引用时,在组件上定义 ``click`` 等原生事件、``v-show``(可用 ``v-if`` 代替)和 ``class`` ``style`` 等样式属性(例:``<card class="class-name"> </card>`` 样式是不会生效的)。建议更新为自定义组件模式
* [老的非自定义组件编译模式](https://ask.dcloud.net.cn/article/35843)组件里使用 ``slot`` 嵌套的其他组件时不支持 ``v-for``。建议更新为自定义组件模式

[Vue官方文档参考:组件](https://cn.vuejs.org/v2/guide/components.html)

### uni-app内置基础组件

``uni-app`` 内置了小程序的所有[组件](component/),比如: ``picker``,``map`` 等,需要注意的是原生组件上的事件绑定,需要以 ``vue`` 的事件绑定语法来绑定,如 ``bindchange="eventName"`` 事件,需要写成 ``@change="eventName"`` 

**示例**

```html
<picker mode="date" :value="date" start="2015-09-01" end="2017-09-01" @change="bindDateChange">
    <view class="picker">
      当前选择: {{date}}
    </view>
</picker>
```

### 全局组件

```uni-app``` 支持配置全局组件,需在 ``main.js`` 里进行全局注册,注册后就可在所有页面里使用该组件。

395 396 397 398
**注意**

- ``Vue.component`` 的第一个参数必须是静态的字符串。
- nvue页面暂不支持全局组件
M
mehaotian 已提交
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587

**示例**

main.js 里进行全局导入和注册
```javascript
import Vue from 'vue'
import pageHead from './components/page-head.vue'
Vue.component('page-head',pageHead)
```
index.vue 里可直接使用组件
```html
<template>
  <view>
    <page-head></page-head>
	</view>
</template>
```

### 命名限制
在 `uni-app` 中以下这些作为保留关键字,不可作为组件名。

- `a`
- `canvas`
- `cell`
- `content`
- `countdown`
- `datepicker`
- `div`
- `element`
- `embed`
- `header`
- `image`
- `img`
- `indicator`
- `input`
- `link`
- `list`
- `loading-indicator`
- `loading`
- `marquee`
- `meta`
- `refresh`
- `richtext`
- `script`
- `scrollable`
- `scroller`
- `select`
- `slider-neighbor`
- `slider`
- `slot`
- `span`
- `spinner`
- `style`
- `svg`
- `switch`
- `tabbar`
- `tabheader`
- `template`
- `text`
- `textarea`
- `timepicker`
- `trisition-group`
- `trisition`
- `video`
- `view`
- `web`

**Tips**

- 除以上列表中的名称外,标准的 HTML 及 SVG 标签名也不能作为组件名。


## 常见问题

**1. 如何获取上个页面传递的数据**

在 ``onLoad`` 里得到,``onLoad`` 的参数是其他页面打开当前页面所传递的数据。

**2. 如何设置全局的数据和全局的方法**

``uni-app`` 内置了 [vuex](https://vuex.vuejs.org/zh/guide/) ,在app里的使用,可参考``hello-uniapp`` ``store/index.js``。

```javascript
//store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
    state: {...},
    mutations: {...},
    actions: {...}
})

export default store

//main.js
...
import store from './store'
Vue.prototype.$store = store
const app = new Vue({
    store,...
})
...

//test.vue 使用时:
import {mapState,mapMutations} from 'vuex'
```

**3. 如何捕获 app 的 onError**

由于 ``onError`` 并不是完整意义的生命周期,所以只提供一个捕获错误的方法,在 ``app`` 的根组件上添加名为 ``onError`` 的回调函数即可。如下:

```javascript
export default {
   // 只有 app 才会有 onLaunch 的生命周期
   onLaunch () {
       // ...
   },

   // 捕获 app error
   onError (err) {
       console.log(err)
   }
}
```

**4. 组件属性设置不生效解决办法**

当重复设置某些属性为相同的值时,不会同步到view层。
例如:每次将scroll-view组件的scroll-top属性值设置为0,只有第一次能顺利返回顶部。
这和props的单向数据流特性有关,组件内部scroll-top的实际值改动后,其绑定的属性并不会一同变化。

解决办法有两种(以scroll-view组件为例):

* 监听scroll事件,记录组件内部变化的值,在设置新值之前先设置为记录的当前值

```html
<scroll-view :scroll-top="scrollTop" scroll-y="true" @scroll="scroll">
```

```js
export 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-top="scrollTop" scroll-y="true" @scroll="scroll">
```

```js
export default {
	data() {
		return {
			scrollTop: 0,
		}
	},
	methods: {
		scroll: function(e) {
			this.scrollTop = e.detail.scrollTop
		},
		goTop: function(e) {
			this.scrollTop = 0
		}
	}
}
```

第二种解决方式在某些组件可能造成抖动,推荐第一种解决方式。