/
NyutaNecoder
/
todo_list
Обзор
Документация
Войти
/
NyutaNecoder
/
todo_list
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
main
src/main.js
326 строк
12 KB
AnyaNecoder
add js code
10 авг 2026, 18:30
10 авг 2026, 18:30
4e051c2
Код
Авторство
О чём код?
import './styles/index.css' const rootElement = document.querySelector('[data-js-todo]') const elements = { newTaskFormElement: rootElement.querySelector('[data-js-todo-new-task-form]'), newTaskInputElement: rootElement.querySelector('[data-js-todo-new-task-input]'), tasksTotalElement: rootElement.querySelector('[data-js-todo-tasks-total]'), listElement: rootElement.querySelector('[data-js-todo-list]'), emptyMessageElement: rootElement.querySelector('[data-js-todo-empty-message]'), filterButtons: rootElement.querySelectorAll('[data-filter]'), } let tasks = [] let currentFilter = 'all' // отрисовка задач const renderTasks = () => { // фильтрация const filteredTasks = currentFilter === 'active' ? tasks.filter(task => !task.completed) : currentFilter === 'completed' ? tasks.filter(task => task.completed) : tasks elements.listElement.innerHTML = filteredTasks.map(({ id, text, completed }) => ` <li class="todo__item todo-item" data-js-todo-item> <input class="todo-item__checkbox" id="${id}" type="checkbox" ${completed ? 'checked' : ''} data-js-todo-item-checkbox> <label class="todo-item__label" for="${id}" data-js-todo-item-label>${text}</label> <div class="todo-item__task-actions" role="group" aria-label="Actions with the task"> <button class="todo-item__edit-button" type="button" aria-label="Edit a task" title="Edit a task" data-js-todo-item-edit-button> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M21.1739 6.812C21.7026 6.28342 21.9997 5.56647 21.9998 4.81885C21.9999 4.07124 21.703 3.35421 21.1744 2.8255C20.6459 2.29679 19.9289 1.99971 19.1813 1.99962C18.4337 1.99952 17.7166 2.29642 17.1879 2.825L3.84193 16.174C3.60975 16.4055 3.43805 16.6905 3.34193 17.004L2.02093 21.356C1.99509 21.4425 1.99314 21.5343 2.01529 21.6219C2.03743 21.7094 2.08285 21.7892 2.14673 21.853C2.21061 21.9168 2.29055 21.9621 2.37809 21.9841C2.46563 22.0061 2.55749 22.004 2.64393 21.978L6.99693 20.658C7.3101 20.5628 7.59511 20.3921 7.82693 20.161L21.1739 6.812Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> <path d="M15 5L19 9" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> </svg> </button> <button class="todo-item__delete-button" type="button" aria-label="Delete a task" title="Delete a task" data-js-todo-item-delete-button> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M19 6V20C19 20.5304 18.7893 21.0391 18.4142 21.4142C18.0391 21.7893 17.5304 22 17 22H7C6.46957 22 5.96086 21.7893 5.58579 21.4142C5.21071 21.0391 5 20.5304 5 20V6" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> <path d="M3 6H21" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> <path d="M8 6V4C8 3.46957 8.21071 2.96086 8.58579 2.58579C8.96086 2.21071 9.46957 2 10 2H14C14.5304 2 15.0391 2.21071 15.4142 2.58579C15.7893 2.96086 16 3.46957 16 4V6" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> </svg> </button> </div> </li> `).join('') // обновление счетчика оставшихся тасок и вывод сообщения const activeCount = tasks.filter(task => !task.completed).length elements.tasksTotalElement.textContent = activeCount const isEmptyAll = tasks.length === 0 const isEmptyFiltered = filteredTasks.length === 0 elements.emptyMessageElement.textContent = isEmptyAll ? 'There are no tasks yet' : isEmptyFiltered ? 'Tasks not found' : '' } // фильтр по статусу const onFilterButtonClick = (event) => { const filter = event.currentTarget.dataset.filter currentFilter = filter elements.filterButtons.forEach(button => { button.ariaPressed = button.dataset.filter === filter ? 'true' : 'false' }) renderTasks() } // добавление задачи const addItem = (text) => { tasks.push({ id: crypto?.randomUUID() ?? Date.now().toString(), text, completed: false, }) } // oбработчик сабмита const onNewTaskFormSubmit = (event) => { event.preventDefault() const newTodoItemText = elements.newTaskInputElement.value.trim() if (newTodoItemText) { addItem(newTodoItemText) elements.newTaskInputElement.value = '' elements.newTaskInputElement.focus() renderTasks() } } // обработчики событий elements.newTaskFormElement.addEventListener('submit', onNewTaskFormSubmit) elements.filterButtons.forEach(button => { button.addEventListener('click', onFilterButtonClick) }) // class Todo { // selectors = { // root: '[data-js-todo]', // newTaskForm: '[data-js-todo-new-task-form]', // newTaskInput: '[data-js-todo-new-task-input]', // tasksLeft: '[data-js-todo-tasks-left]', // list: '[data-js-todo-list]', // item: '[data-js-todo-item]', // itemCheckbox: '[data-js-todo-item-checkbox]', // itemLabel: '[data-js-todo-item-label]', // itemEditButton: '[data-js-todo-item-edit-button]', // itemDeleteButton: '[data-js-todo-item-delete-button]', // emptyMessage: '[data-js-todo-empty-message]', // } // stateClasses = { // isDisappearing: 'is-disappearing', // } // localStorageKey = 'todo-items' // constructor() { // this.rootElement = document.querySelector(this.selectors.root) // this.newTaskFormElement = this.rootElement.querySelector(this.selectors.newTaskForm) // this.newTaskInputElement = this.rootElement.querySelector(this.selectors.newTaskInput) // this.tasksLeftElement = this.rootElement.querySelector(this.selectors.tasksLeft) // this.listElement = this.rootElement.querySelector(this.selectors.list) // this.emptyMessageElement = this.rootElement.querySelector(this.selectors.emptyMessage) // this.state = { // items: this.getItemsFromLocalStorage(), // filteredItems: null, // } // this.render() // this.bindEvents() // } // getItemsFromLocalStorage() { // const rawData = localStorage.getItem(this.localStorageKey) // if (!rawData) { // return [] // } // try { // const parsedData = JSON.parse(rawData) // return Array.isArray(parsedData) ? parsedData : [] // } catch { // console.error('Todo items parse error') // return [] // } // } // saveItemsToLocalStorage() { // localStorage.setItem( // this.localStorageKey, // JSON.stringify(this.state.items) // ) // } // render() { // // this.totalTasksElement.textContent = this.state.items.length (дописать логику для tasksLeft) // const items = this.state.filteredItems ?? this.state.items // this.listElement.innerHTML = items.map(({ id, title, isChecked }) => ` // <li class="todo__item todo-item" data-js-todo-item> // <input class="todo-item__checkbox" id="${id}" type="checkbox" ${isChecked ? 'checked' : ''} data-js-todo-item-checkbox> // <label class="todo-item__label" for="${id}" data-js-todo-item-label>${title}</label> // <div class="todo-item__task-actions" role="group" aria-label="Actions with the task"> // <button class="todo-item__edit-button" type="button" aria-label="Edit a task" title="Edit a task" data-js-todo-item-edit-button> // <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> // <path // d="M21.1739 6.812C21.7026 6.28342 21.9997 5.56647 21.9998 4.81885C21.9999 4.07124 21.703 3.35421 21.1744 2.8255C20.6459 2.29679 19.9289 1.99971 19.1813 1.99962C18.4337 1.99952 17.7166 2.29642 17.1879 2.825L3.84193 16.174C3.60975 16.4055 3.43805 16.6905 3.34193 17.004L2.02093 21.356C1.99509 21.4425 1.99314 21.5343 2.01529 21.6219C2.03743 21.7094 2.08285 21.7892 2.14673 21.853C2.21061 21.9168 2.29055 21.9621 2.37809 21.9841C2.46563 22.0061 2.55749 22.004 2.64393 21.978L6.99693 20.658C7.3101 20.5628 7.59511 20.3921 7.82693 20.161L21.1739 6.812Z" // stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> // <path d="M15 5L19 9" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> // </svg> // </button> // <button class="todo-item__delete-button" type="button" aria-label="Delete a task" title="Delete a task" data-js-todo-item-delete-button> // <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> // <path // d="M19 6V20C19 20.5304 18.7893 21.0391 18.4142 21.4142C18.0391 21.7893 17.5304 22 17 22H7C6.46957 22 5.96086 21.7893 5.58579 21.4142C5.21071 21.0391 5 20.5304 5 20V6" // stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> // <path d="M3 6H21" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> // <path // d="M8 6V4C8 3.46957 8.21071 2.96086 8.58579 2.58579C8.96086 2.21071 9.46957 2 10 2H14C14.5304 2 15.0391 2.21071 15.4142 2.58579C15.7893 2.96086 16 3.46957 16 4V6" // stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> // </svg> // </button> // </div> // </li> // `).join('') // const isEmptyFilteredItems = this.state.filteredItems?.length === 0 // const isEmptyItems = this.state.items.length === 0 // this.emptyMessageElement.textContent = isEmptyFilteredItems ? 'Tasks not found' // : isEmptyItems ? 'There are no tasks yet' // : '' // } // addItem(title) { // this.state.items.push({ // id: crypto?.randomUUID() ?? Date.now().toString(), // title, // isChecked: false, // }) // this.saveItemsToLocalStorage() // this.render() // } // deleteItem(id) { // this.state.items = this.state.items.filter((item) => item.id !== id) // this.saveItemsToLocalStorage() // this.render() // } // toggleCheckedState(id) { // this.state.items = this.state.items.map((item) => { // if (item.id === id) { // return { // ...item, // isChecked: !item.isChecked, // } // } // return item // }) // this.saveItemsToLocalStorage() // this.render() // } // filter() { // const queryFormatted = this.state.items.filter(({ title }) => { // const titleFormatted = title.toLowerCase() // return titleFormatted.includes(queryFormatted) // }) // this.render() // } // resetFilter() { // this.state.filteredItems = null // this.state.searchQuery = '' // this.render() // } // onNewTaskFormSubmit = (event) => { // event.preventDefault() // const newTodoItemTitle = this.newTaskInputElement.value // if (newTodoItemTitle.trim().length > 0) { // this.addItem(newTodoItemTitle) // this.resetFilter() // this.newTaskInputElement.value = '' // this.newTaskInputElement.focus() // } // } // onClick = ({ target }) => { // if (target.matches(this.selectors.itemDeleteButton)) { // const itemElement = target.closest(this.selectors.item) // const itemCheckboxElement = itemElement.querySelector(this.selectors.itemCheckbox) // itemElement.classList.add(this.stateClasses.isDisappearing) // setTimeout(() => { // this.deleteItem(itemCheckboxElement.id) // }, 400) // } // } // onChange = ({ target }) => { // if (target.matches(this.selectors.itemCheckbox)) { // this.toggleCheckedState(target.id) // } // } // bindEvents() { // this.newTaskFormElement.addEventListener('submit', this.onNewTaskFormSubmit) // this.listElement.addEventListener('click', this.onClick) // this.listElement.addEventListener('change', this.onChange) // } // } // new Todo()