Как не писать пять раз один и тот же код только с разными классами?
С помощью js я оформила выпадающий список вместо select. Но если я буду использовать 5 списков, то мне придется 5 раз js код писать только с разными классами.
Я думаю, это плохая практика.
Подскажите пожалуйста как можно сделать единую функцию для всех выпадающих списков?
function ready() {
const select = document.querySelector('.select');
const select_title = select.querySelector('.select_title');
const select_labels = select.querySelectorAll('.select_label');
select_title.addEventListener('click', () => {
if ('active' === select.getAttribute('data-state')) {
select.setAttribute('data-state', '');
} else {
select.setAttribute('data-state', 'active');
}
});
// Close when click to option
for (let i = 0; i < select_labels.length; i++) {
select_labels[i].addEventListener('click', (evt) => {
select_title.textContent = evt.target.textContent;
select.setAttribute('data-state', '');
});
}
///close outside the element
$(document).mouseup(function (e) {
select.setAttribute('data-state', '');
});
}
document.addEventListener("DOMContentLoaded", ready);
.select {
position: relative;
width: 300px;
height: 40px;
margin: 20px 0;
}
.select[data-state="active"] .select_title::before {
transform: translate(-3px, -50%) rotate(-45deg);
}
.select[data-state="active"] .select_title::after {
transform: translate(3px, -50%) rotate(45deg);
}
.select[data-state="active"] .select_content {
opacity: 1;
}
.select[data-state="active"] .select_label + .select_input + .select_label {
max-height: 40px;
border-top-width: 1px;
}
.select_title {
display: flex;
align-items: center;
width: 100%;
height: 100%;
padding: 8px 16px;
border-radius: 5px;
border: solid 1px #c7ccd1;
cursor: pointer;
background-color: #38b0ff;
color: #e9e9e9;
}
.select_title::before, .select_title::after {
content: "";
position: absolute;
top: 50%;
right: 16px;
display: block;
width: 10px;
height: 2px;
transition: all 0.3s ease-out;
background-color: #e9e9e9;
transform: translate(-3px, -50%) rotate(45deg);
}
.select_title::after {
transform: translate(3px, -50%) rotate(-45deg);
}
.select_title:hover {
color: #ffffff;
}
.select_title:hover::before, .select_title:hover::after {
background-color: #f3fdff;
}
.select_content {
position: absolute;
top: 40px;
left: 3px;
display: flex;
flex-direction: column;
width: calc(100% - 6px);
background-color: #ffffff;
border: 1px solid #c7ccd1;
border-top: none;
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
transition: all 0.3s ease-out;
opacity: 0;
z-index: 8;
}
.select_input {
display: none;
}
.select_input:checked + label {
background-color: #dedede;
}
.select_input:disabled + label {
opacity: 0.6;
pointer-events: none;
}
.select_label {
display: flex;
align-items: center;
width: 100%;
height: 40px;
max-height: 0;
padding: 0 20px;
transition: all 0.1s ease-out;
cursor: pointer;
overflow: hidden;
}
.select_label + input + .select_label {
border-top: 0 solid #C7CCD160;
}
.select_label:hover {
background-color: #38b0ff !important;
color: #ffffff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="select" data-state="">
<div class="select_title type_request" value="" data-default="">Выберите тип</div>
<div class="select_content">
<input id="option0" class="select_input" value="" type="radio" name="singleSelect" />
<label for="option0" class="select_label">Выберите тип</label>
<input id="option1" class="select_input type_request" value="1" type="radio" name="singleSelect" />
<label for="option1" class="select_label">Один</label>
<input id="option2" class="select_input type_request" value="2" type="radio" name="singleSelect" />
<label for="option2" class="select_label">Два</label>
<input id="option3" class="select_input type_request" value="3" type="radio" name="singleSelect" />
<label for="option3" class="select_label">Три</label>
<input id="option4" class="select_input type_request" value="4" type="radio" name="singleSelect" />
<label for="option4" class="select_label">Четыре</label>
</div>
</div>
Ответы (1 шт):
Автор решения: InDevX
→ Ссылка
Как вариант - на лету рендерить html.
function createElement(items) {
let elem = document.createElement("div");
elem.classList.add('select');
elem.dataset.state = "";
addToggleEvent(elem);
let title = document.createElement("div");
title.classList.add('select_title','type_request');
title.dataset.default = "";
title.innerHTML = items[0].title;
elem.append(title);
let content = document.createElement("div");
content.classList.add('select_content');
items.forEach(function(item, idx) {
let input = createInputItem(idx),
label = createLabelItem(idx, item);
content.append(input);
content.append(label);
addLabelEvent(label, title, elem);
});
elem.append(content);
document.querySelector('body').append(elem);
function createInputItem(idx) {
let input = document.createElement("input");
input.id = "option" + idx;
input.classList.add('select_input');
if (idx > 0) {
input.classList.add('type_request');
}
input.value = idx == 0 ? "" : idx;
input.type = "radio";
input.name = "singleSelect";
return input;
}
function createLabelItem(idx, item) {
let label = document.createElement("label");
label.for = "option" + idx;
label.classList.add('select_label');
label.innerHTML = item.title;
return label;
}
function addToggleEvent(title){
elem.addEventListener('click', e => {
elem.dataset.state = elem.dataset.state === 'active' ? '' : 'active';
});
}
function addLabelEvent(label, title, elem){
label.addEventListener('click', e => {
e.stopPropagation();
title.textContent = e.target.textContent;
elem.dataset.state = "";
});
}
$(document).mouseup(function (e) {
elem.dataset.state = "";
});
}
createElement([
{ title: "1-5" },
{ title: "Один" },
{ title: "Два" },
{ title: "Три" },
{ title: "Четыре" },
{ title: "Пять" }
]);
createElement([
{ title: "6-10" },
{ title: "Шесть" },
{ title: "Сумь" },
{ title: "Восемь" },
{ title: "Девять" },
{ title: "Десять" }
]);
createElement([
{ title: "Да/Нет?" },
{ title: "Нет" },
{ title: "Да" }
]);
.select {
position: relative;
width: 300px;
height: 40px;
margin: 20px 0;
}
.select[data-state="active"] .select_title::before {
transform: translate(-3px, -50%) rotate(-45deg);
}
.select[data-state="active"] .select_title::after {
transform: translate(3px, -50%) rotate(45deg);
}
.select[data-state="active"] .select_content {
opacity: 1;
}
.select[data-state="active"] .select_label + .select_input + .select_label {
max-height: 40px;
border-top-width: 1px;
}
.select_title {
display: flex;
align-items: center;
width: 100%;
height: 100%;
padding: 8px 16px;
border-radius: 5px;
border: solid 1px #c7ccd1;
cursor: pointer;
background-color: #38b0ff;
color: #e9e9e9;
}
.select_title::before, .select_title::after {
content: "";
position: absolute;
top: 50%;
right: 16px;
display: block;
width: 10px;
height: 2px;
transition: all 0.3s ease-out;
background-color: #e9e9e9;
transform: translate(-3px, -50%) rotate(45deg);
}
.select_title::after {
transform: translate(3px, -50%) rotate(-45deg);
}
.select_title:hover {
color: #ffffff;
}
.select_title:hover::before, .select_title:hover::after {
background-color: #f3fdff;
}
.select_content {
position: absolute;
top: 40px;
left: 3px;
display: flex;
flex-direction: column;
width: calc(100% - 6px);
background-color: #ffffff;
border: 1px solid #c7ccd1;
border-top: none;
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
transition: all 0.3s ease-out;
opacity: 0;
z-index: 8;
}
.select_input {
display: none;
}
.select_input:checked + label {
background-color: #dedede;
}
.select_input:disabled + label {
opacity: 0.6;
pointer-events: none;
}
.select_label {
display: flex;
align-items: center;
width: 100%;
height: 40px;
max-height: 0;
padding: 0 20px;
transition: all 0.1s ease-out;
cursor: pointer;
overflow: hidden;
}
.select_label + input + .select_label {
border-top: 0 solid #C7CCD160;
}
.select_label:hover {
background-color: #38b0ff !important;
color: #ffffff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
upd.: если нужно будет значение "передавать дальше" то можно, к примеру, в функцию которая создаёт эл-т вторым параметром передавать class/name, по которому можно будет взять значение, и добавить этот параметр в тот же input.
upd. добавил вариант с 1 js методом + html...
function ready() {
const selects = document.querySelectorAll('.select');
selects.forEach(function (select){
const select_title = select.querySelector('.select_title');
const select_labels = select.querySelectorAll('.select_label');
select_title.addEventListener('click', () => {
if ('active' === select.dataset.state) {
select.dataset.state = '';
} else {
select.dataset.state = 'active';
}
});
// Close when click to option
for (let i = 0; i < select_labels.length; i++) {
select_labels[i].addEventListener('click', (evt) => {
select_title.textContent = evt.target.textContent;
select.dataset.state = '';
});
}
///close outside the element
window.addEventListener('mouseup', e => select.dataset.state = '');
});
}
document.addEventListener("DOMContentLoaded", ready);
.select {
position: relative;
width: 300px;
height: 40px;
margin: 20px 0;
}
.select[data-state="active"] .select_title::before {
transform: translate(-3px, -50%) rotate(-45deg);
}
.select[data-state="active"] .select_title::after {
transform: translate(3px, -50%) rotate(45deg);
}
.select[data-state="active"] .select_content {
opacity: 1;
}
.select[data-state="active"] .select_label + .select_input + .select_label {
max-height: 40px;
border-top-width: 1px;
}
.select_title {
display: flex;
align-items: center;
width: 100%;
height: 100%;
padding: 8px 16px;
border-radius: 5px;
border: solid 1px #c7ccd1;
cursor: pointer;
background-color: #38b0ff;
color: #e9e9e9;
}
.select_title::before, .select_title::after {
content: "";
position: absolute;
top: 50%;
right: 16px;
display: block;
width: 10px;
height: 2px;
transition: all 0.3s ease-out;
background-color: #e9e9e9;
transform: translate(-3px, -50%) rotate(45deg);
}
.select_title::after {
transform: translate(3px, -50%) rotate(-45deg);
}
.select_title:hover {
color: #ffffff;
}
.select_title:hover::before, .select_title:hover::after {
background-color: #f3fdff;
}
.select_content {
position: absolute;
top: 40px;
left: 3px;
display: flex;
flex-direction: column;
width: calc(100% - 6px);
background-color: #ffffff;
border: 1px solid #c7ccd1;
border-top: none;
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
transition: all 0.3s ease-out;
opacity: 0;
z-index: 8;
}
.select_input {
display: none;
}
.select_input:checked + label {
background-color: #dedede;
}
.select_input:disabled + label {
opacity: 0.6;
pointer-events: none;
}
.select_label {
display: flex;
align-items: center;
width: 100%;
height: 40px;
max-height: 0;
padding: 0 20px;
transition: all 0.1s ease-out;
cursor: pointer;
overflow: hidden;
}
.select_label + input + .select_label {
border-top: 0 solid #C7CCD160;
}
.select_label:hover {
background-color: #38b0ff !important;
color: #ffffff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="select" data-state="">
<div class="select_title type_request" value="" data-default="">1-4</div>
<div class="select_content">
<input id="option0" class="select_input" value="" type="radio" name="singleSelect" />
<label for="option0" class="select_label">1-4</label>
<input id="option1" class="select_input type_request" value="1" type="radio" name="singleSelect" />
<label for="option1" class="select_label">Один</label>
<input id="option2" class="select_input type_request" value="2" type="radio" name="singleSelect" />
<label for="option2" class="select_label">Два</label>
<input id="option3" class="select_input type_request" value="3" type="radio" name="singleSelect" />
<label for="option3" class="select_label">Три</label>
<input id="option4" class="select_input type_request" value="4" type="radio" name="singleSelect" />
<label for="option4" class="select_label">Четыре</label>
</div>
</div>
<div class="select" data-state="">
<div class="select_title type_request" value="" data-default="">4-7</div>
<div class="select_content">
<input id="option0" class="select_input" value="" type="radio" name="singleSelect" />
<label for="option0" class="select_label">4-7</label>
<input id="option1" class="select_input type_request" value="1" type="radio" name="singleSelect" />
<label for="option1" class="select_label">Четыре</label>
<input id="option2" class="select_input type_request" value="2" type="radio" name="singleSelect" />
<label for="option2" class="select_label">Пять</label>
<input id="option3" class="select_input type_request" value="3" type="radio" name="singleSelect" />
<label for="option3" class="select_label">Шесть</label>
<input id="option4" class="select_input type_request" value="4" type="radio" name="singleSelect" />
<label for="option4" class="select_label">Семь</label>
</div>
</div>
<div class="select" data-state="">
<div class="select_title type_request" value="" data-default="">Да/Нет?</div>
<div class="select_content">
<input id="option0" class="select_input" value="" type="radio" name="singleSelect" />
<label for="option0" class="select_label">Да/Нет?</label>
<input id="option0" class="select_input type_request" value="1" type="radio" name="singleSelect" />
<label for="option0" class="select_label">Да</label>
<input id="option1" class="select_input type_request" value="2" type="radio" name="singleSelect" />
<label for="option1" class="select_label">Нет</label>
</div>
</div>