如何将这两个函数优化成干净的代码(没有jQuery)



我有这个非常"不干净";我用动画打开一个模态的代码:

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新手

提前感谢!

不需要将受影响的DOM节点与预期的行为硬连接,也不需要将css数据嵌入到JavaScript代码中,而是可以使用组件(DOM)模块(JavaScript)基于的方法不仅仅是一个单一的想法。

顶部的动画行为完全留给CSS,通过一组通用的CSS类名来定位这个行为。

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

因此,OP的原始CSS根据新的标记稍微重新组装。

OP还可能注意到active,before-deactivationdeactivating下/的类名特定规则,其中每个目标刚好或仍然凸起模态的特定状态

可以通过每个modal组件根节点上的相关data-*

属性进行自定义。modals模块背后的思想是方便和灵活。模块内部根据每个项目对应的元素节点存储modal项目。

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

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

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

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

最后的可执行代码片段的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为基础的选择器。

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

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

// `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>

你可以在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>

你可以使用样式类重写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>

您可以在关闭模态时添加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>

最新更新