工作自动化(1)用户引导自动化教程开发——仙盟创梦IDE

Intro.js 多流程分步引导开发入门:从基础到企业级实践

在企业级后台系统、多租户业务平台开发中,引导用户完成核心操作是提升易用性的关键。Intro.js 作为轻量无依赖的原生 JS 引导库(体积仅 10KB 左右),能快速实现分步引导,但面对 "多角色、多流程、表单校验" 等复杂场景时,需要一套标准化的开发思路。本文从基础入门到企业级多流程封装,完整讲解 Intro.js 分步引导的开发实践。

一、Intro.js 核心优势(为什么选它?)

相比其他引导库,Intro.js 最适合企业级原生 JS 项目的核心原因:

  1. 无依赖:纯原生 JS 实现,不依赖 Vue/React/Angular,兼容 jQuery、自研基础库(如 ZQ.js);
  2. 轻量:压缩后 JS 仅 10KB,CSS 2.5KB,对页面性能几乎无影响;
  3. 灵活:支持自定义步骤、样式、交互逻辑,可适配表单校验、权限控制等业务场景;
  4. 易维护:独立引入、独立修改,无需打包编译,手机端也能快速调整代码;
  5. 开源安全:MIT 协议,无后门风险,可直接下载源码二次开发。

二、基础入门:单流程分步引导

1. 快速上手(5 分钟实现基础引导)

步骤 1:引入资源

直接通过 CDN 引入压缩版资源(生产环境推荐本地保存):

复制代码
<!-- Intro.js 样式 -->
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/intro.js/7.2.0/introjs.min.css">
<!-- Intro.js 核心 JS -->
<script src="https://cdn.bootcdn.net/ajax/libs/intro.js/7.2.0/intro.min.js"></script>
步骤 2:标记引导元素

通过 data-step(步骤序号)、data-intro(引导文案)、data-title(步骤标题)标记需要引导的元素:

复制代码
<!-- 引导步骤1:填写姓名 -->
<div data-step="1" data-intro="请填写真实姓名(必填)" data-title="基础信息填写-第一步">
  姓名:<input type="text" id="userName" class="required">
</div>
<!-- 引导步骤2:选择公司 -->
<div data-step="2" data-intro="选择您所属的公司" data-title="基础信息填写-第二步">
  公司:<select id="company" class="required">
    <option value="">请选择</option>
    <option value="1">公司A</option>
    <option value="2">公司B</option>
  </select>
</div>
<!-- 启动引导按钮 -->
<button onclick="startIntro()">启动引导</button>
步骤 3:初始化并启动引导
复制代码
// 全局保存引导实例,方便控制
let introInstance = null;

// 启动引导函数
function startIntro() {
  // 初始化实例,配置基础参数
  introInstance = introJs().setOptions({
    showButtons: true, // 显示下一步/上一步按钮
    nextLabel: "下一步 →", // 自定义下一步按钮文本
    overlayClickToClose: false, // 点击遮罩层不关闭引导
    exitOnEsc: false, // 禁用ESC键退出(强制完成引导)
    keyboardNavigation: false // 禁用键盘方向键(避免误操作)
  });
  
  // 启动引导
  introInstance.start();
}

// 可选:停止引导函数
function stopIntro() {
  if (introInstance) {
    introInstance.exit();
    introInstance = null; // 销毁实例释放内存
  }
}

2. 核心配置说明(新手必看)

