Kaynağa Gözat

登录、注册、忘记密码添加滑动验证

wangzhiqiang 1 ay önce
ebeveyn
işleme
590d1f825e

+ 3 - 0
.vscode/settings.json

@@ -0,0 +1,3 @@
+{
+    "vue3snippets.enable-compile-vue-file-on-did-save-code": false
+}

+ 29 - 6
pages/login/forget.vue

@@ -1,7 +1,7 @@
 <template>
 	<view class="content">
 		<view class="top_bg">
-			<image class="top_close" src="/static/image/login/close_icon.png" mode="scaleToFill" />
+			<image class="top_close" @click="$navBack()" src="/static/image/login/close_icon.png" mode="scaleToFill" />
 			<view class="top_text">
 				<view>忘记密码</view>
 				<view class="top_icon"></view>
@@ -14,14 +14,14 @@
 			<u--input class="h-112 mgt-16" v-model="loginParam.code" placeholder="请输入验证码" border="bottom" clearable>
 				<template slot="suffix">
 					<u-code :seconds="seconds" @end="end" @start="start" change-text="xs" ref="uCode"
-						@change="codeChange"></u-code>
-					<u-button :disabled="!isShowCode" @tap="getCode" class="code_btn">{{ tips }}</u-button>
+						:keep-running="true" @change="codeChange"></u-code>
+					<u-button :disabled="!isShowCode" @tap="sliderVerify" class="code_btn">{{ tips }}</u-button>
 				</template>
 			</u--input>
 			<u--input class="h-112 mgt-16" v-model="loginParam.password" :password="!isViewPassword" placeholder="请输入密码"
 				border="bottom" clearable>
 				<template slot="suffix">
-					<u-icon @click="isViewPassword = !isViewPassword" :name="!isViewPassword ? 'eye-fill' : 'eye-off'"
+					<u-icon @click="isViewPassword = !isViewPassword" :name="isViewPassword ? 'eye-fill' : 'eye-off'"
 						color="#303030" size="24"></u-icon>
 				</template>
 			</u--input>
@@ -29,17 +29,19 @@
 				placeholder="请确认密码" border="bottom" clearable>
 				<template slot="suffix">
 					<u-icon @click="isViewConfirmPwd = !isViewConfirmPwd"
-						:name="!isViewConfirmPwd ? 'eye-fill' : 'eye-off'" color="#303030" size="24"></u-icon>
+						:name="isViewConfirmPwd ? 'eye-fill' : 'eye-off'" color="#303030" size="24"></u-icon>
 				</template>
 			</u--input>
 
 			<u-button :disabled="!isSubmit" class="login" @tap="submit">提交</u-button>
 		</view>
-
+		<zmm-slider-verify ref="sliderVerify" @success="successHandle" @error="errorHandle"
+			@close="closeHandle"></zmm-slider-verify>
 	</view>
 </template>
 
 <script>
