【问题标题】:How to optimize these two functions into clean code (No jQuery)如何将这两个函数优化为干净的代码(无 jQuery)
【发布时间】:2021-10-30 17:18:11
【问题描述】:

我有这个非常“不干净”的代码,我在其中打开一个带有动画的模式:

const modal = document.getElementById("modal");
const modalDarkBackground = document.getElementById("modalDarkBackground");

document.getElementById("openModal").onclick = function() {
  modal.style.opacity = "1";
  modal.style.zIndex = "9999";
  modal.style.transform = "translate(-50%, -50%) scale(1)";
  modalDarkBackground.style.zIndex = "9998";
  modalDarkBackground.style.opacity = "1";
}

document.getElementById("closeModal").onclick = function() {
  modal.style.transform = "translate(-50%, -50%) scale(1.1)";

  setTimeout(function() {
    modal.style.opacity = "0";
    modal.style.zIndex = "-1";
    modal.style.transform = "translate(-50%, -50%) scale(0)";
    modalDarkBackground.style.zIndex = "-1";
    modalDarkBackground.style.opacity = "0";
  }, 500);
}
* {
  margin: 0;
  padding: 0;
  font-family: 'Roboto', sans-serif;
}

#modalDarkBackground {
  height: 100vh;
  width: 100%;
  background: rgba(0,0,0,0.5);
  transition: all 0.5s;
  position: absolute;
  top: 0;
  left: 0;
  opacity: 0;
  z-index: -1;
}

#modal {
  width: 300px;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) scale(0);
  overflow: hidden;
  transition: all 0.5s;
  opacity: 0;
  background: #fff;
}
#modal h1 {
  background: #E6E6E6;
  color: #ff0C0C;
  font-size: 20px;
  padding: 0.5em;
  border-bottom: 1px solid #C0C0C0;
}
#modal p {
  min-height: 70px;
  padding: 0.5em;
  color: #ff0C0C;
  font-weight: 400;
  font-size: 15px;
}
#modal button {
  display: block;
  width: 50%;
  padding: 0.5em 1em;
  background: #EDB44C;
  color: #fff;
  font-size: 15px;
  margin: 0 auto 0.5em auto;
  border: 1px solid #BEBEBE;
  border-radius: 3px;
}
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@100;300;400&display=swap" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<button id="openModal">
  Open Modal
</button>

<div id="modalDarkBackground"></div>
<div id="modal">
  <h1>Error</h1>

  <p id="modalContent">
    You do not seem to have an Internet connection.
    Please check your connection.
  </p>

  <button id="closeModal">
    OK
  </button>
</div>

我注意到我的 JavaScript 代码的内联样式非常糟糕,而且太长了。有没有办法用例如优化这个 JavaScript 代码? AddClass,也许可以用它做一个函数?抱歉,我是 JavaScript 新手

提前致谢!

【问题讨论】:

  • 您不使用alert() 之类的东西有什么原因吗?这对可访问性更好。

标签: javascript html dom modal-dialog css-transitions


【解决方案1】:

您可以在 css 类中描述转换并添加/删除它们以显示/隐藏模式

const modal = document.getElementById("modal");
const modalDarkBackground = document.getElementById("modalDarkBackground");

const show = () => {
    modal.classList.add('show');
    modalDarkBackground.classList.add('show');
};

const hide = () => {
    modal.classList.add('prepare-hide');
    setTimeout(function() {
        modal.classList.remove('prepare-hide');
        modal.classList.remove('show');
        modalDarkBackground.classList.remove('show');
    }, 500);
};

modalDarkBackground.onclick = hide;

document.getElementById("openModal").onclick = show;

document.getElementById("closeModal").onclick = hide;
* {
    margin: 0;
    padding: 0;
    font-family: 'Roboto', sans-serif;
}

#modalDarkBackground {
    height: 100vh;
    width: 100%;
    background: rgba(0,0,0,0.5);
    transition: all 0.5s;
    position: absolute;
    top: 0;
    left: 0;
    opacity: 0;
    z-index: -1;
}

