You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何基于模态框实现可复用的用户决策等待逻辑(避免拆分函数)

如何基于模态框实现可复用的用户决策等待逻辑(避免拆分函数)

我完全懂你的痛点——不想把好好的函数拆成前后两半,就想在函数中间“停一下”等用户点模态框,然后接着往下走,还得让这个模态框逻辑能复用在不同函数里。其实用Promise + async/await就能完美解决,既不用拆分函数,还能把模态框交互封装成可复用的模块,咱们一步步来:


第一步:封装可复用的模态框交互函数

首先,咱们先写一个通用函数,它负责显示模态框,并且返回一个Promise——当用户点击“保存”或“丢弃”按钮时,这个Promise会根据用户的选择resolve对应的结果(比如true代表保存,false代表丢弃)。这样任何需要等待用户决策的地方,只要await这个函数就行。

// 封装可复用的模态框决策函数
function showSaveDiscardModal() {
  return new Promise((resolve) => {
    // 显示模态框(这里用Bootstrap模态框为例,自定义模态框逻辑同理)
    $('#saveDiscardModal').modal('show');

    // 按钮点击后的处理逻辑
    function handleSave() {
      $('#saveDiscardModal').modal('hide');
      resolve(true); // 告知调用者:用户选择了保存
      cleanUpEvents(); // 清理事件,避免重复绑定
    }

    function handleDiscard() {
      $('#saveDiscardModal').modal('hide');
      resolve(false); // 告知调用者:用户选择了丢弃
      cleanUpEvents();
    }

    // 绑定按钮事件
    $('#btnSave').on('click', handleSave);
    $('#btnDiscard').on('click', handleDiscard);

    // 清理事件的辅助函数
    function cleanUpEvents() {
      $('#btnSave').off('click', handleSave);
      $('#btnDiscard').off('click', handleDiscard);
    }
  });
}

第二步:修改原有函数为async函数,用await等待用户决策

接下来,把你的doSomethingdoSomethingElse改成async函数,在需要等待用户决策的地方,用await调用上面的showSaveDiscardModal()——这样代码会“暂停”在这里,直到用户做出选择,然后根据返回结果继续执行后续逻辑,完全不用拆分函数!

// 改成async函数,保留完整逻辑
async function doSomething() {
  let a = new Date();
  console.log("it is " + a);

  // 等待用户在模态框的选择,shouldSave就是用户的决策结果
  const shouldSave = await showSaveDiscardModal();

  if (!shouldSave) { // 用户选择丢弃
    $("#myContainer").replaceWith("<div></div>");
  } else { // 用户选择保存
    saveChanges();
  }
}

async function doSomethingElse() {
  let b = 12 * 12;
  console.log("12 x 12 is " + b);
  let c = 1 + 1;
  console.log("1 + 1 is " + c);

  // 同样等待用户决策
  const shouldSave = await showSaveDiscardModal();

  if (!shouldSave) { // 用户选择丢弃
    $("#myContainer").replaceWith("<div></div>");
  } else { // 用户选择保存
    alert("Saving Changes Now!");
    saveChanges();
  }
}

第三步:补上模态框的HTML结构

你需要有对应的模态框DOM结构,这里用Bootstrap模态框为例(不用Bootstrap的话,自己写隐藏div+显示/隐藏逻辑也完全可以):

<!-- 通用的保存/丢弃模态框 -->
<div class="modal fade" id="saveDiscardModal" tabindex="-1" role="dialog">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title">确认操作</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        <p>是否要保存当前更改?</p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" id="btnDiscard">丢弃更改</button>
        <button type="button" class="btn btn-primary" id="btnSave">保存更改</button>
      </div>
    </div>
  </div>
</div>

第四步:修改事件监听(调用async函数)

最后,调用这些async函数的时候,在事件回调里要加上async/await

// 按钮点击事件绑定
$("#button1").on("click", async () => {
  await doSomething();
});

$("#button2").on("click", async () => {
  await doSomethingElse();
});

为什么这个方案可行?

这里的核心逻辑是用Promise把异步的用户交互(点击按钮)转换成可以用await等待的“同步”代码——async/await就是为了让异步代码看起来像同步代码而设计的,刚好命中你的需求:

  1. 不用拆分函数:原来的函数逻辑完完整整,只是在需要等待的地方加了一行await
  2. 完全复用:所有需要用户决策的地方,都只需要调用showSaveDiscardModal()就行,模态框逻辑只写一次;
  3. 可读性拉满:代码流程和你最开始写的伪代码几乎一致,一眼就能看懂逻辑走向。

额外注意事项

  • 如果不用jQuery/Bootstrap,用原生JS实现模态框的显示/隐藏和事件绑定也完全可以,核心思路还是返回Promise
  • 一定要清理事件绑定(比如示例里的cleanUpEvents),避免多次点击导致事件重复绑定;
  • 如果需要自定义模态框的提示文案,可以给showSaveDiscardModal加个参数,比如showSaveDiscardModal("是否确认丢弃表单内容?"),在函数里修改模态框的提示文本,进一步提升复用性。

火山引擎 最新活动