PM:“用户需要同意XXX协议,才能点击按钮,否则就给它置灰!!!” 我:你说的对
在项目中经常会有这样需求,特别是在H5移动端,成了家常便饭,今天来详细讲讲代码实现过程。
技术栈:react + material-ui + typescript
实现效果如下
下面放上主要代码,主要逻辑在于复选框checkbox和按钮button,上面的文字布局就不赘述喽。
由于使用的是material-ui,所以部分组件名字和antd是有区别的,大家举一反三就好啦。
部分逻辑会写在注释里!!!
HTML
<Grid className={classes.checkboxItem}>
<FormControlLabel
control={
<Checkbox
classes={{
root: classes.radioRoot
}}
checked={checked}
onChange={() => {
if(checked===false){
setChecked(true)
}else if (checked===true){
setChecked(false)
}
}}
size="small"
color="primary"
/>
}
label="我已阅读并同意以上须知"
/>
</Grid>
<div className={classes.bottomContainer}>
<Fab
variant="extended"
color="primary"
aria-label="add"
className={classes.bottomLink}
disabled={btndisabled}
onClick={getCountDown}
style={{opacity:bottonOpa,backgroundColor:bottonBgColor,color:bottonColor}}
>
<Avatar
variant="square"
className={classes.bottomLinkIcon}
src={img1}
/>
立即申请
{visible?
<>{` (${time}s)`}</>
:""}
</Fab>
</div>
</Grid>
CSS
bottomLink: {
position:'fixed',
bottom:10,
left:0,
height: theme.typography.pxToRem(48),
width: theme.typography.pxToRem(350),
boxShadow: "0px 2px 8px 0px rgba(0, 127, 254, 0.3)",
margin: `0 ${theme.typography.pxToRem(13)}`,
},
bottomLinkIcon: {
width: 16,
height: 19,
marginRight: 8,
marginTop: -2,
},
bottomContainer: {
position: "fixed",
bottom: 0,
left: 0,
right: 0,
padding: "8px 12px",
},
checkboxItem:{
position:'fixed',
bottom:70,
left:55,
},
radioRoot: {
position: 'fixed',
left: 10,
},
JS
1、引用相关组件库
import React, {useState, useEffect}from "react";
import { useHistory } from 'react-router-dom';
import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
import { Typography, Grid , Avatar, Fab} from "@material-ui/core";
import Checkbox from '@material-ui/core/Checkbox';
import FormControlLabel from '@material-ui/core/FormControlLabel';
2、定义初始变量
let bottonOpa = 0.5;
let bottonBgColor = '#007FFE';
let bottonColor = '#fff';
const img1 = require('@/assets/images/notice_button@2x.png')
3、react hook在场景中的应用
const history = useHistory(); //按钮点击后路由跳转
const [checked, setChecked] = useState(false); //复选框状态,默认未勾选
const [btndisabled, setBtndisabled] = useState(true); //按钮状态,默认为不可点击
const [timerDisabled, setTimerDisabled] = useState(false); //监听时间
const [time, setTime] = useState(15); //倒计时15s
const [visible, setVisible] = useState(true); //按钮的倒计时文案
4、点击按钮触发的事件
const getCountDown = () => {
setTimerDisabled(true); //开始倒计时,并进行倒计时需要的一系列监听事件
history.push('/nextPage') //路由跳转到下一页
};
5、监听时间+复选框
useEffect(() => {
const timeChange = setTimeout(() => { //初始时间15s,开始倒计时,间隔为1s
setTime((oldTime) => oldTime - 1);
}, 1000);
if (timerDisabled) { //判断如果没有进行时间监听,清除计时器
clearInterval(timeChange);
}
if(time === 0){ //当倒计时为0
clearInterval(timeChange); //清除计时器
setVisible(false) // 按钮的时间文案不用显示了
}
if (time === 0 && checked === true) { // 倒计时为0,且已勾选复选框☑️
setBtndisabled(false) //按钮可点击
setVisible(false) //按钮的时间文案不用显示了
bottonOpa = 1 //按钮不用置灰
clearInterval(timeChange); //清除定时器
}
return ()=>{
clearInterval(timeChange)
}
}, [time, timerDisabled]);
useEffect(()=>{
if(checked === true && !time){ //已勾选复选框☑️,时间为0
setBtndisabled(false) // 按钮可点击
bottonOpa = 1 //按钮不用置灰
}else { //已勾选复选框勾选,但是时间还在走
setBtndisabled(true) //按钮不可点击
bottonOpa = 0.5 //按钮置灰
}
},[checked])
整个操作流程就完成啦。
题外话:
1)为什么我写这么多变量来控制css样式(按钮半透明,不透明两个状态)?为什么我不直接给按钮添加disabled属性就好了?
谁不想呢!可是materi-ui他的设计师
是这样设计的,disabled灰的像天空刚哭过一样。。。
这根本满足不了我们高端洋气的产品的审美,所以只能通过变量的方式(虽然累了点),但是他要的我都能给!
2)为什么不去全局css文件里写disabled的样式??
我也希望material-ui能够普通平凡一点,直接可以.button_disabled{balabalabala},就覆盖它原本的样式,但是不行!!
他是这样的,我们只能改一写基本的属性值,比如root、input属性,所以。。。如果有小伙伴成功改变了disabled属性,请速速与我联系!