#modal {
    width: 300px;
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%) scale(0);
    overflow: hidden;
    transition: all 0.5s;
    opacity: 0;
    background: #fff;
}

#modal h1 {
    background: #E6E6E6;
    color: #ff0C0C;
    font-size: 20px;
    padding: 0.5em;
    border-bottom: 1px solid #C0C0C0;
}

#modal p {
    min-height: 70px;
    padding: 0.5em;
    color: #ff0C0C;
    font-weight: 400;
    font-size: 15px;
}

#modal button {
    display: block;
    width: 50%;
    padding: 0.5em 1em;
    background: #EDB44C;
    color: #fff;
    font-size: 15px;
    margin: 0 auto 0.5em auto;
    border: 1px solid #BEBEBE;
    border-radius: 3px;
}

#modalDarkBackground.show {
    z-index: 9998;
    opacity: 1;
}

#modal.show {
    opacity: 1;
    z-index: 9999;
    transform: translate(-50%, -50%) scale(1);
}

#modal.prepare-hide {
    transform: translate(-50%, -50%) scale(1.1);
}
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@100;300;400&display=swap" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<button id="openModal">
Open Modal
</button>


<div id="modalDarkBackground"></div>
<div id="modal">
<h1>Error</h1>

<p id="modalContent">
    You do not seem to have an Internet connection. Please check your connection.
</p>

<button id="closeModal">
    OK
</button>

</div>

【讨论】:

  • 深色背景的关闭动画效果不太好
  • @GucciBananaKing99 我没有改作者设置的属性,我只是用css描述的
  • @GucciBananaKing99 在后台添加了一个点击处理程序
【解决方案2】:

您可以使用样式类重写 JS 代码。

我将样式从 JS 移到了样式块中。

现在 JS 看起来更好了。

const modal = document.getElementById('modal');
const modalDarkBackground = document.getElementById('modalDarkBackground');

document.getElementById('openModal').onclick = function() {
  modal
    .classList.add('openModal');
  modalDarkBackground
    .classList.add('modalDarkBackgroundOpen');
}

document.getElementById('closeModal').onclick = function() {
  modal
    .classList.add('transformScale');

  setTimeout(function() {
    modal
      .classList.replace('openModal', 'closeModal');
    modalDarkBackground
      .classList.replace('modalDarkBackgroundOpen', 'modalDarkBackgroundClose');
  }, 500);
}
* {
  margin: 0;
  padding: 0;
  font-family: 'Roboto', sans-serif;
}

#modalDarkBackground {
  height: 100vh;
  width: 100%;
  background: rgba(0,0,0,0.5);
  transition: all 0.5s;
  position: absolute;
  top: 0;
  left: 0;
  opacity: 0;
  z-index: -1;
}

#modal {
  width: 300px;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) scale(0);
  overflow: hidden;
  transition: all 0.5s;
  opacity: 0;
  background: #fff;
}
#modal h1 {
  background: #E6E6E6;
  color: #ff0C0C;
  font-size: 20px;
  padding: 0.5em;
  border-bottom: 1px solid #C0C0C0;
}
#modal p {
  min-height: 70px;
  padding: 0.5em;
  color: #ff0C0C;
  font-weight: 400;
  font-size: 15px;
}
#modal button {
  display: block;
  width: 50%;
  padding: 0.5em 1em;
  background: #EDB44C;
  color: #fff;
  font-size: 15px;
  margin: 0 auto 0.5em auto;
  border: 1px solid #BEBEBE;
  border-radius: 3px;
}

#modal.openModal {
  opacity: 1;
  z-index: 9999;
  transform: translate(-50%, -50%) scale(1);
}
#modal.closeModal {
  opacity: 0;
  z-index: -1;
  transform: translate(-50%, -50%) scale(0);
}
#modal.transformScale {
  transform: translate(-50%, -50%) scale(1.1);
}
#modalDarkBackground.modalDarkBackgroundOpen {
  z-index: 9998;
  opacity: 1;
}
#modalDarkBackground.modalDarkBackgroundClose {
  z-index: -1;
  opacity: 0;
}
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@100;300;400&display=swap" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<button id="openModal">
  Open Modal
