Создание сайтов в Красноармейске, ДНР. Используйте Notion API для создания викторины с помощью JavaScript

Notion — это многофункциональное приложение для организации любого контента, от заметок до календарей и напоминаний. В нашей последней статье «Начало работы с Notion API и его JavaScript SDK «мы углубились в то, как использовать API Notion и создали небольшой интерфейс для взаимодействия с ним. В этой статье мы рассмотрим еще один пример использования Notion API: создание викторины JavaScript.

Хотя для изучения этой статьи не требуется никаких предварительных знаний (я предоставлю все необходимые шаги), мы будем иметь дело с внешним и внутренним кодом, так как потребуется немного Node.js и экспресс-настройки., поэтому предполагаются некоторые навыки работы с JavaScript.

Настройка проекта викторины JavaScript

Мы собираемся разделить нашу установку на две части. В первой мы пройдем необходимую настройку на стороне Notion, а во второй части мы будем работать с нашим кодом.

Чтобы продолжить, вам понадобится учетная запись Notion (подробнее об этом ниже), а также последняя копия Node, установленная на вашем компьютере. Как всегда, окончательный код руководства можно найти на GitHub.

Настройка понятия

Если у вас еще нет учетной записи Notion, создайте ее, перейдя по этой ссылке. После создания учетной записи и входа в систему создайте новую страницу, выбрав Добавить страницу и дав ей имя. В этом руководстве мы будем использовать Tableбазу данных. Хотя это не идеальная база данных для создания викторины, это самое близкое, чего мы можем достичь с помощью Notion!

Внесение информации в таблицу

Теперь, когда у нас есть пустой файл Table, нам нужно выяснить, как правильно вставить в него нашу информацию.

Наша предполагаемая схема для нашей викторины следующая:

