秋名山最速传说,2分钟,模态框
最土最简单的模态框。
这个模态框的名字叫起来特别古怪,其实就是高亮显示一个东西(比如图中的搜索框),
根据不同需要:
- 只有被高亮显示的那个东东可以进行交互,半透明的黑色背景上鼠标点击是无效的
- 被高亮显示的东东可以交互,但是半透明的黑色背景上鼠标点击是有效,效果一般就是让高亮显示的那个东东消失掉。
下面一段程序文本就是一个最简单的模态框背景,他是一个react function component,
html模板是一个fixed定位的、高度为100vh、宽度为100vw、opacity为0.8的div,
他有三个参数,state、setstate、zIndex。state是必选参数,控制modal背景是否出现,setstate可选参数,若传入这个参数,黑色背景对点击是有反馈的(也就是点了会切换state),不传入,那么黑色背景对点击没有反馈。zIndex默认是10,可以根据需要来调整,不过建议你调整你需要高亮显示的模态框卡片的zIndex,这样更好。
import React, { ReactElement } from "react";
import cs from "classnames";
import ButtonCustomized from "../../../../lib/Button/ButtonCustomized/ButtonCutomized";
interface Props {}
/**
*a custom hook ,can make your input auto focus
* @param inputRef the ref of the input elment which u wanna focus on
* @param state the state that decides whether your input is visible
*/
function useFocusInputDependOnState(
inputRef: React.MutableRefObject<null>,
state: any
) {
// 注意, 即使是useLayoutEffect ,自动focus也失效.
//用setTimeout做个更慢的延迟。。
React.useEffect(() => {
setTimeout(() => {
(inputRef.current as any).focus();
}, 100);
(inputRef.current as any).focus();
return () => {
// can this clear operation work? will it cause any trouble?
inputRef = null as unknown as React.MutableRefObject<null>;
};
}, [state]);
}
export default function RollingInput({}: Props): ReactElement {
// 开合状态的state
const [state, setstate] = React.useState(false);
//input value的状态
const [val, setval] = React.useState("");
let inputRef = React.useRef(null);
useFocusInputDependOnState(inputRef, state);
return (
<div className="tw-relative">
<div
className={cs("tw-absolute tw-w-4/5 tw-transition-all ", {
"tw-pt-0": state === false,
"tw-pt-4": state,
"tw-h-0": state === false,
"tw-duration-300": state,
})}
>
<div
//z-index 仅在有定位属性的元素上生效,所以下面的tw-relative 就是为了让tw-z-50生效
className={cs(
"-tw-mt-4 tw-flex tw-duration-100 tw-relative tw-z-50 ",
{
"tw-invisible": !state,
}
)}
>
<input
className="tw-caret-purple-800 tw-rounded-l-md tw-outline-none tw-leading-[3.5rem] tw-text-4xl tw-pl-3 tw-align-middle tw-h-14 tw-text-black tw-w-4/5 "
type="text"
value={val}
ref={inputRef}
onChange={(e) => {
e.preventDefault();
setval(e.target.value);
}}
autoFocus
/>
<div className="">
<ButtonCustomized
color="primary"
onClick={(e) => {
e.preventDefault();
setstate(!state);
}}
height={3.5}
width={6}
>
提交
</ButtonCustomized>
</div>
</div>
</div>
<div
className="tw-h-16 tw-w-4/5 tw-bg-orange-500"
onClick={(e) => {
e.preventDefault();
setstate(!state);
}}
>
在这里添加任务
</div>
<ModalBackground state={state} setstate={setstate}></ModalBackground>
</div>
);
}
/**
* a violent overlay
*
*two params:
state,decide whether it's show,
setstate, change the state.
it's a controlled component;
attention,if u want a modal mask(which means background overlay doesn't respond to click),
pass in the setstate,
if u want a non-modal one,don't pass in the setstate.
the overlay's default zIndex is 10,make sure your dialog or some other modal card's index is higher.
*/
export function ModalBackground({
state,
setstate,
zIndex = 10,
}: {
state: boolean;
setstate?: React.Dispatch<React.SetStateAction<boolean>>;
zIndex?: number;
}): ReactElement {
return (
<div
onClick={() => {
if (setstate !== undefined) {
if (state === true) {
setstate(!state);
}
} else {
if (process.env.NODE_ENV === "development")
console.log("seems you want a non-modal mask");
}
}}
className={cs(
"tw-fixed tw-w-screen tw-h-screen tw-bg-black tw-opacity-80 tw-top-0 tw-left-0",
{
"tw-invisible": !state,
}
)}
style={{ zIndex: `${zIndex}` }}
></div>
);
}