面试官:如何实现表单退出时的警告提示

大家好,今天的分享由团队的 uncle13 老师提供。

在前端表单项目中,提供最佳的用户体验对于涉及表单提交的 Web 应用程序非常重要。直接影响用户体验的一个常见原因是由于意外导航离开页面而丢失未保存的更改。当用户在表单上进行编辑并尚未保存时,退出页面可能会导致数据丢失。为了提醒用户保存或确认退出操作,可以使用警告提示来处理。

常用的方法:浏览器的beforeunload事件

// 监听窗口关闭或刷新事件
window.addEventListener('beforeunload'function (event{
  // 检查表单是否已被修改
  if (formIsModified()) {
    // 显示警告消息
    event.preventDefault();
    event.returnValue = ''// 设置空字符串以触发浏览器默认的提示消息
  }
});

// 检查表单是否已被修改
function formIsModified({
  // 获取表单元素
  var form = document.getElementById('myForm');

  // 比较当前表单值与原始表单值是否相同
  // 这里可以根据实际情况做一些比较逻辑,比如对表单字段进行遍历、比较等
  // 返回 true 表示表单已被修改,否则返回 false
  return form.value !== form.defaultValue;
}

我们通过监听beforeunload事件来捕获用户离开页面的行为。如果表单已被修改,就会显示一个警告提示框。用户可以选择继续离开页面或取消操作。

注意,由于安全限制,浏览器不允许自定义提示消息。浏览器将显示默认的提示消息,例如:"此页上的更改还未保存。确定离开此页吗?"。

另外,需要根据实际项目的表单结构和需求进行适当的修改和扩展,比如可以针对不同的表单元素添加特定的判断逻辑,或者使用框架提供的组件来处理表单退出时的警告提示。

此外,除了使用浏览器的beforeunload事件外,还有其他方法可以处理表单退出时的警告提示。以下是另外两种常见的处理方式:

1. 自定义确认对话框

使用自定义的确认对话框来提醒用户保存或放弃修改。当用户点击页面上的退出按钮或关闭按钮时,触发自定义对话框,让用户选择继续编辑或离开页面。

// 监听退出按钮点击事件
document.getElementById('exitButton').addEventListener('click'function ({
  if (formIsModified()) {
    // 显示自定义确认对话框
    showConfirmationDialog();
  } else {
    // 直接离开页面
    window.location.href = 'exit.html';
  }
});

// 显示自定义确认对话框
function showConfirmationDialog({
  // 使用第三方库或自定义模态框组件显示对话框
  // 对话框包含保存、放弃和取消按钮,根据用户选择进行相应操作
  // 点击保存按钮:执行保存逻辑,并离开页面
  // 点击放弃按钮:直接离开页面
  // 点击取消按钮:关闭对话框,用户可以继续编辑
}

在此示例中,我们监听了一个名为exitButton的退出按钮的点击事件。如果表单已被修改,则会显示自定义的确认对话框,让用户选择保存、放弃或取消操作。根据用户的选择,执行相应的逻辑。

2. 单页应用(SPA)路由守卫

如果你的项目是一个单页应用(SPA),可以使用前端框架提供的路由守卫来处理表单退出时的警告提示。通过在路由守卫中检查表单是否已被修改,并根据用户选择进行相应操作。

Vue的例子:

// 在路由配置中添加守卫
const routes = [
  {
    path'/form',
    name'Form',
    component: FormComponent,
    beforeEnter(to, from, next) => {
      if (formIsModified()) {
        // 显示确认对话框或其他警告提示
        showConfirmationDialog().then(choice => {
          if (choice === 'save') {
            // 执行保存逻辑
            saveForm().then(() => {
              next(); // 继续导航到目标页面
            });
          } else if (choice === 'discard') {
            next(); // 继续导航到目标页面
          } else {
            // 取消导航
            next(false);
          }
        });
      } else {
        next(); // 继续导航到目标页面
      }
    },
  },
];

在这个示例中,我们在路由配置中使用了beforeEnter守卫,当用户尝试导航到表单页面时触发该守卫。如果表单已被修改,则显示自定义确认对话框,让用户选择保存、放弃或取消操作。根据用户的选择,执行相应的逻辑。

React的例子

当处理表单退出时的警告提示时,我们可以使用自定义的useBeforeUnload钩子来优化React示例代码。这个钩子可以将beforeunload事件的监听和取消监听逻辑封装起来,以更好地与React组件进行集成。

下面是一个优化后的React示例:

import React, { useState } from 'react';

// 自定义useBeforeUnload钩子
const useBeforeUnload = (shouldPrompt) => {
  const [isDirty, setDirty] = useState(false);

  const handleBeforeUnload = (event) => {
    if (shouldPrompt && isDirty) {
      event.preventDefault();
      event.returnValue = '';
    }
  };

  const enableBeforeUnload = () => {
    setDirty(true);
  };

  const disableBeforeUnload = () => {
    setDirty(false);
  };

  // 监听和取消监听beforeunload事件
  React.useEffect(() => {
    window.addEventListener('beforeunload', handleBeforeUnload);
    return () => {
      window.removeEventListener('beforeunload', handleBeforeUnload);
    };
  }, []);

  return { enableBeforeUnload, disableBeforeUnload };
};

function FormComponent({
  const [formIsModified, setFormIsModified] = useState(false);

  const handleInputChange = (event) => {
    setFormIsModified(true);
  };

  const { enableBeforeUnload, disableBeforeUnload } = useBeforeUnload(formIsModified);

  const handleFormSubmit = () => {
    disableBeforeUnload(); // 停止显示警告提示
    // 提交表单逻辑
  };

  return (
    <div>
      {/* 表单内容 */}
      <form onSubmit={handleFormSubmit}>
        <input type="text" onChange={handleInputChange} />
        <button onClick={enableBeforeUnload}>编辑中离开</button>
        <button type="submit">提交</button>
      </form>
    </div>

  );
}

export default FormComponent;

在这个优化后的示例中,我们定义了一个自定义的useBeforeUnload钩子。这个钩子内部管理了isDirty状态,用于跟踪表单是否已被修改。它还提供了enableBeforeUnloaddisableBeforeUnload函数,用于启用和禁用警告提示。

在组件的返回部分,通过调用enableBeforeUnload函数来启用警告提示,并将其绑定到“编辑中离开”的按钮上。当用户点击此按钮时,如果表单已被修改,会触发beforeunload事件的监听器,显示警告提示。

另外,我们还添加了一个处理表单提交的函数handleFormSubmit。在提交表单之前,我们调用disableBeforeUnload函数来停止显示警告提示,以确保用户可以顺利提交表单。

通过使用自定义的useBeforeUnload钩子,我们可以更好地将警告提示与React组件集成,并提供更灵活的控制和优化选项。根据实际需求进行适当的修改和扩展即可。

在前端项目中处理表单退出时的警告提示时,以下是一些需要注意的问题:

  1. 用户体验优化: 警告提示应该提供清晰明确的信息,以帮助用户做出正确的决策。确保消息简洁易懂,并且能够有效地传达给用户为什么需要警告提示以及可能的后果。

  2. 合适的时机触发: 决定何时触发警告提示很关键。通常,在用户进行修改但尚未保存时,触发警告提示是合适的。避免在用户刚打开页面或只是浏览内容时就显示警告提示,这可能会干扰用户。

  3. 选择合适的提示方式: 警告提示可以以对话框、弹出层、通知条或自定义的界面形式呈现。选择适合你项目和用户界面的方式,并确保用户能够清楚地理解提示内容。

  4. 灵活的操作选择: 提供让用户选择的操作,例如保存、放弃或取消。这样用户可以根据他们的意愿和需求来选择下一步的操作。确保按钮或链接的标签文字能准确反映它们的功能,以避免用户混淆。

  5. 处理不同场景: 在某些情况下,用户可能会有额外的提示需求,例如在关闭浏览器标签或离开页面时。要考虑这些场景,并根据需要进行相应的处理。

  6. 状态管理和清除: 在表单退出前,确保适当地管理表单状态。在用户确认离开页面后,清除表单数据或将其重置为原始状态,以避免保存了不必要的、过时或敏感信息。

  7. 移动设备适配: 考虑在移动设备上使用警告提示的特殊注意事项。确保在不同移动设备和浏览器中进行测试,以验证警告提示的可靠性和一致性。

  8. 安全性考虑: 当处理涉及敏感信息或用户隐私的表单时,需要特别注意安全性。避免将敏感信息显示在警告提示中,确保对用户数据的保护。