
udemy
Udemy - одна из самых больших площадок в мире по доставке обучающего контента от разных авторов всего мира. Присутсвуют курсы практически на любую тему.
Получи реальную практику на реальных проектах! Создай свою JavaScript UI библиотеку! Этот курс направлен на практическое применение языка программирования JavaScript на реальных проектах. Вы получаете реальное техническое задание, исходные файлы и мы на практике учимся выполнять такие проекты до самого конца.
Для кого подойдет этот курс?
Если у вас есть теоретические знания JavaScript, но не хватает практики
Если вы хотите создать себе потрясающее портфолио проектов
Если вы хотите поработать с реальными проектами, но пока без лишних проблем: общения с заказчиком, сроков и задач, которые вы не знаете как решить
Если вы хотите создать свою JavaScript библиотеку
Что внутри курса?
Знания теории - это полезно, но в реальной жизни мы сталкиваемся с самыми разнообразными проектами и прихотями заказчика. Так что в этом курсе мы шаг за шагом разберем реальные проекты, как лучше их выполнять, какие подходы мы можем использовать и многое другое.
Курс направлен исключительно на практику, но сложные и потенциально непонятные моменты я все равно буду объяснять и с теоретической стороны. Все материалы для работы и ответы на домашние задания будут предоставлены. И вы всегда можете задавать вопросы в специальном разделе.
Чем мы займемся?
мы настроим сборку проектов для комфортной работы
мы изучим различные подходы выполнения проектов: объектно-ориентированный, императивный и тд.
мы будем использовать самые современные возможности языка, но и не будем забывать о поддержке старых браузеров
мы научимся подстраиваться под самые разные требования технического задания (ТЗ)
мы сформируем портфолио проектов, которое будет не стыдно показать на собеседовании
мы создадим свою библиотеку, которую можно использовать и расширять по своему усмотрению
Если у вас еще недостаточно знаний для прохождения данного курса, то на этой платформе есть и первая часть, позволяющая получить все необходимые теоретические знания. Найти его можно у меня в профиле.
Что такое JavaScript и почему его нужно освоить уже сейчас?
JS - это язык интерактивности на веб-страницах. Без него сейчас не обходится ни один сайт в интернете. И даже больше! Используя различные фрэймворки, JavaScript заполоняет интернет: серверная сторона (Node.js), мобильные приложения (React Native, Ionic), виртуальная реальность (React VR) и так далее. Поэтому, если вы хотите пойти по одному из этих путей - нативный JS станет для вас просто необходимой базой.
Udemy - одна из самых больших площадок в мире по доставке обучающего контента от разных авторов всего мира. Присутсвуют курсы практически на любую тему.
Освой самый популярный язык программирования - JavaScript и научись применять его на практике! Этот курс направлен на подробное изучение JavaScript без воды, но главное - немедленноеприменение его на практике. Это значит, что вы получите материал для работы и мы вместе будем создавать реальные проекты шаг за шагом.
Освой все, что необходимо для создания web-сайтов и начни зарабатывать на этом! Этот курс направлен на подробное обучение созданию сайтов, без воды, но главное, что здесь мы немедленно применяем все знания на практике.
try catch блок используется не для таких "примитивных" надобностей. Самое основное, конструкция используется для правильной обработки ошибки. Когда вызов функции может бросить любую ошибку, а не вернуть null.
Что касается querySelector - функция возвращает null, если ничего не найдено. В этом случае, достаточно поставить обычный guard, то есть, if (!hanson) return;
1) Автор, использует try catch блок, такое ощущение, как будто, если один блок (слайд) у нас установлен в display: block, а всем остальные в display: none, то HTML будет отсутствовать на странице. блок с классом .hanson будет в любом случае, потому что css параметры не влияют на это. Следовательно, неконтроллируемого состояния у нас не может быть. Максимум, это к свойству объекта будет присвоен null.
2) Как я писал ранее, если мы обращаемся к переменной, то мы можем установить guard
3) Непонятно, что Иван имел ввиду под ООП-ным проектом. Чем дальше, тем проект меньше напоминает ООП. Мало создать объект. Мы должны больше придерживаться абстракций, а тут, происходит хард кодинг...
Делаем npm install, потом сразу апдейтим npm update
Инсталлируем: npm install --save-dev @babel/plugin-proposal-class-properties
Далее, открыавем gulpfile.js, находим поле options: { (в двух местах, build-js и build-prod-js) и добавляем в него после present: [...],
plugins: [
"@babel/plugin-proposal-class-properties"
]
должно получиться типа:
options: {
presets: [['@babel/preset-env', {
debug: true,
corejs: 3,
useBuiltIns: "usage"
}]],
plugins: [
"@babel/plugin-proposal-class-properties"
]
}
Непонятно, какое ООП без инкапсулирования?
Хрен знает, что там Ванька задумал, пока как-то так
https://github.com/hazartilirot/slider_spa/blob/main/src/js/modules/slider.js
1) По всплывающей кнопке для проброса на верх. animated, fadein лишнее - так как у нас по умолчанию плавно исчезает/появляется кнопка. Кроме опасити, нужно установить визэбилити на хидэн. Иначе кнопки видно не будет, а поинтер на курсоре останется.
window.addEventListener('scroll', () => {
const scrollTop = document.documentElement.scrollTop | 0;
toTheTopBtn.style.opacity =
scrollTop >= mainSectionHeight + headerHeight ? '1' : '0';
toTheTopBtn.style.visibility =
scrollTop >= mainSectionHeight + headerHeight ? 'visible' : 'hidden';
})
2) Что происходит в этом блоке никто не знает.... Я, конечно, догадываюсь, но, меня бесит, когда человек тратит моё время на набор текста, при этом жадный на объяснения. Как по мне - вставь этот блок кода, но потрать больше времени на объяснения. При чём, лучше, если это будет графическое объяснение, т.к. контейнеры прозрачные, и с какими параметрами мы работаем сразу не въедешь.
while (anchorElement.offsetParent) {
anchorElementParent += anchorElement.offsetTop;
anchorElement = anchorElement.offsetParent
}
3) Везде используется выражение let scrollTop = Math.round( document.body.scrollTop || document.documentElement.scrollTop)
при этом, в конце, без проверок, используется
document.documentElement.scrollTop += speed;
document.body.scrollTop += speed;
4) history.replaceState(history.state, document.title, location.href.replace(/\/#[a-z]+$/g, '')) - зачем используется эта функция, если мы прэвэнтим дефолтное поведение? Линк будет без энкера.
5) Нефиговый if на пять условий, который для меня, на 28:30 минуте, пока абсолютно непонятный. У нас динамически меняется document.documentElement.scrollTop, и также, нам, по-идее, известная конечная точка, которую мы получаем в while лупе. Иначе, что там делает второй параметр в smoothScroll? Отсюда вытекает следующий вопрос, а зачем нам prevScrollTop вообще?
6) Зачем такой объёмный код в котором чёрт-знает-что происходит? Пару строчек делают абсолютно тоже самое.
const toTheTopBtn = document.querySelector('.pageup');
toTheTopBtn.addEventListener('click', (e) => {
e.preventDefault();
window.scrollTo({top: 0, left: 0, behavior: 'smooth'})
})
Ванька фрик))) Нужно досмотреть. Может там какая-то гениальная комбинация?)
Поставь задачи.
Объясни с какими проблемами человек может столкнуться
Как решить эту проблему (на словах, не на коде)
Какие особенности.
Научи разбивать таски на мелкие задачи
Протестируй тщательно работоспособность
Какой-то прогресс, время, какие-то непонятные вычисления, скорость - которая от большего значения становиться только медленее, позиционирование раздела без учёта padding-top. У меня складывается такое впечатление, что Ваня, в процессе своего обучения, старается научить ещё и нас. Жду недождусь когда закончу этот курс....
Не понимаю смысла аттачить 25 ивэнт лысынэс, которые бросают ошибку, если нажать на энкэ с псотым хэш тегом. Один бабблинг и всё путём.
В общем, кто хочет нормальное решение, прошу
https://github.com/hazartilirot/portraits_canvas/blob/main/src/js/modals/navigateToSection.js
Нейминг меня не перестаёт удивлять.)
класс often-questions - вообще-то, нужно обозначать как FAQ (Frequently Asked Questions). Это правильно, и сразу понятно.
Классический Аккордион - это следующая выбранная категория, закрывает текущее выпадающую информацию (подменю), и открывает новую. Не закрывается категория тогда, когда есть подкатегория с последующим выпаданием при условии, если на неё нажали. В первом случае, с имплементацией CSS правильно работает. Вторая, имплементация на JS - полная туфта.
Ванька, всё чешет про какие-то алгоритмы. Где они?
Моя версия будет потяжелее для понимания, но интереснее)
https://github.com/hazartilirot/portraits_canvas/blob/main/src/js/modals/makeAnyCanvasFrame.js
Два раза травёрсим, туева хуча querySelector(ов), addEvenListener(ов).
Нет, конечно, всё работает. Но это, по моему мнению, говно код, который не может писать человек с пятью годами опыта. Скажите мне, что это шутка? Такое можно показать на первых уроках по JS DOM, и то, в контексте, практика обработчиков событий с аннотацией - так, никогда не делайте. :)
Вот, не стал делать как Ванька, и получилось красиво)
https://github.com/hazartilirot/portraits_canvas/blob/main/src/js/modals/portfolioMenu.js
https://github.com/hazartilirot/portraits_canvas
forms.js - файл работающий с формами.
inputChecker.js - файл работающий с проверками input полей. В нём две функции, код читается легко, в отличие от твоего кода с масками, где кучка вложенных условий.
regex.js - хранит регулярные выражения по всем input полям. Можно легко адаптировать.
Чтобы запретить пользователю вставлять текст (который противоречит условиям), достаточно добавить аттрибут onpaste="return false" в input.
По 16 уроку, опять ненужные переборы. Всё делается проще. Мы за один проход перезначаем целую строку с разными классами. Мало того, если я не ошибаюсь, перед удалением самой кнопки, мы должны удалить EventListener, который остаётся сидеть в памяти. То есть, мы должны или использовать removeEventListener или же, мы можем воспользоваться опциями и передать третий аргумент {once: true} - который удалит событие автоматически как только у нас пользователь кликнит один раз на кнопку.
button.addEventListener('click', () => {
cards.forEach(card =>
card.className = 'col-sm-3 col-sm-offset-0 col-xs-10 col-xs-offset-1 animated fadeInUp');
button.remove();
}, {once: true})
а что касается реализации через .json файл, лаконичнее использовать axios. Вместо, innerHTML, использовать insertAdjacentHTML, он универсальнее.
Нам не нужен дополнительный селектор, достаточно кнопки. В db.json файле, убрать лишний {"styles": }, достаточно [] и всё что внутри.
button.addEventListener('click', async () => {
const { data } = await axios('assets/styles.json');
data.forEach(({ src, title, link }) =>
button.previousElementSibling.insertAdjacentHTML('beforeend', `
${ title }
Подробнее
`))
button.remove()
}, {once: true})
15-ый урок. Маска - это полная ерунда. В ней нет никакого смысла. Правильнее контролировать каждую цифру особенно те, которые касаются кода оператора. Я показывал регулярные выражения ранее, целый массив валидации.
08:00 минута. Ванька даже не соображает о чём говорит. Это не диапазон. Диапазон
[a-zA-Z] указывается дашом. В квадратных же скобках указывается любое из перечисленных условий (совпадений). То есть, [_d] - может быть или underscore или же любая цифра, причём 100 в данном случае будет рассматриваться не вместе, а по-отдельности. Один ноль ноль.
Тут, есть курс хороший, называется MASTERING REGULAR EXPRESSIONS IN JAVASCRIPT. Вань, посмотри, хоть минимально начнёшь разбираться.)
А если пользователь загрузит файл, у которого имя будет содержать несколько точек в названии файла? :) Использовать точки в имени - это распространенная практика. Такие вещи нужно делать через регулярные выражения и проверять/сплитить файл через расширение файлов.
Ну, и там на 15:00 минуте, ситаксис просто убил
let api;
item.closest('.popup-design') ? api = path.designer : path.question
Уж если писать такую хрень тернарным оператором, тогда правильнее
let api = item.closest('.popup-design') ? path.designer : path.question;
Ох, Ванька.... ты убиваешь меня.... откуда ты взялся на мою голову....
Вот же ботинок) Пять лет опыта - я, блин, в ужасе от таких учителей. Всё стараюсь, не комментировать произношение английский слов, типа, Хайден, Майнут.... это же вообще позорище какое-то. Advanced level(у) он решил научить людей.
Если есть состояние в котором мы храним данные, то подсчёт стоимости должен начинаться с учётом выбора остекление (на верхнем слайдере, который по дефолту деревянный) и, тёплый/холодный сохраняться в нашем состоянии, собственно тот, на который мы нажимает "посчитать". Получается, что ты перешёл в алюминиевое остекление, нажал на тёплый просчитать - а потом заново нужно выбирать) БРЕЕЕЕЕЕЕЕД! )
Таймер сделан неплохо, есть несколько нюансов
1) Почему нельзя изначально экспортировать так:
export default () => {
блок кода
}
и зампортировать в main.js
import timer from "./modules/timer";
2) Что такое первый параметр id, который передаётся в main.js в функцию timer? Зачем он нужен я так и не смог разобраться))))))
const typeOfWindow = document.querySelector('.balcon_icons');
сажаем на него один event listener и далее, собираем dataset.id -шки каждого элемента.
typeOfWindow.addEventListener('click', ({target}) => {
state.form = target.closest('.balcon_icons_img').dataset.id
})
то есть, в , добавляем для каждого
data-id="0", data-id="1", data-id="2" и т.д.
Один слушает, closest объединяет вложенные теги и bubbling поднимает id на самый верх.
О, боги.... такой курс, я смотрю впервые.))))))) Ну, Ваня, ну, даёшь)))))))
+380671111111 или
+38067111-11-11 или
38067111-11-11 или
067111-11-11 или
(067) 111-11-11 и т.д.
всё остальное вызывает ошибку. Ошибка или исчезает сама через 3 секунды или, при следующем нажатии (например, если пользователь нажал быстро три раза 111, такая строка нам не подходит, т.к. она должна начинаться с +, 3, 0), проверит на присутствие ошибки, если она уже присутствует, то предыдущая будет удалена, а новая, встанет вместо неё с новым таймером.
const phones = document.querySelectorAll('input[name=user_phone]');
phones.forEach(i => {
i.addEventListener('input', () => {
const regexArray = [
/^\+$/,
/^\+?3$/,
/^(\+?38)?$/,
/^(\+?38)?\($/,
/^(\+?38)?0$/,
/^(\+?38)?\(?0$/,
/^(\+?38)?\(?0[9675]$/,
/^(\+?38)?\(?0[9675][2356790]$/,
/^(\+?38)?\(?0[9675][2356790]\)?$/,
/^(\+?38)?\(?0[9675][2356790]\)?[\-\s]?$/,
/^(\+?38)?\(?0[9675][2356790]\)?[\-\s]?\d$/,
/^(\+?38)?\(?0[9675][2356790]\)?[\-\s]?\d{2}$/,
/^(\+?38)?\(?0[9675][2356790]\)?[\-\s]?\d{3}$/,
/^(\+?38)?\(?0[9675][2356790]\)?[\-\s]?\d{3}[\-\s]?$/,
/^(\+?38)?\(?0[9675][2356790]\)?[\-\s]?\d{3}[\-\s]?\d$/,
/^(\+?38)?\(?0[9675][2356790]\)?[\-\s]?\d{3}[\-\s]?\d{2}$/,
/^(\+?38)?\(?0[9675][2356790]\)?[\-\s]?\d{3}[\-\s]?\d{2}[\-\s]?$/,
/^(\+?38)?\(?0[9675][2356790]\)?[\-\s]?\d{3}[\-\s]?\d{2}[\-\s]?\d$/,
/^(\+?38)?\(?0[9675][2356790]\)?[\-\s]?\d{3}[\-\s]?\d{2}[\-\s]?\d{2}$/,
];
let statusMessage;
if (!regexArray.some(regex => regex.test(i.value))) {
i.value = i.value.substring(0, i.value.length - 1);
const form = i.parentNode;
statusMessage = document.createElement('div');
statusMessage.classList.add('status');
form.appendChild(statusMessage);
if (statusMessage.previousSibling.className === 'status')
statusMessage.previousSibling.remove();
statusMessage.textContent = 'Use a correct number order for mobile phones'
setTimeout(() => statusMessage.remove(), 3000);
}
})
})
что касается модального окна с таймером 60 секунд - тоже быдло код (или правильнее сказать, быдло имплементация). Зачем нам просто показывать окно? Нам нужно следить или происходит какая-то активность. То есть, например, пользователь скроллит, набирает текст (имя или телефон) или же, двигает курсором мыши. Зачем нам выводить модалку через 60 секунд при любом случае? Это неудобно. Поэтому, мы следим, и если существует хоть какая-то активность, мы ресетим таймер снова на 60 секунд и выводим его исключительно только, если активность пользователя на сайте отсутствует как таковая.
const showModalByTimer = (selector, time) => {
let id;
const resetTimer = () => {
clearTimeout(id);
id = setTimeout(() => {
document.querySelector(selector).style.display = 'block';
document.body.style.overflow = 'hidden';
}, time);
};
window.addEventListener('load', resetTimer, true);
const events = [
'mousedown',
'mousemove',
'keypress',
'scroll',
'touchstart',
];
events.forEach(e => document.addEventListener(e, resetTimer, true));
};
showModalByTimer('.popup', 60000);