<template>
<view class="title">
<text>老师快速登录</text>
</view>
<view class="login-info">
<view class="input-phone">
<uni-easyinput v-model="phoneNumber" type="number" maxlength="11" trim="all" :errorMessage="phoneInputError"
placeholder="请输入手机号" @input="onInputPhone" @clear="onClearPhone"></uni-easyinput>
<view class="input-error">
<text>{{phoneInputError}}</text>
</view>
</view>
<view class="input-code" v-if="isLogin">
<view class="code">
<uni-easyinput type="number" maxlength="6" trim="all" :errorMessage="codeInputError"
placeholder="请输入验证码" @input="onInputVerifyCode" @clear="onClearVerifyCode"></uni-easyinput>
<view class="input-error">
<text>{{codeInputError}}</text>
</view>
</view>
<view class="countdown" v-if="!isReget">
<uni-countdown :color="color" :second="60" @timeup="onTimeupdate" :showDay='false' :showHour='false'
:showMinute="false" />
<text>秒后重新获取</text>
</view>
<view class="reget-code" v-if="isReget" @click="onGetVerifyCode">
<text>重新获取</text>
</view>
</view>
<view class="protocols">
<uni-data-checkbox class="checkbox" multiple v-model="checkboxV" @change="onChangeBox" :localdata="hobby">
</uni-data-checkbox>
<text class="text">已详读并同意</text>
<text class="link-text" @click="onUserAgreement">用户协议</text>
<text>和</text>
<text class="link-text" @click="onPrivacyPolicy">隐私政策</text>
<text>,新手机号将自动注册</text>
</view>
<button class="get-code" v-if="!isLogin" @click="onGetVerifyCode">获取验证码</button>
<button class="get-code" v-if="isLogin" :disabled="loginDisabled" @click="onLogin">登录</button>
</view>
</template>
<script setup>
import teacher from '@/api/teacher.js'
import student from '@/api/student.js'
import {
ref
} from "vue";
import tools from '@/utils/tools.js'
// 手机号
const phoneNumber = ref('')
// 用户协议和隐私政策
const hobby = ref([{
text: '',
value: true
}])
// 选中用户协议和隐私政策的值
const checkboxV = ref()
// 验证码
const verifyCode = ref('')
const phoneInputError = ref('')
const codeInputError = ref('')
// 获取验证码按钮是否置灰
const buttonDisabled = ref(true)
// 验证码倒计时文字颜色
const color = ref('#d5d5d5')
// 判断是否显示重新获取
const isReget = ref(false)
// 登录按钮是否置灰
const loginDisabled = ref(true)
// 是否显示登录按钮
const isLogin = ref(false)
// 判断输入的手机号格式是否正确
const onInputPhone = (e) => {
phoneInputError.value = ''
console.log("phoneNumber:", e)
if (e && isNaN(parseInt(e))) {
phoneInputError.value = '只能输入手机号'
return
}
}
// 判断选中用户协议和隐私政策
const isProtocolSelect = () => {
if (!(checkboxV.value && checkboxV.value[0])) {
uni.showToast({
title: "阅读并勾选用户协议和隐私政策",
icon: 'none',
})
return false
}
return true
}
// 查看用户协议
const onUserAgreement = () => {
uni.navigateTo({
url: '/pages/protocols/user_agreement'
})
}
// 查看隐私政策
const onPrivacyPolicy = () => {
uni.navigateTo({
url: '/pages/protocols/privacy_policy'
})
}
// 获取验证码按钮置灰
const onClearPhone = () => {
buttonDisabled.value = true
}
// 获取验证码
const onGetVerifyCode = async () => {
// 判断选中用户协议和隐私政策
if (!isProtocolSelect()) {
return
}
console.log("phoneNumber:", phoneNumber.value)
if (
phoneNumber.value.length != 11 ||
isNaN(parseInt(phoneNumber.value.length))
) {
isLogin.value = false
phoneInputError.value = "手机号错误,请重新输入"
return
}
let {
message,
data
} = await teacher.apiSendVerifyCode({
phone: tools.phoneToE16(phoneNumber.value)
})
if (message == '0') {
isReget.value = false
isLogin.value = true
}
// isReget.value = false
// isLogin.value = true
}
// 判断输入的验证码的格式是否正确
const onInputVerifyCode = async (e) => {
codeInputError.value = ''
verifyCode.value = e
if (e && isNaN(parseInt(verifyCode.value))) {
codeInputError.value = '只能输入验证码'
return
}
if (verifyCode.value.length == 6) {
loginDisabled.value = false
await onLogin()
} else {
loginDisabled.value = true
}
}
// 登录按钮置灰
const onClearVerifyCode = () => {
loginDisabled.value = true
}
// 倒计时结束时显示重新获取
const onTimeupdate = () => {
isReget.value = true
}
// 登录
const onLogin = async () => {
// 判断选中用户协议和隐私政策
if (!isProtocolSelect()) {
return
}
// 退出学生账户
if (uni.getStorageSync('role') == "student") {
await student.apiLogout()
}
let {
message,
data
} = await teacher.apiUserLogin2({
phone: tools.phoneToE16(phoneNumber.value),
verify_code: verifyCode.value,
})
if (message == '0') {
// console.log("resp data:", data)
uni.setStorageSync("accessToken", {
token: data.access_token,
expiresAt: data.access_token_expires_at,
})
uni.setStorageSync('role', 'teacher')
await beforNavigate()
} else {
codeInputError.value = '验证码错误'
// console.log('登陆失败:', message)
}
}
const beforNavigate = async () => {
let {
message,
data
} = await teacher.apiGetBriefInfo()
if (message == '0') {
if (!data.name) {
// 先补充个人基本信息
uni.redirectTo({
url: '/pages/teacher-my/improve-information'
})
} else {
// 返回上一页并重载
let pages = getCurrentPages()
uni.reLaunch({
url: "/" + pages[pages.length - 2]?.route
})
}
}
}
</script>
<style lang="scss">
page {
background-color: #fff;
display: flex;
flex-direction: column;
justify-content: center;
}
.title {
margin: 94rpx auto 0 auto;
font-size: 48rpx;
color: #232832;
}
.login-info {
// margin: 240rpx 72rpx 0 72rpx;
margin: 144rpx 48rpx 0 48rpx;
.input-error {
height: 14rpx;
font-size: 24rpx;
color: #dd524d;
}
.input-phone {
display: flex;
flex-direction: column;
}
.input-code {
// margin-top: 10rpx;
display: flex;
flex-direction: row;
.code {
width: 380rpx;
}
.countdown {
width: 226rpx;
height: 72rpx;
background-color: #F7F6F6;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
font-size: 26rpx;
color: #d5d5d5;
}
.reget-code {
width: 226rpx;
height: 70rpx;
border: 1px solid #d5d5d5;
// border-radius: 8rpx;
display: flex;
justify-content: center;
align-items: center;
font-size: 26rpx;
}
}
.protocols {
// width: 480rpx;
font-size: 24rpx;
color: #787B86;
margin: 30rpx auto;
text-align: left;
display: flex;
flex-direction: row;
align-items: center;
.checkbox {
width: 48rpx;
}
.link-text {
color: #4594FF;
text-decoration: underline;
}
// .text {
// vertical-align: middle;
// }
}
.get-code {
height: 88rpx;
font-size: 32rpx;
color: white;
background-color: #FF4E4D;
}
}
@import "@/static/icons/iconfont.css";
.login-phone {
width: 630rpx;
border-radius: 46rpx;
background-color: #fff;
border: solid 2rpx #D1D1D6;
color: #232832;
// margin: 0 auto 0 auto;
// background-color: #00BAAD;
.icon {
position: absolute;
left: 40rpx;
}
}
</style>
- 发布:2024-03-26 19:31
- 更新:2024-08-23 01:54
- 阅读:511
产品分类: uniapp/小程序/字节跳动
PC开发环境操作系统: Windows
PC开发环境操作系统版本号: Windows 11 专业版 22631.3296
HBuilderX类型: 正式
HBuilderX版本号: 4.06
第三方开发者工具版本号: V4.2.1
基础库版本号: 3.14.0.1
项目创建方式: HBuilderX
示例代码:
操作步骤:
输入手机号码
输入手机号码
预期结果:
被uni-easyinput的@input事件所调用的onInputPhone函数应该实时获取参数结果,并且v-model所绑定的phoneNumber的值也应该实时更新
被uni-easyinput的@input事件所调用的onInputPhone函数应该实时获取参数结果,并且v-model所绑定的phoneNumber的值也应该实时更新
实际结果:
uni-easyinput的@input事件没有执行,v-model也没有绑定到phoneNumber
uni-easyinput的@input事件没有执行,v-model也没有绑定到phoneNumber
bug描述:
今下午更新到最新版Hbuilder后,抖音小程序突然不支持uni-easyinput组件的@input事件和v-model了,同时微信小程序和QQ小程序目前没遇到同样的问题
DCloud_UNI_OttoJi - 日常回复 uni-app/x 问题,如果艾特我没看到,请主动私信
感谢反馈,你提到相同的代码在微信、qq 上可以,在抖音上不行,我已复现,通过调试发现
临时解决方案
进入 umi module 文件夹找到easyinput 组件,
方案一 推荐
源码中现在是开启 options.virtualHost=true
会导致这个问题,你可以尝试临时设置 options.virrtualHost=false
来绕过该问题。
方案二
或者你对平台进行兼容。通过判断 ifdef 是抖音就设置为 false,其他平台默认为 true,这也是官方接下来的修复方案
原因分析
的确是本次升级带来的一个潜在影响,抖音小程序开启 virtualHost 之后,会影响自定义绑定的事件。https://developer.open-douyin.com/docs/resource/zh-CN/mini-app/develop/framework/custom-component/component-model-and-style/#7417c627 ,而微信平台没有这个问题。本次升级正好在抖音刚刚支持 fragment 的时间点,旧版本默认不生效,新版本生效了,对比之下产生了差异
后续解决
后续会对 easyinput 进行兼容,在抖音平台默认关闭虚拟节点
我是cli vscode ,抖音小程序依然不能用。 v-model 一输入 抖音开放工具卡死,:value @input 方式,还可以响应一个字母,然后继续卡死。
DCloud_UNI_OttoJi
原因分析:的确是本次升级带来的一个潜在影响,抖音小程序开启 virtualHost 之后,会影响自定义绑定的事件。https://developer.open-douyin.com/docs/resource/zh-CN/mini-app/develop/framework/custom-component/component-model-and-style/#7417c627 ,而微信平台没有这个问题。本次升级正好在抖音刚刚支持 fragment 的时间点,旧版本默认不生效,新版本生效了,对比之下产生了差异
后续解决:后续会对 easyinput 进行兼容,在抖音平台默认关闭虚拟节点
2024-03-27 16:16
b***@163.com (作者)
收到,回退到上一版BuilderX,目前先用着旧版,等新版bug解决后再升级吧。
2024-03-28 11:44