Создание сайтов в Донецке, ДНР. Как сделать простую викторину по JavaScript

 
 

«Как мне сделать викторину по JavaScript?» — один из самых распространенных вопросов, задаваемых людьми, изучающими веб-разработку, и не зря. Викторины — это весело! Это отличный способ узнать о новых предметах, и они позволяют вам увлечь вашу аудиторию чем-то веселым и игривым.

Эта популярная статья была обновлена ​​в 2020 году, чтобы отразить современные передовые практики в JavaScript. Для получения более глубоких знаний о JavaScript прочитайте нашу книгу JavaScript: Novice to Ninja, 2nd Edition.

Как сделать викторину по JavaScript

«>Написание собственной викторины на JavaScript также является прекрасным обучающим упражнением. Он учит вас, как справляться с событиями, манипулировать DOM, обрабатывать пользовательский ввод, давать обратную связь пользователю и отслеживать его оценку (например, с помощью хранилища на стороне клиента). И когда у вас есть базовая викторина и работает, есть множество возможностей для добавления более продвинутых функций, таких как нумерация страниц. Я вхожу в это в конце статьи.

В этом уроке я покажу вам, как создать многоэтапный тест JavaScript, который вы сможете адаптировать к своим потребностям и добавить на свой сайт. Если вы хотите узнать, чем мы закончим, вы можете пропустить этот этап и просмотреть рабочий тест.

Что нужно знать перед началом

Несколько вещей, которые нужно знать перед началом:

Это руководство по интерфейсу, а это означает, что любой, кто знает, как просматривать исходный код страницы, может найти ответы. Для серьезных тестов данные должны обрабатываться через серверную часть, что выходит за рамки этого руководства.

Код в этой статье использует современный синтаксис JavaScript (ES6+), что означает, что он не будет совместим ни с одной версией Internet Explorer. Тем не менее, он будет отлично работать в современных браузерах, включая Microsoft Edge.

Если вам нужна поддержка старых браузеров, я написал учебное пособие по JavaScript, совместимое с IE8. Или, если вы хотите освежить в памяти ES6, ознакомьтесь с этим курсом Дарина Хейнера на SitePoint Premium.

Вам потребуется некоторое знакомство с HTML, CSS и JavaScript, но каждая строка кода будет объясняться отдельно.

Базовая структура вашей викторины по JavaScript

В идеале мы хотим, чтобы вопросы и ответы викторины были в нашем коде JavaScript, и чтобы наш сценарий автоматически генерировал викторину. Таким образом, нам не нужно будет писать много повторяющейся разметки, и мы сможем легко добавлять и удалять вопросы.

Чтобы настроить структуру нашего теста JavaScript, нам нужно начать со следующего HTML:

А

провести викторину

 

A

 

для отображения результатов

 

Вот как это будет выглядеть:

 

 

 

 

 

 

 

Затем мы можем выбрать эти элементы HTML и сохранить ссылки на них в переменных следующим образом:

