Przeglądaj źródła

feat: 图库支持左右滑动

小莫唐尼 8 miesięcy temu
rodzic
commit
4611932ad8

+ 81 - 37
pages/tabbar/gallery/gallery.vue

@@ -3,44 +3,50 @@
         <!-- 顶部切换 -->
         <view class="e-fixed" v-if="category.list.length > 0">
             <tm-tabs color="light-blue" :shadow="0" v-model="category.activeIndex" range-key="displayName" :list="category.list"
-                     align="left" @change="fnOnCategoryChange"></tm-tabs>
+                     align="left" @change="fnOnCategoryChange($event, false)"></tm-tabs>
         </view>
         <!-- 占位区域 -->
         <view v-if="category.list.length > 0" style="width: 100vw;height: 90rpx;"></view>
         <!-- 加载区域 -->
-        <view v-if="loading !== 'success'" class="loading-wrap">
+        <view v-if="loading == 'loading'" class="loading-wrap">
             <tm-skeleton model="card"></tm-skeleton>
             <tm-skeleton model="card"></tm-skeleton>
             <tm-skeleton model="card"></tm-skeleton>
             <tm-skeleton model="card"></tm-skeleton>
         </view>
+		<view v-else-if="loading == 'error'" class="flex flex-col flex-center" style="width:100%;height:60vh;">
+			<tm-empty icon="icon-wind-cry" label="阿偶,似乎获取数据失败了~">
+				<tm-button theme="light-blue" size="m" :shadow="0" @click="fnGetData(true)">刷新试试</tm-button>
+			</tm-empty>
+		</view>	
         <!-- 内容区域 -->
-        <view class="content" v-else>
-            <view v-if="dataList.length === 0" class="content-empty">
-                <!-- 空布局 -->
-                <tm-empty icon="icon-shiliangzhinengduixiang-" label="博主还没有分享图片~"></tm-empty>
-            </view>
-            <block v-else>
-                <block v-if="galleryConfig.useWaterfall">
-                    <!--瀑布流-->
-                    <tm-flowLayout-custom ref="wafll" style="width: 100%;" @click="fnOnFlowClick"></tm-flowLayout-custom>
-                </block>
-                <!--   列表   -->
-                <block v-else>
-                    <tm-translate v-for="(item, index) in dataList" :key="index"
-                                  style="box-sizing: border-box;padding: 6rpx;width: 50%;height: 250rpx;"
-                                  animation-name="fadeUp" :wait="calcAniWait(index)">
-                        <view style="border-radius: 12rpx;overflow: hidden;width: 100%;height: 250rpx;">
-                            <image style="width: 100%;height: 100%;" mode="aspectFill" :src="item.spec.url"
-                                   @click="fnPreview(item)"/>
-                        </view>
-                    </tm-translate>
-                </block>
-
-                <tm-flotbutton @click="fnToTopPage" color="light-blue" size="m" icon="icon-angle-up"></tm-flotbutton>
-                <view class="load-text">{{ loadMoreText }}</view>
-            </block>
+        <view v-else class="content">
+			<k-touch-listen @touchLeft="touchLeft" @touchRight="touchRight">
+				<view v-if="dataList.length === 0" class="content-empty">
+					<!-- 空布局 -->
+					<tm-empty icon="icon-shiliangzhinengduixiang-" label="博主还没有分享图片~"></tm-empty>
+				</view>
+				<block v-else>
+					<block v-if="galleryConfig.useWaterfall">
+						<!--瀑布流-->
+						<tm-flowLayout-custom ref="wafll" style="width: 100%;" @click="fnOnFlowClick"></tm-flowLayout-custom>
+					</block>
+					<!--   列表   -->
+					<block v-else>
+						<tm-translate v-for="(item, index) in dataList" :key="index"
+									  style="box-sizing: border-box;padding: 6rpx;width: 50%;height: 250rpx;"
+									  animation-name="fadeUp" :wait="calcAniWait(index)">
+							<view style="border-radius: 12rpx;overflow: hidden;width: 100%;height: 250rpx;">
+								<image style="width: 100%;height: 100%;" mode="aspectFill" :src="item.spec.url"
+									   @click="fnPreview(item)"/>
+							</view>
+						</tm-translate>
+					</block>
 
+					<tm-flotbutton @click="fnToTopPage" color="light-blue" size="m" icon="icon-angle-up"></tm-flotbutton>
+					<view class="load-text">{{ loadMoreText }}</view>
+				</block>
+			</k-touch-listen>
         </view>
     </view>
 </template>
@@ -55,6 +61,7 @@ import tmIcons from '@/tm-vuetify/components/tm-icons/tm-icons.vue';
 import tmImages from '@/tm-vuetify/components/tm-images/tm-images.vue';
 import tmFlowLayoutCustom from '@/tm-vuetify/components/tm-flowLayout-custom/tm-flowLayout-custom.vue';
 import tmTabs from '@/tm-vuetify/components/tm-tabs/tm-tabs.vue';
