У меня есть этот простой код, но он беспорядочный — как мне его очистить?
Это работает так: если вы нажмете на menu-btn1
то div
появляется и скрывает других, но если вы нажмете на menu-btn1
снова он тоже скроется.
let coll = document.getElementsByClassName('collection');
let dis = document.getElementsByClassName('display');
let drop = document.getElementsByClassName('drop');
document.getElementById("menu-btn1").addEventListener("click", function() {
if(coll[0].style.display == 'none') {
coll[0].style.display = 'block';
dis[0].style.display = 'none';
drop[0].style.display = 'none';
} else {
coll[0].style.display = 'none';
}
});
<div class="menu">
<span id="text"><span id="menu-btn1">collection</span></span>
</div>
<div class="collection" style="display:none;"></div>
<div class="display" style="display:none;"></div>
<div class="drop style="display:none;"></div>
На самом деле в css нет ничего важного, только позиционирование сетки.
1 ответ
Сначала я думаю, что используя document.querySelector
кажется намного удобнее, чем использование document.getElementsByClassName
. Вместо let coll = document.getElementsByClassName('collection'); coll[0].xxx
, мы можем просто использовать document.querySeletor('collection').xxx
.
Таким образом, код можно немного реорганизовать, чтобы
let coll = document.querySelector('.collection');
let dis = document.querySelector('.display');
let drop = document.querySelector('.drop');
document.getElementById("menu-btn1").addEventListener("click", function() {
if(coll.style.display == 'none') {
coll.style.display = 'block';
dis.style.display = 'none';
drop.style.display = 'none';
} else {
coll.style.display = 'none';
}
});
Затем я помещу код извлечения DOM в обработчик событий, чтобы предотвратить ненужное загрязнение пространства имен. Хотя, возможно, в вашем рабочем коде вы можете использовать coll
для другой обработки, то можно разместить там. Кроме того, я не думаю, что кто-то изменит переменную DOM на другое значение, поэтому я бы использовал constant
вместо.
document.getElementById("menu-btn1").addEventListener("click", function() {
const coll = document.querySelector('.collection');
const dis = document.querySelector('.display');
const drop = document.querySelector('.drop');
if(coll.style.display == 'none') {
coll.style.display = 'block';
dis.style.display = 'none';
drop.style.display = 'none';
} else {
coll.style.display = 'none';
}
});
Однако эти изменения не решают того факта, что
display: none
фактически разбросан как в HTML, так и в Javascript. Я думаю, что лучше просто разместить код в одном месте. То есть удалите стили в HTML.
Для этого, я думаю, есть два подхода, один из них — использование RxJS
, другой способ — использовать подход, основанный на данных, например React
, Angular
, Vue
, …
Подход, основанный на данных: использование VueJS
Давайте сначала посмотрим, как мы можем реализовать это в подходе, основанном на данных. Я буду использовать Vue для демонстрации, так как он самый простой в настройке из трех.
new Vue({
el: "#app",
template: `
<div class="ui">
<div class="menu">
<span id="text"><span @click="show = !show">collection</span></span>
</div>
<div class="collection" :style="styles">
Collection Inside
</div>
</div>
`,
data: function() {
return {
show: false
}
},
computed: {
styles: function() {
return {
"display": this.show ? "block": "none"
};
},
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
</div>
Как видите, HTML-код теперь помещен в Javascript в качестве шаблона, и мы используем :style
и @click
в шаблоне вместо обычного HTML. Это специфический синтаксис Vue, который используется во Vue для упрощения взаимодействия между Javascript-компонентом Vue и шаблоном.
Подход, основанный на событиях: RxJS
Другой подход — RxJS, который просто работает без фреймворка, что упрощает его внедрение в унаследованное веб-приложение.
rxjs.merge(
rxjs.of(1), // so that it immediately triggers
rxjs.fromEvent(document.querySelector("#menu-btn1"), 'click'),
)
.pipe(
rxjs.operators.scan((accum, value, index) => {
return index % 2 == 1;
}, false)
).subscribe(show => {
const coll = document.querySelector(".collection");
const value = show ? "block" : "none";
coll.style.display = value;
}
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.6.3/rxjs.umd.min.js"></script>
<div class="menu">
<span id="text"><span id="menu-btn1">collection</span></span>
</div>
<div class="collection">
Collection Inside
</div>
Вот все решения, о которых я думаю, и вам остается решить, какой из них является наиболее чистым кодом. Мне просто нравится способ RxJS
сконструирован, и не нужно поддерживать дополнительные данные для хранения.