## 小程序自定义组件支持
``uni-app`` 支持在 App 和 小程序 中使用**小程序自定义组件**,从HBuilderX2.4.7起,H5端也可以运行微信小程序组件。
小程序组件不是vue组件,并且每家小程序都有自己的组件规范,比如微信小程序的组件是wxml格式。
**平台差异说明**
|平台|支持情况|小程序组件存放目录|
|---|---|---|
|H5|支持微信小程序组件(2.4.7+)|wxcomponents|
|App(不含nvue)|支持微信小程序组件|wxcomponents|
|微信小程序|支持微信小程序组件|wxcomponents|
|支付宝小程序|支持支付宝小程序组件|mycomponents|
|百度小程序|支持百度小程序组件|swancomponents|
|字节跳动小程序、飞书小程序|支持字节跳动小程序、飞书小程序组件|ttcomponents|
|QQ小程序|支持QQ小程序组件|wxcomponents|
|快手小程序|支持快手小程序组件|kscomponents|
此文档要求开发者对各端小程序的**自定义组件**有一定了解,没接触过小程序**自定义组件**的可以参考:
- [微信小程序自定义组件](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/)
- [百度小程序自定义组件](https://smartprogram.baidu.com/docs/develop/framework/custom-component/)
- [支付宝小程序自定义组件](https://docs.alipay.com/mini/framework/custom-component-overview)
- [字节跳动小程序自定义组件](https://developer.toutiao.com/docs/framework/custom_component_intro.html)
- [飞书小程序自定义组件](https://open.feishu.cn/document/uYjL24iN/ugTOugTOugTO)
- [QQ小程序自定义组件](https://q.qq.com/wiki/develop/miniprogram/frame/diy_components/)
- [快手小程序自定义组件](https://mp.kuaishou.com/docs/develop/frame/custom_comp/component_temp_style.html)
**目录结构**
┌─wxcomponents 微信小程序自定义组件存放目录
│ └──custom 微信小程序自定义组件
│ ├─index.js
│ ├─index.wxml
│ ├─index.json
│ └─index.wxss
├─mycomponents 支付宝小程序自定义组件存放目录
│ └──custom 支付宝小程序自定义组件
│ ├─index.js
│ ├─index.axml
│ ├─index.json
│ └─index.acss
├─swancomponents 百度小程序自定义组件存放目录
│ └──custom 百度小程序自定义组件
│ ├─index.js
│ ├─index.swan
│ ├─index.json
│ └─index.css
├─pages
│ └─index
│ └─index.vue
│
├─static
├─main.js
├─App.vue
├─manifest.json
└─pages.json
**使用方式**
在 ``pages.json`` 对应页面的 style -> usingComponents 引入组件:
```javascript
{
"pages": [{
"path": "index/index",
"style": {
// #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-QQ
"usingComponents": {
"custom": "/wxcomponents/custom/index"
},
// #endif
// #ifdef MP-BAIDU
"usingComponents": {
"custom": "/swancomponents/custom/index"
},
// #endif
// #ifdef MP-ALIPAY
"usingComponents": {
"custom": "/mycomponents/custom/index"
},
// #endif
"navigationBarTitleText": "uni-app"
}
}]
}
```
在页面中使用
```html
```
**代码示例**
下面以微信小程序官方自定义组件示例 [miniprogram-slide-view](https://github.com/wechat-miniprogram/slide-view) 为例演示小程序自定义组件的使用方式。
其他组件使用示例见GitHub:[wxcomponents-template](https://github.com/dcloudio/uni-app/tree/master/examples/wxcomponents-template)。
插件市场有一个完整的``vant weapp`` 引用好的示例工程,详见[https://ext.dcloud.net.cn/plugin?id=302](https://ext.dcloud.net.cn/plugin?id=302)。
目录结构
┌─components
├─wxcomponents
│ └──miniprogram-slide-view
│ ├─index.js
│ ├─index.wxml
│ ├─index.json
│ └─index.wxss
│
├─pages
│ └─slide-view
│ └─slide-view.vue
│
├─static
├─main.js
├─App.vue
├─manifest.json
└─pages.json
pages.json
```json
{
"pages": [
{
"path": "slide-view/slide-view",
"style": {
"navigationBarTitleText": "slide-view",
"usingComponents": {
"slide-view": "/wxcomponents/miniprogram-slide-view/index"
}
}
}
]
}
```
slide-view.vue
```html
文件传输助手
7:00 PM
标为已读
删除
```
**注意事项**
* 小程序组件需要放在项目特殊文件夹 ``wxcomponents``(或 mycomponents、swancomponents)。HBuilderX 建立的工程 ``wxcomponents`` 文件夹在 项目根目录下。vue-cli 建立的工程 ``wxcomponents`` 文件夹在 ``src`` 目录下。可以在 vue.config.js 中自定义其他目录
* 小程序组件的性能,不如vue组件。使用小程序组件,需要自己手动setData,很难自动管理差量数据更新。而使用vue组件会自动diff更新差量数据。所以如无明显必要,建议使用vue组件而不是小程序组件。比如某些小程序ui组件,完全可以用更高性能的uni ui替代。
* 当需要在 `vue` 组件中使用小程序组件时,注意在 `pages.json` 的 `globalStyle` 中配置 `usingComponents`,而不是页面级配置。
* 注意数据和事件绑定的差异,组件使用时应按照 `vue` 的数据和事件绑定方式
- 属性绑定从 `attr="{{ a }}"`,改为 `:attr="a"`;从 `title="复选框{{ item }}"` 改为 `:title="'复选框' + item"`
- 事件绑定从 `bind:click="toggleActionSheet1"` 改为 `@click="toggleActionSheet1"`,目前支付宝小程序不支持 `vue` 的事件绑定方式,具体参考:[支付宝小程序组件事件监听示例](https://github.com/dcloudio/uni-app/issues/917#issuecomment-653329693)
- 阻止事件冒泡 从 `catch:tap="xx"` 改为 `@tap.native.stop="xx"`
- `wx:if` 改为 `v-if`
- `wx:for="{{ list }}" wx:key="{{ index }}"` 改为`v-for="(item,index) in list"`
详细的小程序转uni-app语法差异可参考文档[https://ask.dcloud.net.cn/article/35786](https://ask.dcloud.net.cn/article/35786)。
## WXS
WXS是一套运行在视图层的脚本语言,[微信端的规范详见](https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxs/)。
它的特点是运行在视图层。当需要避免逻辑层和渲染层交互通信折损时,可采用wxs。
uni-app可以将wxs代码编译到微信小程序、QQ小程序、app-vue、H5上(`uni-app 2.2.5`及以上版本)
与wxs类似,百度小程序提供了Filter、阿里小程序提供了SJS,uni-app也支持使用这些功能,并将它们编译到百度和阿里的小程序端。不过它们的功能还不如wxs强大。此外头条系小程序自身不支持类似功能。
**平台差异说明**
|App|H5|微信小程序|支付宝小程序|百度小程序|字节跳动小程序、飞书小程序|QQ小程序|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|√(不支持nvue)|√|√|SJS|Filter|x|√|
App端nvue解决此类需求,不应该使用wxs,而是使用bindingx。
**wxs示例**
以下是一些使用 WXS 的简单示例,要完整了解 WXS 语法,请参考[WXS 语法参考](https://developers.weixin.qq.com/miniprogram/dev/reference/wxs/)。本示例使用wxs响应`touchmove`事件,减少视图层与逻辑层通信,使滑动更加丝滑。
```html
{{test.msg}}
```
支付宝小程序,百度小程序官方暂未支持事件响应,不过也可以使用对应的SJS、Filter过滤器实现一些数据处理的操作,以下代码展示了一个时间格式化的小功能
`index.vue`
```html
{{timestr}} 是
{{utils.friendlyDate(timestamp)}}
```
`utils.sjs` 与 `utils.filter.js` 内容一致
```js
export default {
friendlyDate: (timestamp) => {
var formats = {
'year': '%n% 年前',
'month': '%n% 月前',
'day': '%n% 天前',
'hour': '%n% 小时前',
'minute': '%n% 分钟前',
'second': '%n% 秒前',
};
var now = Date.now();
var seconds = Math.floor((now - parseInt(timestamp)) / 1000);
var minutes = Math.floor(seconds / 60);
var hours = Math.floor(minutes / 60);
var days = Math.floor(hours / 24);
var months = Math.floor(days / 30);
var years = Math.floor(months / 12);
var diffType = '';
var diffValue = 0;
if (years > 0) {
diffType = 'year';
diffValue = years;
} else {
if (months > 0) {
diffType = 'month';
diffValue = months;
} else {
if (days > 0) {
diffType = 'day';
diffValue = days;
} else {
if (hours > 0) {
diffType = 'hour';
diffValue = hours;
} else {
if (minutes > 0) {
diffType = 'minute';
diffValue = minutes;
} else {
diffType = 'second';
diffValue = seconds === 0 ? (seconds = 1) : seconds;
}
}
}
}
}
return formats[diffType].replace('%n%', diffValue);
}
}
```
**注意**
引入方式
```html
```
- **【重要】** 编写wxs、sjs、filter.js 内容时必须遵循相应语法规范
- **【重要】** `module`所指定的模块名不可与`data`、`methods`、`computed`内的属性重名
- 目前各个小程序正在完善相关规范,可能会有较大改动,请务必仔细阅读相应平台的文档
- 支付宝小程序请使用sjs规范,[详见](https://docs.alipay.com/mini/framework/sjs)
- 支付宝小程序sjs只能定义在.sjs 文件中,然后使用```