配置项 作用 常用值
showButtons 是否显示操作按钮 true/false
nextLabel/prevLabel 下一步 / 上一步按钮文本 自定义字符串(如 "下一步 →")
overlayClickToClose 点击遮罩层是否关闭引导 true/false
exitOnEsc 按 ESC 键是否退出引导 true/false
keyboardNavigation 是否允许键盘方向键切换步骤 true/false
steps 自定义引导步骤(替代 data 属性) 数组(如 [{element: '#id', intro: '文案'}]

三、进阶实践:表单校验联动引导

企业级场景中,引导不能仅 "展示",还需强制用户完成核心操作(如必填项填写)。通过 onbeforechange 事件实现 "未填必填项,禁止下一步"。

完整示例:带表单校验的引导

复制代码
function startIntro() {
  introInstance = introJs().setOptions({
    showButtons: true,
    nextLabel: "下一步 →",
    overlayClickToClose: false,
    exitOnEsc: false,
    keyboardNavigation: false
  });

  // 切换步骤前校验表单
  introInstance.onbeforechange(function(step) {
    // 当前步骤序号(Intro.js 步骤从0开始,需+1)
    const currentStep = this._currentStep + 1;
    // 获取当前步骤的必填项
    const requiredInput = document.querySelector(`[data-step="${currentStep}"] .required`);
    
    // 校验逻辑:必填项为空则阻止下一步
    if (requiredInput && !requiredInput.value.trim()) {
      alert(`第${currentStep}步:必填项未填写!`);
      return false; // 返回false阻止步骤切换
    }
    return true; // 校验通过,允许下一步
  });

  introInstance.start();
}

四、企业级实战:单页面多流程引导

多租户、多角色系统中(如新用户、管理员、商家),不同角色需不同引导流程。核心思路:流程配置化 + 实例隔离 + 逻辑定制

1. 核心设计思路

  • data-flow 标记不同流程的元素(如 data-flow="newUser"/data-flow="admin");
  • 封装流程配置对象,每个流程独立配置样式、校验逻辑;
  • 统一流程管理器,控制流程启停、切换,避免多个流程同时运行。

2. 完整实现代码

复制代码
<!-- 页面元素:不同流程标记 -->
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/intro.js/7.2.0/introjs.min.css">
<script src="https://cdn.bootcdn.net/ajax/libs/intro.js/7.2.0/intro.min.js"></script>

<!-- 流程1:新用户引导 -->
<div data-flow="newUser" data-step="1" data-intro="欢迎使用系统!填写姓名" data-title="新用户引导-第一步">
  姓名:<input type="text" id="userName" class="required">
</div>
<div data-flow="newUser" data-step="2" data-intro="选择所属公司" data-title="新用户引导-第二步">
  公司:<select id="company" class="required"><option value="">请选择</option><option value="1">公司A</option></select>
</div>

<!-- 流程2:管理员引导 -->
<div data-flow="admin" data-step="1" data-intro="配置用户权限" data-title="管理员引导-第一步">
  权限配置:<button id="authBtn">配置权限</button>
</div>
<div data-flow="admin" data-step="2" data-intro="查看数据报表" data-title="管理员引导-第二步">
  数据报表:<a href="#report">查看报表</a>
</div>

<!-- 流程3:商家引导 -->
<div data-flow="store" data-step="1" data-intro="编辑商品名称" data-title="商家引导-第一步">
  商品名称:<input type="text" id="goodsName" placeholder="非必填">
</div>
<div data-flow="store" data-step="2" data-intro="查看订单统计" data-title="商家引导-第二步">
  订单统计:<div id="orderChart">📊 订单数据</div>
</div>

<!-- 流程切换按钮 -->
<button onclick="startFlow('newUser')">新用户引导</button>
<button onclick="startFlow('admin')">管理员引导</button>
<button onclick="startFlow('store')">商家引导</button>
<button onclick="stopCurrentFlow()">停止引导</button>

<script>
// 流程管理器核心:当前实例 + 流程配置
let currentIntro = null;
const flowConfigs = {
  // 新用户流程:强制表单校验
  newUser: {
    showButtons: true,
    nextLabel: "下一步 →",
    overlayClickToClose: false,
    exitOnEsc: false,
    steps: document.querySelectorAll('[data-flow="newUser"]'),
    validate: (step) => {
      const stepNum = step._currentStep + 1;
      const input = document.querySelector(`[data-flow="newUser"][data-step="${stepNum}"] .required`);
      if (!input?.value.trim()) {
        alert(`新用户引导第${stepNum}步:必填项未填写!`);
        return false;
      }
      return true;
    }
  },
  // 管理员流程:无校验,简单操作
  admin: {
    showButtons: true,
    nextLabel: "下一步 →",
    overlayClickToClose: false,
    exitOnEsc: false,
    steps: document.querySelectorAll('[data-flow="admin"]')
  },
  // 商家流程:轻量提示(非强制)
  store: {
    showButtons: true,
    nextLabel: "下一步 →",
    overlayClickToClose: false,
    exitOnEsc: false,
    steps: document.querySelectorAll('[data-flow="store"]'),
    validate: (step) => {
      const stepNum = step._currentStep + 1;
      if (stepNum === 1) {
        const input = document.getElementById('goodsName');
        if (!input.value.trim()) {
          alert(`商家引导提示:建议填写商品名称(非必填)`);
        }
      }
      return true;
    }
  }
};

// 启动指定流程
function startFlow(flowId) {
  // 先停止当前流程,避免冲突
  if (currentIntro) {
    currentIntro.exit();
  }

  const config = flowConfigs[flowId];
  if (!config) {
    alert(`流程${flowId}不存在!`);
    return;
  }

  // 初始化当前流程实例
  currentIntro = introJs().setOptions({
    showButtons: config.showButtons,
    nextLabel: config.nextLabel,
    overlayClickToClose: config.overlayClickToClose,
    exitOnEsc: config.exitOnEsc,
    // 仅加载当前流程的步骤
    steps: Array.from(config.steps).map(el => ({
      element: el,
      intro: el.dataset.intro,
      title: el.dataset.title
    }))
  });

  // 绑定当前流程的校验逻辑
  if (config.validate) {
    currentIntro.onbeforechange(config.validate);
  }

  currentIntro.start();
}

// 停止当前流程
function stopCurrentFlow() {
  if (currentIntro) {
    currentIntro.exit();
    currentIntro = null;
  }
}
</script>

3. 多流程核心优势

  • 隔离性 :不同流程通过 data-flow 标记,启动时仅加载对应步骤,互不干扰;
  • 定制化:每个流程可配置专属校验逻辑(强制 / 提示 / 无校验),适配不同角色需求;
  • 易维护 :新增流程只需在 flowConfigs 中添加配置,无需修改核心逻辑;
  • 轻量化:保留 Intro.js 原生特性,不引入额外依赖,符合原生 JS 项目架构。

五、开发避坑与最佳实践

1. 常见问题解决

  • 步骤串线 :切换流程前必须调用 exit() 销毁旧实例,避免多个引导同时运行;
  • 校验失效onbeforechange 中需返回 false 才能阻止步骤切换,仅 alert 无效果;
  • 样式冲突 :Intro.js 样式可通过自定义类名覆盖(如 .introjs-tooltip { background: #xxx; });
  • 性能问题 :避免一次性获取大量 DOM 元素,通过 data-flow 精准筛选步骤元素。

2. 企业级最佳实践

  • 基础库独立:Intro.js 作为基础模块独立引入,不与业务代码打包,方便升级替换;
  • 流程配置解耦:流程配置可从后端接口获取,适配多租户个性化引导需求;
  • 进度记忆:将当前流程 + 步骤存入 localStorage,用户刷新页面后自动恢复引导;
  • 权限控制 :启动流程前校验用户角色(如仅管理员可启动 admin 流程);
  • 兼容移动端:调整引导弹窗样式,适配手机屏幕,保留 "点击按钮切换" 核心逻辑。

六、总结

Intro.js 是原生 JS 项目实现分步引导的最优选择,其轻量、无依赖的特性完美适配 "基础模块独立、业务模块分离" 的企业级架构。从基础单流程引导,到表单校验联动,再到多流程管理,核心思路是 **"配置化、隔离化、定制化"**:

  1. data-step/data-flow 标记元素,实现流程与元素的绑定;
  2. 封装流程管理器,统一控制实例启停,避免冲突;
  3. 针对不同角色定制校验逻辑,兼顾强制引导与用户体验;
  4. 保留原生 JS 项目的灵活性,无需打包编译,支持快速修改和移动端编辑。

这套方案已适配五家公司共用基础模块的场景,既保证了基础库的稳定性,又满足了各业务线的个性化引导需求,是企业级原生 JS 项目引导功能的最优解

东方仙盟昭和调用

复制代码
introJs().setOptions({
  steps: [{
    title: '欢迎使用未来之窗软件引导',
    intro: '未来之窗模拟操作!👋'
  },
  {
    element: $cq('#setp4cont').me,
    intro: '合同管理:管理合同列表,合同到期'
  },
   {
    element: $cq('#setp5fee').me,
    intro: '水电费管理<img src="/manager.png" />'
  },
  
  {
    title: '结束',
    element: document.querySelector('.card__image'),
    intro: '<img src="manager.png" />'
  }],
  // 按钮文本全部改为中文
  nextLabel: '下一步',
  backLabel: '上一步',
  doneLabel: '完成'
}).start();

阿雪技术观

让我们积极投身于技术共享的浪潮中,不仅仅是作为受益者,更要成为贡献者。无论是分享自己的代码、撰写技术博客,还是参与开源项目的维护和改进,每一个小小的举动都可能成为推动技术进步的巨大力量

Embrace open source and sharing, witness the miracle of technological progress, and enjoy the happy times of humanity! Let's actively join the wave of technology sharing. Not only as beneficiaries, but also as contributors. Whether sharing our own code, writing technical blogs, or participating in the maintenance and improvement of open source projects, every small action may become a huge force driving technological progress.

相关推荐
hopsky2 小时前
限制 Docker Desktop 的资源使用
运维·docker·容器
JQLvopkk2 小时前
VSCode基础使用
ide·vscode·编辑器
馨谙2 小时前
Ansible Playbook 完全指南:从入门到实践
运维·ansible
一个没有本领的人2 小时前
vscode选择了正确的解释器,但终端显示运行的依然为原来的python版本
ide·vscode·python
Suchadar2 小时前
Docker搭建Web测试靶场
运维·docker·容器
Yana.nice2 小时前
chrony中“prefer”指定首选服务器
运维·服务器
NOVAnet20232 小时前
南凌科技「Bot防护」:让恶意爬虫、刷票薅羊毛等自动化攻击无处遁形
爬虫·科技·网络安全·自动化·南凌科技
GAOJ_K2 小时前
弧形导轨与直线导轨:曲线运动与直线运动
运维·人工智能·科技·机器人·自动化·制造
梦想的旅途22 小时前
如何优雅地实现企微外部群消息自动化(Java/Python/Go 多语言版)
java·自动化·企业微信