+import tmButton from '@/tm-vuetify/components/tm-button/tm-button.vue';
 
 export default {
     options: {
@@ -69,7 +76,8 @@ export default {
         tmIcons,
         tmImages,
         tmFlowLayoutCustom,
-        tmTabs
+        tmTabs,
+		tmButton
     },
     data() {
         return {
@@ -88,7 +96,8 @@ export default {
             isLoadMore: false,
             loadMoreText: '',
             hasNext: false,
-            dataList: []
+            dataList: [],
+			lock:false
         };
     },
     computed: {
@@ -142,13 +151,23 @@ export default {
         }
     },
     methods: {
+		fnGetDataByCategory(index){
+			this.fnResetSetAniWaitIndex();
+			this.queryParams.group = this.category.list[index].name;
+			this.queryParams.page = 1;
+			this.fnToTopPage();
+			this.dataList = [];
+			this.fnGetData(true);
+		},
         fnOnCategoryChange(index) {
-            this.fnResetSetAniWaitIndex();
-            this.queryParams.group = this.category.list[index].name;
-            this.queryParams.page = 1;
-            this.fnToTopPage();
-            this.dataList = [];
-            this.fnGetData(true);
+			if(this.lock) {
+				// uni.showToast({
+				// 	title: "上一个请求进行中...",
+				// 	icon: "none"
+				// })
+				return;
+			}
+			this.fnGetDataByCategory(index)
         },
         fnGetCategory() {
             if (this.calcAuditModeEnabled) {
@@ -171,7 +190,12 @@ export default {
                     this.queryParams.group = this.category.list[0].name;
                     this.fnGetData(true);
                 }
-            });
+            }).catch(e=>{
+				this.loading = 'error'
+				this.category.list = []
+				this.category.activeIndex = 0
+				this.category.activeValue = ""
+			});
         },
         fnGetData(isClearWaterfall = false) {
             if (this.calcAuditModeEnabled) {
@@ -201,6 +225,7 @@ export default {
                 this.loadMoreText = '呜呜,没有更多数据啦~';
                 uni.hideLoading();
                 uni.stopPullDownRefresh();
+				this.lock = false;
                 return;
             }
 
@@ -244,6 +269,7 @@ export default {
                     setTimeout(() => {
                         uni.hideLoading();
                         uni.stopPullDownRefresh();
+						this.lock = false;
                     }, 500);
                 });
         },
@@ -258,7 +284,25 @@ export default {
                 indicator: 'number',
                 loop: true
             });
-        }
+        },
+		touchLeft(){
+			if(this.loading != "success") return; 
+			this.category.activeIndex += 1
+			if(this.category.activeIndex >= this.category.list.length){
+				this.category.activeIndex = 0
+			}
+			this.lock = true
+			this.fnGetDataByCategory(this.category.activeIndex)
+		},
+		touchRight(){
+			if(this.loading != "success") return;
+			this.category.activeIndex -= 1
+			if(this.category.activeIndex < 0){
+				this.category.activeIndex = 0
+			}
+			this.lock = true
+			this.fnGetDataByCategory(this.category.activeIndex)
+		} 
     }
 };
 </script>

+ 0 - 4
tm-vuetify/components/tm-flowLayout-custom/tm-flowLayout-custom.vue