</button>

<div id="modalDarkBackground"></div>
<div id="modal">
  <h1>Error</h1>

  <p id="modalContent">
    You do not seem to have an Internet connection.
    Please check your connection.
  </p>

  <button id="closeModal">
    OK
  </button>
</div>

【讨论】:

  • 我将您的代码转换为可执行的 sn-p 并且还使新引入的 css 规则更加具体,以便最初至少看到模态。但事实证明,模态只会显示一次。第一次关闭后不能再升起。
【解决方案3】:

您可以在关闭模态时添加close 类,该类可以具有不同的过渡属性-此属性将使用cubic-berzier 来给出在完全收缩之前扩展模态的效​​果。然后您可以使用setTimeout 删除close 类。

代码如下:

        const modal = document.getElementById("modal");
        const modalDarkBackground = document.getElementById("modalDarkBackground");

        document.getElementById("openModal").onclick = function () {
            modal.classList.add("open");
            modalDarkBackground.classList.add("open");
        }

        document.getElementById("closeModal").onclick = function () {
            modal.classList.add("close");
            modal.classList.remove("open");
            modalDarkBackground.classList.remove("open");
            setTimeout(function () { modal.classList.remove("close"); }, 500);
        }
        * {
            margin: 0;
            padding: 0;
            font-family: 'Roboto', sans-serif;
        }

        #modalDarkBackground {
            height: 100vh;
            width: 100%;
            background: rgba(0, 0, 0, 0.5);
            transition: all 0.5s;
            position: absolute;
            top: 0;
            left: 0;
            opacity: 0;
            z-index: -1;
        }

        #modalDarkBackground.open {
            opacity: 1;
            z-index: 9998;
        }

        #modal {
            width: 300px;
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%) scale(0);
            overflow: hidden;
            transition: all 0.5s;
            opacity: 0;
            background: #fff;
        }

        #modal.open {
            opacity: 1;
            z-index: 9999;
            transform: translate(-50%, -50%) scale(1);
        }

        #modal.close {
            opacity: 0;
            transform: translate(-50%, -50%) scale(0);
            transition: all 0.5s cubic-bezier(0.17, -0.16, 0.54, -0.42) !important;
        }

        #modal h1 {
            background: #E6E6E6;
            color: #ff0C0C;
            font-size: 20px;
            padding: 0.5em;
            border-bottom: 1px solid #C0C0C0;
        }

        #modal p {
            min-height: 70px;
            padding: 0.5em;
            color: #ff0C0C;
            font-weight: 400;
            font-size: 15px;
        }

        #modal button {
            display: block;
            width: 50%;
            padding: 0.5em 1em;
            background: #EDB44C;
            color: #fff;
            font-size: 15px;
            margin: 0 auto 0.5em auto;
            border: 1px solid #BEBEBE;
            border-radius: 3px;
        }
    <button id="openModal">
        Open Modal
    </button>

    <div id="modalDarkBackground"></div>
    <div id="modal">
        <h1>Error</h1>

        <p id="modalContent">
            You do not seem to have an Internet connection. Please check your connection.
        </p>

        <button id="closeModal">
            OK
        </button>
    </div>

