Bladeren bron

添加聊天列表 滑动删除组件

wly 1 week geleden
bovenliggende
commit
b53e3dc923

+ 20 - 6
pages/chat/message.scss

@@ -118,12 +118,26 @@ page {
 
 		.list {
 			padding: 35rpx 30rpx;
-		padding-top:80rpx;
+			padding-top:80rpx;
 			
+			.list-content{
+				height: 130rpx;
+				display: flex;
+				align-items: center;
+				border-bottom: 2rpx solid #ebebeb;
+				position: relative;
+			}
+			.list-content:before{
+				content:'';
+				width: 120rpx;
+				height: 10rpx;
+				background-color: #161616;
+				position: absolute;
+				bottom: -6rpx;
+			}
 			.item {
 				display: flex;
-				margin-bottom: 32rpx;
-
+				margin-right: 20rpx;
 				.avatar {
 					position: relative;
 					width: 90rpx;
@@ -181,8 +195,8 @@ page {
 
 				.content {
 					display: flex;
-					padding-bottom: 25rpx;
-					border-bottom: 2rpx solid #ebebeb;
+					// padding-bottom: 25rpx;
+					// border-bottom: 2rpx solid #ebebeb;
 					flex: 1;
 
 					.info {
@@ -258,7 +272,7 @@ page {
 	}
 }
 	.PopMain {
-		padding: 4rpx 50rpx;
+		// padding: 4rpx 50rpx;
 		line-height: 80rpx;
 		text-align: center;
 		color: #8e8e8e;

+ 71 - 44
pages/chat/message.vue

@@ -60,61 +60,69 @@
 		</view>
 		<block v-if="tab == 0">
 			<view class="list">
-				<view class="item" v-for="(item, index) in list" :key="index" @tap="navigateToChatDetail(item)"
-					@longtap="deletec(item.conversationID)">
-					<template v-if="item.type=='GROUP' || item.type=='C2C'">
-						<!-- 头像 -->
-						<view class="avatar">
-							<template v-if="item.type=='GROUP'">
-								<!-- <view class="avatorImg">{{item.groupProfile.ava_name}}</view> -->
-								<image lazy-load="true" :src="item.groupProfile.avator" mode="aspectFill" />
-							</template>
-							<template v-else>
-								<view v-if="false" class="avatorImg2">{{item.userProfile.ava_name}}</view>
-								<image lazy-load="true" :src="item.userProfile.avator" mode="aspectFill" />
-							</template>
-							<view class="number" v-if="item.unreadCount!=0">{{ item.unreadCount }}</view>
-						</view>
+				<view v-for="(item, index) in list" :key="item.conversationID" class="list-content">
+					<next-swipe-action :btnGroup="btnGroup" :index="item.conversationID" @btnClick="onclick" @nextSwipeActive="nextSwipeActive"  :activeKey="activeKey">
+						<view class="item" @tap="navigateToChatDetail(item)">
+							<template v-if="item.type=='GROUP' || item.type=='C2C'">
+								<!-- 头像 -->
+								<view class="avatar">
+									<template v-if="item.type=='GROUP'">
+										<!-- <view class="avatorImg">{{item.groupProfile.ava_name}}</view> -->
+										<image lazy-load="true" :src="item.groupProfile.avator" mode="aspectFill" />
+									</template>
+									<template v-else>
+										<view v-if="false" class="avatorImg2">{{item.userProfile.ava_name}}</view>
+										<image lazy-load="true" :src="item.userProfile.avator" mode="aspectFill" />
+									</template>
+									<view class="number" v-if="item.unreadCount!=0">{{ item.unreadCount }}</view>
+								</view>
 
-						<view class="content">
-							<view class="info">
-								<template v-if="item.type=='GROUP'">
-									<text class="name">{{ item.groupProfile.name }}</text>
-								</template>
-								<template v-else>
-									<text class="name">{{ item.userProfile.nick }}</text>
-								</template>
+								<view class="content">
+									<view class="info">
+										<template v-if="item.type=='GROUP'">
+											<text class="name">{{ item.groupProfile.name }}</text>
+										</template>
+										<template v-else>
+											<text class="name">{{ item.userProfile.nick }}</text>
+										</template>
 
-								<text class="last">{{ item.lastMessage.messageForShow }}</text>
-							</view>
-							<text class="time">
-								{{ item.lastMessage.lastTimeFormat }}
-							</text>
+										<text class="last">{{ item.lastMessage.messageForShow }}</text>
+									</view>
+									<text class="time">
+										{{ item.lastMessage.lastTimeFormat }}
+									</text>
+								</view>
+							</template>
 						</view>
-					</template>
+					</next-swipe-action>
 				</view>
+
 			</view>
 			<view style="height:100rpx;"></view>
 
 		</block>
 		<block v-if="tab == 3">
-			<view class="listSys">
-				<view class="item" v-for="(item, index) in sysmsg_list" :key="index">
-					<view class="img">
-						<view class="bg">
-							<image class="icon" mode="widthFix" src="../../static/icon/icon_msg.png"></image>
-						</view>
 
-					</view>
-					<view class="content">
-						<view class="title">
-							{{item.content}}
+			<view class="listSys">
+				<block v-for="(item, index) in sysmsg_list" :key="index">
+					<next-swipe-action :btnGroup="btnGroup" :index="index" @btnClick="onclick">
+						<view class="item">
+							<view class="img">
+								<view class="bg">
+									<image class="icon" mode="widthFix" src="../../static/icon/icon_msg.png"></image>
+								</view>
+							</view>
+							<view class="content">
+								<view class="title">
+									{{item.content}}
+								</view>
+								<text class="time">
+									{{item.create_time}}
+								</text>
+							</view>
 						</view>
-						<text class="time">
-							{{item.create_time}}
-						</text>
-					</view>
-				</view>
+					</next-swipe-action>
+				</block>
 			</view>
 		</block>
 
@@ -161,6 +169,16 @@
 				showMore: false,
 				sysmsg_list: [],
 				conversationID: '',
+				activeKey:'',
+				btnGroup: [
+					{
+						name: '删除',
+						action: 'del',
+						style: {
+							bgColor: '#ff4d4f'
+						}
+					}
+				]
 			};
 		},
 		onLoad(params) {
@@ -191,6 +209,15 @@
 			this.loadSystemMsg();
 		},
 		methods: {
+			nextSwipeActive(activeKey){
+				console.log(activeKey,'activeKeyactiveKey');
+				this.activeKey = activeKey
+			},
+			onclick(e) {
+				// this.deletec(e.index)
+				console.log('所点击的列表索引:', e.index)
+				console.log('所点击的按钮数据:', e.item)
+			},
 			deletec(conversationID) {
 				this.conversationID = conversationID;
 				console.log("conversationID", conversationID);

+ 4 - 0
uni_modules/next-swipe-action/changelog.md

@@ -0,0 +1,4 @@
+## 1.0.1(2024-09-14)
+更新说明
+## 1.0.0(2023-11-22)
+组件初始化

+ 194 - 0
uni_modules/next-swipe-action/components/next-swipe-action/next-swipe-action.vue

@@ -0,0 +1,194 @@
+<template>
+	<view class="next-slide" :class="{'next-slide-disabled': disabled}">
+		<view class="next-slide-left" :style="'position: relative;left:'+left+'rpx'" @touchstart="ontouchstart"
+			@touchmove="ontouchmove" @touchend="ontouchend">
+			<slot></slot>
+		</view>
+		<view class="next-slide-right">
+			<view 
+				class="next-btn-item" 
+				v-for="(item,index) in btnGroup" 
+				:key="index"
+				:style="getStyle(item)"
+				@click.stop="btnClick(item)">
+				{{item.name }}
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	const defBtnStyle = {
+		width: '100rpx',
+		bgColor: '#f9ae3d',
+		color: '#FFFFFF',
+		fontSize: '28rpx',
+		fontWeight: 300
+	};
+	
+	export default {
+		name: 'NextSwipeAction',
+		props: {
+			btnGroup: {
+				type: Array,
+				default: () => {
+					return [{
+						name: '修改',	
+						style: {
+							bgColor: '#f9ae3d'
+						}
+					}, {
+						name: '删除',
+						style: {
+							bgColor: '#ff4d4f'
+						}
+					}]
+				}
+			},
+			//当前列索引
+			index: {
+				type: [Number,String],
+				require: true,
+				default: 0
+			},
+			activeKey:{
+				type: [Number,String],
+				default:''
+			},
+			//是否禁用
+			disabled: {
+				type: Boolean,
+				default: false
+			},
+			// 是否按钮点击后自定重置
+			btnClickAutoReset: {
+				type: Boolean,
+				default: true
+			}
+		},
+		data() {
+			return {
+				x: 0,
+				left: 0,
+				operation: 0,
+				height: 0,
+				screenWidth: 0,
+				isActive:false,
+			};
+		},
+		watch:{
+			activeKey(newV){
+				if(!this.isActive)return;
+				if(newV != this.index){
+					this.reset()
+				}
+			}
+		},
+		mounted() {
+			this.$nextTick(res => {
+				const systemInfo = uni.getSystemInfoSync()
+				this.screenWidth = systemInfo.screenWidth
+				this.getBtnWidth()
+				this.getListHeight()
+			})
+		},
+		methods: {
+			getStyle(item) {
+				const style = item.style || {};
+				const styleStr = 'width:'+ (style.width || defBtnStyle.width) + 
+				';height:' + this.height + 
+				'rpx;background-color:' + (style.bgColor || defBtnStyle.bgColor) + 
+				';color:' + (style.color || defBtnStyle.color) + 
+				';font-size:' + (style.fontSize || defBtnStyle.fontSize) + 
+				'font-weight:' + (style.fontWeight || defBtnStyle.fontWeight);
+				return styleStr
+			},
+			btnClick(item) {
+				const it = Object.assign({}, item);
+				delete it.style;
+				this.$emit('btnClick', {
+					index: this.index,
+					item: it
+				})
+				if(this.btnClickAutoReset) {
+					this.reset()
+				}
+			},
+			//重置方法
+			reset() {
+				this.left = 0
+				this.isActive = false;
+			},
+			getBtnWidth() {
+				const element = uni.createSelectorQuery().in(this).select(".next-slide-right");
+				element.boundingClientRect(rect => {
+					this.operation = this.px2rpx(rect.width, this.screenWidth)
+				}).exec()
+			},
+			getListHeight() {
+				const element = uni.createSelectorQuery().in(this).select(".next-slide-left");
+				element.boundingClientRect(rect => {
+					this.height = this.px2rpx(rect.height, this.screenWidth)
+				}).exec()
+			},
+			px2rpx(px, screenWidth) {
+				return px / (screenWidth / 750)
+			},
+			ontouchstart(e) {
+				if(this.disabled) return
+				this.x = this.px2rpx(e.touches[0].clientX, this.screenWidth)
+			},
+			ontouchmove(e) {
+				if(this.disabled) return
+				let clientX = this.x - this.px2rpx(e.touches[0].clientX, this.screenWidth)
+				if (clientX <= 0) this.left = 0
+				else if (this.operation <= clientX) this.left = this.operation * -1
+				else this.left = clientX * -1
+			},
+			ontouchend(e) {
+				if(this.disabled) return
+				let clientX = this.x - this.px2rpx(e.changedTouches[0].clientX, this.screenWidth)
+				this.left = clientX > this.operation / 2 ? this.operation * -1 : 0
+				if(this.left !== 0){
+					this.isActive = true;
+					this.$emit('nextSwipeActive', this.index)
+				}
+			},
+		}
+	}
+</script>
+
+<style scoped>
+	.next-slide {
+		width: 100%;
+		position: relative;
+		overflow: hidden;
+	}
+	.next-slide-disabled {
+		background-color: #333333;
+		opacity: 0.6;
+	}
+	.next-slide-left {
+		width: 100%;
+		overflow: hidden;
+		background-color: #161616;
+		transition: left 0.2s ease-in-out;
+		z-index: 999;
+	}
+
+	.next-slide-right {
+		position: absolute;
+		top: 0rpx;
+		right: 0;
+		z-index: 99;
+		display: flex;
+		align-items: center;
+		justify-content: flex-end;
+	}
+
+	.next-btn-item {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+</style>

+ 86 - 0
uni_modules/next-swipe-action/package.json

@@ -0,0 +1,86 @@
+{
+	"id": "next-swipe-action",
+	"displayName": "next-swipe-action,滑动操作、左滑删除、滑动删除",
+	"version": "1.0.1",
+	"description": "滑动操作、左滑删除、滑动删除组件,可禁用,可自动重置h5/小程序/APP通用",
+	"keywords": [
+        "滑动操作",
+        "左滑删除",
+        "滑动组件",
+        "滑动删除",
+        "swipe-action"
+    ],
+	"repository": "",
+	"engines": {
+		"HBuilderX": "^3.1.0"
+	},
+	"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",
+                "alipay": "n"
+			},
+			"client": {
+				"Vue": {
+					"vue2": "y",
+					"vue3": "y"
+				},
+				"App": {
+					"app-vue": "y",
+					"app-nvue": "u"
+				},
+				"H5-mobile": {
+					"Safari": "y",
+					"Android Browser": "y",
+					"微信浏览器(Android)": "y",
+					"QQ浏览器(Android)": "y"
+				},
+				"H5-pc": {
+					"Chrome": "u",
+					"IE": "u",
+					"Edge": "u",
+					"Firefox": "u",
+					"Safari": "u"
+				},
+				"小程序": {
+					"微信": "y",
+					"阿里": "u",
+					"百度": "u",
+					"字节跳动": "u",
+					"QQ": "u",
+					"钉钉": "u",
+					"快手": "u",
+					"飞书": "u",
+					"京东": "u"
+				},
+				"快应用": {
+					"华为": "u",
+					"联盟": "u"
+				}
+			}
+		}
+	}
+}

+ 114 - 0
uni_modules/next-swipe-action/readme.md

@@ -0,0 +1,114 @@
+# next-swipe-action适用于uni-app项目的滑动操作、左滑删除、滑动删除组件
+### 本组件目前兼容微信小程序、H5、APP
+
+
+> 遇到问题或有建议可以加入QQ群(<font color=#f00>455948571</font>)反馈;  
+> 如果觉得组件不错,<font color=#f00>给五星鼓励鼓励</font>咯;
+
+### 如果有使用问题请加群
+
+注意:如果插件问题,请务必给一个完整的复现demo,谢谢配合;
+[点击链接加入群聊前端开发(uniapp插件)】](https://qm.qq.com/q/S1bJzQfJAG)
+
+### vue3使用示例
+``` 
+<template>
+	<view class="container">
+		<view class="title"><text>next-swipe-action 演示demo</text></view>
+		<view class="list" v-for="(item,index) in list" :key="index">
+			<next-swipe-action :btnGroup="btnGroup" :disabled="index===2 || index===4" :index="index" @btnClick="onclick">
+				<view class="item">
+					<image class="item-img" src="https://img0.baidu.com/it/u=2337762009,1252339875&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500">
+					</image>
+					<view class="item-name">{{item}}</view>
+				</view>
+			</next-swipe-action>
+		</view>
+	</view>
+</template>
+<script setup lang="ts">
+	import { ref } from 'vue'
+
+	const list = ref(['李先生','张小姐','武sir-禁用','黎先生','刘sir-禁用','欧阳小姐'])
+	const btnGroup = ref([
+		{
+			name: '修改',
+			action: 'edit',
+			style: {
+				bgColor: '#f9ae3d'
+			}
+		},
+		{
+			name: '删除',
+			action: 'del',
+			style: {
+				bgColor: '#ff4d4f'
+			}
+		},
+		{
+			name: '审核',
+			action: 'audit',
+			style: {
+				bgColor: '#b7eb8f'
+			}
+		},
+	]);
+	//点击操作回调事件
+	function onclick(e) {
+		console.log('所点击的列表索引:' , e.index)
+		console.log('所点击的按钮数据:' , e.item)
+	}
+</script>
+<style scoped>
+	.container {
+		width: 100%;
+		height: 100vh;
+		background-color: #ffffff;
+	}
+	.title {
+		color: #666;
+		padding: 30rpx;
+		
+	}
+	.list {
+		width: 100%;
+		margin-top: 1px;
+	}
+
+	.item {
+		width: 100%;
+		height: 120rpx;
+		border-bottom: 1rpx solid #f0f0f0;
+		display: flex;
+		align-items: center;
+		justify-content: flex-start;
+	}
+
+	.item-img {
+		width: 80rpx;
+		height: 80rpx;
+		border-radius: 50%;
+		margin-left: 30rpx;
+	}
+
+	.item-name {
+		margin-left: 20rpx;
+		font-size: 30rpx;
+		color: #666666;
+	}
+</style>
+```
+
+### 属性说明
+| 名称                         | 类型           | 默认值               | 描述            |
+| ----------------------------|--------------- | -------------------- | ---------------|
+| index                       | Number         | 0                    | 当前列索引
+| disabled                    | Boolean        | false                | 是否禁用左滑
+| btnGroup                    | Array          | 默认显示编辑、删除     | 操作按钮数组信息,默认显示编辑、删除,可自定义传入
+| btnClickAutoReset           | Boolean        | true                 | 按钮点击后是否重置
+
+
+## Event 事件
+|事件名	|说明																										|类型	|回调参数	|
+|----		|----																										|----	|----			|
+|btnClick|自定义按钮点击事件																		  |emit	|Object		|