Feat/add dropdown list via js (#1)

* [feat/add-dropdown-list] Refactoring dropdown list.

* Refactoring class Dropdown

* [feat/add-dropdown-list] Added bandler(parcler)

* Added mouseenter event handling

* Fix bug open dropdown and added main.scss

* Added private fild and changed methods

* Refactoring DropDown

* Added placeholder

* Added customStyle

* Fixed initSelected

* Refactored initSelected

* Added feature in customize select

* featch customStyle complited!

* Delited file customStyle.scss

Co-authored-by: MaxOvs <rock_maksimus@mail.ru>
This commit is contained in:
MaxOvs19 2022-09-21 11:54:22 +03:00 committed by GitHub
parent 80ae89f920
commit 8c0e972883
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 5109 additions and 66 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
node_modules
dist
.parcel-cache

4796
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

24
package.json Normal file
View File

@ -0,0 +1,24 @@
{
"name": "dropdown-list",
"version": "0.0.1",
"description": "",
"scripts": {
"start": "parcel ./src/index.html -p 4500 --open",
"build": "parcel build ./src/index.html"
},
"repository": {
"type": "git",
"url": "git+https://github.com/MaxOvs19/Dropdown-list.git"
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/MaxOvs19/Dropdown-list/issues"
},
"homepage": "https://github.com/MaxOvs19/Dropdown-list#readme",
"devDependencies": {
"@parcel/transformer-sass": "^2.7.0",
"parcel": "^2.7.0",
"prettier": "^2.7.1"
}
}

205
src/cg-dropdown.js Normal file
View File

@ -0,0 +1,205 @@
export class DropDown {
#element;
#list;
#options;
#caret;
//ToDo: Added url
constructor(options = {}) {
this.#init(options);
this.#initSelected();
this.#initAmount();
this.#initItems();
this.#initEvent();
}
#open() {
this.#list.classList.toggle('open');
this.#caret.classList.toggle('caret_rotate');
}
#init(options) {
this.#options = options;
const elem = document.querySelector(options.selector);
if (!elem) {
throw new Error(`Element with selector ${options.selector}`);
}
this.#element = elem;
}
#initSelected() {
const { styles } = this.#options;
if (this.#options.selected) {
this.#createSelected(this.#options.selected);
} else {
this.#createSelected('Select...');
}
if (!this.#options.selected && this.#options.placeholder) {
this.#createSelected(this.#options.placeholder);
}
if ((styles && this.#options.placeholder) || (styles && this.#options.selected)) {
this.#createSelected(this.#options.placeholder);
this.#customStyles(styles);
} else {
this.#createSelected('Select...');
this.#customStyles(styles);
}
this.#element.addEventListener('click', () => {
this.#open();
});
}
#initAmount() {
const { amount } = this.#options;
if (!amount) {
return;
}
let templete = '';
for (let i = 0; i < amount; i++) {
templete += `<li class="list__item">${i + 1}</li>`;
}
this.#element.innerHTML += `<ul class="list">${templete}</ul>`;
}
#initItems() {
const { items, styles } = this.#options;
if (!Array.isArray(items)) {
return;
}
const templete = items.map((item) => `<li class="list__item" >${item}</li>`).join('');
this.#element.innerHTML += `<ul class="list">${templete}</ul>`;
if (styles) {
const templete = items.map((item) => `<li class="list__item" >${item}</li>`).join('');
this.#element.innerHTML += `<ul class="list style = "${styles}">${templete}</ul>`;
this.#customStyles(styles);
}
const options = this.#element.querySelectorAll('.list__item');
const selected = this.#element.querySelector('.selected');
options.forEach((option) => {
option.addEventListener('click', () => {
selected.innerText = option.innerText;
options.forEach((option) => {
option.classList.remove('active');
});
option.classList.add('active');
});
});
//ToDo: finish this function(catigories)
items.forEach((item) => {
if (typeof item === 'object') {
for (const key in item) {
const element = item[key];
// console.log(element);
if (typeof element === 'string') {
console.log(element);
}
}
}
});
}
#initEvent() {
const { event } = this.#options;
this.#list = this.#element.querySelector('.list');
this.#caret = this.#element.querySelector('.caret');
if (event === 'mouseenter') {
this.#element.addEventListener(event, () => {
this.#list.classList.add('open');
this.#caret.classList.add('caret_rotate');
});
this.#element.addEventListener('mouseleave', () => {
this.#list.classList.remove('open');
this.#caret.classList.remove('caret_rotate');
});
}
}
#customStyles(styles) {
if (!styles) {
return;
}
const { head, caret, list, placeholder } = styles;
const select = this.#element.querySelector('.cg-select');
const crt = this.#element.querySelector('.caret');
const ul = this.#element.querySelector('.list');
const placeh = this.#element.querySelector('.selected');
if (head) {
Object.entries(head).forEach(([key, value]) => {
select.style[key] = value;
});
}
if (caret) {
Object.entries(caret).forEach(([key, value]) => {
crt.style[key] = value;
});
}
if (ul) {
if (list) {
Object.entries(list).forEach(([key, value]) => {
ul.style[key] = value;
});
}
}
if (placeh) {
if (placeholder) {
Object.entries(placeholder).forEach(([key, value]) => {
placeh.style[key] = value;
});
}
}
}
#createSelected(content, styles) {
this.#element.innerHTML = `
<div class="cg-select">
<span class="selected">${content}</span>
<div class="caret"></div>
</div>
`;
if (styles) {
this.#customStyles(styles);
this.#element.innerHTML = `
<div class="cg-select" style = "${styles}">
<span class="selected" style = "${styles}">${content}</span>
<div class="caret" style = "${styles}"></div>
</div>
`;
}
}
// addItem(item) {
// const { items } = this.#options;
// console.log('Добавление елемента', item);
// items.push(item);
// console.log(items);
// }
}

View File

@ -4,26 +4,18 @@
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Dropdown-list</title>
<link href="main.css" rel="stylesheet" />
<title>Cg-Select</title>
<link href="./style/main.scss" rel="stylesheet" />
<link rel="stylesheet" href="style/customStyle.scss" />
</head>
<body>
<div class="container">
<div class="dropdown">
<div class="select">
<span class="selected">BMW</span>
<div class="caret"></div>
</div>
<div class="cg-dropdown"></div>
<ul class="list">
<li class="list__item">Nissan</li>
<li class="list__item">Mersedes</li>
<li class="list__item">Ford</li>
<li class="list__item active">Opel</li>
<li class="list__item">Chevrolet</li>
</ul>
</div>
<div class="cg-dropdown2"></div>
<!-- <div class="cg-dropdown3"></div> -->
</div>
</body>
<script src="index.js"></script>
<script type="module" src="index.js"></script>
</html>

View File

@ -1,27 +1,48 @@
const dropdowns = document.querySelectorAll('.dropdown');
import { DropDown } from './cg-dropdown';
dropdowns.forEach(drop => {
const select = drop.querySelector('.select');
const caret = drop.querySelector('.caret');
const list = drop.querySelector('.list');
const options = drop.querySelectorAll('.list__item')
const selected = drop.querySelector('.selected')
const dropdown = new DropDown({
selector: '.cg-dropdown',
select.addEventListener('click', () => {
caret.classList.toggle('caret-rotate');
list.classList.toggle('open');
});
items: ['BMW', 'Opel', 'Mersedes', 'MAN', 'max'],
});
options.forEach(option => {
option.addEventListener('click', () =>{
selected.innerText = option.innerText;
caret.classList.remove('caret-rotate');
list.classList.remove('open');
const dropdown2 = new DropDown({
selector: '.cg-dropdown2',
placeholder: 'Выберите авто',
items: ['BMW', 'Opel', 'Mersedes', 'MAN', 'Kamaz'],
event: 'mouseenter',
styles: {
head: {
background: 'red',
color: 'black',
width: '400px',
},
placeholder: {
color: 'grey',
},
caret: {
'border-top': '6px solid black',
},
list: {
background: 'red',
color: 'black',
width: '412px',
},
},
});
options.forEach(option =>{
option.classList.remove('active');
})
option.classList.add('active');
})
})
})
// dropdown.addItem('Zaz');
// const dropdown3 = new DropDown({
// selector: '.cg-dropdown3',
// selected: '',
// items: [
// {
// title: 'Russia',
// item: ['Rostov', 'Moskow'],
// },
// {
// title: 'Germany',
// item: ['Germany', 'Berlin'],
// },
// ],
// });

View File

@ -1,26 +1,26 @@
* {
font-size: 14px;
font-family: Arial, Helvetica, sans-serif;
}
body{
body {
background: #1b1e25;
}
.container {
display: flex;
margin: 50px auto;
width: 800px;
height: 200px;
}
.dropdown {
.cg-dropdown {
position: relative;
margin-right: 10px;
}
.select {
.cg-select {
padding: 14px;
max-width: 200px;
min-width: 200px;
height: 30px;
color: #fff;
display: flex;
@ -31,11 +31,11 @@ body{
cursor: pointer;
border-radius: 5px;
transition: 0.5s;
}
.select:hover {
transition: 0.5s;
&:hover {
transition: 0.5s;
background: #394050;
}
}
.caret {
@ -45,18 +45,20 @@ transition: 0.5s;
border-right: 5px solid transparent;
border-top: 6px solid #fff;
transition: 0.5s;
}
.caret-rotate {
&_rotate {
transform: rotate(180deg);
transition: 0.5s;
}
}
.list {
max-height: 230px;
overflow-y: auto;
position: absolute;
width: 212px;
padding: 7px;
margin-top: 1px;
margin-top: -0.2px;
list-style: none;
color: white;
@ -69,24 +71,24 @@ transition: 0.5s;
opacity: 0;
display: none;
z-index: 1;
}
.list__item {
&__item {
transition: 0.5s;
padding: 15px;
}
.list__item:hover {
&:hover {
transition: 0.5s;
cursor: pointer;
background: #394050;
background: #8282822c;
}
}
}
.active {
background: #394050;
background: #8282822c;
}
.open {
.open {
transition: 0.5s;
display: block;
opacity: 1;