@@ -100,8 +100,6 @@ export default {
         },
         //向列表添加数据
         pushData(list) {
-            console.log('添加图片数据----------',list)
-
             let prIdx_i = this.list2.length;
             if (!Array.isArray(list) || typeof list == 'undefined') {
                 return false;
@@ -122,8 +120,6 @@ export default {
             return this.dataList;
         },
         async loadimg(event, isLoad, index) {
-            console.log('图片加载事件----------',event)
-
             this.isLoading = true;
             let ps = this.list2[index];
             ps.isLoad = true;

+ 18 - 0
uni_modules/k-touch-listen/changelog.md

@@ -0,0 +1,18 @@
+## 1.0.2(2023-09-14)
+更新使用文档:
+引入本插件 然后使用,手动滑稽,教程简单吗?
+<k-touch-listen @touchUp="touchUp" @touchDown="touchDown" @touchLeft="touchLeft" @touchRight="touchRight">
+  <view>
+   //您需要监听的区域的代码
+  </view>
+</k-touch-listen>
+## 1.0.1(2023-09-14)
+更新使用文档:
+引入本插件 然后使用,手动滑稽,教程简单吗?
+<k-touch-listen @touchUp="touchUp" @touchDown="touchDown" @touchLeft="touchLeft" @touchRight="touchRight">
+  <view>
+   //您需要监听的区域的代码
+  </view>
+</k-touch-listen>
+## 1.0.0(2023-09-14)
+首次提交

+ 113 - 0
uni_modules/k-touch-listen/components/k-touch-listen/k-touch-listen.vue

@@ -0,0 +1,113 @@
+<template>
+	<view class="touch-box" @touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd">
+		<slot></slot>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'k-touch-listen',
+		data() {
+			return {
+				touchStartX: 0, // 触摸时的原点
+				touchStartY: 0, // 触摸时的原点
+				time: 0, // 时间记录,用于滑动时且时间小于1s则执行左右滑动
+				interval: '', // 记录/清理时间记录
+				touchMoveX: 0, // x轴方向移动的距离
+				touchMoveY: 0, // y轴方向移动的距离
+				touchMoveTag: false // 定义滑动状态
+			}
+		},
+		props: {
+			direction: {
+				type: String,
+				default: 'all'
+			},
+			distance: {
+				type: [String, Number],
+				default: 30
+			}
+		},
+		emits: ['touchUp', 'touchDown', 'touchLeft', 'touchRight'],
+		methods: {
+			// 触摸开始事件
+			touchStart(e) {
+				this.touchStartX = e.touches[0].pageX // 获取触摸时的原点
+				this.touchStartY = e.touches[0].pageY // 获取触摸时的原点
+				// 使用js计时器记录时间
+				this.interval = setInterval(() => {
+					this.time++
+				}, 100)
+			},
+			// 触摸移动事件
+			touchMove(e) {
+				this.touchMoveTag = true
+				this.touchMoveX = e.touches[0].pageX
+				this.touchMoveY = e.touches[0].pageY
+			},
+			ressetData() {
+				this.touchStartX = 0 // 触摸时的原点
+				this.touchStartY = 0 // 触摸时的原点
+				this.time = 0 // 时间记录,用于滑动时且时间小于1s则执行左右滑动
+				this.interval = '' // 记录/清理时间记录
+				this.touchMoveX = 0 // x轴方向移动的距离
+				this.touchMoveY = 0 // y轴方向移动的距离
+				this.touchMoveTag = false // 定义滑动状态
+			},
+			// 触摸结束事件
+			touchEnd(e) {
+				let moveX = this.touchMoveX - this.touchStartX
+				let moveY = this.touchMoveY - this.touchStartY
+				if (Math.sign(moveX) == -1) {
+					moveX *= -1
+				}
+				if (Math.sign(moveY) == -1) {
+					moveY *= -1
+				}
+				if (2 * moveX <= moveY && this.touchMoveTag) {
+					// 上下
+					if (this.direction != 'all' && this.direction != 'vertical') return
+					// 向上滑动
+					if (
+						this.touchMoveY - this.touchStartY <= -this.distance &&
+						this.time < 10
+					) {
+						this.$emit('touchUp')
+					}
+					// 向下滑动
+					if (
+						this.touchMoveY - this.touchStartY >= this.distance &&
+						this.time < 10
+					) {
+						this.$emit('touchDown')
+					}
+				} else if (moveX > 2 * moveY && this.touchMoveTag) {
+					// 左右
+					if (this.direction != 'all' && this.direction != 'horizontal') return
+					// 向左滑动
+					if (
+						this.touchMoveX - this.touchStartX <= -this.distance &&
+						this.time < 10
+					) {
+						this.$emit('touchLeft')
+					}
+					// 向右滑动
+					if (
+						this.touchMoveX - this.touchStartX >= this.distance &&
+						this.time < 10
+					) {
+						this.$emit('touchRight')
+					}
+				}
+				clearInterval(this.interval) // 清除setInterval
+				this.ressetData()
+			}
+		}
+	}
+</script>
+<style scoped>
+	.touch-box {
+		width: 100%;
+		height: 100%;
+	}
+</style>

+ 85 - 0
uni_modules/k-touch-listen/package.json

@@ -0,0 +1,85 @@
+{
+	"id": "k-touch-listen",
+	"displayName": "k-touch-listen 手势监听  全面兼容小程序、vue2、vue3等多端",
+	"version": "1.0.2",
+	"description": "用于监听用户滑动手势,左滑右滑,上滑下滑等一系列手势监听",
+	"keywords": [
+        "touch",
+        "手势",
+        "手势监听",
+        "手势监听",
+        "vue3"
+    ],
+	"repository": "",
+	"engines": {
+		"HBuilderX": "^3.7.6"
+	},
+	"dcloudext": {
+		"type": "component-vue",
+		"sale": {
+			"regular": {
+				"price": "0.00"
+			},
+			"sourcecode": {
+				"price": "0.00"
+			}
+		},
+		"contact": {
+			"qq": ""
+		},
+		"declaration": {
+			"ads": "无",
+			"data": "插件不采集任何数据",
+			"permissions": "无"
+		},
+		"npmurl": ""
+	},
+	"uni_modules": {
+		"dependencies": [],
+		"encrypt": [],
+		"platforms": {
+			"cloud": {
+				"tcb": "y",
+				"aliyun": "y"
+			},
+			"client": {
+				"Vue": {
+					"vue2": "y",
+					"vue3": "y"
+				},
+				"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",
+					"飞书": "u",
+					"京东": "u"
+				},
+				"快应用": {
+					"华为": "u",
+					"联盟": "u"
+				}
+			}
+		}
+	}
+}