插件库选型背景
市面上有很多页面指引的插件,例如:
ReactourJs:https://reactour.js.org/
Shepherdjs:https://shepherdjs.dev/
但以上都在使用中有些问题,就放弃了
最终使用的
IntroJs:https://introjs.com/docs/getting-started/install
使用场景介绍及插件使用难点
项目是使用的React+Antd+Next
在页面指引的步骤中,有切换页面,有点击打开弹窗等操作
IntroJs和很多其他的页面指引的插件,核心思路是,通过dom查询,把当前这个dom找到,然后进行样式处理
使用中最大的问题和难题就是:在初始化时未渲染的dom如何查找
,IntroJs没有提供实例属性,重启等API,仅能通过自己的代码进行手动处理
代码介绍**
我使用的是IntroJS
的React
版本:intro.js-react
因为这个版本的API里可以读取到,当前到了第几步!
-
安装
npm install intro.js --save npm install intro.js-react
-
首先项目中的引用
import dynamic from "next/dynamic"; const Steps = dynamic(() => import("intro.js-react").then((mod: any) => mod.Steps), { ssr: false, }); import "intro.js/introjs.css"; // 一定要引用样式
-
基础使用
<Steps enabled={stepsEnabled} // 控制是否显示 boolean steps={steps} // 步骤数组 Step[] initialStep={initialStep} // 默认从第几步开始 数组下标 onExit={this.onExit} // 退出时触发的方法 onBeforeExit={this.onBeforeExit} //退出前触发的方法,返回false 则不会退出,也不会进入onExit onChange={this.onChange} // 更替时触发的方法,参数(nextStepIndex, nextElement),可以拿到下一步是第几步 onBeforeChange={this.onBeforeChange} //在change之前的方法,返回false可以阻止进入下一步 />
-
结合业务使用
难点:
步骤中有需要跳转到其他页面和打开弹窗以后介绍内部部分
总结就是在初次渲染时,没有这个DOM元素
解决思路:
有很多组件都会有重启这种api
,但是IntroJs
没有提供,
所以只有在对应的步骤,去手动重启
。重启涉及到的处理有:
1.重启后,需要定位到对应的步骤,比如是到第3步需要跳转页面,那么在跳转页面后,重启Steps,打开的应该是第3步
2.重启就意味着需要结束上一个实例,就会走【退出】步骤,但是点击遮罩也是代表要退出导航,需要加判断值,何时是真的退出,何时是重启的退出。
3.不仅需要考虑顺着的顺序,当回到上一步,需要重启到对应的状态步骤介绍
CODEimport React, { useState, useEffect } from "react"; import { useRouter } from "next/router"; import "intro.js/introjs.css"; import dynamic from "next/dynamic"; const Steps = dynamic(() => import("intro.js-react").then((mod: any) => mod.Steps), { ssr: false, }); const stepList = [ { element: "#A1", intro: `首页介绍1`, }, { element: "#A2", intro: "首页介绍2", }, { element: "#B1", intro: `下一页介绍1`, }, { element: "#B2", intro: "下一页介绍2", }, { element: "#C1", intro: "弹窗介绍1", }, { element: "#C2", intro: "弹窗介绍2", }, ]; const Test: React.FC = () => { const router = useRouter(); const [pageHasLoad, setPageHasLoad] = useState<boolean>(false); const [nextStep, setNextStep] = useState(0); const [curType, setCurType] = useState("home"); const [exitWarn, setExitWarn] = useState(true); useEffect(() => { setTimeout(() => { setPageHasLoad(true); }, 2000); }, []); // 重启页面指引,因为在初始化时未渲染的Dom,会找不到 const handleRelaod = (e: string) => { setCurType(e); setExitWarn(false); setPageHasLoad(false); setTimeout(() => { setPageHasLoad(true); }, 1000); }; return ( <Steps //@ts-ignore enabled={pageHasLoad} steps={stepList} initialStep={nextStep} onExit={(e: any) => { if (exitWarn) { console.log("退出时的操作"); } }} onBeforeExit={() => { if (exitWarn) { return confirm("提示是否要关闭弹窗"); } }} onBeforeChange={async (nextStepIndex: number) => { setNextStep(nextStepIndex); if (nextStepIndex ==0 || nextStepIndex === 1) { // 如果不处于当前模式就需要重启 if (router.pathname !== "首页路径") { await router.push("首页路径"); setExitWarn(false); handleRelaod("home"); } if (curType !== "home") { setExitWarn(false); handleRelaod("home"); } else { setExitWarn(true); } } else if (nextStepIndex == 2 || nextStepIndex == 3) { if (curType !== "nextPage") { setExitWarn(false); await router.push("下一页的路径"); handleRelaod("nextPage"); } else { setExitWarn(true); } } else { if (curType !== "modal") { setExitWarn(false); // 弹窗模式 if (弹窗是否打开了) { //打开弹窗 } handleRelaod("modal"); } else { setExitWarn(true); } } }} /> ); } export default Test;
如若IntroJS提供了解决方案,麻烦留言给我蟹蟹~