时间来到4月,4个月没更了,鬼晓得自己在干嘛🙈
今天(额,已经是昨天了…)下午进了新需求,其中有一个登录模块,有登陆就少不了表单,借今天的踩坑过程聊一聊对
wechat miniprogram
中表单的认识,如有理解错误,还请留言告知,thx honey~😋😋😋
Key point✨
input
的双向绑定- 无法通过
js
动态切换type
值为text/passworld
- 通过
js
变更的布尔值 在行内简写时行为与预期不符 input
的层级遮盖问题
项目构建可参考 官方文档
view
是这样的
<view class="login-wrap">
<view class="menu-cover">
<view class="item " bindtap='toggleLoginType' data-type='0'>账号密码登录</view>
<view class="item " bindtap='toggleLoginType' data-type='1'>验证码登录</view>
<view class="bb "></view>
</view>
<view class="form-ls">
<input value="" bindinput='bindUsername' type="text" placeholder="请输入用户名" placeholder-style="color:#ccc"></input>
<input value="" bindinput='bindPassworld' type="text" placeholder="请输入密码" placeholder-style="color:#ccc" wx-if=''></input>
<input value="" bindinput='bindPassworld' type="password" placeholder="请输入密码" placeholder-style="color:#ccc" wx-if=''></input>
<input value="" bindinput='bindRegCode' type="text" placeholder="请输入验证码" placeholder-style="color:#ccc" wx-if=''></input>
<view class="iconfont show-pswd" bindtap='togglePswd' wx-if=''></view>
<view class="get-regCode" wx-if=''><text>获取验证码</text></view>
</view>
<button class="btn-login ">登录</button>
</view>
js
是这样的
Page({
/**
* 页面的初始数据
*/
data: {
loginType:0, //0:账号密码登录 1:验证码登录
showPswd:0, //0:密码 1:明文
canSubmit:0, //0:不可提交 1:可提交
username:'', //用户名
passworld:'', //密码
regCode:'', //验证码
},
/**
* 自定义函数
*/
// 切换登录方式
toggleLoginType(e){
let type = e.target.dataset.type
// console.log(type)
this.setData({
loginType:type
})
this._canSubmit()
},
// 切换密码/明文
togglePswd(){
let showPswd = !this.data.showPswd
// console.log(showPswd)
this.setData({
showPswd:showPswd
})
},
// bind 用户名
bindUsername(e){
let username = e.detail.value
this.setData({
username:username
})
this._canSubmit()
},
// bind 密码
bindPassworld(e){
let passworld = e.detail.value
this.setData({
passworld:passworld
})
this._canSubmit()
},
// bind 验证码
bindRegCode(e){
let regCode = e.detail.value
this.setData({
regCode:regCode
})
this._canSubmit()
},
// 表单是否可提交
_canSubmit(){
let _username = this.data.username.length>0,
_passworld = this.data.passworld.length>0,
_regCode = this.data.regCode.length>0,
_canSubmit = 0
// console.log(_username,_passworld,_regCode,_canSubmit)
if(this.data.loginType==0){ //账号密码登录
_canSubmit = _username && _passworld
}else{ //验证码登录
if(_username && _regCode){
_canSubmit = _username && _regCode
}
}
this.setData({
canSubmit:_canSubmit
})
},
})
css
就不贴了,脑补一下吧😂
1.input
的双向绑定
疑问:
- 有用过
vue
的小伙伴写起小程序一定觉得得心应手,不过有些地方就会觉得自己又回到了石器时代,比如说表单元素的双向绑定机制。既然都是以监听状态变更来触发结果的,为什么鹅厂FE不给双向绑定呢🤔
导致的问题:
- 当需要监测表单填写状态时,除了要
bind
一次value
以外,还要bindinput
一个function()
用来监听输入的变更 - 当多个
input
在bind
同一个值的时候,也只能通过bindinput
去监听变更 - 如果表单结构比较复杂,需要维护多一倍的代码去监听表单变更真的真的很不尤雨奚🤣
- 引出第二个问题
2.无法通过 js
动态切换 type
值为 text/passworld
疑问:
- 其实这个问题不是小程序的问题,在浏览器中的表现也是一样的
导致的问题:
- 因为
js
触发的状态变更不能改变input
的type
值,所以就要通过js
去动态生成input
节点,或者将两种状态都写出来,再通过状态去判断显示哪一个(总之会受回流和重绘影响)
3.通过 js
变更的布尔值 在行内简写时行为与预期不符
疑问:
- 在
data:{}
中,loginType
是以Boolean
类型存在的,所以在行内进行三元判断的时候,会直接把他当作判断条件,诡异的是在小程序中,js
触发的变更只执行了一次,而不是可以反复切换true/false
或者说1/0
解决方案:
- 行内不使用简写,三元的判断条件写完整就ok了
4.input
的层级遮盖问题
疑问:
- 可以看到,用来切换 密码/明文 的那个
iconfont
,一开始怎么也触发不了bindtap
解决方案:
- 首先想到的是不是
js
出错了,当把bindtap
绑到其他节点上时,却是可以正常触发的,pass - 其次想到,是不是因为
iconfont
是伪元素,如果父元素的innerHtml
为空的话,不能触发BFC
,导致没有可触发的热区?so,马上在节点内添了些文字,刷新,再看,还是不能触发bindtap
,pass - 然后想到的是审查元素,当通过审查工具检查的时候,只看到了
input
而看不到iconfont
,但是通过审查Elements
的时候却是能看到iconfont
的,突然明白了,应该是z-index
作祟 - 最后,因为
iconfont
是position:fixed
,所以直接设置z-index:1
,结果不行,设置为z-index:2
也没有生效,直到z-index:3
才生效 - 具体为什么
input
没有浮动也没有脱离文档流却有等同于z-index:2
的层级,文档中也没有相关解释,总之下次遇到类似的问题要留意下这个方向了
总结
- 小程序对于状态的绑定还是比较方便的,双花括号好像哪里都可以直接用。但是在
js
处理数据变更 和 表单元素的双向绑定问题上相对于vue
还是比较麻烦的 - 最后吐槽下鹅厂的开发者工具,四个字“无力吐槽”🙈