{

«1»: {

«Question»: «Which is the purpose of JavaScript?»,

«Answers»: {

«1»: «To style HTML Pages»,

«2»: «To add interactivity to HTML pages»,

«3»: «To perform server side scripting operations»

},

«Correct»: «To add interactivy to HTML pages»

},

«2»: {

«Question»: «To insert a JavaScript into an HTML page, which tag is used?»,

«Answers»: {

«1»: «

|--------- Database ID --------|

Если нас беспокоит наличие ключей API Notion в файле внутри нашего репозитория, обратите внимание, что.gitignoreу нас есть.envфайл; позволяет нам.gitignoreпомещать внутрь разные имена файлов/папок, а это означает, что эти файлы/папки не будут добавлены в наш репозиторий, когда мы отправим наш код.

Теперь, когда у нас есть начальный репозиторий и необходимые учетные данные от Notion, мы можем начать работу над нашей викториной!

Получение данных викторины JavaScript

Сначала мы должны проверить, успешно ли мы подключились к нашей базе данных Notion, поэтому мы перейдем к нашему.index.jsфайлу и зарегистрируем нашу reponseпеременную (посмотрите, как мы получаем нашу databaseIdиз нашего.envфайла и используем ее в нашем запросе к базе данных?).

Если мы затем запустим yarn start, мы должны увидеть что-то вроде следующего снимка экрана на нашем терминале.

Какой журнал извлекает ответный запрос

Увидев это на нашем терминале, мы правильно подключились к нашей базе данных Notion и теперь можем получить необходимые данные. Наша getDatabaseфункция будет выглядеть так:

exports.getDatabase = async function () {

const response = await notion.databases.query ({ database_id: databaseId }) ;

const responseResults = response.results.map ((page) => {

return {

id: page.id,

question: page.properties.Question.title[0].plain_text,

answers: page.properties.Answers.multi_select,

correct: page.properties.Correct.rich_text[0].plain_text,

};

}) ;

return responseResults;

};

С помощью responseResultsмы сопоставляем наши results (соответствующие записи в нашей базе данных) и сопоставляем пути для различных свойств с именами, которые мы выбираем (в данном случае, id, questionи answers) correct. Обратите внимание, насколько конкретен путь к объекту. Это предусмотрено дизайном, а это означает, что при разработке и работе с собственной базой данных вы должны постоянно исследовать возвращаемые свойства, пока не найдете нужную информацию (на самом деле это вопрос проб и ошибок).

С этим новым кодом мы в значительной степени обращаемся к нашему API и выбираем свойства, которые мы хотим использовать в нашем коде, что означает, что мы готовы работать с ними в нашем интерфейсе!

Отображение наших данных в браузере

Давайте начнем с нашего HTML и CSS, так как они довольно прямолинейны! Мы не будем вносить никаких изменений в наш HTML-код из шаблона, и style.cssмы можем вставить следующий код под существующим:

.questionContainer {

padding: 30px;

display: flex;

flex-direction: column;

justify-content: center;

align-items: center;

box-shadow: rgba (149, 157, 165, 0.2) 0px 8px 24px;

border-radius: 10px;

}

.numberElement {

margin: 0px auto 10px;

font-size: 12px;

font-weight: 700;

text-transform: uppercase;

}

.question {

margin: 0px auto 40px;

}

.answersDiv {

width: 100%;

display: flex;

flex-direction: column;

gap: 20px;

}

.answerOption {

padding: 20px;

margin: 0px;

font-size: 18px;

text-align: center;

cursor: pointer;

border: 1px solid rgb (42, 43, 44) ;

border-radius: 40px;

}

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

Если мы теперь перейдем к main.jsфайлу внутри publicпапки, мы увидим, что мы уже получаем наши данные из нашей серверной части с помощью getDataFromBackendфункции. Если вас это смущает, в разделе «Начало работы с Notion API и его JavaScript SDK «есть более подробное объяснение, но в основном server.jsмы создали маршрут, который получает нашу базу данных, и здесь getDataFromBackendмы делаем fetchдля этого тот же маршрут, который заберет наши данные для нас.

Обратите внимание, как внутри addDataу нас уже есть const data = await getDataFromBackend () ;. Это означает, что мы готовы начать работу с нашими данными, и мы действительно можем это проверить! logэту dataпеременную, и мы должны увидеть на нашей консоли массив записей нашей базы данных.

Регистрация наших данных

Отображение наших данных на экране

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

Начнем с создания файла

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

Итак, внутри нашей addDataфункции мы можем сделать это:

const addData = async () => {

const data = await getDataFromBackend () ;

data.forEach ((value, index) => {

const div = document.createElement ('div’) ;

div.classList.add ('questionContainer’) ;

container.append (div) ;

}) ;

};

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

const addData = async () => {

const data = await getDataFromBackend () ;

data.forEach ((value, index) => {

const div = document.createElement ('div’) ;

div.classList.add ('questionContainer’) ;

const numberElement = document.createElement ('p’) ;

numberElement.classList.add ('numberElement’) ;

numberElement.innerHTML = `Question ${index + 1}`;

div.appendChild (numberElement) ;

container.append (div) ;

}) ;

};

Здесь мы создаем и присваиваем ему класс, и мы работаем с index + 1, потому что массивы в JavaScript отсчитываются от нуля, и мы не хотим видеть Вопрос 0, так как это не имеет смысла! Если мы сейчас запустим наше приложение, мы должны увидеть что-то вроде того, что изображено ниже.

Теперь мы визуализируем карточку для каждого вопроса и отображаем для него заголовок, который гласит «Вопрос ${index + 1}».

Самое интересное: новые функции для рендеринга вопросов и ответов

Теперь самое интересное! Мы могли бы сделать всю нашу логику внутри addData, но это может стать слишком запутанным, поэтому мы собираемся создать новые функции для отображения нашего вопроса и ответов.

Давайте начнем с вопроса, и давайте немного поработаем над нашей addDataфункцией, которая пока не принесет многого:

const addData = async () => {

const data = await getDataFromBackend () ;

data.forEach ((value, index) => {

const div = document.createElement ('div’) ;

div.classList.add ('questionContainer’) ;

const numberElement = document.createElement ('p’) ;

numberElement.classList.add ('numberElement’) ;

numberElement.innerHTML = `Question ${index + 1}`;

div.appendChild (numberElement) ;

// OUR NEWLY ADDED CODE

const question = createQuestion (value.question) ;

div.appendChild (question) ;

// END OF OUR NEWLY ADDED CODE

container.append (div) ;

}) ;

};

Код, который мы только что добавили, очень похож на код для numberElement, но здесь мы присваиваем функцию переменной и добавляем эту переменную. Заметьте также, что мы переходим value.questionв наш createQuestion, потому что мы, конечно же, хотим работать с вопросом и визуализировать его. Все это будет иметь смысл в кратчайшие сроки — не волнуйтесь!

Теперь снаружи и выше addDataдавайте создадим эту новую createQuestionфункцию. Внутри него нам нужна та же логика, которую мы добавили для нашего numberElement: создать элемент, присвоить ему класс и добавить к нему некоторый контент. Здесь мы будем использовать not innerHTMLbut createTextNode: поскольку наши вопросы связаны с кодом, если бы мы использовали что- innerHTMLто вроде text, это фактически отображало бы слово, textно жирным шрифтом вместо всего синтаксиса (вы можете увидеть пример здесь). Наш финал createQuestionбудет выглядеть так:

const createQuestion = (question) => {

const questionElement = document.createElement ('h3') ;

questionElement.classList.add ('question’) ;

const questionNode = document.createTextNode (question) ;

questionElement.appendChild (questionNode) ;

return questionElement;

};

Если мы сейчас запустим yarn start, наш браузер должен выглядеть, как показано ниже.

Теперь мы должны увидеть карточку вопроса с заголовком вопроса и недавно добавленным вопросом.

Теперь наша установка для наших ответов почти такая же. Давайте сначала сделаем то же самое, что мы сделали с createQuestioninside addData:

const addData = async () => {

const data = await getDataFromBackend () ;

data.forEach ((value, index) => {

const div = document.createElement ('div’) ;

div.classList.add ('questionContainer’) ;

const numberElement = document.createElement ('p’) ;

numberElement.classList.add ('numberElement’) ;

numberElement.innerHTML = `Question ${index + 1}`;

div.appendChild (numberElement) ;

const question = createQuestion (value.question) ;

div.appendChild (question) ;

// OUR NEWLY ADDED CODE

const answers = createAnswers (value) ;

div.appendChild (answers) ;

// END OF OUR NEWLY ADDED CODE

container.append (div) ;

}) ;

};

И теперь наш первоначальный поиск createAnswersбудет выглядеть так:

const createAnswers = (value) => {

const answersDiv = document.createElement ('div’) ;

answersDiv.classList.add ('answersDiv’) ;

return answersDiv;

};

Обратите внимание, как мы работаем const answers = createAnswers (value) ;. Мы не можем просто перейти value.answersк нашей функции, потому что нам также нужен файл value.correct. Мы могли бы вместо этого передать нашей функции два аргумента: один для массива ответов, а другой будет правильным.

Отображение массива ответов

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

const createAnswers = (value) => {

const answersDiv = document.createElement ('div’) ;

answersDiv.classList.add ('answersDiv’) ;

for (let i = 0; i < value.answers.length; i++) {

const answerElement = document.createElement ('p’) ;

answerElement.classList.add ('answerOption’) ;

const answerNode = document.createTextNode (value.answers[i].name) ;

answerElement.appendChild (answerNode) ;

answersDiv.appendChild (answerElement) ;

}

return answersDiv;

};

С помощью этого кода мы зацикливаемся на нашем array, создаем элемент, присваиваем ему класс и используем createTextNodeего для отображения наших ответов. (Как ни странно, если бы мы использовали innerHTMLздесь, ответы с

Частичный вид нашей викторины со всеми необходимыми элементами

Взаимодействие с ответами

Хм... Но мы не можем взаимодействовать с ответами, и это не совсем викторина, если мы не узнаем, правильно мы ответили или нет, верно? Мы должны это исправить!

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

const createAnswers = (value) => {

const answersDiv = document.createElement ('div’) ;

answersDiv.classList.add ('answersDiv’) ;

for (let i = 0; i < value.answers.length; i++) {

const answerElement = document.createElement ('p’) ;

answerElement.classList.add ('answerOption’) ;

const answerNode = document.createTextNode (value.answers[i].name) ;

// OUR NEWLY ADDED CODE

answerElement.addEventListener ('click’, () => {}) ;

// END OF OUR NEWLY ADDED CODE

answerElement.appendChild (answerNode) ;

answersDiv.appendChild (answerElement) ;

}

return answersDiv;

};

Помните, что мы сделали createAnswers (value), чтобы мы могли получить value.correct? Теперь пришло время сиять! Когда мы нажимаем на ответ, возможны два результата: пользователь выбирает ответ, равный правильному ответу, или пользователь выбирает ответ, не равный правильному ответу. Чтобы справиться с этими возможными результатами, мы собираемся использовать оператор if, и способ, которым мы собираемся показать нашим пользователям, что они получили правильный или неправильный ответ, — это изменение background-colorответа. Итак, наша логика будет выглядеть так:

const createAnswers = (value) => {

const answersDiv = document.createElement ('div’) ;

answersDiv.classList.add ('answersDiv’) ;

for (let i = 0; i < value.answers.length; i++) {

const answerElement = document.createElement ('p’) ;

answerElement.classList.add ('answerOption’) ;

const answerNode = document.createTextNode (value.answers[i].name) ;

answerElement.addEventListener ('click’, () => {

// OUR NEWLY ADDED CODE

answerElement.style.color = 'white’;

if (value.answers[i].name≠= value.correct) {

// colour our answerElement red

answerElement.style.backgroundColor = '#f55142';

} else {

// colour our answerElement green

answerElement.style.backgroundColor = '#6dbf39';

}

// END OF OUR NEWLY ADDED CODE

}) ;

answerElement.appendChild (answerNode) ;

answersDiv.appendChild (answerElement) ;

}

return answersDiv;

};

Таким образом, с каждым щелчком мы меняем цвет текста на белый, а затем проверяем, nameравно ли свойство каждого ответа value.correct (это, очевидно, не идеально, и индекс был бы намного лучше, но мы сделали лучше всего с базами данных Notion!). Если это не так, мы меняем его цвет на красный, а если да, то меняем на зеленый!

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

Вот и закончилась наша викторина! ? Разве это не фантастика?

Завершение викторины Notion JavaScript

В этом уроке мы рассмотрели множество функций, предоставляемых API Notion, и, честно говоря, всегда очень интересно видеть, как много вы можете сделать с помощью такого простого инструмента!

Я надеюсь, что этот пост вдохновит вас на изучение Notion API и создание собственных викторин и других интересных вещей с помощью Notion!

Если вы хотите быстро протестировать этот проект Notion, вы можете клонировать его из нашего репозитория GitHub.

Делитесь нашими материалами с друзьями!

 

 

Заказать разработку сайта