赞
踩
一、前言
在跟需求方对接研发的需求,人家说要做一个悬浮在页面的图标,点击完截图然后进入一个新页面,填完一些数据,提交给接口。那么问题来了,怎么制作一个悬浮框,还是可拖拽的悬浮框,还是可拖拽的H5悬浮框?于是,就开始了研发之旅。
制作之后的效果:
二、总代码
InformErrorHover.tsx悬浮图标总代码:
// 报错悬浮框 const InformErrorHover: FC<InformErrorHoverProps> = (props) => { const { visible = false, location } = props; const { errorFileList, imgBase64 } = useSelector((state) => state['informError']); const dispatch = useDispatch(); const divRef = useRef<any>(); const [itemHeight, setItemHeight] = useState<number>(80); const [itemWidth, setItemWidth] = useState<number>(80); const [left, setLeft] = useState<number>(0); const [top, setTop] = useState<number>(0); const [clientWidth, setClientWidth] = useState<number>(0); const [clientHeight, setClientHeight] = useState<number>(0); const [gapWidth, setGapWidth] = useState<number>(30); useEffect(() => { setClientWidth(document.documentElement.clientWidth); setClientHeight(document.documentElement.clientHeight); setLeft(document.documentElement.clientWidth - clientWidth - gapWidth); setTop(document.documentElement.clientHeight * 0.8); }, []); /** * 开始拖拽 * @param e */ const dragStart = (e: any) => { divRef!.current!.style.transition = 'none'; }; /** * 结束拖拽 * @param e */ const dragEnd = (e: any) => { divRef!.current!.style.transition = 'all 0.3s'; if (left > clientWidth / 2) { setLeft(clientWidth - itemWidth - gapWidth); } else { setLeft(gapWidth); } }; const touchmove = (e: any) => { if (e.targetTouches.length === 1) { let touch = e.targetTouches[0]; setLeft(touch.clientX - itemWidth / 2); setTop(touch.clientY - itemHeight / 2); } }; /** * 将base64转文件 * @param dataurl * @param filename * @returns */ const dataURLtoFile = (dataurl: any, filename: any) => { var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new File([u8arr], filename, { type: mime }); }; const generateImage = async () => { // console.log('点击截图'); Toast.loading('正在截图中...'); await html2canvas(document.body).then((canvas) => { // document.body.appendChild(canvas); let url = canvas.toDataURL('image/png'); // console.log({ url }); let files = dataURLtoFile(url, '文件1'); // console.log({ files }); dispatch!({ type: 'informError/save', payload: { errorFileList: [files], imgBase64: url, }, }); Toast.hide(); history.push({ pathname: '/informError' }); }); }; return ( <div className={styles.informErrorHoverStyle} style={{ top: `${itemHeight}px` }} // onTouchMove={(e) => { // console.log(e); // }}= > <div className={styles.imgDiv} ref={divRef} style={{ backgroundImage: `url(${require('@/assets/images/inforErrorPng.png')})`, width: `${itemWidth}px`, height: `${itemHeight}px`, left: `${left}px`, // right: '0px', top: `${top}px`, }} onClick={() => { generateImage(); }} onTouchStart={(e) => { dragStart(e); }} onTouchEnd={(e) => { dragEnd(e); }} onTouchMove={(e) => { touchmove(e); }} > </div> </div> ); };
less样式代码:
.informErrorHoverStyle{ .imgDiv{ position: fixed; right: 20px; z-index: 9999; width: 40px; height: 40px; white-space: nowrap; background-size: 100% 100%; transition: all 0.3s; } .imgStyle{ width: 40px; height: 40px; } }
三、详解:
1、需要定义的数据
// 图标的ref const divRef = useRef<any>(); // 图标的高度 const [itemHeight, setItemHeight] = useState<number>(80); // 图标的宽度 const [itemWidth, setItemWidth] = useState<number>(80); // 向左移动的距离 const [left, setLeft] = useState<number>(0); // 向上移动的距离 const [top, setTop] = useState<number>(0); // 获取浏览器窗口文档显示区域的宽度 const [clientWidth, setClientWidth] = useState<number>(0); // 获取浏览器窗口文档显示区域的宽高度 const [clientHeight, setClientHeight] = useState<number>(0); // 图标距离边距的距离 const [gapWidth, setGapWidth] = useState<number>(30);
2、需要定义的方法
/** * 开当按下手指时,触发 * @param e */ const dragStart = (e: any) => { divRef!.current!.style.transition = 'none'; }; /** * 当移走手指时,触发 * @param e */ const dragEnd = (e: any) => { divRef!.current!.style.transition = 'all 0.3s'; if (left > clientWidth / 2) { setLeft(clientWidth - itemWidth - gapWidth); } else { setLeft(gapWidth); } }; /** * 当移动手指时,触发 * @param e */ const touchmove = (e: any) => { if (e.targetTouches.length === 1) { let touch = e.targetTouches[0]; setLeft(touch.clientX - itemWidth / 2); setTop(touch.clientY - itemHeight / 2); } };
3、dom节点内容
return ( <div className={styles.informErrorHoverStyle} style={{ top: `${itemHeight}px` }} // onTouchMove={(e) => { // console.log(e); // }}= > <div className={styles.imgDiv} ref={divRef} style={{ // 图片 backgroundImage: `url(${require('@/assets/images/inforErrorPng.png')})`, // 初始化宽度 width: `${itemWidth}px`, // 初始化高度 height: `${itemHeight}px`, // 距左边的距离 left: `${left}px`, // 距上面的距离 top: `${top}px`, }} onClick={() => { generateImage(); }} // 开当按下手指时,触发 onTouchStart={(e) => { dragStart(e); }} // 当移走手指时,触发 onTouchEnd={(e) => { dragEnd(e); }} // 当移动手指时,触发 onTouchMove={(e) => { touchmove(e); }} > {/* <img src={img ? img : InforErrorPng} className={styles.imgStyle} /> */} </div> </div> );
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。