页面指引 IntroJS在React+Next中的使用 (解决初始化时未渲染的dom如何查找)

插件库选型背景

市面上有很多页面指引的插件,例如:
ReactourJshttps://reactour.js.org/
Shepherdjs:https://shepherdjs.dev/
但以上都在使用中有些问题,就放弃了
最终使用的
IntroJs:https://introjs.com/docs/getting-started/install

使用场景介绍及插件使用难点

项目是使用的React+Antd+Next
在页面指引的步骤中,有切换页面,有点击打开弹窗等操作

IntroJs和很多其他的页面指引的插件,核心思路是,通过dom查询,把当前这个dom找到,然后进行样式处理

使用中最大的问题和难题就是:在初始化时未渲染的dom如何查找,IntroJs没有提供实例属性,重启等API,仅能通过自己的代码进行手动处理

代码介绍**

我使用的是IntroJSReact版本:intro.js-react
因为这个版本的API里可以读取到,当前到了第几步!

  1. 安装

    npm install intro.js --save
    npm install intro.js-react
    
  2. 首先项目中的引用

    import dynamic from "next/dynamic";
    const Steps = dynamic(() => import("intro.js-react").then((mod: any) => mod.Steps), {
      ssr: false,
    });
    import "intro.js/introjs.css"; // 一定要引用样式
    
  3. 基础使用

    <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可以阻止进入下一步
    />
    
  4. 结合业务使用

    难点
    步骤中有需要跳转到其他页面和打开弹窗以后介绍内部部分
    总结就是在初次渲染时,没有这个DOM元素

    解决思路
    有很多组件都会有重启这种api,但是IntroJs没有提供,
    所以只有在对应的步骤,去手动重启

    重启涉及到的处理有

    1.重启后,需要定位到对应的步骤,比如是到第3步需要跳转页面,那么在跳转页面后,重启Steps,打开的应该是第3步
    2.重启就意味着需要结束上一个实例,就会走【退出】步骤,但是点击遮罩也是代表要退出导航,需要加判断值,何时是真的退出,何时是重启的退出。
    3.不仅需要考虑顺着的顺序,当回到上一步,需要重启到对应的状态

    步骤介绍
    在这里插入图片描述
    CODE

    import 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提供了解决方案,麻烦留言给我蟹蟹~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值