const quizContainer = document.getElementById ('quiz’) ;

const resultsContainer = document.getElementById ('results’) ;

const submitButton = document.getElementById ('submit’) ;

Далее нам понадобится способ создать викторину, показать результаты и соединить все это воедино. Мы можем начать с размещения наших функций, и мы будем заполнять их по мере продвижения:

function buildQuiz () {}

function showResults () {}

// display quiz right away

buildQuiz () ;

// on submit, show results

submitButton.addEventListener ('click’, showResults) ;

Здесь у нас есть функции для создания викторины и отображения результатов. Мы запустим нашу buildQuizфункцию немедленно, и наша showResultsфункция будет запущена, когда пользователь нажмет кнопку отправки.

Отображение вопросов викторины

Следующее, что нужно нашей викторине, это несколько вопросов для отображения. Мы будем использовать литералы объектов для представления отдельных вопросов и массив для хранения всех вопросов, составляющих наш тест. Использование массива упростит повторение вопросов:

const myQuestions = [

{

question: «Who invented JavaScript?»,

answers: {

a: «Douglas Crockford»,

b: «Sheryl Sandberg»,

c: «Brendan Eich»

},

correctAnswer: «c»

},

{

question: «Which one of these is a JavaScript package manager?»,

answers: {

a: «Node.js»,

b: «TypeScript»,

c: «npm»

},

correctAnswer: «c»

},

{

question: «Which tool can you use to ensure code quality?»,

answers: {

a: «Angular»,

b: «jQuery»,

c: «RequireJS»,

d: «ESLint»

},

correctAnswer: «d»

}

];

Не стесняйтесь задавать столько вопросов или ответов, сколько хотите.

Примечание: поскольку это массив, вопросы будут отображаться в том порядке, в котором они перечислены. Если вы хотите каким-либо образом отсортировать вопросы перед тем, как представить их пользователю, ознакомьтесь с нашим кратким советом по сортировке массива объектов в JavaScript.

Теперь, когда у нас есть список вопросов, мы можем отобразить их на странице. Мы рассмотрим следующий код JavaScript построчно, чтобы увидеть, как он работает:

function buildQuiz () {

// variable to store the HTML output

const output = [];

// for each question...

myQuestions.forEach (

(currentQuestion, questionNumber) => {

// variable to store the list of possible answers

const answers = [];

// and for each available answer...

for (letter in currentQuestion.answers) {

//...add an HTML radio button

answers.push (

`

${letter}:

${currentQuestion.answers[letter]}

`

) ;

}

// add this question and its answers to the output

output.push (

`

${currentQuestion.question}

 

 

${answers.join ('') }
`

 

) ;

}

) ;

// finally combine our output list into one string of HTML and put it on the page

quizContainer.innerHTML = output.join ('') ;

}

Во- первых, мы создаем outputпеременную, содержащую весь вывод HTML, включая вопросы и варианты ответов.

Далее мы можем начать создавать HTML для каждого вопроса. Нам нужно будет пройтись по каждому вопросу следующим образом:

myQuestions.forEach ((currentQuestion, questionNumber) => {

// the code we want to run for each question goes here

}) ;

Для краткости мы используем функцию стрелки для выполнения операций над каждым вопросом. Поскольку это цикл forEach, мы получаем текущее значение, индекс (номер позиции текущего элемента в массиве) и сам массив в качестве параметров. Нам нужно только текущее значение и индекс, который для наших целей мы назовем currentQuestionи questionNumberсоответственно.

Теперь давайте посмотрим на код внутри нашего цикла:

// we’ll want to store the list of answer choices

const answers = [];

// and for each available answer...

for (letter in currentQuestion.answers) {

//...add an html radio button

answers.push (

`

${letter}:

${currentQuestion.answers[letter]}

`

) ;

}

// add this question and its answers to the output

output.push (

`

${currentQuestion.question}

 

 

${answers.join ('') }
`

 

) ;

Для каждого вопроса мы хотим сгенерировать правильный HTML, поэтому наш первый шаг — создать массив для хранения списка возможных ответов.

Далее мы будем использовать цикл для заполнения возможных ответов на текущий вопрос. Для каждого варианта мы создаем радиокнопку HTML, которую заключаем в

Обратите внимание, что мы используем шаблонные литералы, которые являются строками, но более мощными. Мы будем использовать следующие функции:

многострочные возможности

больше не нужно экранировать кавычки внутри кавычек, потому что литералы шаблонов вместо этого используют обратные кавычки

интерполяции строк, поэтому вы можете встраивать выражения JavaScript прямо в свои строки, например: ${code_goes_here}.

Когда у нас есть список кнопок для ответов, мы можем поместить HTML-код вопроса и HTML-код ответа в наш общий список выходных данных.

Обратите внимание, что мы используем литерал шаблона и некоторые встроенные выражения, чтобы сначала создать раздел вопросов, а затем создать раздел ответов. Выражение joinберет наш список ответов и объединяет их в одну строку, которую мы можем вывести в наш answersdiv.

Теперь, когда мы сгенерировали HTML для каждого вопроса, мы можем соединить все это вместе и показать на странице:

quizContainer.innerHTML = output.join ('') ;

Теперь наша buildQuizфункция завершена.

На этом этапе вы сможете запустить викторину и увидеть отображаемые вопросы. Обратите внимание, однако, что структура вашего кода важна. Из-за того, что называется временной мертвой зоной, вы не можете ссылаться на свой массив вопросов до того, как он будет определен.

Напомним, это правильная структура:

// Functions

function buildQuiz () {... }

function showResults () {... }

// Variables

const quizContainer = document.getElementById ('quiz’) ;

const resultsContainer = document.getElementById ('results’) ;

const submitButton = document.getElementById ('submit’) ;

const myQuestions = [... ];

// Kick things off

buildQuiz () ;

// Event listeners

submitButton.addEventListener ('click’, showResults) ;

Отображение результатов теста

На этом этапе мы хотим построить нашу showResultsфункцию, чтобы перебирать ответы, проверять их и показывать результаты.

Вот функция, которую мы подробно рассмотрим далее:

function showResults () {

// gather answer containers from our quiz

const answerContainers = quizContainer.querySelectorAll ('.answers’) ;

// keep track of user’s answers

let numCorrect = 0;

// for each question...

myQuestions.forEach ((currentQuestion, questionNumber) => {

// find selected answer

const answerContainer = answerContainers[questionNumber];

const selector = `input[name=question${questionNumber}]: checked`;

const userAnswer = (answerContainer.querySelector (selector) || {}).value;

// if answer is correct

if (userAnswer === currentQuestion.correctAnswer) {

// add to the number of correct answers

numCorrect++;

// color the answers green

answerContainers[questionNumber].style.color = 'lightgreen’;

}

// if answer is wrong or blank

else{

// color the answers red

answerContainers[questionNumber].style.color = 'red’;

}

}) ;

// show number of correct answers out of total

resultsContainer.innerHTML = `${numCorrect} out of ${myQuestions.length}`;

}

Сначала мы выбираем все контейнеры ответов в HTML-коде нашего теста. Затем мы создадим переменные для отслеживания текущего ответа пользователя и общего количества правильных ответов.

// gather answer containers from our quiz

const answerContainers = quizContainer.querySelectorAll ('.answers’) ;

// keep track of user’s answers

let numCorrect = 0;

Теперь мы можем просмотреть каждый вопрос и проверить ответы.

// for each question...

myQuestions.forEach ((currentQuestion, questionNumber) => {

// find selected answer

const answerContainer = answerContainers[questionNumber];

const selector = `input[name=question${questionNumber}]: checked`;

const userAnswer = (answerContainer.querySelector (selector) || {}).value;

// if answer is correct

if (userAnswer === currentQuestion.correctAnswer) {

// add to the number of correct answers

numCorrect++;

// color the answers green

answerContainers[questionNumber].style.color = 'lightgreen’;

}

// if answer is wrong or blank

else{

// color the answers red

answerContainers[questionNumber].style.color = 'red’;

}

}) ;

Общий смысл этого кода таков:

найти выбранный ответ в HTML

обрабатывать, что произойдет, если ответ правильный

справиться с тем, что произойдет, если ответ будет неправильным.

Давайте более подробно рассмотрим, как мы находим выбранный ответ в нашем HTML:

// find selected answer

const answerContainer = answerContainers[questionNumber];

const selector = `input[name=question${questionNumber}]: checked`;

const userAnswer = (answerContainer.querySelector (selector) || {}).value;

Во-первых, мы убеждаемся, что ищем внутри контейнера ответов для текущего вопроса.

В следующей строке мы определяем селектор CSS, который позволит нам найти, какой переключатель отмечен.

Затем мы используем JavaScript querySelectorдля поиска нашего селектора CSS в ранее определенном файле answerContainer. По сути, это означает, что мы найдем, какой переключатель ответа отмечен.

Наконец, мы можем получить значение этого ответа, используя.value.

Работа с неполным пользовательским вводом

Но что, если пользователь оставил ответ пустым? В этом случае использование.valueвызовет ошибку, потому что вы не можете получить значение того, чего нет. Чтобы решить эту проблему, мы добавили ||, что означает «или», и {}, который является пустым объектом. Теперь общее заявление гласит:

Получите ссылку на выбранный нами элемент ответа ИЛИ, если он не существует, используйте пустой объект.

Получите значение того, что было в первом выражении.

В результате значением будет либо ответ пользователя, либо undefined, что означает, что пользователь может пропустить вопрос без сбоя нашего теста.

Оценка ответов и отображение результата

Следующие операторы в нашем цикле проверки ответов позволят нам обрабатывать правильные и неправильные ответы.

// if answer is correct

if (userAnswer === currentQuestion.correctAnswer) {

// add to the number of correct answers

numCorrect++;

// color the answers green

answerContainers[questionNumber].style.color = 'lightgreen’;

}

// if answer is wrong or blank

else{

// color the answers red

answerContainers[questionNumber].style.color = 'red’;

}

Если ответ пользователя соответствует правильному выбору, увеличьте количество правильных ответов на один и (необязательно) покрасьте набор вариантов в зеленый цвет. Если ответ неверный или пустой, раскрасьте варианты ответа красным (опять же, необязательно).

После завершения цикла проверки ответов мы можем показать, на сколько вопросов пользователь ответил правильно:

// show number of correct answers out of total

resultsContainer.innerHTML = `${numCorrect} out of ${myQuestions.length}`;

И теперь у нас есть работающая викторина по JavaScript!

Если хотите, вы можете обернуть всю викторину в IIFE (немедленно вызываемое функциональное выражение) — функцию, которая запускается, как только вы ее определяете. Это позволит сохранить ваши переменные вне глобальной области видимости и гарантировать, что ваш тест не будет мешать другим сценариям, работающим на странице.

(function () {

// put the rest of your code here

}) () ;

Теперь все готово! Не стесняйтесь добавлять или удалять вопросы и ответы и оформлять викторину по своему усмотрению.

На этом этапе ваша викторина может выглядеть так (с небольшим количеством стилей):

Добавление пагинации

Теперь у нас запущена основная викторина, давайте взглянем на некоторые более продвинутые функции. Например, допустим, вы хотите показывать только один вопрос за раз.

Вам понадобиться:

способ показать и скрыть вопросы

кнопки для навигации по тесту.

Нам нужно будет внести некоторые изменения, поэтому давайте начнем с HTML:

 

 

 

 

 

 

 

 

 

 

Большая часть этой разметки такая же, как и раньше, но теперь мы добавили кнопки навигации и контейнер викторины. Контейнер викторины поможет нам расположить вопросы как слои, которые мы можем показывать и скрывать.

Затем внутри buildQuizфункции нам нужно добавить

элемент с классом slideдля хранения контейнеров вопросов и ответов, которые мы только что создали:

 

output.push (

`

 

 

${currentQuestion.question}

 

 

${answers.join («») }

 

 

`

 

) ;

Затем мы можем использовать позиционирование CSS, чтобы слайды располагались слоями друг над другом. В этом примере вы заметите, что мы используем z-индексы и переходы непрозрачности, чтобы позволить нашим слайдам появляться и исчезать. Вот как может выглядеть этот CSS:

.slide{

position: absolute;

left: 0px;

top: 0px;

width: 100%;

z-index: 1;

opacity: 0;

transition: opacity 0.5s;

}

.active-slide{

opacity: 1;

z-index: 2;

}

.quiz-container{

position: relative;

height: 200px;

margin-top: 40px;

}

Теперь мы добавим немного JavaScript, чтобы разбивка на страницы работала. Как и прежде, важен порядок, поэтому это измененная структура нашего кода:

// Functions

// New functions go here

// Variables

// Same code as before

// Kick things off

buildQuiz () ;

// Pagination

// New code here

// Show the first slide

showSlide (currentSlide) ;

// Event listeners

// New event listeners here

Мы можем начать с некоторых переменных, чтобы хранить ссылки на наши кнопки навигации и отслеживать, на каком слайде мы находимся. Добавьте их после вызова buildQuiz (), как показано выше:

// Pagination

const previousButton = document.getElementById («previous») ;

const nextButton = document.getElementById («next») ;

const slides = document.querySelectorAll («.slide») ;

let currentSlide = 0;

Далее мы напишем функцию для показа слайда. Добавьте это под существующими функциями (buildQuizи showResults):

function showSlide (n) {

slides[currentSlide].classList.remove ('active-slide’) ;

slides[n].classList.add ('active-slide’) ;

currentSlide = n;

if (currentSlide === 0) {

previousButton.style.display = 'none’;

}

else{

previousButton.style.display = 'inline-block’;

}

if (currentSlide === slides.length-1) {

nextButton.style.display = 'none’;

submitButton.style.display = 'inline-block’;

}

else{

nextButton.style.display = 'inline-block’;

submitButton.style.display = 'none’;

}

}

Вот что делают первые три строки:

Скройте текущий слайд, удалив active-slideкласс.

Покажите новый слайд, добавив active-slideкласс.

Обновите текущий номер слайда.

Следующие строки вводят следующую логику:

Если мы находимся на первом слайде, скройте кнопку «Предыдущий слайд «. В противном случае покажите кнопку.

Если мы находимся на последнем слайде, скройте кнопку «Следующий слайд «и покажите кнопку «Отправить «. В противном случае покажите кнопку «Следующий слайд «и скройте кнопку «Отправить «.

После того, как мы написали нашу функцию, мы можем немедленно вызвать showSlide (0) ее для показа первого слайда. Это должно идти после кода разбиения на страницы:

// Pagination

...

showSlide (currentSlide) ;

Далее мы можем написать функции, чтобы кнопки навигации работали. Они идут ниже showSlideфункции:

function showNextSlide () {

showSlide (currentSlide + 1) ;

}

function showPreviousSlide () {

showSlide (currentSlide — 1) ;

}

Здесь мы используем нашу showSlideфункцию, позволяющую кнопкам навигации показывать предыдущий слайд и следующий слайд.

Наконец, нам нужно привязать кнопки навигации к этим функциям. Это происходит в конце кода:

// Event listeners

...

previousButton.addEventListener («click», showPreviousSlide) ;

nextButton.addEventListener («click», showNextSlide) ;

Теперь ваша викторина имеет работающую навигацию!

Что дальше?

Теперь, когда у вас есть базовая викторина по JavaScript, пришло время проявить творческий подход и поэкспериментировать.

Вот несколько предложений, которые вы можете попробовать:

Попробуйте по-разному реагировать на правильный или неправильный ответ.

Красиво оформить викторину.

Добавьте индикатор выполнения.

Позвольте пользователям просматривать ответы перед отправкой.

Дайте пользователям сводку их ответов после отправки.

Обновите навигацию, чтобы пользователи могли переходить к любому номеру вопроса.

Создавайте собственные сообщения для каждого уровня результатов. Например, если кто-то набрал 8/10 или выше, назовите его ниндзя викторины.

Добавьте кнопку, чтобы поделиться результатами в социальных сетях.

Сохраняйте свои рекорды с помощью localStorage.

Добавьте таймер обратного отсчета, чтобы увидеть, смогут ли люди опередить время.

Примените концепции из этой статьи для других целей, таких как оценка стоимости проекта или социальная викторина «Какой вы персонаж?».

3D-печать5GABC-анализAndroidAppleAppStoreAsusCall-центрChatGPTCRMDellDNSDrupalExcelFacebookFMCGGoogleHuaweiInstagramiPhoneLinkedInLinuxMagentoMicrosoftNvidiaOpenCartPlayStationPOS материалPPC-специалистRuTubeSamsungSEO-услугиSMMSnapchatSonyStarlinkTikTokTwitterUbuntuUp-saleViasatVPNWhatsAppWindowsWordPressXiaomiYouTubeZoomАвдеевкаАктивные продажиАкцияАлександровск ЛНРАлмазнаяАлчевскАмвросиевкаАнализ конкурентовАнализ продажАнтимерчандайзингАнтрацитАртемовскАртемовск ЛНРАссортиментная политикаБелгородБелицкоеБелозерскоеБердянскБизнес-идеи (стартапы)БрендБрянкаБукингВахрушевоВендорВидеоВикипедияВирусная рекламаВирусный маркетингВладивостокВнутренние продажиВнутренний маркетингВолгоградВолновахаВоронежГорловкаГорнякГорскоеДебальцевоДебиторкаДебиторская задолженностьДезинтермедитацияДзержинскДивизионная система управленияДизайнДимитровДирект-маркетингДисконтДистрибьюторДистрибьюцияДобропольеДокучаевскДоменДружковкаЕкатеринбургЕнакиевоЖдановкаЗапорожьеЗимогорьеЗолотоеЗоринскЗугрэсИжевскИловайскИрминоКазаньКалининградКировскКировскоеКомсомольскоеКонстантиновкаКонтент-маркетингКонтент-планКопирайтингКраматорскКрасноармейскКрасногоровкаКраснодарКраснодонКраснопартизанскКрасный ЛиманКрасный ЛучКременнаяКураховоКурскЛисичанскЛуганскЛутугиноМакеевкаМариупольМаркетингМаркетинговая информацияМаркетинговые исследованияМаркетинговый каналМаркетинг услугМаркетологМарьинкаМедиаМелекиноМелитопольМенеджментМерчандайзерМерчандайзингМиусинскМолодогвардейскМоскваМоспиноНижний НовгородНиколаевНиколаевкаНишевой маркетингНовоазовскНовогродовкаНоводружескНовосибирскНумерическая дистрибьюцияОдессаОмскОтдел маркетингаПартизанский маркетингПервомайскПеревальскПетровскоеПлата за кликПоисковая оптимизацияПопаснаяПравило ПаретоПривольеПрогнозирование продажПродвижение сайтов в ДонецкеПроизводство видеоПромоПромоушнПрямой маркетингРабота для маркетологаРабота для студентаРазработка приложенийРаспродажаРегиональные продажиРекламаРеклама на асфальтеРемаркетингРетро-бонусРибейтРитейлРовенькиРодинскоеРостов-на-ДонуРубежноеСамараСанкт-ПетербургСаратовСватовоСвердловскСветлодарскСвятогорскСевастопольСеверодонецкСеверскСедовоСейлз промоушнСелидовоСимферопольСинергияСколковоСлавянскСнежноеСоздание сайтов в ДонецкеСоледарСоциальные сетиСочиСтаробельскСтаробешевоСтахановСтимулирование сбытаСуходольскСчастьеТелемаркетингТельмановоТираспольТорговый представительТорезТрейд маркетингТрейд промоушнТюменьУглегорскУгледарУкраинскХабаровскХарцызскХерсонХостингЦелевая аудиторияЦифровой маркетингЧасов ЯрЧелябинскШахтерскЮжно-СахалинскЮнокоммунаровскЯндексЯсиноватая