chubiao 1 éve
szülő
commit
87c915ba93
26 módosított fájl, 3328 hozzáadás és 31 törlés
  1. 14 4
      api/dict.js
  2. 18 0
      api/order.js
  3. 1 1
      common/request.js
  4. 2 1
      pages.json
  5. 234 1
      pages/order/add.vue
  6. 184 24
      pages/order/index.vue
  7. 23 0
      uni_modules/uni-fab/changelog.md
  8. 491 0
      uni_modules/uni-fab/components/uni-fab/uni-fab.vue
  9. 84 0
      uni_modules/uni-fab/package.json
  10. 9 0
      uni_modules/uni-fab/readme.md
  11. 9 0
      uni_modules/uni-segmented-control/changelog.md
  12. 145 0
      uni_modules/uni-segmented-control/components/uni-segmented-control/uni-segmented-control.vue
  13. 87 0
      uni_modules/uni-segmented-control/package.json
  14. 13 0
      uni_modules/uni-segmented-control/readme.md
  15. 47 0
      uni_modules/uni-swipe-action/changelog.md
  16. 302 0
      uni_modules/uni-swipe-action/components/uni-swipe-action-item/bindingx.js
  17. 12 0
      uni_modules/uni-swipe-action/components/uni-swipe-action-item/isPC.js
  18. 195 0
      uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpalipay.js
  19. 260 0
      uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpother.js
  20. 84 0
      uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpwxs.js
  21. 270 0
      uni_modules/uni-swipe-action/components/uni-swipe-action-item/render.js
  22. 348 0
      uni_modules/uni-swipe-action/components/uni-swipe-action-item/uni-swipe-action-item.vue
  23. 341 0
      uni_modules/uni-swipe-action/components/uni-swipe-action-item/wx.wxs
  24. 60 0
      uni_modules/uni-swipe-action/components/uni-swipe-action/uni-swipe-action.vue
  25. 84 0
      uni_modules/uni-swipe-action/package.json
  26. 11 0
      uni_modules/uni-swipe-action/readme.md

+ 14 - 4
api/dict.js

@@ -2,8 +2,18 @@ import request from '@/common/request.js'
 
 // 根据字典类型查询字典数据信息
 export const getDicts = (dictType) => {
-  return request({
-    url: '/system/dict/data/type/' + dictType,
-    method: 'get',
-  })
+	return request({
+		url: '/system/dict/data/type/' + dictType,
+		method: 'get',
+	})
+}
+
+
+// 业务字典查询
+export const ObjdictList = (query) => {
+	return request({
+		url: '/system/dict/type/objdict',
+		method: 'get',
+		data: query
+	})
 }

+ 18 - 0
api/order.js

@@ -8,4 +8,22 @@ export function List(data) {
 		method: 'get',
 		data: data
 	})
+}
+
+// 新增订单
+export function Save(data) {
+	return request({
+		url: '/system/ddjy',
+		method: 'post',
+		data: data
+	})
+}
+
+// 修改养老机构为老产品服务订单交易信息
+export function UpdateDdjy(data) {
+  return request({
+    url: '/system/ddjy',
+    method: 'put',
+    data: data
+  })
 }

+ 1 - 1
common/request.js