+import { isValidPhone, isValidPassword } from '@/utils/index'
 export default {
 	data() {
 		return {
@@ -73,6 +75,27 @@ export default {
 
 	},
 	methods: {
+		//显示验证组件
+		sliderVerify() {
+			if(isValidPhone(this.loginParam.phone)) {
+				this.$refs['sliderVerify'].show()
+			} else {
+				uni.$u.toast('请输入正确手机号');
+			}
+		},
+		//验证通过回调
+		successHandle(e) {
+			console.log(e)
+			this.getCode()
+		},
+		//验证失败回调
+		errorHandle(e) {
+			console.log(e)
+		},
+		//组件关闭回调
+		closeHandle(e) {
+			console.log(e)
+		},
 		codeChange(text) {
 			this.tips = text;
 		},

+ 33 - 7
pages/login/index.vue

@@ -1,7 +1,7 @@
 <template>
 	<view class="content">
 		<view class="top_bg">
-			<image class="top_close" src="/static/image/login/close_icon.png" mode="scaleToFill" />
+			<image class="top_close" @click="$navTo('/pages/my/index','tabbar')" src="/static/image/login/close_icon.png" mode="scaleToFill" />
 			<view class="top_text">
 				<view>欢迎来到众酬帮</view>
 				<view class="top_icon"></view>
@@ -14,7 +14,7 @@
 			<u--input v-if="loginParam.loginWay === 'password'" class="h-112 mgt-16" v-model="loginParam.password"
 				:password="!isViewPassword" placeholder="请输入密码" border="bottom" clearable>
 				<template slot="suffix">
-					<u-icon @click="isViewPassword = !isViewPassword" :name="!isViewPassword ? 'eye-fill' : 'eye-off'"
+					<u-icon @click="isViewPassword = !isViewPassword" :name="isViewPassword ? 'eye-fill' : 'eye-off'"
 						color="#303030" size="24"></u-icon>
 				</template>
 			</u--input>
@@ -22,19 +22,19 @@
 				clearable>
 				<template slot="suffix">
 					<u-code :seconds="seconds" @end="end" @start="start" change-text="xs" ref="uCode"
-						@change="codeChange"></u-code>
-					<u-button :disabled="!isShowCode" @tap="getCode" class="code_btn">{{ tips }}</u-button>
+						:keep-running="true" @change="codeChange"></u-code>
+					<u-button :disabled="!isShowCode" @tap="sliderVerify" class="code_btn">{{ tips }}</u-button>
 				</template>
 			</u--input>
 			<view class="flex jc_between mgt-32">
 				<view v-if="loginParam.loginWay === 'password'" @click="loginParam.loginWay = 'code'"
 					class="text-24 text-500 text-303030">验证码登录</view>
 				<view v-else @click="loginParam.loginWay = 'password'" class="text-24 text-500 text-303030">密码登录</view>
-				<view class="text-24 text-500 text-303030">注册</view>
+				<view class="text-24 text-500 text-303030" @click="$navTo('/pages/login/register')">注册</view>
 			</view>
 
 			<button class="login" @tap="submit">登录</button>
-			<view class="mgt-32 text-24 text-500 text-303030 text-center">忘记密码</view>
+			<view class="mgt-32 text-24 text-500 text-303030 text-center" @click="$navTo('/pages/login/forget')">忘记密码</view>
 			<view class="mgt-130">
 				<u-divider text="快捷登录"></u-divider>
 			</view>
@@ -48,11 +48,13 @@
 				<text class="text-303030">《隐私政策》</text>
 			</view>
 		</view>
-
+		<zmm-slider-verify ref="sliderVerify" @success="successHandle" @error="errorHandle"
+			@close="closeHandle"></zmm-slider-verify>
 	</view>
 </template>
 
 <script>
+import { isValidPhone, isValidPassword } from '@/utils/index'
 export default {
 	data() {
 		return {
@@ -81,6 +83,27 @@ export default {
 
 	},
 	methods: {
+		//显示验证组件
+		sliderVerify() {
+			if(isValidPhone(this.loginParam.phone)) {
+				this.$refs['sliderVerify'].show()
+			} else {
+				uni.$u.toast('请输入正确手机号');
+			}
+		},
+		//验证通过回调
+		successHandle(e) {
+			console.log(e)
+			this.getCode()
+		},
+		//验证失败回调
+		errorHandle(e) {
+			console.log(e)
+		},
+		//组件关闭回调
+		closeHandle(e) {
+			console.log(e)
+		},
 		codeChange(text) {
 			this.tips = text;
 		},
@@ -111,6 +134,9 @@ export default {
 		},
 		submit() {
 			console.log('提交参数 :===>>', this.loginParam);
+			//todo 请求后端接口 
+			// 通过后跳转到个人中心
+			this.$navTo('/pages/my/index','redirect')
 		}
 	}
 }

+ 38 - 7
pages/login/register.vue

@@ -1,7 +1,7 @@
 <template>
 	<view class="content">
 		<view class="top_bg">
-			<image class="top_close" src="/static/image/login/close_icon.png" mode="scaleToFill" />
+			<image class="top_close" @click="$navBack()" src="/static/image/login/close_icon.png" mode="scaleToFill" />
 			<view class="top_text">
 				<view>注册众酬帮</view>
 				<view class="top_icon"></view>
@@ -16,14 +16,14 @@
 			<u--input class="h-112 mgt-16" v-model="loginParam.code" placeholder="请输入验证码" border="bottom" clearable>
 				<template slot="suffix">
 					<u-code :seconds="seconds" @end="end" @start="start" change-text="xs" ref="uCode"
-						@change="codeChange"></u-code>
-					<u-button :disabled="!isShowCode" @tap="getCode" class="code_btn">{{ tips }}</u-button>
+						:keep-running="true" @change="codeChange"></u-code>
+					<u-button :disabled="!isShowCode" @tap="sliderVerify" class="code_btn">{{ tips }}</u-button>
 				</template>
 			</u--input>
 			<u--input class="h-112 mgt-16" v-model="loginParam.password" :password="!isViewPassword" placeholder="请输入密码"
 				border="bottom" clearable>
 				<template slot="suffix">
-					<u-icon @click="isViewPassword = !isViewPassword" :name="!isViewPassword ? 'eye-fill' : 'eye-off'"
+					<u-icon @click="isViewPassword = !isViewPassword" :name="isViewPassword ? 'eye-fill' : 'eye-off'"
 						color="#303030" size="24"></u-icon>
 				</template>
 			</u--input>
@@ -31,7 +31,7 @@
 				placeholder="请确认密码" border="bottom" clearable>
 				<template slot="suffix">
 					<u-icon @click="isViewConfirmPwd = !isViewConfirmPwd"
-						:name="!isViewConfirmPwd ? 'eye-fill' : 'eye-off'" color="#303030" size="24"></u-icon>
+						:name="isViewConfirmPwd ? 'eye-fill' : 'eye-off'" color="#303030" size="24"></u-icon>
 				</template>
 			</u--input>
 
@@ -43,11 +43,13 @@
 				<text class="text-303030">《隐私政策》</text>
 			</view>
 		</view>
-
+		<zmm-slider-verify ref="sliderVerify" @success="successHandle" @error="errorHandle"
+			@close="closeHandle"></zmm-slider-verify>
 	</view>
 </template>
 
 <script>
+import { isValidPhone, isValidPassword } from '@/utils/index'
 export default {
 	data() {
 		return {
@@ -82,6 +84,27 @@ export default {
 
 	},
 	methods: {
+		//显示验证组件
+		sliderVerify() {
+			if(isValidPhone(this.loginParam.phone)) {
+				this.$refs['sliderVerify'].show()
+			} else {
+				uni.$u.toast('请输入正确手机号');
+			}
+		},
+		//验证通过回调
+		successHandle(e) {
+			console.log(e)
+			this.getCode()
+		},
+		//验证失败回调
+		errorHandle(e) {
+			console.log(e)
+		},
+		//组件关闭回调
+		closeHandle(e) {
+			console.log(e)
+		},
 		codeChange(text) {
 			this.tips = text;
 		},
@@ -111,7 +134,15 @@ export default {
 			this.isCode = true
 		},
 		submit() {
-			console.log('提交参数 :===>>', this.loginParam);
+			if(isValidPhone(this.loginParam.phone)) return uni.$u.toast('请输入正确手机号');
+			if(isValidPassword(this.loginParam.password)) {
+				if(this.loginParam.password !== this.loginParam.confirmPwd) return uni.$u.toast('两次输入的密码不一致');
+				console.log('提交参数 :===>>', this.loginParam);
+				//todo 请求后端接口 
+
+				// 通过后跳转到个人中心
+				this.$navTo('/pages/my/index','redirect')
+			}
 		}
 	}
 }

+ 8 - 0
uni_modules/zmm-slider-verify/changelog.md

@@ -0,0 +1,8 @@
+## 1.0.3(2025-08-10)
+默认打开底部滑动条
+## 1.0.2(2025-08-10)
+感谢评论区的反馈,修复底部滑块层级问题,滑动超出问题,增加pc端滑动
+## 1.0.1(2024-06-02)
+增加底部滑动条
+## 1.0.0(2022-12-27)
+提交1.0.0版本

+ 386 - 0
uni_modules/zmm-slider-verify/components/zmm-slider-verify/zmm-slider-verify.vue

@@ -0,0 +1,386 @@
+<template>
+	<view class="zmm-slider-verify" v-if="isShow" @touchmove.stop.prevent="stopMoveHandle">
+		<view class="zmm-slider-verify-mask" :style="{ 'background-color': maskColor }"></view>
+		<view class="zmm-slider-verify-wrap" :style="{ 'background-color': wrapColor }">
+			<view class="zmm-slider-verify-top">
+				<text class="zmm-slider-verify-title">{{ title }}</text>
+				<text class="zmm-slider-verify-close" @click="closeHandle">关闭</text>
+			</view>
+			<view class="zmm-slider-verify-tips">
+				<text class="zmm-slider-verify-tips-text">{{ tips }}</text>
+			</view>
+			<view class="zmm-slider-verify-box">
+				<image class="zmm-slider-verify-img" v-if="verifyImg" :src="verifyImg" mode="scaleToFill"></image>
+				<image class="zmm-slider-verify-img" v-else src="@/uni_modules/zmm-slider-verify/static/img/Verify.jpg"
+					mode="scaleToFill"></image>
+				<!-- 右侧用来验证的滑块 -->
+				<view class="zmm-slider-verify-block-verify" :style="blockVerifyStyle"></view>
+				<!-- 被css操控的滑块 -->
+				<view class="zmm-slider-verify-block-move" :style="blockMoveStyle"></view>
+				<!-- 手指触摸的滑块 -->
+				<view class="zmm-slider-verify-block-touch" :style="blockTouchStyle" @touchstart="touchstartHandle"
+					@touchmove="touchmoveHandle" @touchend="touchendHandle" @mousedown="mousedownHandle"
+					@mousemove="mousemoveHandle" @mouseup="mouseupHandle">
+				</view>
+			</view>
+			<view class="zmm-slider-verify-slider" v-if="showBottomSlider">
+				<!-- 被css操控的滑块 -->
+				<view class="zmm-slider-verify-slider-move" :style="sliderMoveStyle"></view>
+				<!-- 手指触摸的滑块 -->
+				<view class="zmm-slider-verify-slider-touch" :style="sliderTouchStyle" @touchstart="touchstartHandle"
+					@touchmove="touchmoveHandle" @touchend="touchendHandle" @mousedown="mousedownHandle"
+					@mousemove="mousemoveHandle" @mouseup="mouseupHandle">
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	/**
+	 * zmm-slider-verify 滑动验证组件
+	 * @description 滑动验证组件
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=10513
+	 * @property {String} title 弹窗标题
+	 * @property {String} tips 弹窗提示
+	 * @property {Number} slideSize 滑块大小
+	 * @property {String} slideColor 滑块颜色
+	 * @property {String} maskColor 遮罩层背景色
+	 * @property {String} wrapColor 主题背景色
+	 * @property {String} verifyImg 图片
+	 * @property {Number} between 校验正负差值区间像素
+	 * @property {Boolean} showBottomSlider 是否显示底部滑动条
+	 * @property {String} bottomSlideSize 底部滑块大小
+	 * @property {String} bottomSlideColor 底部滑块颜色
+	 * @event {Function} success 验证通过事件
+	 * @event {Function} error 验证失败事件
+	 * @event {Function} close 组件关闭事件
+	 */
+
+	export default {
+		name: 'zmmSliderVerify',
+		emits: ['success', 'error', 'close'],
+		props: {
+			//标题
+			title: {
+				type: String,
+				default: '滑动校验'
+			},
+			//提醒
+			tips: {
+				type: String,
+				default: '请将左侧透明滑块拖进白色框内'
+			},
+			//滑块大小
+			slideSize: {
+				type: Number,
+				default: 40
+			},
+			//滑块颜色
+			slideColor: {
+				type: String,
+				default: 'rgba(0,0,0,0.4)'
+			},
+			//遮罩层背景色
+			maskColor: {
+				type: String,
+				default: 'rgba(0,0,0,0.4)'
+			},
+			// 图片
+			verifyImg: {
+				type: String,
+				default: ''
+			},
+			//主体背景色
+			wrapColor: {
+				type: String,
+				default: '#ffffff'
+			},
+			//校验正负差值区间像素
+			between: {
+				type: Number,
+				default: 10
+			},
+			// 是否显示底部滑动条
+			showBottomSlider: {
+				type: Boolean,
+				default: true
+			},
+			//底部滑块大小
+			bottomSlideSize: {
+				type: Number,
+				default: 40
+			},
+			//底部滑块颜色
+			bottomSlideColor: {
+				type: String,
+				default: '#2b94e7'
+			},
+		},
+		data() {
+			return {
+				startPageX: 0, //开始距离
+				moveLeft: 0, //滑动距离
+				done: false, //是否成功
+				autoLeft: 80, //验证滑块随机的像素
+				autoTop: 80, //验证滑块随机的top像素
+				isShow: false,
+				width: 280 //主体宽度
+			};
+		},
+		computed: {
+			blockVerifyStyle() {
+				return `top:${this.autoTop}px;left:${this.autoLeft}px;height:${this.slideSize}px;width:${this.slideSize}px;background-color:${this.slideColor};`
+			},
+			blockMoveStyle() {
+				return `top:${this.autoTop}px;left:${this.moveLeft}px;height:${this.slideSize}px;width:${this.slideSize}px;background-color: ${this.slideColor};`
+			},
+			blockTouchStyle() {
+				return `top:${this.autoTop}px;height:${this.slideSize}px;width:${this.slideSize}px;`
+			},
+			sliderMoveStyle() {
+				return `left:${this.moveLeft}px;height:${this.bottomSlideSize}px;width:${this.bottomSlideSize}px;background-color: ${this.bottomSlideColor};`
+			},
+			sliderTouchStyle() {
+				return `height:${this.bottomSlideSize}px;width:${this.bottomSlideSize}px;`
+			}
+		},
+		methods: {
+			// 拦截其他触摸事件防止nvue下input等元素层级问题
+			stopMoveHandle(e) {
+				if (e.preventDefault) {
+					// 阻止页面滚动
+					e.preventDefault()
+				}
+			},
+			// 随机数
+			rMathfloor(min, max) {
+				//返回包括最大/小值
+				return Math.floor(Math.random() * (max - min + 1)) + min;
+			},
+			// 初始化
+			init() {
+				this.moveLeft = 0;
+				this.done = false;
+				this.autoTop = this.rMathfloor(0, 170 - this.slideSize);
+				this.autoLeft = this.rMathfloor(this.slideSize + 20, this.width - this.slideSize);
+			},
+			// 显示
+			show() {
+				this.isShow = true;
+				this.init()
+			},
+			// 关闭
+			hide() {
+				this.closeHandle()
+			},
+			//按下
+			touchstartHandle(e) {
+				if (this.done) {
+					return;
+				}
+				this.startPageX = e.changedTouches[0].pageX;
+			},
+			// 滑动
+			touchmoveHandle(e) {
+				// 滑动分两个块来操作不然会有数据抖动
+				if (this.done) {
+					return;
+				}
+				var left = e.changedTouches[0].pageX - this.startPageX; //补偿起始位置
+				// 限制边界
+				if (left < 0) {
+					left = 0;
+				};
+				const maxLeft = this.width - this.slideSize;
+				if (left > maxLeft) {
+					left = maxLeft;
+				};
+				this.moveLeft = left;
+			},
+			// 滑动离开(最终)
+			touchendHandle(e) {
+				var endLeft = e.changedTouches[0].pageX;
+				var verifyLeft = this.autoLeft + this.startPageX; //补偿起始位置
+				var chazhi = verifyLeft - endLeft; //最终差值
+				// 判断是否在正负差值区间
+				if (chazhi >= 0 - this.between && chazhi <= this.between) {
+					this.done = true;
+					// 通过会执行成功和关闭
+					this.closeHandle()
+					this.$emit('success', '验证通过');
+					this.$emit('close', '关闭');
+				} else {
+					this.$emit('error', '验证失败');
+					// 失败会执行失败并重新初始化
+					this.init();
+					uni.showToast({
+						title: this.tips,
+						icon: 'none'
+					});
+				}
+			},
+			// 关闭事件
+			closeHandle() {
+				this.isShow = false
+				this.$emit('close', '关闭');
+			},
+			// pc端
+			mousedownHandle(e) {
+				if (this.done) return;
+				this.startPageX = e.pageX;
+				this.isDragging = true;
+				document.addEventListener('mousemove', this.mousemoveHandle);
+				document.addEventListener('mouseup', this.mouseupHandle);
+			},
+			mousemoveHandle(e) {
+				if (!this.isDragging || this.done) return;
+				let left = e.pageX - this.startPageX;
+				const maxLeft = this.width - this.slideSize;
+				if (left < 0) left = 0;
+				if (left > maxLeft) left = maxLeft;
+				this.moveLeft = left;
+			},
+			mouseupHandle(e) {
+				if (!this.isDragging) return;
+				this.isDragging = false;
+				document.removeEventListener('mousemove', this.mousemoveHandle);
+				document.removeEventListener('mouseup', this.mouseupHandle);
+				if (this.done) return;
+				var endLeft = e.pageX;
+				var verifyLeft = this.autoLeft + this.startPageX;
+				var chazhi = verifyLeft - endLeft;
+				if (chazhi >= -this.between && chazhi <= this.between) {
+					this.done = true;
+					this.closeHandle();
+					this.$emit('success', '验证通过');
+					this.$emit('close', '关闭');
+				} else {
+					this.$emit('error', '验证失败');
+					uni.showToast({
+						title: this.tips,
+						icon: 'none'
+					});
+					this.init();
+				}
+			},
+		}
+	};
+</script>
+
+<style lang="scss" scoped>
+	$sliderVerifyWidth: 280px;
+
+	.zmm-slider-verify {
+		position: fixed;
+		top: 0;
+		left: 0;
+		right: 0;
+		bottom: 0;
+		z-index: 999;
+		display: flex;
+		flex-direction: row;
+		align-items: center;
+		justify-content: center;
+
+		.zmm-slider-verify-mask {
+			position: absolute;
+			top: 0;
+			left: 0;
+			right: 0;
+			bottom: 0;
+		}
+
+		.zmm-slider-verify-wrap {
+			display: flex;
+			flex-direction: column;
+			position: relative;
+			padding: 34rpx;
+			border-radius: 24rpx;
+			background-color: #ffffff;
+
+			.zmm-slider-verify-top {
+				display: flex;
+				flex-direction: row;
+				align-items: center;
+
+				.zmm-slider-verify-title {
+					flex: 1;
+					color: #333;
+					font-size: 32rpx;
+				}
+
+				.zmm-slider-verify-close {
+					font-size: 28rpx;
+					color: #333;
+				}
+			}
+
+			.zmm-slider-verify-tips {
+				margin-top: 12rpx;
+				margin-bottom: 12rpx;
+
+				.zmm-slider-verify-tips-text {
+					color: #999;
+					font-size: 28rpx;
+				}
+			}
+
+			.zmm-slider-verify-box {
+				position: relative;
+				width: $sliderVerifyWidth;
+				height: 170px;
+				overflow: hidden;
+
+				.zmm-slider-verify-img {
+					width: $sliderVerifyWidth;
+					height: 170px;
+					border-radius: 8rpx;
+				}
+
+				.zmm-slider-verify-block-verify,
+				.zmm-slider-verify-block-move,
+				.zmm-slider-verify-block-touch {
+					position: absolute;
+					left: 0px;
+					top: 0;
+					border-radius: 8rpx;
+				}
+
+				.zmm-slider-verify-block-verify {
+					border: 1px #fff solid;
+					/* #ifndef APP-NVUE */
+					box-sizing: border-box;
+					/* #endif */
+				}
+			}
+
+			.zmm-slider-verify-slider {
+				margin-top: 34rpx;
+				width: $sliderVerifyWidth;
+				background-color: rgba(0, 0, 0, 0.07);
+				position: relative;
+				overflow: hidden;
+				border-radius: 8rpx;
+				border-radius: 750rpx;
+
+				.zmm-slider-verify-slider-move,
+				.zmm-slider-verify-slider-touch {
+					border-radius: 750rpx;
+				}
+
+				.zmm-slider-verify-slider-move {
+					position: absolute;
+					left: 0px;
+					top: 0px;
+					z-index: 1;
+				}
+
+				.zmm-slider-verify-slider-touch {
+					position: relative;
+					z-index: 2;
+				}
+			}
+		}
+	}
+</style>

+ 101 - 0
uni_modules/zmm-slider-verify/package.json

@@ -0,0 +1,101 @@
+{
+  "id": "zmm-slider-verify",
+  "displayName": "zmm-slider-verify通用滑动验证组件",
+  "version": "1.0.3",
+  "description": "简单易用,支持自定义图片,滑动区间等",
+  "keywords": [
+    "zmm-slider-verify",
+    "滑动验证",
+    "滑块验证",
+    "拼图验证",
+    "通用滑动验证"
+],
+  "repository": "",
+  "engines": {
+    "HBuilderX": "^3.6.17",
+    "uni-app": "^4.07",
+    "uni-app-x": ""
+  },
+  "dcloudext": {
+    "type": "component-vue",
+    "sale": {
+      "regular": {
+        "price": "0.00"
+      },
+      "sourcecode": {
+        "price": "0.00"
+      }
+    },
+    "contact": {
+      "qq": "1278787712"
+    },
+    "declaration": {
+      "ads": "无",
+      "data": "插件不采集任何数据",
+      "permissions": "无"
+    },
+    "npmurl": "",
+    "darkmode": "x",
+    "i18n": "x",
+    "widescreen": "√"
+  },
+  "uni_modules": {
+    "dependencies": [],
+    "encrypt": [],
+    "platforms": {
+      "cloud": {
+        "tcb": "x",
+        "aliyun": "x",
+        "alipay": "x"
+      },
+      "client": {
+        "uni-app": {
+          "vue": {
+            "vue2": "√",
+            "vue3": "√"
+          },
+          "web": {
+            "safari": "√",
+            "chrome": "√"
+          },
+          "app": {
+            "vue": "√",
+            "nvue": "√",
+            "android": "√",
+            "ios": "√",
+            "harmony": "√"
+          },
+          "mp": {
+            "weixin": "√",
+            "alipay": "√",
+            "toutiao": "√",
+            "baidu": "√",
+            "kuaishou": "√",
+            "jd": "√",
+            "harmony": "√",
+            "qq": "√",
+            "lark": "√"
+          },
+          "quickapp": {
+            "huawei": "√",
+            "union": "√"
+          }
+        },
+        "uni-app-x": {
+          "web": {
+            "safari": "-",
+            "chrome": "-"
+          },
+          "app": {
+            "android": "-",
+            "ios": "-",
+            "harmony": "-"
+          },
+          "mp": {
+            "weixin": "-"
+          }
+        }
+      }
+    }
+  }
+}

+ 69 - 0
uni_modules/zmm-slider-verify/readme.md

@@ -0,0 +1,69 @@
+#uniapp通用滑动验证组件
+
+原理   
+图片上放两个块滑动对比区间
+
+作者   
+`zmm2113@qq.com`
+
+版本  
+`1.0.0`
+> 兼容性支持:安卓、苹果、H5、微信小程序(其他平台未测试理论上支持)。
+
+一、使用示例
+```
+<template>
+	<view>
+		<button type="default" @click="sliderVerify()">显示滑动验证</button>
+		<zmm-slider-verify ref="sliderVerify" @success="successHandle" @error="errorHandle" @close="closeHandle"></zmm-slider-verify>
+	</view>
+</template>
+
+<script>
+	export default {
+		methods: {
+			//显示验证组件
+			sliderVerify(){
+				this.$refs['sliderVerify'].show()
+			},
+			//验证通过回调
+			successHandle(e) {
+				console.log(e)
+			},
+			//验证失败回调
+			errorHandle(e) {
+				console.log(e)
+			},
+			//组件关闭回调
+			closeHandle(e){
+				console.log(e)
+			}
+		}
+	}
+</script>
+```  
+二、配置(注意配置数据类型)
+
+配置|数据类型|默认参数|说明
+-|-|-|-
+title|String|"滑动校验"|顶部标题
+tips|String|"请将左侧透明滑块拖进白色框内"|默认提醒文字
+slideSize|Number|40|滑块大小
+slideColor|String|"rgba(0,0,0,0.4)"|滑块颜色
+maskColor|String|"rgba(0,0,0,0.4)"|遮罩层颜色
+verifyImg|String|""|背景图片可自定义自己的图片
+wrapColor|String|"#ffffff"|主体背景色
+between|Number|10|校验正负差值区间像素
+showBottomSlider|Boolean|true|是否显示底部滑动条
+bottomSlideSize|Number|40|底部滑块大小
+bottomSlideColor|String|#2b94e7|底部滑块颜色
+
+三、事件
+
+配置|数据类型|说明
+-|-|-
+@success|function|验证通过事件
+@error|function|验证失败回调
+@close|function|组件关闭回调
+this.$refs['sliderVerify'].show()|function|显示组件
+this.$refs['sliderVerify'].hide()|function|隐藏组件

BIN
uni_modules/zmm-slider-verify/static/img/Verify.jpg


+ 31 - 2
utils/index.js

@@ -21,10 +21,39 @@ export function throttle(fn, delay) {
 	};
 }
 
-/**验证手机号格式
+/**
+ * 验证手机号格式 以13/15/17/18/19开头
  * @param {Number} phone 手机号码
  */
 export function isValidPhone(phone) {
-	const regex = /^1[3-9]\d{9}$/;
+	const regex = /^1[35789]\d{9}$/;
 	return regex.test(phone.trim());
+}
+
+/**
+ * 验证密码格式:6-16位数字+字母组合,需包含至少1位字母
+ * @param {String} password 密码
+ */
+export function isValidPassword(password) {
+	const pwd = password.trim();
+
+	// 检查长度
+	if (pwd.length < 6 || pwd.length > 16) {
+		uni.$u.toast('密码长度应大于6小于16');
+		return false;
+	}
+
+	// 检查是否只包含字母和数字
+	if (!/^[a-zA-Z0-9]+$/.test(pwd)) {
+		uni.$u.toast('密码只能使用字母和数字,不能使用其他字符');
+		return false;
+	}
+
+	// 检查是否包含至少1个字母
+	if (!/[a-zA-Z]/.test(pwd)) {
+		uni.$u.toast('密码中至少包含1个字母');
+		return false;
+	}
+
+	return true;
 }