【讨论】:

    【解决方案4】:

    与其将受影响的 DOM 节点硬连接到它们的预期行为,也不必将 CSS 数据也烘焙到 JavaScript 代码中,而是可以提供一个 组件 (DOM)模块 (JavaScript) 不仅仅是一个单一的想法。

    最重要的是,通过 JavaScript 逻辑将使用的一组通用 css 类名来定位此行为,将动画行为完全留给 CSS。

    当然,必须从更通用、结构更好的标记开始。尤其是嵌套对于如何定位布局规则至关重要,更重要的是,对于如何实现元素特定 css 转换的细粒度定位。

    因此,OP 的原始 CSS 根据新标记进行了轻微重组。

    OP 还可能会注意到 activebefore-deactivationdeactivating 的类名称特定规则,每个规则都针对刚刚或仍然提升的模态的特定状态 组件,可以通过每个modal 组件根节点上的相关data-* 属性进行自定义。

    modals-module 背后的理念是方便和灵活。模块内部按每个项目对应的元素节点存储modal 项目。

    该模块只有getinitialize 两种方法。后者通过其特定的data-component-modal 属性识别所有与modal 相关的元素节点,并创建一个特定于节点的modal-item。

    因此,每个模态相关元素节点都可以被模块的get 方法使用,用于检索已经存在的modal-item,或者创建、存储和获取新元素-节点特定modal-item。

    每个项目都拥有两个方法activatedeactivate,它们根据其命名/措辞从字面上触发一个行为。

    因此,组件方法允许在同一个文档中使用多个模态组件。它允许其他程序逻辑或组件通过它们的元素节点引用单独检索和使用modal-items,例如触发模态行为,例如提升/打开 (activate) 或关闭 (deactivate) 模态相关的元素节点。

    最终可执行sn-p的main函数的实现确实示范了刚才所说的...

    function main() {
      modals.initialize();
    
      document
        .querySelectorAll('[data-activate-modal]')
        .forEach(triggerNode => document
          .querySelectorAll(triggerNode.dataset.activateModal)
          .forEach(componentNode => triggerNode
            .addEventListener('click', modals.get(componentNode).activate)
          )
        );
    }
    

    ...modals 确实首先被初始化。然后是一些按钮,我们希望它们成为触发不同模式的触发器。这样的按钮/触发器由其data-activate-modal 属性标识。后者的值将用作目标模态的元素查询。例如像...这样的按钮

    <button data-activate-modal='#warningModal'>
      Open Warning Modal
    </button>
    

    ... 确实针对'#warningModal' 查询的任何模态,由于使用了基于id 的选择器,因此该示例的原因只是一个唯一的模态组件。

    最后,任何触发元素都将通过activate-ing 处理此类触发器上的每个相关项目来处理其任何目标modal-items,例如click 事件。

    但是,通过相关的元素节点引用存储和检索模态项的方法还有更多选择。

    // `modals` module.
    const modals = (function () {
    
      function getSafeInteger(value) {
        value = parseInt(value, 10);
        return Number.isSafeInteger(value) ? value : 0;
      }
    
      function activateBoundModalTarget() {
        this.classList.add('active');
      }
      function deactivateBoundModalTarget() {
        const modalNode = this;
        let {
          deactivationDuration: delayDefault,
          deactivationDelay: delayBefore,
        } = modalNode.dataset;
    
        delayDefault = getSafeInteger(delayDefault);
        delayBefore = getSafeInteger(delayBefore);
    
        modalNode.classList.add('before-deactivation', 'deactivating');
    
        setTimeout(() => {
          modalNode.classList.remove('active', 'before-deactivation');
    
          setTimeout(() =>
            modalNode.classList.remove('deactivating'), delayDefault
          );
        }, delayBefore);
      }
    
      // `modal` item/type factory
      function createModal(rootNode) {
        const activate = activateBoundModalTarget.bind(rootNode);
        const deactivate = deactivateBoundModalTarget.bind(rootNode);
        rootNode
          .querySelectorAll('[data-trigger-inactive]')
          .forEach(triggerNode => triggerNode
            .addEventListener('click', deactivate)
          );
        return {
          rootNode,
          activate,
          deactivate
        }
      }
      const storage = new WeakMap;
    
      function getModal(rootNode) {
        let modal = storage.get(rootNode);
        if (
          !modal &&
          (rootNode instanceof HTMLElement) &&
          rootNode.hasAttribute('data-component-modal')
        ) {
          if (modal = createModal(rootNode)) {
    
            storage.set(rootNode, modal);
          }
        }
        return modal ?? null;
      }
    
      function initialize() {
        document
          .querySelectorAll('[data-component-modal]')
          .forEach(getModal);
      }
    
      // export module.
      return {
        get: getModal,
        initialize,
      };
    }());
    
    
    function main() {
      modals.initialize();
    
      document
        .querySelectorAll('[data-activate-modal]')
        .forEach(triggerNode => document
          .querySelectorAll(triggerNode.dataset.activateModal)
          .forEach(componentNode => triggerNode
            .addEventListener('click', modals.get(componentNode).activate)
          )
        );
    }
    main();
    * {
      margin: 0;
      padding: 0;
      font-family: 'Roboto', sans-serif;
    }
    
    [data-component-modal] {
      z-index: -1;
      position: fixed;
      left: 0;
      top: 0;
      width: 100%;
      height: 100%;
    }
    [data-component-modal] .background {
      opacity: 0;
      z-index: 0;
      position: absolute;
      left: 0;
      top: 0;
      width: 100%;
      height: 100vh;
      background: rgba(192, 192, 192, 0.9);
      transition: all 0.5s;
    }
    [data-component-modal] .content {
      zoom: .8;
      opacity: 0;
      z-index: 1;
      position: absolute;
      left: 50%;
      top: 50%;
      width: 300px;
      background: #fff;
      overflow: hidden;
      transition: all 0.5s;
      transform: translate(-50%, -50%) scale(1);
    }
    
    [data-component-modal].deactivating,
    [data-component-modal].active {
      z-index: 99;
    }
    [data-component-modal].active .background,
    [data-component-modal].active .content {
      opacity: 1;
    }
    [data-component-modal].active.before-deactivation .content {
      transform: translate(-50%, -50%) scale(1.1);
    }
    
    [data-component-modal].error .background {
      background: rgba(255, 192, 192, 0.9);
    }
    
    [data-component-modal] .content h1 {
      background: #E6E6E6;
      font-size: 20px;
      padding: 0.5em;
      border-bottom: 1px solid #C0C0C0;
    }
    [data-component-modal] .content p {
      min-height: 70px;
      padding: 0.5em;
      font-weight: 400;
      font-size: 15px;
    }
    [data-component-modal].error .content h1,
    [data-component-modal].error .content p {
      color: #ff0C0C;
    }
    [data-component-modal] .content button {
      display: block;
      width: 50%;
      padding: 0.5em 1em;
      background: #EDB44C;
      color: #fff;
      font-size: 15px;
      margin: 0 auto 0.5em auto;
      border: 1px solid #BEBEBE;
      border-radius: 3px;
    }
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@100;300;400&display=swap" rel="stylesheet">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    
    <button data-activate-modal='#errorModal'>
      Open Error Modal
    </button>
    <button data-activate-modal='#warningModal'>
      Open Warning Modal
    </button>
    <button data-activate-modal='#errorModal'>
      Open Error Modal
    </button>
    <button data-activate-modal='#warningModal'>
      Open Warning Modal
    </button>
    
    <div
      data-component-modal
      data-deactivation-duration='500'
      id="errorModal"
      class="error"
      >
      <div class="content">
        <h1>Error</h1>
    
        <p id="modalContent">
          You do not seem to have an Internet connection.
          Please check your connection.
        </p>
    
        <button data-trigger-inactive>
          OK
        </button>
      </div>
      <div class="background"></div>
    </div>
    
    <div
      data-component-modal
      data-deactivation-duration='500'
      data-deactivation-delay='500'
      id="warningModal"
      >
      <div class="content">
        <h1>Warning</h1>
    
        <p id="modalContent">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
        </p>
    
        <button data-trigger-inactive>
          OK
        </button>
        <button data-trigger-inactive>
          close
        </button>
      </div>
      <div class="background"></div>
    </div>

    【讨论】:

      猜你喜欢
      • 2019-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-13
      • 1970-01-01
      • 1970-01-01
      • 2016-05-27
      相关资源
      最近更新 更多