@@ -70,7 +70,7 @@ const request = config => {
 
 
 	if (isRequest) {
-		console.log("请求", config)
+		console.log("请求",BASE_URL + config.url, config)
 		return new Promise((resolve, reject) => {
 			uni.request({
 				header: config.header,

+ 2 - 1
pages.json

@@ -44,7 +44,8 @@
 		{
 			"path": "pages/order/index",
 			"style": {
-				"navigationBarTitleText": "新增订单"
+				"navigationBarTitleText": "订单",
+				"enablePullDownRefresh": true
 			}
 		},
 		{

+ 234 - 1
pages/order/add.vue

@@ -1,8 +1,241 @@
 <template>
+
+	<view>
+		<uni-section padding>
+			<uni-forms ref="baseForm" :modelValue="baseFormData" :rules="rules">
+				<uni-forms-item label="产品" required name="cpId">
+					<uni-data-select v-model="baseFormData.cpId" placeholder="请选择产品" :localdata="cpData"
+						@change="xzcp" />
+				</uni-forms-item>
+				<uni-forms-item label="产品编码">
+					<uni-easyinput v-model="baseFormData.cpbm" placeholder="请输入产品编码" disabled />
+				</uni-forms-item>
+				<uni-forms-item label="产品名称">
+					<uni-easyinput v-model="baseFormData.cpName" placeholder="请输入产品名称" disabled />
+				</uni-forms-item>
+				<uni-forms-item label="单价">
+					<uni-easyinput v-model="baseFormData.dj" placeholder="请输入单价" disabled />
+				</uni-forms-item>
+				<uni-forms-item label="客户" required name="lrId">
+					<uni-data-select v-model="baseFormData.lrId" placeholder="请选择客户" :localdata="khData"
+						@change="xzkh" />
+				</uni-forms-item>
+				<uni-forms-item label="收货人">
+					<uni-easyinput v-model="baseFormData.shxm" placeholder="请输入收货人" disabled />
+				</uni-forms-item>
+				<uni-forms-item label="收货电话">
+					<uni-easyinput v-model="baseFormData.shdh" placeholder="请输入收货电话" disabled />
+				</uni-forms-item>
+				<uni-forms-item label="收货地址" required name="shdz">
+					<uni-easyinput v-model="baseFormData.shdz" placeholder="请输入收货地址" />
+				</uni-forms-item>
+				<uni-forms-item label="下单数量">
+					<uni-easyinput v-model="baseFormData.xdsl" type="number" placeholder="请输入下单数量" @blur="sl" />
+				</uni-forms-item>
+				<uni-forms-item label="金额">
+					<uni-easyinput v-model="baseFormData.je" placeholder="请输入金额" />
+				</uni-forms-item>
+				<uni-forms-item label="买家留言">
+					<uni-easyinput v-model="baseFormData.xdbz" placeholder="请输入买家留言" />
+				</uni-forms-item>
+				<uni-forms-item label="支付凭据">
+					<uni-easyinput v-model="baseFormData.zfpj" placeholder="请输入支付凭据" />
+				</uni-forms-item>
+				<uni-forms-item label="运单号">
+					<uni-easyinput v-model="baseFormData.ydh" placeholder="请输入运单号" />
+				</uni-forms-item>
+				<uni-forms-item label="取货码">
+					<uni-easyinput v-model="baseFormData.qhm" placeholder="请输入取货码" />
+				</uni-forms-item>
+				<uni-forms-item label="发货时间">
+					<uni-datetime-picker type="datetime" v-model="baseFormData.fhsjs" placeholder="请选择发货时间" />
+				</uni-forms-item>
+				<uni-forms-item label="到货时间">
+					<uni-datetime-picker type="datetime" v-model="baseFormData.dhsjs" placeholder="请选择到货时间" />
+				</uni-forms-item>
+
+				<view class="bottomButton">
+					<button type="primary" @click="submit()" v-show="baseFormData.ddzt == null ||baseFormData.ddzt == 0">保存</button>
+				</view>
+			</uni-forms>
+		</uni-section>
+	</view>
+
 </template>
 
 <script>
+	import {
+		ObjdictList
+	} from '@/api/dict.js'
+	import {
+		Save
+	} from '@/api/order.js'
+	import {
+		showConfirm
+	} from '@/common/common.js'
+	export default {
+		data() {
+			return {
+				baseFormData: {},
+				rules: {
+					cpId: {
+						rules: [{
+							required: true,
+							errorMessage: '产品不能为空'
+						}]
+					},
+					lrId: {
+						rules: [{
+							required: true,
+							errorMessage: '客户不能为空'
+						}]
+					},
+					shdz: {
+						rules: [{
+							required: true,
+							errorMessage: '收货地址不能为空'
+						}]
+					},
+
+				},
+				cpData: [],
+				khData: [],
+			}
+		},
+		onLoad(options) {
+			if (Object.keys(options).length !== 0) {
+				this.baseFormData = JSON.parse(options.item)
+				this.baseFormData.fhsjs = new Date(this.baseFormData.fhsj)
+				this.baseFormData.dhsjs = new Date(this.baseFormData.dhsj)
+			}
+		},
+		mounted() {
+			this.getCpList()
+			this.getKhList()
+		},
+		methods: {
+			sl(e) {
+				let sl = e.detail.value
+				if (!sl || sl < 1) {
+					showConfirm("请输入正确下单数量")
+				} else {
+					if (this.baseFormData.dj) {
+						this.baseFormData.je = this.baseFormData.dj * sl
+					}
+				}
+			},
+			xzkh(e) {
+				let kh = this.khData.filter(obj => obj.value == e)
+				this.baseFormData.shxm = kh[0].obj[1]
+				this.baseFormData.shdh = kh[0].obj[2]
+				this.baseFormData.shdz = kh[0].obj[3]
+			},
+			xzcp(e) {
+				let kh = this.cpData.filter(obj => obj.value == e)
+
+				this.baseFormData.cpbm = kh[0].obj[2]
+				this.baseFormData.cpName = kh[0].obj[1]
+				this.baseFormData.dj = kh[0].obj[3]
+
+				this.baseFormData.xdsl = 1
+				this.baseFormData.je = this.baseFormData.dj
+			},
+			getCpList() {
+				ObjdictList({
+					dictType: 'cpxz',
+					outType: 0,
+					para1: uni.getStorageSync('userInfo').jgId
+				}).then(res => {
+					if (res.data.data) {
+						Object.keys(res.data.data).map(e => {
+							let obj = res.data.data[e]
+							this.cpData.push({
+								value: obj[0],
+								text: obj[1],
+								obj: {
+									...obj
+								}
+							})
+						})
+
+					}
+
+				})
+			},
+			getKhList() {
+				ObjdictList({
+					dictType: 'kh',
+					outType: 0,
+					para1: uni.getStorageSync('userInfo').jgId
+				}).then(res => {
+					if (res.data.data) {
+						Object.keys(res.data.data).map(e => {
+							let obj = res.data.data[e]
+							this.khData.push({
+								value: obj[0],
+								text: obj[1],
+								obj: {
+									...obj
+								}
+							})
+						})
+
+					}
+
+				})
+			},
+			submit() {
+				if (this.baseFormData.fhsjs) {
+					this.baseFormData.fhsj = this.baseFormData.fhsjs.replaceAll('-', '').replace(' ', '').replaceAll(':', '')
+				}
+				if (this.baseFormData.dhsjs) {
+					this.baseFormData.dhsj = this.baseFormData.dhsjs.replaceAll('-', '').replace(' ', '').replaceAll(':', '')
+				}
+				this.$refs['baseForm'].validate().then(res => {
+
+					Save(this.baseFormData).then(r => {
+						if (r.code == 200) {
+							uni.showToast({
+							  title: `保存成功!`,
+							  duration: 2000,
+							  success: function(res) {
+							
+							    setTimeout(function() {
+							      uni.switchTab({
+							        url: '/pages/order/index'
+							      });
+							    }, 2000)
+							
+							
+							  }
+							})
+						}
+					})
+				}).catch(err => {
+					console.log("err", err)
+					uni.showModal({
+						title: '错误提示',
+						content: err[0].errorMessage,
+						showCancel: false,
+						success: function(res) {
+							if (res.confirm) {
+								console.log('用户点击确定');
+							} else if (res.cancel) {
+								console.log('用户点击取消');
+							}
+						}
+					});
+
+				})
+			}
+		}
+	}
 </script>
 
-<style>
+<style scoped>
+	.bottomButton {
+		height: 140rpx;
+		width: 80%;
+		margin-left: 10%;
+	}
 </style>

+ 184 - 24
pages/order/index.vue

@@ -1,36 +1,135 @@
 <template>
 	<view>
-		<view style="width: 90%;margin-left: 5%;">
-			<uni-easyinput type="text" trim="all" prefixIcon="search" v-model="form.xm" placeholder="请输入产品名称搜索"
-				confirmType="search" @blur="getList(true)"></uni-easyinput>
-		</view>
-		<view style="margin-top: 10rpx;">
-			<uni-list :border="true">
-				<uni-list-item :title="item.cpName" :note="item.shxm" v-for="(item,index) in dataList" :key="index"
-					link="navigateTo" :to="`/pages/order/add?item=`+JSON.stringify(item)">
+		<uni-segmented-control :current="current" :values="items" @clickItem="onClickItem" styleType="text"
+			activeColor="#ffaa00"></uni-segmented-control>
+		<view class="content">
+			<view style="margin-top: 10rpx;">
+				<uni-list :border="true">
+
+					<uni-swipe-action>
+						<uni-swipe-action-item v-show="current == 0 && item.ddzt == 3" :right-options="options"
+							:show="isOpened" :auto-close="false" @click="bindClick(item)"
+							v-for="(item,index) in dataList" :key="index">
+							<uni-list-item :title="item.cpName" :note="item.shxm" link="navigateTo" :thumb="item.tx"
+								thumb-size="lg" :to="`/pages/order/add?item=`+JSON.stringify(item)">
+
+								<template v-slot:footer>
+									<view>
+										<view>
+											{{item.ddztStr}}
+										</view>
+										<view>
+											{{item.je}}元
+										</view>
+									</view>
+								</template>
+							</uni-list-item>
+						</uni-swipe-action-item>
+					</uni-swipe-action>
+					<uni-list-item v-show="current == 0 && item.ddzt != 3" :title="item.cpName" :note="item.shxm"
+						:thumb="item.tx" thumb-size="lg" v-for="(item,index) in dataList" :key="index" link="navigateTo"
+						:to="`/pages/order/add?item=`+JSON.stringify(item)">
+
+						<template v-slot:footer>
+							<view>
+								<view>
+									{{item.ddztStr}}
+								</view>
+								<view>
+									{{item.je}}元
+								</view>
+							</view>
+						</template>
+					</uni-list-item>
+
+					<uni-list-item v-show="current == 1" :title="item.cpName" :note="item.shxm"
+						v-for="(item,index) in dataList1" :key="index" link="navigateTo" :thumb="item.tx"
+						thumb-size="lg" :to="`/pages/order/add?item=`+JSON.stringify(item)">
+
+						<template v-slot:footer>
+							<view>
+								<view>
+									{{item.ddztStr}}
+								</view>
+								<view>
+									{{item.je}}元
+								</view>
+							</view>
+						</template>
+					</uni-list-item>
 
-					<template v-slot:footer>
-						<view>
+					<uni-list-item v-show="current == 2" :title="item.cpName" :note="item.shxm"
+						v-for="(item,index) in dataList2" :key="index" link="navigateTo" :thumb="item.tx"
+						thumb-size="lg" :to="`/pages/order/add?item=`+JSON.stringify(item)">
+
+						<template v-slot:footer>
 							<view>
-								{{item.ddztStr}}
+								<view>
+									{{item.ddztStr}}
+								</view>
+								<view>
+									{{item.je}}元
+								</view>
 							</view>
+						</template>
+					</uni-list-item>
+
+
+
+					<uni-swipe-action>
+						<uni-swipe-action-item v-show="current == 3" :right-options="options" :show="isOpened"
+							:auto-close="false" @click="bindClick(item)" v-for="(item,index) in dataList3" :key="index">
+							<uni-list-item :title="item.cpName" :note="item.shxm" link="navigateTo" :thumb="item.tx"
+								thumb-size="lg" :to="`/pages/order/add?item=`+JSON.stringify(item)">
+
+								<template v-slot:footer>
+									<view>
+										<view>
+											{{item.ddztStr}}
+										</view>
+										<view>
+											{{item.je}}元
+										</view>
+									</view>
+								</template>
+							</uni-list-item>
+						</uni-swipe-action-item>
+					</uni-swipe-action>
+
+
+					<uni-list-item v-show="current == 4" :title="item.cpName" :note="item.shxm"
+						v-for="(item,index) in dataList4" :key="index" link="navigateTo" :thumb="item.tx"
+						thumb-size="lg" :to="`/pages/order/add?item=`+JSON.stringify(item)">
+
+						<template v-slot:footer>
 							<view>
-								{{item.je}}元
+								<view>
+									{{item.ddztStr}}
+								</view>
+								<view>
+									{{item.je}}元
+								</view>
 							</view>
-						</view>
-					</template>
-				</uni-list-item>
-			</uni-list>
+						</template>
+					</uni-list-item>
+				</uni-list>
+			</view>
+			<view>
+				<uni-load-more :status="status" :content-text="contentText" @clickLoadMore="clickLoadMore" />
+			</view>
+
 		</view>
 		<view>
-			<uni-load-more :status="status" :content-text="contentText" @clickLoadMore="clickLoadMore" />
+			<uni-fab :pattern="pattern" :horizontal="horizontal" :vertical="vertical" @fabClick="fabClick"></uni-fab>
 		</view>
 	</view>
+
 </template>
 
 <script>
 	import {
-		List
+		List,
+		UpdateDdjy
 	} from '@/api/order.js'
 	import config from '@/config.js'
 	import {
@@ -39,6 +138,21 @@
 	export default {
 		data() {
 			return {
+				isOpened: 'none',
+				options: [{
+					text: '完成',
+					style: {
+						backgroundColor: '#F56C6C'
+					}
+				}],
+				items: ['全部', '待接单', '待派单', '进行中', '完成'],
+				current: 0,
+				horizontal: 'right',
+				vertical: 'bottom',
+				pattern: {
+					buttonColor: '#ffaa00',
+					iconColor: '#fff'
+				},
 				status: 'more',
 				contentText: {
 					contentdown: '查看更多',
@@ -51,6 +165,10 @@
 				},
 				total: 0,
 				dataList: [],
+				dataList1: [],
+				dataList2: [],
+				dataList3: [],
+				dataList4: [],
 				ddztData: [{
 					value: '1',
 					text: '待接单',
@@ -73,11 +191,12 @@
 			}
 		},
 		onLoad() {
-
 		},
-		mounted() {
+		onShow() {
 			this.getList()
 		},
+		mounted() {
+		},
 		onReachBottom() {
 
 		},
@@ -85,15 +204,56 @@
 			this.getList(true)
 		},
 		methods: {
+			bindClick(e) {
+				this.isOpened = 'none'
+				UpdateDdjy({
+					id: e.id,
+					ddzt: 4
+				}).then(res => {
+					if (res.code == 200) {
+						let that = this
+						uni.showToast({
+							title: `保存成功!`,
+							duration: 2000,
+							success: function(res) {
+
+								that.getList(true)
 
+							}
+						})
+					}
+				})
+			},
+			onClickItem(e) {
+				if (this.current != e.currentIndex) {
+					this.current = e.currentIndex;
+				}
+			},
+			fabClick() {
+				uni.navigateTo({
+					url: '/pages/order/add'
+				})
+			},
 			getList(isClear) {
 				isClear ? this.dataList = [] : ''
+				isClear ? this.dataList2 = [] : ''
+				isClear ? this.dataList3 = [] : ''
+				isClear ? this.dataList4 = [] : ''
+				isClear ? this.dataList1 = [] : ''
 				List(this.form).then(res => {
-				
-				
 					let list = res.rows
-					list.forEach(e=>{
-						e.ddztStr = this.ddztData[parseInt(e.ddzt)-1]
+					list.forEach(e => {
+						e.tx = e.tx ? config.baseUrl + e.tx : config.baseUrl + config.head;
+						e.ddztStr = this.ddztData[parseInt(e.ddzt) - 1].text
+						if (e.ddzt == 1) {
+							this.dataList1.push(e)
+						} else if (e.ddzt == 2) {
+							this.dataList2.push(e)
+						} else if (e.ddzt == 3) {
+							this.dataList3.push(e)
+						} else if (e.ddzt == 4) {
+							this.dataList4.push(e)
+						}
 					})
 					this.dataList.push(...list)
 					this.total = res.total

+ 23 - 0
uni_modules/uni-fab/changelog.md

@@ -0,0 +1,23 @@
+## 1.2.5(2023-03-29)
+- 新增 pattern.icon 属性,可自定义图标
+## 1.2.4(2022-09-07)
+小程序端由于 style 使用了对象导致报错,[详情](https://ask.dcloud.net.cn/question/152790?item_id=211778&rf=false)
+## 1.2.3(2022-09-05)
+- 修复 nvue 环境下,具有 tabBar 时,fab 组件下部位置无法正常获取 --window-bottom 的bug,详见:[https://ask.dcloud.net.cn/question/110638?notification_id=826310](https://ask.dcloud.net.cn/question/110638?notification_id=826310)
+## 1.2.2(2021-12-29)
+- 更新 组件依赖
+## 1.2.1(2021-11-19)
+- 修复 阴影颜色不正确的bug
+## 1.2.0(2021-11-19)
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-fab](https://uniapp.dcloud.io/component/uniui/uni-fab)
+## 1.1.1(2021-11-09) 
+- 新增 提供组件设计资源,组件样式调整
+## 1.1.0(2021-07-30)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 1.0.7(2021-05-12)
+- 新增 组件示例地址
+## 1.0.6(2021-02-05)
+- 调整为uni_modules目录规范
+- 优化 按钮背景色调整
+- 优化 兼容pc端

+ 491 - 0
uni_modules/uni-fab/components/uni-fab/uni-fab.vue

@@ -0,0 +1,491 @@
+<template>
+	<view class="uni-cursor-point">
+		<view v-if="popMenu && (leftBottom||rightBottom||leftTop||rightTop) && content.length > 0" :class="{
+        'uni-fab--leftBottom': leftBottom,
+        'uni-fab--rightBottom': rightBottom,
+        'uni-fab--leftTop': leftTop,
+        'uni-fab--rightTop': rightTop
+      }" class="uni-fab"
+				:style="nvueBottom"
+			>
+			<view :class="{
+          'uni-fab__content--left': horizontal === 'left',
+          'uni-fab__content--right': horizontal === 'right',
+          'uni-fab__content--flexDirection': direction === 'vertical',
+          'uni-fab__content--flexDirectionStart': flexDirectionStart,
+          'uni-fab__content--flexDirectionEnd': flexDirectionEnd,
+		  'uni-fab__content--other-platform': !isAndroidNvue
+        }" :style="{ width: boxWidth, height: boxHeight, backgroundColor: styles.backgroundColor }"
+				class="uni-fab__content" elevation="5">
+				<view v-if="flexDirectionStart || horizontalLeft" class="uni-fab__item uni-fab__item--first" />
+				<view v-for="(item, index) in content" :key="index" :class="{ 'uni-fab__item--active': isShow }"
+					class="uni-fab__item" @click="_onItemClick(index, item)">
+					<image :src="item.active ? item.selectedIconPath : item.iconPath" class="uni-fab__item-image"
+						mode="aspectFit" />
+					<text class="uni-fab__item-text"
+						:style="{ color: item.active ? styles.selectedColor : styles.color }">{{ item.text }}</text>
+				</view>
+				<view v-if="flexDirectionEnd || horizontalRight" class="uni-fab__item uni-fab__item--first" />
+			</view>
+		</view>
+		<view :class="{
+		  'uni-fab__circle--leftBottom': leftBottom,
+		  'uni-fab__circle--rightBottom': rightBottom,
+		  'uni-fab__circle--leftTop': leftTop,
+		  'uni-fab__circle--rightTop': rightTop,
+		  'uni-fab__content--other-platform': !isAndroidNvue
+		}" class="uni-fab__circle uni-fab__plus" :style="{ 'background-color': styles.buttonColor, 'bottom': nvueBottom }" @click="_onClick">
+			<uni-icons class="fab-circle-icon" :type="styles.icon" :color="styles.iconColor" size="32"
+				:class="{'uni-fab__plus--active': isShow && content.length > 0}"></uni-icons>
+			<!-- <view class="fab-circle-v"  :class="{'uni-fab__plus--active': isShow && content.length > 0}"></view>
+			<view class="fab-circle-h" :class="{'uni-fab__plus--active': isShow  && content.length > 0}"></view> -->
+		</view>
+	</view>
+</template>
+
+<script>
+	let platform = 'other'
+	// #ifdef APP-NVUE
+	platform = uni.getSystemInfoSync().platform
+	// #endif
+
+	/**
+	 * Fab 悬浮按钮
+	 * @description 点击可展开一个图形按钮菜单
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=144
+	 * @property {Object} pattern 可选样式配置项
+	 * @property {Object} horizontal = [left | right] 水平对齐方式
+	 * 	@value left 左对齐
+	 * 	@value right 右对齐
+	 * @property {Object} vertical = [bottom | top] 垂直对齐方式
+	 * 	@value bottom 下对齐
+	 * 	@value top 上对齐
+	 * @property {Object} direction = [horizontal | vertical] 展开菜单显示方式
+	 * 	@value horizontal 水平显示
+	 * 	@value vertical 垂直显示
+	 * @property {Array} content 展开菜单内容配置项
+	 * @property {Boolean} popMenu 是否使用弹出菜单
+	 * @event {Function} trigger 展开菜单点击事件,返回点击信息
+	 * @event {Function} fabClick 悬浮按钮点击事件
+	 */
+	export default {
+		name: 'UniFab',
+		emits: ['fabClick', 'trigger'],
+		props: {
+			pattern: {
+				type: Object,
+				default () {
+					return {}
+				}
+			},
+			horizontal: {
+				type: String,
+				default: 'left'
+			},
+			vertical: {
+				type: String,
+				default: 'bottom'
+			},
+			direction: {
+				type: String,
+				default: 'horizontal'
+			},
+			content: {
+				type: Array,
+				default () {
+					return []
+				}
+			},
+			show: {
+				type: Boolean,
+				default: false
+			},
+			popMenu: {
+				type: Boolean,
+				default: true
+			}
+		},
+		data() {
+			return {
+				fabShow: false,
+				isShow: false,
+				isAndroidNvue: platform === 'android',
+				styles: {
+					color: '#3c3e49',
+					selectedColor: '#007AFF',
+					backgroundColor: '#fff',
+					buttonColor: '#007AFF',
+					iconColor: '#fff',
+					icon: 'plusempty'
+				}
+			}
+		},
+		computed: {
+			contentWidth(e) {
+				return (this.content.length + 1) * 55 + 15 + 'px'
+			},
+			contentWidthMin() {
+				return '55px'
+			},
+			// 动态计算宽度
+			boxWidth() {
+				return this.getPosition(3, 'horizontal')
+			},
+			// 动态计算高度
+			boxHeight() {
+				return this.getPosition(3, 'vertical')
+			},
+			// 计算左下位置
+			leftBottom() {
+				return this.getPosition(0, 'left', 'bottom')
+			},
+			// 计算右下位置
+			rightBottom() {
+				return this.getPosition(0, 'right', 'bottom')
+			},
+			// 计算左上位置
+			leftTop() {
+				return this.getPosition(0, 'left', 'top')
+			},
+			rightTop() {
+				return this.getPosition(0, 'right', 'top')
+			},
+			flexDirectionStart() {
+				return this.getPosition(1, 'vertical', 'top')
+			},
+			flexDirectionEnd() {
+				return this.getPosition(1, 'vertical', 'bottom')
+			},
+			horizontalLeft() {
+				return this.getPosition(2, 'horizontal', 'left')
+			},
+			horizontalRight() {
+				return this.getPosition(2, 'horizontal', 'right')
+			},
+			// 计算 nvue bottom
+			nvueBottom() {
+				const safeBottom = uni.getSystemInfoSync().windowBottom;
+				// #ifdef APP-NVUE
+				return 30 + safeBottom
+				// #endif
+				// #ifndef APP-NVUE
+				return 30
+				// #endif
+			}
+		},
+		watch: {
+			pattern: {
+				handler(val, oldVal) {
+					this.styles = Object.assign({}, this.styles, val)
+				},
+				deep: true
+			}
+		},
+		created() {
+			this.isShow = this.show
+			if (this.top === 0) {
+				this.fabShow = true
+			}
+			// 初始化样式
+			this.styles = Object.assign({}, this.styles, this.pattern)
+		},
+		methods: {
+			_onClick() {
+				this.$emit('fabClick')
+				if (!this.popMenu) {
+					return
+				}
+				this.isShow = !this.isShow
+			},
+			open() {
+				this.isShow = true
+			},
+			close() {
+				this.isShow = false
+			},
+			/**
+			 * 按钮点击事件
+			 */
+			_onItemClick(index, item) {
+				if (!this.isShow) {
+					return
+				}
+				this.$emit('trigger', {
+					index,
+					item
+				})
+			},
+			/**
+			 * 获取 位置信息
+			 */
+			getPosition(types, paramA, paramB) {
+				if (types === 0) {
+					return this.horizontal === paramA && this.vertical === paramB
+				} else if (types === 1) {
+					return this.direction === paramA && this.vertical === paramB
+				} else if (types === 2) {
+					return this.direction === paramA && this.horizontal === paramB
+				} else {
+					return this.isShow && this.direction === paramA ? this.contentWidth : this.contentWidthMin
+				}
+			}
+		}
+	}
+</script>
+
+<style lang="scss" >
+	$uni-shadow-base:0 1px 5px 2px rgba($color: #000000, $alpha: 0.3) !default;
+
+	.uni-fab {
+		position: fixed;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		justify-content: center;
+		align-items: center;
+		z-index: 10;
+		border-radius: 45px;
+		box-shadow: $uni-shadow-base;
+	}
+
+	.uni-cursor-point {
+		/* #ifdef H5 */
+		cursor: pointer;
+		/* #endif */
+	}
+
+	.uni-fab--active {
+		opacity: 1;
+	}
+
+	.uni-fab--leftBottom {
+		left: 15px;
+		bottom: 30px;
+		/* #ifdef H5 */
+		left: calc(15px + var(--window-left));
+		bottom: calc(30px + var(--window-bottom));
+		/* #endif */
+		// padding: 10px;
+	}
+
+	.uni-fab--leftTop {
+		left: 15px;
+		top: 30px;
+		/* #ifdef H5 */
+		left: calc(15px + var(--window-left));
+		top: calc(30px + var(--window-top));
+		/* #endif */
+		// padding: 10px;
+	}
+
+	.uni-fab--rightBottom {
+		right: 15px;
+		bottom: 30px;
+		/* #ifdef H5 */
+		right: calc(15px + var(--window-right));
+		bottom: calc(30px + var(--window-bottom));
+		/* #endif */
+		// padding: 10px;
+	}
+
+	.uni-fab--rightTop {
+		right: 15px;
+		top: 30px;
+		/* #ifdef H5 */
+		right: calc(15px + var(--window-right));
+		top: calc(30px + var(--window-top));
+		/* #endif */
+		// padding: 10px;
+	}
+
+	.uni-fab__circle {
+		position: fixed;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		justify-content: center;
+		align-items: center;
+		width: 55px;
+		height: 55px;
+		background-color: #3c3e49;
+		border-radius: 45px;
+		z-index: 11;
+		// box-shadow: $uni-shadow-base;
+	}
+
+	.uni-fab__circle--leftBottom {
+		left: 15px;
+		bottom: 30px;
+		/* #ifdef H5 */
+		left: calc(15px + var(--window-left));
+		bottom: calc(30px + var(--window-bottom));
+		/* #endif */
+	}
+
+	.uni-fab__circle--leftTop {
+		left: 15px;
+		top: 30px;
+		/* #ifdef H5 */
+		left: calc(15px + var(--window-left));
+		top: calc(30px + var(--window-top));
+		/* #endif */
+	}
+
+	.uni-fab__circle--rightBottom {
+		right: 15px;
+		bottom: 30px;
+		/* #ifdef H5 */
+		right: calc(15px + var(--window-right));
+		bottom: calc(30px + var(--window-bottom));
+		/* #endif */
+	}
+
+	.uni-fab__circle--rightTop {
+		right: 15px;
+		top: 30px;
+		/* #ifdef H5 */
+		right: calc(15px + var(--window-right));
+		top: calc(30px + var(--window-top));
+		/* #endif */
+	}
+
+	.uni-fab__circle--left {
+		left: 0;
+	}
+
+	.uni-fab__circle--right {
+		right: 0;
+	}
+
+	.uni-fab__circle--top {
+		top: 0;
+	}
+
+	.uni-fab__circle--bottom {
+		bottom: 0;
+	}
+
+	.uni-fab__plus {
+		font-weight: bold;
+	}
+
+	// .fab-circle-v {
+	// 	position: absolute;
+	// 	width: 2px;
+	// 	height: 24px;
+	// 	left: 0;
+	// 	top: 0;
+	// 	right: 0;
+	// 	bottom: 0;
+	// 	/* #ifndef APP-NVUE */
+	// 	margin: auto;
+	// 	/* #endif */
+	// 	background-color: white;
+	// 	transform: rotate(0deg);
+	// 	transition: transform 0.3s;
+	// }
+
+	// .fab-circle-h {
+	// 	position: absolute;
+	// 	width: 24px;
+	// 	height: 2px;
+	// 	left: 0;
+	// 	top: 0;
+	// 	right: 0;
+	// 	bottom: 0;
+	// 	/* #ifndef APP-NVUE */
+	// 	margin: auto;
+	// 	/* #endif */
+	// 	background-color: white;
+	// 	transform: rotate(0deg);
+	// 	transition: transform 0.3s;
+	// }
+
+	.fab-circle-icon {
+		transform: rotate(0deg);
+		transition: transform 0.3s;
+		font-weight: 200;
+	}
+
+	.uni-fab__plus--active {
+		transform: rotate(135deg);
+	}
+
+	.uni-fab__content {
+		/* #ifndef APP-NVUE */
+		box-sizing: border-box;
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		border-radius: 55px;
+		overflow: hidden;
+		transition-property: width, height;
+		transition-duration: 0.2s;
+		width: 55px;
+		border-color: #DDDDDD;
+		border-width: 1rpx;
+		border-style: solid;
+	}
+
+	.uni-fab__content--other-platform {
+		border-width: 0px;
+		box-shadow: $uni-shadow-base;
+	}
+
+	.uni-fab__content--left {
+		justify-content: flex-start;
+	}
+
+	.uni-fab__content--right {
+		justify-content: flex-end;
+	}
+
+	.uni-fab__content--flexDirection {
+		flex-direction: column;
+		justify-content: flex-end;
+	}
+
+	.uni-fab__content--flexDirectionStart {
+		flex-direction: column;
+		justify-content: flex-start;
+	}
+
+	.uni-fab__content--flexDirectionEnd {
+		flex-direction: column;
+		justify-content: flex-end;
+	}
+
+	.uni-fab__item {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: column;
+		justify-content: center;
+		align-items: center;
+		width: 55px;
+		height: 55px;
+		opacity: 0;
+		transition: opacity 0.2s;
+	}
+
+	.uni-fab__item--active {
+		opacity: 1;
+	}
+
+	.uni-fab__item-image {
+		width: 20px;
+		height: 20px;
+		margin-bottom: 4px;
+	}
+
+	.uni-fab__item-text {
+		color: #FFFFFF;
+		font-size: 12px;
+		line-height: 12px;
+		margin-top: 2px;
+	}
+
+	.uni-fab__item--first {
+		width: 55px;
+	}
+</style>

+ 84 - 0
uni_modules/uni-fab/package.json

@@ -0,0 +1,84 @@
+{
+  "id": "uni-fab",
+  "displayName": "uni-fab 悬浮按钮",
+  "version": "1.2.5",
+  "description": "悬浮按钮 fab button ,点击可展开一个图标按钮菜单。",
+  "keywords": [
+    "uni-ui",
+    "uniui",
+    "按钮",
+    "悬浮按钮",
+    "fab"
+],
+  "repository": "https://github.com/dcloudio/uni-ui",
+  "engines": {
+    "HBuilderX": ""
+  },
+  "directories": {
+    "example": "../../temps/example_temps"
+  },
+"dcloudext": {
+    "sale": {
+      "regular": {
+        "price": "0.00"
+      },
+      "sourcecode": {
+        "price": "0.00"
+      }
+    },
+    "contact": {
+      "qq": ""
+    },
+    "declaration": {
+      "ads": "无",
+      "data": "无",
+      "permissions": "无"
+    },
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
+    "type": "component-vue"
+  },
+  "uni_modules": {
+    "dependencies": ["uni-scss","uni-icons"],
+    "encrypt": [],
+    "platforms": {
+      "cloud": {
+        "tcb": "y",
+        "aliyun": "y"
+      },
+      "client": {
+        "App": {
+          "app-vue": "y",
+          "app-nvue": "y"
+        },
+        "H5-mobile": {
+          "Safari": "y",
+          "Android Browser": "y",
+          "微信浏览器(Android)": "y",
+          "QQ浏览器(Android)": "y"
+        },
+        "H5-pc": {
+          "Chrome": "y",
+          "IE": "y",
+          "Edge": "y",
+          "Firefox": "y",
+          "Safari": "y"
+        },
+        "小程序": {
+          "微信": "y",
+          "阿里": "y",
+          "百度": "y",
+          "字节跳动": "y",
+          "QQ": "y"
+        },
+        "快应用": {
+          "华为": "u",
+          "联盟": "u"
+        },
+        "Vue": {
+            "vue2": "y",
+            "vue3": "y"
+        }
+      }
+    }
+  }
+}

+ 9 - 0
uni_modules/uni-fab/readme.md

@@ -0,0 +1,9 @@
+## Fab 悬浮按钮
+> **组件名:uni-fab**
+> 代码块: `uFab`
+
+
+点击可展开一个图形按钮菜单
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-fab)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 

+ 9 - 0
uni_modules/uni-segmented-control/changelog.md

@@ -0,0 +1,9 @@
+## 1.2.0(2021-11-19)
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-segmented-control](https://uniapp.dcloud.io/component/uniui/uni-segmented-control)
+## 1.1.0(2021-07-30)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 1.0.5(2021-05-12)
+- 新增 项目示例地址
+## 1.0.4(2021-02-05)
+- 调整为uni_modules目录规范

+ 145 - 0
uni_modules/uni-segmented-control/components/uni-segmented-control/uni-segmented-control.vue

@@ -0,0 +1,145 @@
+<template>
+	<view :class="[styleType === 'text'?'segmented-control--text' : 'segmented-control--button' ]"
+		:style="{ borderColor: styleType === 'text' ? '' : activeColor }" class="segmented-control">
+		<view v-for="(item, index) in values" :class="[ styleType === 'text' ? '': 'segmented-control__item--button',
+		index === currentIndex&&styleType === 'button' ? 'segmented-control__item--button--active': '',
+		index === 0&&styleType === 'button' ? 'segmented-control__item--button--first': '',
+			index === values.length - 1&&styleType === 'button' ? 'segmented-control__item--button--last': '' ]" :key="index"
+			:style="{ backgroundColor: index === currentIndex && styleType === 'button' ? activeColor : '',borderColor: index === currentIndex&&styleType === 'text'||styleType === 'button'?activeColor:'transparent' }"
+			class="segmented-control__item" @click="_onClick(index)">
+			<view>
+				<text :style="{color:
+				    index === currentIndex
+				      ? styleType === 'text'
+				        ? activeColor
+				        : '#fff'
+				      : styleType === 'text'
+				        ? '#000'
+				        : activeColor}" class="segmented-control__text" :class="styleType === 'text' && index === currentIndex ? 'segmented-control__item--text': ''">{{ item }}</text>
+			</view>
+
+		</view>
+	</view>
+</template>
+
+<script>
+	/**
+	 * SegmentedControl 分段器
+	 * @description 用作不同视图的显示
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=54
+	 * @property {Number} current 当前选中的tab索引值,从0计数
+	 * @property {String} styleType = [button|text] 分段器样式类型
+	 * 	@value button 按钮类型
+	 * 	@value text 文字类型
+	 * @property {String} activeColor 选中的标签背景色与边框颜色
+	 * @property {Array} values 选项数组
+	 * @event {Function} clickItem 组件触发点击事件时触发,e={currentIndex}
+	 */
+
+	export default {
+		name: 'UniSegmentedControl',
+		emits: ['clickItem'],
+		props: {
+			current: {
+				type: Number,
+				default: 0
+			},
+			values: {
+				type: Array,
+				default () {
+					return []
+				}
+			},
+			activeColor: {
+				type: String,
+				default: '#2979FF'
+			},
+			styleType: {
+				type: String,
+				default: 'button'
+			}
+		},
+		data() {
+			return {
+				currentIndex: 0
+			}
+		},
+		watch: {
+			current(val) {
+				if (val !== this.currentIndex) {
+					this.currentIndex = val
+				}
+			}
+		},
+		created() {
+			this.currentIndex = this.current
+		},
+		methods: {
+			_onClick(index) {
+				if (this.currentIndex !== index) {
+					this.currentIndex = index
+					this.$emit('clickItem', {
+						currentIndex: index
+					})
+				}
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.segmented-control {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		box-sizing: border-box;
+		/* #endif */
+		flex-direction: row;
+		height: 36px;
+		overflow: hidden;
+		/* #ifdef H5 */
+		cursor: pointer;
+		/* #endif */
+	}
+
+	.segmented-control__item {
+		/* #ifndef APP-NVUE */
+		display: inline-flex;
+		box-sizing: border-box;
+		/* #endif */
+		position: relative;
+		flex: 1;
+		justify-content: center;
+		align-items: center;
+	}
+
+	.segmented-control__item--button {
+		border-style: solid;
+		border-top-width: 1px;
+		border-bottom-width: 1px;
+		border-right-width: 1px;
+		border-left-width: 0;
+	}
+
+	.segmented-control__item--button--first {
+		border-left-width: 1px;
+		border-top-left-radius: 5px;
+		border-bottom-left-radius: 5px;
+	}
+
+	.segmented-control__item--button--last {
+		border-top-right-radius: 5px;
+		border-bottom-right-radius: 5px;
+	}
+
+	.segmented-control__item--text {
+		border-bottom-style: solid;
+		border-bottom-width: 2px;
+		padding: 6px 0;
+	}
+
+	.segmented-control__text {
+		font-size: 14px;
+		line-height: 20px;
+		text-align: center;
+	}
+</style>

+ 87 - 0
uni_modules/uni-segmented-control/package.json

@@ -0,0 +1,87 @@
+{
+  "id": "uni-segmented-control",
+  "displayName": "uni-segmented-control 分段器",
+  "version": "1.2.0",
+  "description": "分段器由至少 2 个分段控件组成,用作不同视图的显示",
+  "keywords": [
+    "uni-ui",
+    "uniui",
+    "分段器",
+    "segement",
+    "顶部选择"
+],
+  "repository": "https://github.com/dcloudio/uni-ui",
+  "engines": {
+    "HBuilderX": ""
+  },
+  "directories": {
+    "example": "../../temps/example_temps"
+  },
+  "dcloudext": {
+    "category": [
+      "前端组件",
+      "通用组件"
+    ],
+    "sale": {
+      "regular": {
+        "price": "0.00"
+      },
+      "sourcecode": {
+        "price": "0.00"
+      }
+    },
+    "contact": {
+      "qq": ""
+    },
+    "declaration": {
+      "ads": "无",
+      "data": "无",
+      "permissions": "无"
+    },
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+  },
+  "uni_modules": {
+    "dependencies": ["uni-scss"],
+    "encrypt": [],
+    "platforms": {
+      "cloud": {
+        "tcb": "y",
+        "aliyun": "y"
+      },
+      "client": {
+        "App": {
+          "app-vue": "y",
+          "app-nvue": "y"
+        },
+        "H5-mobile": {
+          "Safari": "y",
+          "Android Browser": "y",
+          "微信浏览器(Android)": "y",
+          "QQ浏览器(Android)": "y"
+        },
+        "H5-pc": {
+          "Chrome": "y",
+          "IE": "y",
+          "Edge": "y",
+          "Firefox": "y",
+          "Safari": "y"
+        },
+        "小程序": {
+          "微信": "y",
+          "阿里": "y",
+          "百度": "y",
+          "字节跳动": "y",
+          "QQ": "y"
+        },
+        "快应用": {
+          "华为": "u",
+          "联盟": "u"
+        },
+        "Vue": {
+            "vue2": "y",
+            "vue3": "y"
+        }
+      }
+    }
+  }
+}

+ 13 - 0
uni_modules/uni-segmented-control/readme.md

@@ -0,0 +1,13 @@
+
+
+## SegmentedControl 分段器
+> **组件名:uni-segmented-control**
+> 代码块: `uSegmentedControl`
+
+
+用作不同视图的显示
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-segmented-control)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 
+
+

+ 47 - 0
uni_modules/uni-swipe-action/changelog.md

@@ -0,0 +1,47 @@
+## 1.3.10(2024-01-17)
+- 修复 点击按钮时,按钮会被点击穿透导致自动收缩的 bug(兼容阿里/百度/抖音小程序)
+## 1.3.9(2024-01-17)
+- 修复 点击按钮时,按钮会被点击穿透导致自动收缩的 bug
+## 1.3.8(2023-04-13)
+- 修复`uni-swipe-action`和`uni-swipe-action-item`不同时使用导致 closeOther 方法报错的 bug
+## 1.3.7(2022-06-06)
+- 修复 vue3 下使用组件不能正常运行的Bug
+## 1.3.6(2022-05-31)
+- 修复 h5端点击click触发两次的Bug
+## 1.3.5(2022-05-23)
+- 修复 isPC 找不到的Bug
+## 1.3.4(2022-05-19)
+-  修复 在 nvue 下 disabled 失效的bug
+## 1.3.3(2022-03-31)
+- 修复 按钮字体大小不能设置的bug
+## 1.3.2(2022-03-16)
+- 修复 h5和app端下报el错误的bug
+## 1.3.1(2022-03-07)
+- 修复 HBuilderX 1.4.X 版本中,h5和app端下报错的bug
+## 1.3.0(2021-11-19)
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-swipe-action](https://uniapp.dcloud.io/component/uniui/uni-swipe-action)
+## 1.2.4(2021-08-20)
+- 优化 close-all 方法
+## 1.2.3(2021-08-20)
+- 新增 close-all 方法,关闭所有已打开的组件
+## 1.2.2(2021-08-17)
+- 新增 resize() 方法,在非微信小程序、h5、app-vue端出现不能滑动的问题的时候,重置组件
+- 修复 app 端偶尔出现类似 Page[x][-x,xx;-x,xx,x,x-x] 的问题 
+- 优化 微信小程序、h5、app-vue 滑动逻辑,避免出现动态新增组件后不能滑动的问题
+## 1.2.1(2021-07-30)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+- 修复 跨页面修改组件数据 ,导致不能滑动的问题
+## 1.1.10(2021-06-17)
+- 修复 按钮点击执行两次的bug
+## 1.1.9(2021-05-12)
+- 新增 项目示例地址
+## 1.1.8(2021-03-26)
+- 修复 微信小程序 nv_navigator is not defined 报错的bug
+## 1.1.7(2021-02-05)
+- 调整为uni_modules目录规范
+- 新增 左侧滑动
+- 新增 插槽使用方式
+- 新增 threshold 属性,可以控制滑动缺省值
+- 优化 长列表滚动性能
+- 修复 滚动页面时触发组件滑动的Bug

+ 302 - 0
uni_modules/uni-swipe-action/components/uni-swipe-action-item/bindingx.js

@@ -0,0 +1,302 @@
+let bindIngXMixins = {}
+
+// #ifdef APP-NVUE
+const BindingX = uni.requireNativePlugin('bindingx');
+const dom = uni.requireNativePlugin('dom');
+const animation = uni.requireNativePlugin('animation');
+
+bindIngXMixins = {
+	data() {
+		return {}
+	},
+
+	watch: {
+		show(newVal) {
+			if (this.autoClose) return
+			if (this.stop) return
+			this.stop = true
+			if (newVal) {
+				this.open(newVal)
+			} else {
+				this.close()
+			}
+		},
+		leftOptions() {
+			this.getSelectorQuery()
+			this.init()
+		},
+		rightOptions(newVal) {
+			this.init()
+		}
+	},
+	created() {
+		this.swipeaction = this.getSwipeAction()
+		if (this.swipeaction && Array.isArray(this.swipeaction.children)) {
+			this.swipeaction.children.push(this)
+		}
+	},
+	mounted() {
+		this.box = this.getEl(this.$refs['selector-box--hock'])
+		this.selector = this.getEl(this.$refs['selector-content--hock']);
+		this.leftButton = this.getEl(this.$refs['selector-left-button--hock']);
+		this.rightButton = this.getEl(this.$refs['selector-right-button--hock']);
+		this.init()
+	},
+	// beforeDestroy() {
+	// 	this.swipeaction.children.forEach((item, index) => {
+	// 		if (item === this) {
+	// 			this.swipeaction.children.splice(index, 1)
+	// 		}
+	// 	})
+	// },
+	methods: {
+		init() {
+			this.$nextTick(() => {
+				this.x = 0
+				this.button = {
+					show: false
+				}
+				setTimeout(() => {
+					this.getSelectorQuery()
+				}, 200)
+			})
+		},
+		onClick(index, item, position) {
+			this.$emit('click', {
+				content: item,
+				index,
+				position
+			})
+		},
+		touchstart(e) {
+			// fix by mehaotian 禁止滑动
+			if (this.disabled) return
+			// 每次只触发一次,避免多次监听造成闪烁
+			if (this.stop) return
+			this.stop = true
+			if (this.autoClose && this.swipeaction) {
+				this.swipeaction.closeOther(this)
+			}
+
+			const leftWidth = this.button.left.width
+			const rightWidth = this.button.right.width
+			let expression = this.range(this.x, -rightWidth, leftWidth)
+			let leftExpression = this.range(this.x - leftWidth, -leftWidth, 0)
+			let rightExpression = this.range(this.x + rightWidth, 0, rightWidth)
+
+			this.eventpan = BindingX.bind({
+				anchor: this.box,
+				eventType: 'pan',
+				props: [{
+					element: this.selector,
+					property: 'transform.translateX',
+					expression
+				}, {
+					element: this.leftButton,
+					property: 'transform.translateX',
+					expression: leftExpression
+				}, {
+					element: this.rightButton,
+					property: 'transform.translateX',
+					expression: rightExpression
+				}, ]
+			}, (e) => {
+				// nope
+				if (e.state === 'end') {
+					this.x = e.deltaX + this.x;
+					this.isclick = true
+					this.bindTiming(e.deltaX)
+				}
+			});
+		},
+		touchend(e) {
+			if (this.isopen !== 'none' && !this.isclick) {
+				this.open('none')
+			}
+		},
+		bindTiming(x) {
+			const left = this.x
+			const leftWidth = this.button.left.width
+			const rightWidth = this.button.right.width
+			const threshold = this.threshold
+			if (!this.isopen || this.isopen === 'none') {
+				if (left > threshold) {
+					this.open('left')
+				} else if (left < -threshold) {
+					this.open('right')
+				} else {
+					this.open('none')
+				}
+			} else {
+				if ((x > -leftWidth && x < 0) || x > rightWidth) {
+					if ((x > -threshold && x < 0) || (x - rightWidth > threshold)) {
+						this.open('left')
+					} else {
+						this.open('none')
+					}
+				} else {
+					if ((x < threshold && x > 0) || (x + leftWidth < -threshold)) {
+						this.open('right')
+					} else {
+						this.open('none')
+					}
+				}
+			}
+		},
+
+		/**
+		 * 移动范围
+		 * @param {Object} num
+		 * @param {Object} mix
+		 * @param {Object} max
+		 */
+		range(num, mix, max) {
+			return `min(max(x+${num}, ${mix}), ${max})`
+		},
+
+		/**
+		 * 开启swipe
+		 */
+		open(type) {
+			this.animation(type)
+		},
+
+		/**
+		 * 关闭swipe
+		 */
+		close() {
+			this.animation('none')
+		},
+
+		/**
+		 * 开启关闭动画
+		 * @param {Object} type
+		 */
+		animation(type) {
+			const time = 300
+			const leftWidth = this.button.left.width
+			const rightWidth = this.button.right.width
+			if (this.eventpan && this.eventpan.token) {
+				BindingX.unbind({
+					token: this.eventpan.token,
+					eventType: 'pan'
+				})
+			}
+
+			switch (type) {
+				case 'left':
+					Promise.all([
+						this.move(this.selector, leftWidth),
+						this.move(this.leftButton, 0),
+						this.move(this.rightButton, rightWidth * 2)
+					]).then(() => {
+						this.setEmit(leftWidth, type)
+					})
+					break
+				case 'right':
+					Promise.all([
+						this.move(this.selector, -rightWidth),
+						this.move(this.leftButton, -leftWidth * 2),
+						this.move(this.rightButton, 0)
+					]).then(() => {
+						this.setEmit(-rightWidth, type)
+					})
+					break
+				default:
+					Promise.all([
+						this.move(this.selector, 0),
+						this.move(this.leftButton, -leftWidth),
+						this.move(this.rightButton, rightWidth)
+					]).then(() => {
+						this.setEmit(0, type)
+					})
+
+			}
+		},
+		setEmit(x, type) {
+			const leftWidth = this.button.left.width
+			const rightWidth = this.button.right.width
+			this.isopen = this.isopen || 'none'
+			this.stop = false
+			this.isclick = false
+			// 只有状态不一致才会返回结果
+			if (this.isopen !== type && this.x !== x) {
+				if (type === 'left' && leftWidth > 0) {
+					this.$emit('change', 'left')
+				}
+				if (type === 'right' && rightWidth > 0) {
+					this.$emit('change', 'right')
+				}
+				if (type === 'none') {
+					this.$emit('change', 'none')
+				}
+			}
+			this.x = x
+			this.isopen = type
+		},
+		move(ref, value) {
+			return new Promise((resolve, reject) => {
+				animation.transition(ref, {
+					styles: {
+						transform: `translateX(${value})`,
+					},
+					duration: 150, //ms
+					timingFunction: 'linear',
+					needLayout: false,
+					delay: 0 //ms
+				}, function(res) {
+					resolve(res)
+				})
+			})
+
+		},
+
+		/**
+		 * 获取ref
+		 * @param {Object} el
+		 */
+		getEl(el) {
+			return el.ref
+		},
+		/**
+		 * 获取节点信息
+		 */
+		getSelectorQuery() {
+			Promise.all([
+				this.getDom('left'),
+				this.getDom('right'),
+			]).then((data) => {
+				let show = 'none'
+				if (this.autoClose) {
+					show = 'none'
+				} else {
+					show = this.show
+				}
+
+				if (show === 'none') {
+					// this.close()
+				} else {
+					this.open(show)
+				}
+
+			})
+
+		},
+		getDom(str) {
+			return new Promise((resolve, reject) => {
+				dom.getComponentRect(this.$refs[`selector-${str}-button--hock`], (data) => {
+					if (data) {
+						this.button[str] = data.size
+						resolve(data)
+					} else {
+						reject()
+					}
+				})
+			})
+		}
+	}
+}
+
+// #endif
+
+export default bindIngXMixins

+ 12 - 0
uni_modules/uni-swipe-action/components/uni-swipe-action-item/isPC.js

@@ -0,0 +1,12 @@
+export function isPC() {
+	var userAgentInfo = navigator.userAgent;
+	var Agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
+	var flag = true;
+	for (let v = 0; v < Agents.length - 1; v++) {
+		if (userAgentInfo.indexOf(Agents[v]) > 0) {
+			flag = false;
+			break;
+		}
+	}
+	return flag;
+}

+ 195 - 0
uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpalipay.js

@@ -0,0 +1,195 @@
+export default {
+	data() {
+		return {
+			x: 0,
+			transition: false,
+			width: 0,
+			viewWidth: 0,
+			swipeShow: 0
+		}
+	},
+	watch: {
+		show(newVal) {
+			if (this.autoClose) return
+			if (newVal && newVal !== 'none') {
+				this.transition = true
+				this.open(newVal)
+			} else {
+				this.close()
+			}
+		}
+	},
+	created() {
+		this.swipeaction = this.getSwipeAction()
+		if (this.swipeaction && Array.isArray(this.swipeaction.children)) {
+			this.swipeaction.children.push(this)
+		}
+	},
+	mounted() {
+		this.isopen = false
+		setTimeout(() => {
+			this.getQuerySelect()
+		}, 50)
+	},
+	methods: {
+		appTouchStart(e) {
+			const {
+				clientX
+			} = e.changedTouches[0]
+			this.clientX = clientX
+			this.timestamp = new Date().getTime()
+		},
+		appTouchEnd(e, index, item, position) {
+			const {
+				clientX
+			} = e.changedTouches[0]
+			// fixed by xxxx 模拟点击事件,解决 ios 13 点击区域错位的问题
+			let diff = Math.abs(this.clientX - clientX)
+			let time = (new Date().getTime()) - this.timestamp
+			if (diff < 40 && time < 300) {
+				this.$emit('click', {
+					content: item,
+					index,
+					position
+				})
+			}
+		},
+		/**
+		 * 移动触发
+		 * @param {Object} e
+		 */
+		onChange(e) {
+			this.moveX = e.detail.x
+			this.isclose = false
+		},
+		touchstart(e) {
+			this.transition = false
+			this.isclose = true
+			if (this.autoClose && this.swipeaction) {
+				this.swipeaction.closeOther(this)
+			}
+		},
+		touchmove(e) {},
+		touchend(e) {
+			// 0的位置什么都不执行
+			if (this.isclose && this.isopen === 'none') return
+			if (this.isclose && this.isopen !== 'none') {
+				this.transition = true
+				this.close()
+			} else {
+				this.move(this.moveX + this.leftWidth)
+			}
+		},
+
+		/**
+		 * 移动
+		 * @param {Object} moveX
+		 */
+		move(moveX) {
+			// 打开关闭的处理逻辑不太一样
+			this.transition = true
+			// 未打开状态
+			if (!this.isopen || this.isopen === 'none') {
+				if (moveX > this.threshold) {
+					this.open('left')
+				} else if (moveX < -this.threshold) {
+					this.open('right')
+				} else {
+					this.close()
+				}
+			} else {
+				if (moveX < 0 && moveX < this.rightWidth) {
+					const rightX = this.rightWidth + moveX
+					if (rightX < this.threshold) {
+						this.open('right')
+					} else {
+						this.close()
+					}
+				} else if (moveX > 0 && moveX < this.leftWidth) {
+					const leftX = this.leftWidth - moveX
+					if (leftX < this.threshold) {
+						this.open('left')
+					} else {
+						this.close()
+					}
+				}
+
+			}
+
+		},
+
+		/**
+		 * 打开
+		 */
+		open(type) {
+			this.x = this.moveX
+			this.animation(type)
+		},
+
+		/**
+		 * 关闭
+		 */
+		close() {
+			this.x = this.moveX
+			// TODO 解决 x 值不更新的问题,所以会多触发一次 nextTick ,待优化
+			this.$nextTick(() => {
+				this.x = -this.leftWidth
+				if (this.isopen !== 'none') {
+					this.$emit('change', 'none')
+				}
+				this.isopen = 'none'
+			})
+		},
+
+		/**
+		 * 执行结束动画
+		 * @param {Object} type
+		 */
+		animation(type) {
+			this.$nextTick(() => {
+				if (type === 'left') {
+					this.x = 0
+				} else {
+					this.x = -this.rightWidth - this.leftWidth
+				}
+
+				if (this.isopen !== type) {
+					this.$emit('change', type)
+				}
+				this.isopen = type
+			})
+
+		},
+		getSlide(x) {},
+		getQuerySelect() {
+			const query = uni.createSelectorQuery().in(this);
+			query.selectAll('.movable-view--hock').boundingClientRect(data => {
+				this.leftWidth = data[1].width
+				this.rightWidth = data[2].width
+				this.width = data[0].width
+				this.viewWidth = this.width + this.rightWidth + this.leftWidth
+				if (this.leftWidth === 0) {
+					// TODO 疑似bug ,初始化的时候如果x 是0,会导致移动位置错误,所以让元素超出一点
+					this.x = -0.1
+				} else {
+					this.x = -this.leftWidth
+				}
+				this.moveX = this.x
+				this.$nextTick(() => {
+					this.swipeShow = 1
+				})
+
+				if (!this.buttonWidth) {
+					this.disabledView = true
+				}
+
+				if (this.autoClose) return
+				if (this.show !== 'none') {
+					this.transition = true
+					this.open(this.shows)
+				}
+			}).exec();
+
+		}
+	}
+}

+ 260 - 0
uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpother.js

@@ -0,0 +1,260 @@
+let otherMixins = {}
+
+// #ifndef APP-PLUS|| MP-WEIXIN  ||  H5
+const MIN_DISTANCE = 10;
+otherMixins = {
+	data() {
+		// TODO 随机生生元素ID,解决百度小程序获取同一个元素位置信息的bug
+		const elClass = `Uni_${Math.ceil(Math.random() * 10e5).toString(36)}`
+		return {
+			uniShow: false,
+			left: 0,
+			buttonShow: 'none',
+			ani: false,
+			moveLeft: '',
+			elClass
+		}
+	},
+	watch: {
+		show(newVal) {
+			if (this.autoClose) return
+			this.openState(newVal)
+		},
+		left() {
+			this.moveLeft = `translateX(${this.left}px)`
+		},
+		buttonShow(newVal) {
+			if (this.autoClose) return
+			this.openState(newVal)
+		},
+		leftOptions() {
+			this.init()
+		},
+		rightOptions() {
+			this.init()
+		}
+	},
+	mounted() {
+		this.swipeaction = this.getSwipeAction()
+		if (this.swipeaction && Array.isArray(this.swipeaction.children)) {
+			this.swipeaction.children.push(this)
+		}
+		this.init()
+	},
+	methods: {
+		init() {
+			clearTimeout(this.timer)
+			this.timer = setTimeout(() => {
+				this.getSelectorQuery()
+			}, 100)
+			// 移动距离
+			this.left = 0
+			this.x = 0
+		},
+
+		closeSwipe(e) {
+			if (this.autoClose && this.swipeaction) {
+				this.swipeaction.closeOther(this)
+			}
+		},
+		appTouchStart(e) {
+			const {
+				clientX
+			} = e.changedTouches[0]
+			this.clientX = clientX
+			this.timestamp = new Date().getTime()
+		},
+		appTouchEnd(e, index, item, position) {
+			const {
+				clientX
+			} = e.changedTouches[0]
+			// fixed by xxxx 模拟点击事件,解决 ios 13 点击区域错位的问题
+			let diff = Math.abs(this.clientX - clientX)
+			let time = (new Date().getTime()) - this.timestamp
+			if (diff < 40 && time < 300) {
+				this.$emit('click', {
+					content: item,
+					index,
+					position
+				})
+			}
+		},
+		touchstart(e) {
+			if (this.disabled) return
+			this.ani = false
+			this.x = this.left || 0
+			this.stopTouchStart(e)
+			this.autoClose && this.closeSwipe()
+		},
+		touchmove(e) {
+			if (this.disabled) return
+			// 是否可以滑动页面
+			this.stopTouchMove(e);
+			if (this.direction !== 'horizontal') {
+				return;
+			}
+			this.move(this.x + this.deltaX)
+			return false
+		},
+		touchend() {
+			if (this.disabled) return
+			this.moveDirection(this.left)
+		},
+		/**
+		 * 设置移动距离
+		 * @param {Object} value
+		 */
+		move(value) {
+			value = value || 0
+			const leftWidth = this.leftWidth
+			const rightWidth = this.rightWidth
+			// 获取可滑动范围
+			this.left = this.range(value, -rightWidth, leftWidth);
+		},
+
+		/**
+		 * 获取范围
+		 * @param {Object} num
+		 * @param {Object} min
+		 * @param {Object} max
+		 */
+		range(num, min, max) {
+			return Math.min(Math.max(num, min), max);
+		},
+		/**
+		 * 移动方向判断
+		 * @param {Object} left
+		 * @param {Object} value
+		 */
+		moveDirection(left) {
+			const threshold = this.threshold
+			const isopen = this.isopen || 'none'
+			const leftWidth = this.leftWidth
+			const rightWidth = this.rightWidth
+			if (this.deltaX === 0) {
+				this.openState('none')
+				return
+			}
+			if ((isopen === 'none' && rightWidth > 0 && -left > threshold) || (isopen !== 'none' && rightWidth >
+					0 && rightWidth +
+					left < threshold)) {
+				// right
+				this.openState('right')
+			} else if ((isopen === 'none' && leftWidth > 0 && left > threshold) || (isopen !== 'none' && leftWidth >
+					0 &&
+					leftWidth - left < threshold)) {
+				// left
+				this.openState('left')
+			} else {
+				// default
+				this.openState('none')
+			}
+		},
+
+		/**
+		 * 开启状态
+		 * @param {Boolean} type
+		 */
+		openState(type) {
+			const leftWidth = this.leftWidth
+			const rightWidth = this.rightWidth
+			let left = ''
+			this.isopen = this.isopen ? this.isopen : 'none'
+			switch (type) {
+				case "left":
+					left = leftWidth
+					break
+				case "right":
+					left = -rightWidth
+					break
+				default:
+					left = 0
+			}
+
+
+			if (this.isopen !== type) {
+				this.throttle = true
+				this.$emit('change', type)
+			}
+
+			this.isopen = type
+			// 添加动画类
+			this.ani = true
+			this.$nextTick(() => {
+				this.move(left)
+			})
+			// 设置最终移动位置,理论上只要进入到这个函数,肯定是要打开的
+		},
+		close() {
+			this.openState('none')
+		},
+		getDirection(x, y) {
+			if (x > y && x > MIN_DISTANCE) {
+				return 'horizontal';
+			}
+			if (y > x && y > MIN_DISTANCE) {
+				return 'vertical';
+			}
+			return '';
+		},
+
+		/**
+		 * 重置滑动状态
+		 * @param {Object} event
+		 */
+		resetTouchStatus() {
+			this.direction = '';
+			this.deltaX = 0;
+			this.deltaY = 0;
+			this.offsetX = 0;
+			this.offsetY = 0;
+		},
+
+		/**
+		 * 设置滑动开始位置
+		 * @param {Object} event
+		 */
+		stopTouchStart(event) {
+			this.resetTouchStatus();
+			const touch = event.touches[0];
+			this.startX = touch.clientX;
+			this.startY = touch.clientY;
+		},
+
+		/**
+		 * 滑动中,是否禁止打开
+		 * @param {Object} event
+		 */
+		stopTouchMove(event) {
+			const touch = event.touches[0];
+			this.deltaX = touch.clientX - this.startX;
+			this.deltaY = touch.clientY - this.startY;
+			this.offsetX = Math.abs(this.deltaX);
+			this.offsetY = Math.abs(this.deltaY);
+			this.direction = this.direction || this.getDirection(this.offsetX, this.offsetY);
+		},
+
+		getSelectorQuery() {
+			const views = uni.createSelectorQuery().in(this)
+			views
+				.selectAll('.' + this.elClass)
+				.boundingClientRect(data => {
+					if (data.length === 0) return
+					let show = 'none'
+					if (this.autoClose) {
+						show = 'none'
+					} else {
+						show = this.show
+					}
+					this.leftWidth = data[0].width || 0
+					this.rightWidth = data[1].width || 0
+					this.buttonShow = show
+				})
+				.exec()
+		}
+	}
+}
+
+// #endif
+
+export default otherMixins

+ 84 - 0
uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpwxs.js

@@ -0,0 +1,84 @@
+let mpMixins = {}
+let is_pc = null
+// #ifdef H5
+import {
+	isPC
+} from "./isPC"
+is_pc = isPC()
+// #endif
+// #ifdef APP-VUE|| MP-WEIXIN || H5
+
+mpMixins = {
+	data() {
+		return {
+			is_show: 'none'
+		}
+	},
+	watch: {
+		show(newVal) {
+			this.is_show = this.show
+		}
+	},
+	created() {
+		this.swipeaction = this.getSwipeAction()
+		if (this.swipeaction && Array.isArray(this.swipeaction.children)) {
+			this.swipeaction.children.push(this)
+		}
+	},
+	mounted() {
+		this.is_show = this.show
+	},
+	methods: {
+		// wxs 中调用
+		closeSwipe(e) {
+			if (this.autoClose && this.swipeaction) {
+				this.swipeaction.closeOther(this)
+			}
+		},
+
+		change(e) {
+			this.$emit('change', e.open)
+			if (this.is_show !== e.open) {
+				this.is_show = e.open
+			}
+		},
+
+		appTouchStart(e) {
+			if (is_pc) return
+			const {
+				clientX
+			} = e.changedTouches[0]
+			this.clientX = clientX
+			this.timestamp = new Date().getTime()
+		},
+		appTouchEnd(e, index, item, position) {
+			if (is_pc) return
+			const {
+				clientX
+			} = e.changedTouches[0]
+			// fixed by xxxx 模拟点击事件,解决 ios 13 点击区域错位的问题
+			let diff = Math.abs(this.clientX - clientX)
+			let time = (new Date().getTime()) - this.timestamp
+			if (diff < 40 && time < 300) {
+				this.$emit('click', {
+					content: item,
+					index,
+					position
+				})
+			}
+		},
+		onClickForPC(index, item, position) {
+			if (!is_pc) return
+			// #ifdef H5
+			this.$emit('click', {
+				content: item,
+				index,
+				position
+			})
+			// #endif
+		}
+	}
+}
+
+// #endif
+export default mpMixins

+ 270 - 0
uni_modules/uni-swipe-action/components/uni-swipe-action-item/render.js

@@ -0,0 +1,270 @@
+const MIN_DISTANCE = 10;
+export default {
+	showWatch(newVal, oldVal, ownerInstance, instance, self) {
+		var state = self.state
+		var $el = ownerInstance.$el || ownerInstance.$vm && ownerInstance.$vm.$el
+		if (!$el) return
+		this.getDom(instance, ownerInstance, self)
+		if (newVal && newVal !== 'none') {
+			this.openState(newVal, instance, ownerInstance, self)
+			return
+		}
+
+		if (state.left) {
+			this.openState('none', instance, ownerInstance, self)
+		}
+		this.resetTouchStatus(instance, self)
+	},
+
+	/**
+	 * 开始触摸操作
+	 * @param {Object} e
+	 * @param {Object} ins
+	 */
+	touchstart(e, ownerInstance, self) {
+		let instance = e.instance;
+		let disabled = instance.getDataset().disabled
+		let state = self.state;
+		this.getDom(instance, ownerInstance, self)
+		// fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复
+		disabled = this.getDisabledType(disabled)
+		if (disabled) return
+		// 开始触摸时移除动画类
+		instance.requestAnimationFrame(function() {
+			instance.removeClass('ani');
+			ownerInstance.callMethod('closeSwipe');
+		})
+
+		// 记录上次的位置
+		state.x = state.left || 0
+		// 计算滑动开始位置
+		this.stopTouchStart(e, ownerInstance, self)
+	},
+
+	/**
+	 * 开始滑动操作
+	 * @param {Object} e
+	 * @param {Object} ownerInstance
+	 */
+	touchmove(e, ownerInstance, self) {
+		let instance = e.instance;
+		// 删除之后已经那不到实例了
+		if (!instance) return;
+		let disabled = instance.getDataset().disabled
+		let state = self.state
+		// fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复
+		disabled = this.getDisabledType(disabled)
+		if (disabled) return
+		// 是否可以滑动页面
+		this.stopTouchMove(e, self);
+		if (state.direction !== 'horizontal') {
+			return;
+		}
+		if (e.preventDefault) {
+			// 阻止页面滚动
+			e.preventDefault()
+		}
+		let x = state.x + state.deltaX
+		this.move(x, instance, ownerInstance, self)
+	},
+
+	/**
+	 * 结束触摸操作
+	 * @param {Object} e
+	 * @param {Object} ownerInstance
+	 */
+	touchend(e, ownerInstance, self) {
+		let instance = e.instance;
+		let disabled = instance.getDataset().disabled
+		let state = self.state
+		// fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复
+		disabled = this.getDisabledType(disabled)
+
+		if (disabled) return
+		// 滑动过程中触摸结束,通过阙值判断是开启还是关闭
+		// fixed by mehaotian 定时器解决点击按钮,touchend 触发比 click 事件时机早的问题 ,主要是 ios13
+		this.moveDirection(state.left, instance, ownerInstance, self)
+
+	},
+
+	/**
+	 * 设置移动距离
+	 * @param {Object} value
+	 * @param {Object} instance
+	 * @param {Object} ownerInstance
+	 */
+	move(value, instance, ownerInstance, self) {
+		value = value || 0
+		let state = self.state
+		let leftWidth = state.leftWidth
+		let rightWidth = state.rightWidth
+		// 获取可滑动范围
+		state.left = this.range(value, -rightWidth, leftWidth);
+		instance.requestAnimationFrame(function() {
+			instance.setStyle({
+				transform: 'translateX(' + state.left + 'px)',
+				'-webkit-transform': 'translateX(' + state.left + 'px)'
+			})
+		})
+
+	},
+
+	/**
+	 * 获取元素信息
+	 * @param {Object} instance
+	 * @param {Object} ownerInstance
+	 */
+	getDom(instance, ownerInstance, self) {
+		var state = self.state
+		var $el = ownerInstance.$el || ownerInstance.$vm && ownerInstance.$vm.$el
+		var leftDom = $el.querySelector('.button-group--left')
+		var rightDom = $el.querySelector('.button-group--right')
+
+		state.leftWidth = leftDom.offsetWidth || 0
+		state.rightWidth = rightDom.offsetWidth || 0
+		state.threshold = instance.getDataset().threshold
+	},
+
+	getDisabledType(value) {
+		return (typeof(value) === 'string' ? JSON.parse(value) : value) || false;
+	},
+
+	/**
+	 * 获取范围
+	 * @param {Object} num
+	 * @param {Object} min
+	 * @param {Object} max
+	 */
+	range(num, min, max) {
+		return Math.min(Math.max(num, min), max);
+	},
+
+
+	/**
+	 * 移动方向判断
+	 * @param {Object} left
+	 * @param {Object} value
+	 * @param {Object} ownerInstance
+	 * @param {Object} ins
+	 */
+	moveDirection(left, ins, ownerInstance, self) {
+		var state = self.state
+		var threshold = state.threshold
+		var position = state.position
+		var isopen = state.isopen || 'none'
+		var leftWidth = state.leftWidth
+		var rightWidth = state.rightWidth
+		if (state.deltaX === 0) {
+			this.openState('none', ins, ownerInstance, self)
+			return
+		}
+		if ((isopen === 'none' && rightWidth > 0 && -left > threshold) || (isopen !== 'none' && rightWidth > 0 &&
+				rightWidth +
+				left < threshold)) {
+			// right
+			this.openState('right', ins, ownerInstance, self)
+		} else if ((isopen === 'none' && leftWidth > 0 && left > threshold) || (isopen !== 'none' && leftWidth > 0 &&
+				leftWidth - left < threshold)) {
+			// left
+			this.openState('left', ins, ownerInstance, self)
+		} else {
+			// default
+			this.openState('none', ins, ownerInstance, self)
+		}
+	},
+
+
+	/**
+	 * 开启状态
+	 * @param {Boolean} type
+	 * @param {Object} ins
+	 * @param {Object} ownerInstance
+	 */
+	openState(type, ins, ownerInstance, self) {
+		let state = self.state
+		let leftWidth = state.leftWidth
+		let rightWidth = state.rightWidth
+		let left = ''
+		state.isopen = state.isopen ? state.isopen : 'none'
+		switch (type) {
+			case "left":
+				left = leftWidth
+				break
+			case "right":
+				left = -rightWidth
+				break
+			default:
+				left = 0
+		}
+
+		// && !state.throttle
+
+		if (state.isopen !== type) {
+			state.throttle = true
+			ownerInstance.callMethod('change', {
+				open: type
+			})
+
+		}
+
+		state.isopen = type
+		// 添加动画类
+		ins.requestAnimationFrame(() => {
+			ins.addClass('ani');
+			this.move(left, ins, ownerInstance, self)
+		})
+	},
+
+
+	getDirection(x, y) {
+		if (x > y && x > MIN_DISTANCE) {
+			return 'horizontal';
+		}
+		if (y > x && y > MIN_DISTANCE) {
+			return 'vertical';
+		}
+		return '';
+	},
+
+	/**
+	 * 重置滑动状态
+	 * @param {Object} event
+	 */
+	resetTouchStatus(instance, self) {
+		let state = self.state;
+		state.direction = '';
+		state.deltaX = 0;
+		state.deltaY = 0;
+		state.offsetX = 0;
+		state.offsetY = 0;
+	},
+
+	/**
+	 * 设置滑动开始位置
+	 * @param {Object} event
+	 */
+	stopTouchStart(event, ownerInstance, self) {
+		let instance = event.instance;
+		let state = self.state
+		this.resetTouchStatus(instance, self);
+		var touch = event.touches[0];
+		state.startX = touch.clientX;
+		state.startY = touch.clientY;
+	},
+
+	/**
+	 * 滑动中,是否禁止打开
+	 * @param {Object} event
+	 */
+	stopTouchMove(event, self) {
+		let instance = event.instance;
+		let state = self.state;
+		let touch = event.touches[0];
+
+		state.deltaX = touch.clientX - state.startX;
+		state.deltaY = touch.clientY - state.startY;
+		state.offsetY = Math.abs(state.deltaY);
+		state.offsetX = Math.abs(state.deltaX);
+		state.direction = state.direction || this.getDirection(state.offsetX, state.offsetY);
+	}
+}

+ 348 - 0
uni_modules/uni-swipe-action/components/uni-swipe-action-item/uni-swipe-action-item.vue

@@ -0,0 +1,348 @@
+<template>
+	<!-- 在微信小程序 app vue端 h5 使用wxs 实现-->
+	<!-- #ifdef APP-VUE || MP-WEIXIN || H5 -->
+	<view class="uni-swipe">
+		<!--  #ifdef MP-WEIXIN || VUE3 -->
+		<view class="uni-swipe_box" :change:prop="wxsswipe.showWatch" :prop="is_show" :data-threshold="threshold"
+			:data-disabled="disabled" @touchstart="wxsswipe.touchstart" @touchmove="wxsswipe.touchmove"
+			@touchend="wxsswipe.touchend">
+		<!-- #endif -->
+			<!--  #ifndef MP-WEIXIN || VUE3 -->
+			<view class="uni-swipe_box" :change:prop="renderswipe.showWatch" :prop="is_show" :data-threshold="threshold"
+				:data-disabled="disabled+''" @touchstart="renderswipe.touchstart" @touchmove="renderswipe.touchmove"
+				@touchend="renderswipe.touchend">
+			<!-- #endif -->
+				<!-- 在微信小程序 app vue端 h5 使用wxs 实现-->
+				<view class="uni-swipe_button-group button-group--left">
+					<slot name="left">
+						<view v-for="(item,index) in leftOptions" :key="index" :style="{
+					  backgroundColor: item.style && item.style.backgroundColor ? item.style.backgroundColor : '#C7C6CD'
+					}" class="uni-swipe_button button-hock" @touchstart.stop="appTouchStart"
+							@touchend.stop="appTouchEnd($event,index,item,'left')" @click.stop="onClickForPC(index,item,'left')">
+							<text class="uni-swipe_button-text"
+								:style="{color: item.style && item.style.color ? item.style.color : '#FFFFFF',fontSize: item.style && item.style.fontSize ? item.style.fontSize : '16px'}">{{ item.text }}</text>
+						</view>
+					</slot>
+				</view>
+				<view class="uni-swipe_text--center">
+					<slot></slot>
+				</view>
+				<view class="uni-swipe_button-group button-group--right">
+					<slot name="right">
+						<view v-for="(item,index) in rightOptions" :key="index" :style="{
+					  backgroundColor: item.style && item.style.backgroundColor ? item.style.backgroundColor : '#C7C6CD'
+					}" class="uni-swipe_button button-hock" @touchstart.stop="appTouchStart"
+							@touchend.stop="appTouchEnd($event,index,item,'right')" @click.stop="onClickForPC(index,item,'right')"><text
+								class="uni-swipe_button-text"
+								:style="{color: item.style && item.style.color ? item.style.color : '#FFFFFF',fontSize: item.style && item.style.fontSize ? item.style.fontSize : '16px'}">{{ item.text }}</text>
+						</view>
+					</slot>
+				</view>
+			</view>
+		</view>
+		<!-- #endif -->
+		<!-- app nvue端 使用 bindingx -->
+		<!-- #ifdef APP-NVUE -->
+		<view ref="selector-box--hock" class="uni-swipe" @horizontalpan="touchstart" @touchend="touchend">
+			<view ref='selector-left-button--hock' class="uni-swipe_button-group button-group--left">
+				<slot name="left">
+					<view v-for="(item,index) in leftOptions" :key="index" :style="{
+				  backgroundColor: item.style && item.style.backgroundColor ? item.style.backgroundColor : '#C7C6CD'
+				}" class="uni-swipe_button button-hock" @click.stop="onClick(index,item,'left')">
+						<text class="uni-swipe_button-text"
+							:style="{color: item.style && item.style.color ? item.style.color : '#FFFFFF', fontSize: item.style && item.style.fontSize ? item.style.fontSize : '16px'}">
+							{{ item.text }}
+						</text>
+					</view>
+				</slot>
+			</view>
+			<view ref='selector-right-button--hock' class="uni-swipe_button-group button-group--right">
+				<slot name="right">
+					<view v-for="(item,index) in rightOptions" :key="index" :style="{
+				  backgroundColor: item.style && item.style.backgroundColor ? item.style.backgroundColor : '#C7C6CD'
+				}" class="uni-swipe_button button-hock" @click.stop="onClick(index,item,'right')"><text
+							class="uni-swipe_button-text"
+							:style="{color: item.style && item.style.color ? item.style.color : '#FFFFFF',fontSize: item.style && item.style.fontSize ? item.style.fontSize : '16px'}">{{ item.text }}</text>
+					</view>
+				</slot>
+			</view>
+			<view ref='selector-content--hock' class="uni-swipe_box">
+				<slot></slot>
+			</view>
+		</view>
+		<!-- #endif -->
+		<!-- 其他平台使用 js ,长列表性能可能会有影响-->
+		<!-- #ifdef MP-ALIPAY || MP-BAIDU || MP-TOUTIAO || MP-QQ -->
+		<view class="uni-swipe">
+			<view class="uni-swipe_box" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend"
+				:style="{transform:moveLeft}" :class="{ani:ani}">
+				<view class="uni-swipe_button-group button-group--left" :class="[elClass]">
+					<slot name="left">
+						<view v-for="(item,index) in leftOptions" :key="index" :style="{
+					  backgroundColor: item.style && item.style.backgroundColor ? item.style.backgroundColor : '#C7C6CD',
+					  fontSize: item.style && item.style.fontSize ? item.style.fontSize : '16px'
+					}" class="uni-swipe_button button-hock" @touchstart.stop="appTouchStart"
+							@touchend.stop="appTouchEnd($event,index,item,'left')"><text class="uni-swipe_button-text"
+								:style="{color: item.style && item.style.color ? item.style.color : '#FFFFFF',}">{{ item.text }}</text>
+						</view>
+					</slot>
+				</view>
+				<slot></slot>
+				<view class="uni-swipe_button-group button-group--right" :class="[elClass]">
+					<slot name="right">
+						<view v-for="(item,index) in rightOptions" :key="index" :style="{
+					  backgroundColor: item.style && item.style.backgroundColor ? item.style.backgroundColor : '#C7C6CD',
+					  fontSize: item.style && item.style.fontSize ? item.style.fontSize : '16px'
+					}" @touchstart.stop="appTouchStart" @touchend.stop="appTouchEnd($event,index,item,'right')"
+							class="uni-swipe_button button-hock"><text class="uni-swipe_button-text"
+								:style="{color: item.style && item.style.color ? item.style.color : '#FFFFFF',}">{{ item.text }}</text>
+						</view>
+					</slot>
+				</view>
+			</view>
+		</view>
+		<!-- #endif -->
+
+</template>
+<script src="./wx.wxs" module="wxsswipe" lang="wxs"></script>
+
+<script module="renderswipe" lang="renderjs">
+	import render from './render.js'
+	export default {
+		mounted(e, ins, owner) {
+			this.state = {}
+		},
+		methods: {
+			showWatch(newVal, oldVal, ownerInstance, instance) {
+				render.showWatch(newVal, oldVal, ownerInstance, instance, this)
+			},
+			touchstart(e, ownerInstance) {
+				render.touchstart(e, ownerInstance, this)
+			},
+			touchmove(e, ownerInstance) {
+				render.touchmove(e, ownerInstance, this)
+			},
+			touchend(e, ownerInstance) {
+				render.touchend(e, ownerInstance, this)
+			}
+		}
+	}
+</script>
+<script>
+	import mpwxs from './mpwxs'
+	import bindingx from './bindingx.js'
+	import mpother from './mpother'
+
+	/**
+	 * SwipeActionItem 滑动操作子组件
+	 * @description 通过滑动触发选项的容器
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=181
+	 * @property {Boolean} show = [left|right|none] 	开启关闭组件,auto-close = false 时生效
+	 * @property {Boolean} disabled = [true|false] 		是否禁止滑动
+	 * @property {Boolean} autoClose = [true|false] 	滑动打开当前组件,是否关闭其他组件
+	 * @property {Number}  threshold 					滑动缺省值
+	 * @property {Array} leftOptions 					左侧选项内容及样式
+	 * @property {Array} rgihtOptions 					右侧选项内容及样式
+	 * @event {Function} click 							点击选项按钮时触发事件,e = {content,index} ,content(点击内容)、index(下标)
+	 * @event {Function} change 						组件打开或关闭时触发,left\right\none
+	 */
+
+	export default {
+		mixins: [mpwxs, bindingx, mpother],
+		emits: ['click', 'change'],
+		props: {
+			// 控制开关
+			show: {
+				type: String,
+				default: 'none'
+			},
+
+			// 禁用
+			disabled: {
+				type: Boolean,
+				default: false
+			},
+
+			// 是否自动关闭
+			autoClose: {
+				type: Boolean,
+				default: true
+			},
+
+			// 滑动缺省距离
+			threshold: {
+				type: Number,
+				default: 20
+			},
+
+			// 左侧按钮内容
+			leftOptions: {
+				type: Array,
+				default () {
+					return []
+				}
+			},
+
+			// 右侧按钮内容
+			rightOptions: {
+				type: Array,
+				default () {
+					return []
+				}
+			}
+
+		},
+		// #ifndef VUE3
+		// TODO vue2
+		destroyed() {
+			if (this.__isUnmounted) return
+			this.uninstall()
+		},
+		// #endif
+		// #ifdef VUE3
+		// TODO vue3
+		unmounted() {
+			this.__isUnmounted = true
+			this.uninstall()
+		},
+		// #endif
+
+		methods: {
+			uninstall() {
+				if (this.swipeaction) {
+					this.swipeaction.children.forEach((item, index) => {
+						if (item === this) {
+							this.swipeaction.children.splice(index, 1)
+						}
+					})
+				}
+			},
+			/**
+			 * 获取父元素实例
+			 */
+			getSwipeAction(name = 'uniSwipeAction') {
+				let parent = this.$parent;
+				let parentName = parent.$options.name;
+				while (parentName !== name) {
+					parent = parent.$parent;
+					if (!parent) return false;
+					parentName = parent.$options.name;
+				}
+				return parent;
+			}
+		}
+	}
+</script>
+<style lang="scss">
+	.uni-swipe {
+		position: relative;
+		/* #ifndef APP-NVUE */
+		overflow: hidden;
+		/* #endif */
+	}
+
+	.uni-swipe_box {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		flex-shrink: 0;
+		// touch-action: none;
+		/* #endif */
+		position: relative;
+	}
+
+	.uni-swipe_content {
+		// border: 1px red solid;
+	}
+
+	.uni-swipe_text--center {
+		width: 100%;
+		/* #ifndef APP-NVUE */
+		cursor: grab;
+		/* #endif */
+	}
+
+	.uni-swipe_button-group {
+		/* #ifndef APP-NVUE */
+		box-sizing: border-box;
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		position: absolute;
+		top: 0;
+		bottom: 0;
+		/* #ifdef H5 */
+		cursor: pointer;
+		/* #endif */
+	}
+
+	.button-group--left {
+		left: 0;
+		transform: translateX(-100%)
+	}
+
+	.button-group--right {
+		right: 0;
+		transform: translateX(100%)
+	}
+
+	.uni-swipe_button {
+		/* #ifdef APP-NVUE */
+		flex: 1;
+		/* #endif */
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+		padding: 0 20px;
+	}
+
+	.uni-swipe_button-text {
+		/* #ifndef APP-NVUE */
+		flex-shrink: 0;
+		/* #endif */
+		font-size: 14px;
+	}
+
+	.ani {
+		transition-property: transform;
+		transition-duration: 0.3s;
+		transition-timing-function: cubic-bezier(0.165, 0.84, 0.44, 1);
+	}
+
+	/* #ifdef MP-ALIPAY */
+	.movable-area {
+		/* width: 100%; */
+		height: 45px;
+	}
+
+	.movable-view {
+		display: flex;
+		/* justify-content: center; */
+		position: relative;
+		flex: 1;
+		height: 45px;
+		z-index: 2;
+	}
+
+	.movable-view-button {
+		display: flex;
+		flex-shrink: 0;
+		flex-direction: row;
+		height: 100%;
+		background: #C0C0C0;
+	}
+
+	/* .transition {
+		transition: all 0.3s;
+	} */
+
+	.movable-view-box {
+		flex-shrink: 0;
+		height: 100%;
+		background-color: #fff;
+	}
+
+	/* #endif */
+</style>

+ 341 - 0
uni_modules/uni-swipe-action/components/uni-swipe-action-item/wx.wxs

@@ -0,0 +1,341 @@
+var MIN_DISTANCE = 10;
+
+/**
+ * 判断当前是否为H5、app-vue
+ */
+var IS_HTML5 = false
+if (typeof window === 'object') IS_HTML5 = true
+
+/**
+ * 监听页面内值的变化,主要用于动态开关swipe-action
+ * @param {Object} newValue
+ * @param {Object} oldValue
+ * @param {Object} ownerInstance
+ * @param {Object} instance
+ */
+function showWatch(newVal, oldVal, ownerInstance, instance) {
+	var state = instance.getState()
+	getDom(instance, ownerInstance)
+	if (newVal && newVal !== 'none') {
+		openState(newVal, instance, ownerInstance)
+		return
+	}
+
+	if (state.left) {
+		openState('none', instance, ownerInstance)
+	}
+	resetTouchStatus(instance)
+}
+
+/**
+ * 开始触摸操作
+ * @param {Object} e
+ * @param {Object} ins
+ */
+function touchstart(e, ownerInstance) {
+	var instance = e.instance;
+	var disabled = instance.getDataset().disabled
+	var state = instance.getState();
+	getDom(instance, ownerInstance)
+	// fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复
+	disabled = (typeof(disabled) === 'string' ? JSON.parse(disabled) : disabled) || false;
+	if (disabled) return
+	// 开始触摸时移除动画类
+	instance.requestAnimationFrame(function() {
+		instance.removeClass('ani');
+		ownerInstance.callMethod('closeSwipe');
+	})
+
+	// 记录上次的位置
+	state.x = state.left || 0
+	// 计算滑动开始位置
+	stopTouchStart(e, ownerInstance)
+}
+
+/**
+ * 开始滑动操作
+ * @param {Object} e
+ * @param {Object} ownerInstance
+ */
+function touchmove(e, ownerInstance) {
+	var instance = e.instance;
+	var disabled = instance.getDataset().disabled
+	var state = instance.getState()
+	// fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复
+	disabled = (typeof(disabled) === 'string' ? JSON.parse(disabled) : disabled) || false;
+	if (disabled) return
+	// 是否可以滑动页面
+	stopTouchMove(e);
+	if (state.direction !== 'horizontal') {
+		return;
+	}
+
+	if (e.preventDefault) {
+		// 阻止页面滚动
+		e.preventDefault()
+	}
+
+	move(state.x + state.deltaX, instance, ownerInstance)
+}
+
+/**
+ * 结束触摸操作
+ * @param {Object} e
+ * @param {Object} ownerInstance
+ */
+function touchend(e, ownerInstance) {
+	var instance = e.instance;
+	var disabled = instance.getDataset().disabled
+	var state = instance.getState()
+	// fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复
+	disabled = (typeof(disabled) === 'string' ? JSON.parse(disabled) : disabled) || false;
+
+	if (disabled) return
+	// 滑动过程中触摸结束,通过阙值判断是开启还是关闭
+	// fixed by mehaotian 定时器解决点击按钮,touchend 触发比 click 事件时机早的问题 ,主要是 ios13
+	moveDirection(state.left, instance, ownerInstance)
+
+}
+
+/**
+ * 设置移动距离
+ * @param {Object} value
+ * @param {Object} instance
+ * @param {Object} ownerInstance
+ */
+function move(value, instance, ownerInstance) {
+	value = value || 0
+	var state = instance.getState()
+	var leftWidth = state.leftWidth
+	var rightWidth = state.rightWidth
+	// 获取可滑动范围
+	state.left = range(value, -rightWidth, leftWidth);
+	instance.requestAnimationFrame(function() {
+		instance.setStyle({
+			transform: 'translateX(' + state.left + 'px)',
+			'-webkit-transform': 'translateX(' + state.left + 'px)'
+		})
+	})
+
+}
+
+/**
+ * 获取元素信息
+ * @param {Object} instance
+ * @param {Object} ownerInstance
+ */
+function getDom(instance, ownerInstance) {
+	var state = instance.getState()
+	var leftDom = ownerInstance.selectComponent('.button-group--left')
+	var rightDom = ownerInstance.selectComponent('.button-group--right')
+	var leftStyles = {
+		width: 0
+	}
+	var rightStyles = {
+		width: 0
+	}
+	leftStyles = leftDom.getBoundingClientRect()
+	rightStyles = rightDom.getBoundingClientRect()
+
+	state.leftWidth = leftStyles.width || 0
+	state.rightWidth = rightStyles.width || 0
+	state.threshold = instance.getDataset().threshold
+}
+
+/**
+ * 获取范围
+ * @param {Object} num
+ * @param {Object} min
+ * @param {Object} max
+ */
+function range(num, min, max) {
+	return Math.min(Math.max(num, min), max);
+}
+
+
+/**
+ * 移动方向判断
+ * @param {Object} left
+ * @param {Object} value
+ * @param {Object} ownerInstance
+ * @param {Object} ins
+ */
+function moveDirection(left, ins, ownerInstance) {
+	var state = ins.getState()
+	var threshold = state.threshold
+	var position = state.position
+	var isopen = state.isopen || 'none'
+	var leftWidth = state.leftWidth
+	var rightWidth = state.rightWidth
+	if (state.deltaX === 0) {
+		openState('none', ins, ownerInstance)
+		return
+	}
+	if ((isopen === 'none' && rightWidth > 0 && -left > threshold) || (isopen !== 'none' && rightWidth > 0 &&
+			rightWidth +
+			left < threshold)) {
+		// right
+		openState('right', ins, ownerInstance)
+	} else if ((isopen === 'none' && leftWidth > 0 && left > threshold) || (isopen !== 'none' && leftWidth > 0 &&
+			leftWidth - left < threshold)) {
+		// left
+		openState('left', ins, ownerInstance)
+	} else {
+		// default
+		openState('none', ins, ownerInstance)
+	}
+}
+
+
+/**
+ * 开启状态
+ * @param {Boolean} type
+ * @param {Object} ins
+ * @param {Object} ownerInstance
+ */
+function openState(type, ins, ownerInstance) {
+	var state = ins.getState()
+	var leftWidth = state.leftWidth
+	var rightWidth = state.rightWidth
+	var left = ''
+	state.isopen = state.isopen ? state.isopen : 'none'
+	switch (type) {
+		case "left":
+			left = leftWidth
+			break
+		case "right":
+			left = -rightWidth
+			break
+		default:
+			left = 0
+	}
+
+	// && !state.throttle
+
+	if (state.isopen !== type) {
+		state.throttle = true
+		ownerInstance.callMethod('change', {
+			open: type
+		})
+
+	}
+
+	state.isopen = type
+	// 添加动画类
+	ins.requestAnimationFrame(function() {
+		ins.addClass('ani');
+		move(left, ins, ownerInstance)
+	})
+	// 设置最终移动位置,理论上只要进入到这个函数,肯定是要打开的
+}
+
+
+function getDirection(x, y) {
+	if (x > y && x > MIN_DISTANCE) {
+		return 'horizontal';
+	}
+	if (y > x && y > MIN_DISTANCE) {
+		return 'vertical';
+	}
+	return '';
+}
+
+/**
+ * 重置滑动状态
+ * @param {Object} event
+ */
+function resetTouchStatus(instance) {
+	var state = instance.getState();
+	state.direction = '';
+	state.deltaX = 0;
+	state.deltaY = 0;
+	state.offsetX = 0;
+	state.offsetY = 0;
+}
+
+/**
+ * 设置滑动开始位置
+ * @param {Object} event
+ */
+function stopTouchStart(event) {
+	var instance = event.instance;
+	var state = instance.getState();
+	resetTouchStatus(instance);
+	var touch = event.touches[0];
+	if (IS_HTML5 && isPC()) {
+		touch = event;
+	}
+	state.startX = touch.clientX;
+	state.startY = touch.clientY;
+}
+
+/**
+ * 滑动中,是否禁止打开
+ * @param {Object} event
+ */
+function stopTouchMove(event) {
+	var instance = event.instance;
+	var state = instance.getState();
+	var touch = event.touches[0];
+	if (IS_HTML5 && isPC()) {
+		touch = event;
+	}
+	state.deltaX = touch.clientX - state.startX;
+	state.deltaY = touch.clientY - state.startY;
+	state.offsetY = Math.abs(state.deltaY);
+	state.offsetX = Math.abs(state.deltaX);
+	state.direction = state.direction || getDirection(state.offsetX, state.offsetY);
+}
+
+function isPC() {
+	var userAgentInfo = navigator.userAgent;
+	var Agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
+	var flag = true;
+	for (var v = 0; v < Agents.length - 1; v++) {
+		if (userAgentInfo.indexOf(Agents[v]) > 0) {
+			flag = false;
+			break;
+		}
+	}
+	return flag;
+}
+
+var movable = false
+
+function mousedown(e, ins) {
+	if (!IS_HTML5) return
+	if (!isPC()) return
+	touchstart(e, ins)
+	movable = true
+}
+
+function mousemove(e, ins) {
+	if (!IS_HTML5) return
+	if (!isPC()) return
+	if (!movable) return
+	touchmove(e, ins)
+}
+
+function mouseup(e, ins) {
+	if (!IS_HTML5) return
+	if (!isPC()) return
+	touchend(e, ins)
+	movable = false
+}
+
+function mouseleave(e, ins) {
+	if (!IS_HTML5) return
+	if (!isPC()) return
+	movable = false
+}
+
+module.exports = {
+	showWatch: showWatch,
+	touchstart: touchstart,
+	touchmove: touchmove,
+	touchend: touchend,
+	mousedown: mousedown,
+	mousemove: mousemove,
+	mouseup: mouseup,
+	mouseleave: mouseleave
+}

+ 60 - 0
uni_modules/uni-swipe-action/components/uni-swipe-action/uni-swipe-action.vue

@@ -0,0 +1,60 @@
+<template>
+	<view>
+		<slot></slot>
+	</view>
+</template>
+
+<script>
+	/**
+	 * SwipeAction 滑动操作
+	 * @description 通过滑动触发选项的容器
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=181
+	 */
+	export default {
+		name:"uniSwipeAction",
+		data() {
+			return {};
+		},
+		created() {
+			this.children = [];
+		},
+		methods: {
+			// 公开给用户使用,重制组件样式
+			resize(){
+				// wxs 会自己计算组件大小,所以无需执行下面代码
+				// #ifndef APP-VUE || H5 || MP-WEIXIN
+				this.children.forEach(vm=>{
+					vm.init()
+				})
+				// #endif
+			},
+			// 公开给用户使用,关闭全部 已经打开的组件
+			closeAll(){
+				this.children.forEach(vm=>{
+					// #ifdef APP-VUE || H5 || MP-WEIXIN
+					vm.is_show = 'none'
+					// #endif
+
+					// #ifndef APP-VUE || H5 || MP-WEIXIN
+					vm.close()
+					// #endif
+				})
+			},
+			closeOther(vm) {
+				if (this.openItem && this.openItem !== vm) {
+					// #ifdef APP-VUE || H5 || MP-WEIXIN
+					this.openItem.is_show = 'none'
+					// #endif
+
+					// #ifndef APP-VUE || H5 || MP-WEIXIN
+					this.openItem.close()
+					// #endif
+				}
+				// 记录上一个打开的 swipe-action-item ,用于 auto-close
+				this.openItem = vm
+			}
+		}
+	};
+</script>
+
+<style></style>

+ 84 - 0
uni_modules/uni-swipe-action/package.json

@@ -0,0 +1,84 @@
+{
+	"id": "uni-swipe-action",
+	"displayName": "uni-swipe-action 滑动操作",
+	"version": "1.3.10",
+	"description": "SwipeAction 滑动操作操作组件",
+	"keywords": [
+        "",
+        "uni-ui",
+        "uniui",
+        "滑动删除",
+        "侧滑删除"
+    ],
+	"repository": "https://github.com/dcloudio/uni-ui",
+	"engines": {
+		"HBuilderX": ""
+	},
+	"directories": {
+		"example": "../../temps/example_temps"
+	},
+    "dcloudext": {
+        "sale": {
+			"regular": {
+				"price": "0.00"
+			},
+			"sourcecode": {
+				"price": "0.00"
+			}
+		},
+		"contact": {
+			"qq": ""
+		},
+		"declaration": {
+			"ads": "无",
+			"data": "无",
+			"permissions": "无"
+		},
+        "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
+        "type": "component-vue"
+	},
+	"uni_modules": {
+		"dependencies": ["uni-scss"],
+		"encrypt": [],
+		"platforms": {
+			"cloud": {
+				"tcb": "y",
+				"aliyun": "y"
+			},
+			"client": {
+				"App": {
+					"app-vue": "y",
+					"app-nvue": "y"
+				},
+				"H5-mobile": {
+					"Safari": "y",
+					"Android Browser": "y",
+					"微信浏览器(Android)": "y",
+					"QQ浏览器(Android)": "y"
+				},
+				"H5-pc": {
+					"Chrome": "y",
+					"IE": "y",
+					"Edge": "y",
+					"Firefox": "y",
+					"Safari": "y"
+				},
+				"小程序": {
+					"微信": "y",
+					"阿里": "y",
+					"百度": "y",
+					"字节跳动": "y",
+					"QQ": "y"
+				},
+				"快应用": {
+					"华为": "y",
+					"联盟": "u"
+				},
+				"Vue": {
+					"vue2": "y",
+					"vue3": "y"
+				}
+			}
+		}
+	}
+}

+ 11 - 0
uni_modules/uni-swipe-action/readme.md

@@ -0,0 +1,11 @@
+
+
+## SwipeAction 滑动操作
+> **组件名:uni-swipe-action**
+> 代码块: `uSwipeAction`、`uSwipeActionItem`
+
+
+通过滑动触发选项的容器
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-swipe-action)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839