Интеграция JavaScript с Python и Flask

4.9 (97.78%) 9 vote[s]

По какому принципу взаимодействует JavaScript с python?Важно различать код, который запускается клиентом, пользователем, взаимодействующим с веб-приложением, и сервером, который является приложением Flask, на котором выполняется веб-сайт. Клиент делает HTTP-запрос к серверу, который выполняет некоторый код Python. Сервер обрабатывает ответ, чтобы понять, что запрашивает клиент, и в конечном итоге отправляет обратно некоторое содержимое HTML и CSS, которое отображается в браузере клиента. Однако часто бывает полезно иметь код, который работает на стороне клиента. Клиентские процессы снижают нагрузку на сервер и часто быстрее. JavaScript — это язык программирования, изначально разработанный для запуска в веб-браузере, который запускается на стороне клиента. Существует много разных версий JavaScript, которые поддерживаются разными браузерами, но есть определенные стандартные версии, которые поддерживаются большинством. В этом занятии будет использоваться одна из самых популярных последних версий — ES6.

Использование JavaScript с Python, HTML и CSS

Когда JavaScript встроен непосредственно в HTML-код веб-страницы, он заключен в <script></script>теги.

<script>
      alert('Hello, world!');
</script>

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

<html>
      <head>
          <script>
              function hello() {
                  alert('Hello!');
              }
          </script>
          <title>My Website</title>
      </head>
      <body>
          <h1>Welcome!</h1>
          <button onclick="hello()">Click Here!</button>
      </body>
  </html>

Теперь код JavaScript содержится внутри функции. Обратите внимание, что функция ограничена фигурными скобками.

Функция hello никогда не вызывается внутри элемента script. Есть элемент button с атрибутом onclick, в качестве значения которого используется функция hello. Нажатие кнопки — это одно из событий, которое понимает JavaScript и которое можно использовать в качестве триггера. В этом случае этот триггер запускает функцию hello.

Некоторые другие события JavaScript включают в себя:

      • onmouseover: срабатывает, когда курсор мыши находится над элементом;
      • onkeydown: срабатывает при нажатии клавиши;
      • onkeyup: срабатывает при отпускании клавиши;
      • onload: срабатывает при загрузке страницы;
      • onblur: срабатывает, когда объект теряет фокус (например, при удалении курсора от поля ввода).



Управление DOM

Помимо продемонстрированного отображения предупреждений (алертов), JavaScript имеет возможность реально изменять содержимое веб-страницы.

<html>
      <head>
          <script>
              // Функция изменяет заголовок, чтобы попрощаться
              function hello() {
                  document.querySelector('h1').innerHTML = 'Goodbye!';
              }
          </script>
      </head>
      <body>
          <h1>Welcome!</h1>
          <button onclick="hello()">Click Here!</button>
      </body>
  </html>
    • document относится к веб-странице, отображаемой в данный момент.
    • querySelector(‘tag’) — это функция, которая ищет на веб-странице определенный селектор CSS и возвращает этот элемент. Если результатов несколько, возвращается только первый результат.
      • Эта функция также может быть вызвана как document.querySelector(‘#id’) и document.querySelector(‘.class’). Также могут быть использованы более сложные селекторы, например, выбирающие только потомков определенного элемента.
    • Свойство элемента innerHTML является содержанием HTML, содержащимся в тегах элемента.
    • При нажатии button текст Welcome! меняется на Goodbye!

Следующий немного более сложный пример демонстрирует использование переменных в JavaScript:

<html>
      <head>
          <script>
              let counter = 0;

              function count() {
                  counter++;
                  document.querySelector('#counter').innerHTML = counter;
              }
          </script>
      </head>
      <body>
          <h1 id="counter">0</h1>
          <button onclick="count()">Click Here!</button>
      </body>
  </html>
    • let — это ключевое слово, используемое для определения переменных.
    • counter++ — это сокращение для увеличения counter на 1.

Условные операторы в JavaScript выглядят так:

<script>
      let counter = 0;

      function count() {
          counter++;
          document.querySelector('#counter').innerHTML = counter;

          if (counter % 10 === 0) {
              alert(`Counter is at ${counter}!`);
          }
      }
  </script>
    • % является оператором модуля, который возвращает остаток от первого числа, деленного на второе.
    • === проверяет точное равенство в JavaScript; две вещи должны быть идентичными, чтобы он возвращал истину (true).
    • Аргументом alert является литерал шаблона, который похож на строку формата Python. ${counter} и заменяется любым значением переменной counter. Обратные метки используются для разграничения литерала шаблона.

JavaScript также может быть полностью удалён из HTML-кода:

<html>
      <head>
          <script>
              document.addEventListener('DOMContentLoaded', function() {
                  document.querySelector('button').onclick = count;
              });

              let counter = 0;

              function count() {
                  counter++;
                  document.querySelector('#counter').innerHTML = counter;

                  if (counter % 10 === 0) {
                      alert(`Counter is at ${counter}!`);
                  }
              }
          </script>
      </head>
      <body>
          <h1 id="counter">0</h1>
          <button>Click Here!</button>
      </body>
  </html>
    • Обратите внимание, что в тегах HMTL для элемента botton отсутствует атрибут onclick. Тем не менее, функция addEventListener, которая, как следует из названия, «слушает» или ждет, пока не произойдет событие DOMContentLoaded. Это событие происходит, когда вся структура HTML загружается браузером. Затем вызывается второй аргумент, функция.
    • JavaScript использует «функции более высокого порядка», что означает, что функции можно передавать как любое другое значение. Передаваемая функция называется функцией обратного вызова. Обратный вызов вызывается, когда происходит прослушиваемое событие. В этом случае этот обратный вызов устанавливает свойство onclick элемента button для функции count, что в конечном итоге приводит к той же функциональности, что и раньше.

Если пойти еще дальше, то код JavaScript может быть выделен из файла .html целиком в отдельный файл .js. Все, что находится внутри элемента script из последнего примера, записывается в отдельный файл с расширением .js, и файл .html будет выглядеть так:

<html>
      <head>
          <script src="counter3.js"></script>
      </head>
      <body>
          <h1 id="counter">0</h1>
          <button>Click Here!</button>
      </body>
  </html>

Переменные JavaScript

Есть три основных ключевых слова, используемых для определения переменных в JavaScript:

      • const: определяет постоянную переменную, которая не может быть переопределена позже;
      • let: определяет переменную, локальную для области самой внутренней пары фигурных скобок, окружающих ее;
      • var: определяет переменную, которая является локальной для функции, в которой она определена.

Вот пример, демонстрирующий эти различные способы определения переменных:

<script>
      // This variable exists even outside the loop
      if (true) {
          var message = 'Hello!';
      }

      alert(message);
  </script>
      • Поскольку var использовался для определения message, при выполнении этого кода не будет ошибок.
<script>
  // Эта переменная не существует вне цикла
  if (true) {
      let message = 'Hello!';
  }

  alert(message);
  </script>
      • Поскольку let был использован для определения message, он не может быть передан alert, что выходит за рамки message. Если бы это было на странице HTML, то при открытии страницы предупреждение не появлялось бы. Если бы консоль была открыта в браузере, было бы Uncaught ReferenceError.
<script>
  // Значение константных переменных не может измениться
  const message = 'Hello!';
  message = 'Goodbye!';

  alert(message);
  </script>
      • Как и в предыдущем примере, оповещение не появится. В консоли было бы Uncaught TypeError, так как была попытка переопределить переменную, определенную с const.

Консоль JavaScript, доступная в меню «Разработка» или «Проверка» в веб-браузере, позволяет осуществлять интерактивный ввод JavaScript, аналогично консоли Python.

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

<html>
      <head>
          <script>
              document.addEventListener('DOMContentLoaded', function() {
                  document.querySelector('#form').onsubmit = function() {
                      const name = document.querySelector('#name').value;
                      alert(`Hello ${name}!`);
                  };
              });
          </script>
      </head>
      <body>
          <form id="form">
              <input id="name" autocomplete="off" autofocus placeholder="Name" type="text">
              <input type="submit">
          </form>
      </body>
  </html>
    • Функция обратного вызова здесь выбирает элемент с идентификатором form и устанавливает его свойство onsubmit (другое событие) для другой функции обратного вызова. Она устанавливает в качестве const переменную name  со свойством value, возвращаемое элементом с id name. Элемент name — это поле ввода формы, поэтому значением будет то, что пользователь ввел в форму.
    • Таким образом, этот код создает предупреждение, которое говорит «привет» любому имени, введенному пользователем в форму.

Модификация стилей

JavaScript может изменять свойства CSS элементов:

 <html>
      <head>
          <script>
              document.addEventListener('DOMContentLoaded', function() {

                  // Изменить цвет шрифта на красный
                  document.querySelector('#red').onclick = function() {
                      document.querySelector('#hello').style.color = 'red';
                  };

                  // Изменить цвет шрифта на синй
                  document.querySelector('#blue').onclick = function() {
                      document.querySelector('#hello').style.color = 'blue';
                  };

                  // Изменить цвет шрифта на зелёный
                  document.querySelector('#green').onclick = function() {
                      document.querySelector('#hello').style.color = 'green';
                  };
              });
          </script>
      </head>
      <body>
          <h1 id="hello">Hello!</h1>
          <button id="red">Red</button>
          <button id="blue">Blue</button>
          <button id="green">Green</button>
      </body>
  </html>
    • Есть три кнопки, каждая из которых (после первоначального обратного вызова при загрузке веб-страницы) имеет свои onclick свойства, установленные в функцию, которая устанавливает свойство  style.color элемента hello в другой цвет. Любое свойство CSS может быть изменено, например style.background-color, style.margin и т. д.

Повторяемость последнего примера может быть уменьшена:

<html>
      <head>
          <script>
              document.addEventListener('DOMContentLoaded', function() {

                  // Пусть каждая кнопка меняет цвет заголовка
                  document.querySelectorAll('.color-change').forEach(function(button) {
                      button.onclick = function() {
                          document.querySelector('#hello').style.color = button.dataset.color;
                      };
                  });

              });
          </script>
      </head>
      <body>
          <h1 id="hello">Hello!</h1>
          <button class="color-change" data-color="red">Red</button>
          <button class="color-change" data-color="blue">Blue</button>
          <button class="color-change" data-color="green">Green</button>
      </body>
  </html>
    • document.querySelectorAll(‘.color-change‘) возвращает массив всех элементов класса color-change.
    • forEach является встроенной функцией JavaScript, которую можно вызывать в массиве, который выполняет функцию, переданную ему в каждом элементе массива. Передаваемая функция принимает в качестве аргумента один конкретный элемент массива.
    • Наличие всех трех кнопок с одинаковым классом color-change позволяет выбирать их вместе с querySelectorAll.
    • data-color является атрибутом данных. Атрибуты данных позволяют связывать дополнительную информацию с элементом без изменения способа отображения элемента браузером. Атрибуты данных могут иметь любое имя, если они начинаются с data-.
    • Атрибуты данных могут быть доступны в dataset свойстве элемента. В этом примере доступ к data-color осуществляется в dataset.color.

Функции стрелок

Поскольку функции, особенно анонимные, настолько распространены в JavaScript, ES6 ввел новый синтаксис для функций, называемый стрелочной нотацией, который позволяет определять так называемые функции стрелок.

() => {
      alert('Hello, world!');
  }

  x => {
      alert(x);
  }

  x => x * 2;
    • Функция стрелки определяется без использования слова function, а только с помощью пары скобок, содержащих любые аргументы, которые принимает функция, за которыми следует стрелка и, наконец, тело функции, заключенное в фигурные скобки.
    • Функции с одним аргументом могут быть определены без использования скобок, заключающих список аргументов.
    • Функции, имеющие только одну строку в теле, могут быть без фигурных скобок, а  её тело располагаться в той же строке, что и список аргументов и стрелка.

Предыдущий пример с кнопками можно переписать более кратко с помощью функций стрелок:

document.addEventListener('DOMContentLoaded', () => {

      // Пусть каждая кнопка меняет цвет заголовка
      document.querySelectorAll('.color-change').forEach(button => {
          button.onclick = () => {
              document.querySelector('#hello').style.color = button.dataset.color;
          };
      });

  });

В этом варианте примера цвета можно использовать раскрывающееся меню для выбора цветов вместо кнопок:

<html>
      <head>
          <script>
              document.addEventListener('DOMContentLoaded', () => {

                  // Изменить цвет заголовка при изменении выпадающего списка
                  document.querySelector('#color-change').onchange = function() {
                      document.querySelector('#hello').style.color = this.value;
                  };

              });
          </script>
      </head>
      <body>
          <h1 id="hello">Hello!</h1>
          <select id="color-change">
              <option value="black">Black</option>
              <option value="red">Red</option>
              <option value="blue">Blue</option>
              <option value="green">Green</option>
          </select>
      </body>
  </html>
  • onchange — это событие, инициируемое при изменении выбора в раскрывающемся меню.
  • this относится к любому значению, с которым работает функция, в данном случае это document.querySelector (‘# color-change‘), который является самим выпадающим меню. Выбранный элемент извлекается с помощью атрибута раскрывающегося меню value , который соответствует одному из вариантов цвета.
    • Обратите внимание, что использование this с функциями стрелок приведет к другому поведению. this внутри функции стрелки будет связан с любым значением, которое this принял бы внутри кода, который содержит функцию стрелки. Выписав функцию (), this принимает значение того, к чему вызывается функция.

Больше примеров с JavaScript

В следующем примере целью будет создание приложения списка дел. Вот отправная точка:

<html>
      <head>
          <script>
              document.addEventListener('DOMContentLoaded', () => {

                  document.querySelector('#new-task').onsubmit = () => {

                      // Создать новый элемент для списка
                      const li = document.createElement('li');
                      li.innerHTML = document.querySelector('#task').value;

                      // Добавить новый элемент в список задач
                      document.querySelector('#tasks').append(li);

                      // Очистить поле ввода
                      document.querySelector('#task').value = '';

                      // Остановить отправку формы
                      return false;
                  };

              });
          </script>
          <title>Tasks</title>
      </head>
      <body>
          <h1>Tasks</h1>
          <ul id="tasks">
          </ul>
          <form id="new-task">
              <input id="task" autocomplete="off" autofocus placeholder="New Task" type="text">
              <input type="submit">
          </form>
      </body>
  </html>
    • Вначале неупорядоченный список tasks будет пустым, но но потом будет заполняться вводом данных пользователя.
    • В коде JavaScript при отправке формы новый элемент li назначается const переменной li с помощью функции document.createElement (‘li‘). Затем innerHTML этого li устанавливается равным значению поля ввода задачи.
    • Затем новый li добавляется в задачи ul с помощью функции append (li), вызываемой в ul.
    • Наконец, поле ввода очищается, и поведение по умолчанию для формы, которая заключается в переходе на какой-либо другой веб-сайт и перезагрузку страницы, подавляется возвратом false.

Пустые представления могут быть проигнорированы путем условного включения кнопки отправки:

// По умолчанию кнопка отправки отключена
  document.querySelector('#submit').disabled = true;

  // Кнопка включена, только если в поле ввода есть текст
  document.querySelector('#task').onkeyup = () => {
      document.querySelector('#submit').disabled = false;

  // ...тот же код, что и раньше...

  // Снова отключить кнопку после отправки
  document.querySelector('#submit').disabled = true;

  // Остановить отправку формы
  return false;
  };
      • Это приводит к тому, что кнопка может быть нажата только после того, как было зарегистрировано некоторое нажатие клавиши, при условии, что поле заполнено.

Предыдущая реализация по-прежнему допускала отправку, если текст был введен, а затем удален из формы. Это можно исправить, проверив, что свойство length атрибута value ввода формы действительно больше 0 после каждого нажатия клавиши:

 // Кнопка включена, только если в поле ввода есть текст
  document.querySelector('#task').onkeyup = () => {
      if (document.querySelector('#task').value.length > 0)
          document.querySelector('#submit').disabled = false;
      else
          document.querySelector('#submit').disabled = true;
  };

Еще одна особенность JavaScript — возможность ждать выполнения определенное количество времени:

<html>
      <head>
          <script>
              document.addEventListener('DOMContentLoaded', () => {
                  setInterval(count, 1000);
              });

              let counter = 0;

              function count() {
                  counter++;
                  document.querySelector('#counter').innerHTML = counter;
              }
          </script>
      </head>
      <body>
          <h1 id="counter">0</h1>
      </body>
  </html>
    • Функция setInterval принимает другую функцию, а затем интервал (в миллисекундах), после которого переданная функция будет автоматически вызываться снова и снова.
    • Результатом в этом примере является автоматически увеличивающийся счетчик без каких-либо кнопок.

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

<html>
      <head>
          <script>
              // Установите начальное значение счетчика на 0
              if (!localStorage.getItem('counter'))
                  localStorage.setItem('counter', 0);

              // Загрузить текущее значение счетчика
              document.addEventListener('DOMContentLoaded', () => {
                  document.querySelector('#counter').innerHTML = localStorage.getItem('counter');

                  // Считать каждый раз, когда нажата кнопка
                  document.querySelector('button').onclick = () => {
                      // Приращение счетчика
                      let counter = localStorage.getItem('counter');
                      counter++;

                      // Обновить счетчик
                      document.querySelector('#counter').innerHTML = counter;
                      localStorage.setItem('counter', counter);
                  }
              });
          </script>
      </head>
      <body>
          <h1 id="counter"></h1>
          <button>Click Here!</button>
      </body>
  </html>
    • localStorage — это переменная, в которой JavaScript может хранить информацию. getItem и setItem могут вызываться в localStorage для загрузки или сохранения данных. Этот пример сначала пытается загрузить счетчик, а если его нет, сохраняет новый счетчик со значением 0.
    • Затем counter элемент изначально устанавливается на этот counter элемент в хранилище. После этого переменная counter называется ссылкой на элемент counter, и после каждого обновления переменной counter значение counter в localStorage обновляется.
    • Теперь закрытие и перезагрузка страницы не приведет к сбросу значения счетчика.

Интеграция JavaScript с Python и Flask

Ajax используется для получения дополнительной информации с сервера без перезагрузки страницы. В качестве примера, Ajax можно использовать с примером конвертации валюты с прошлого занятия, чтобы отобразить конверсию без необходимости загружать новую страницу. Это делается не путем предварительной загрузки всех возможных обменных курсов, а путем отправки Ajax-запроса на сервер Flask, который будет получать конкретный обменный курс всякий раз, когда его запрашивают. Затем можно использовать JavaScript для обновления DOM для отображения нового содержимого.

Вот интересная часть application.py. Здесь мало что отличается от примера в прошлом занятии, но обратите внимание, что возвращается не новая веб-страница, а объект JSON:

@app.route("/convert", methods=["POST"])
  def convert():

      # Запрос на обменный курс
      currency = request.form.get("currency")
      res = requests.get("https://api.fixer.io/latest", params={
          "base": "USD", "symbols": currency})

      # Убедитесь, что запрос успешно выполнен
      if res.status_code != 200:
          return jsonify({"success": False})

      # Убедитесь, что валюта есть в ответе
      data = res.json()
      if currency not in data["rates"]:
          return jsonify({"success": False})

      return jsonify({"success": True, "rate": data["rates"][currency]})

HTML это просто базовая форма. Код JavaScript находится в другом файле, ссылка на него в заголовке:

<html>
      <head>
          <script src=""></script>
          <title>Currency Converter</title>
      </head>
      <body>
          <form id="form">
              <input id="currency" autocomplete="off" autofocus placeholder="Currency" type="text">
              <input type="submit" value="Get Exchange Rate">
          </form>
          <br>
          <div id="result"></div>
      </body>
  </html>

url_for (‘static’, filename = ‘index.js’) — это способ Flask для включения файлов JavaScript в python.

static — это отдельная папка.

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

Интересный код внутри index.js:

document.addEventListener('DOMContentLoaded', () => {

      document.querySelector('#form').onsubmit = () => {

          // Инициализировать новый запрос
          const request = new XMLHttpRequest();
          const currency = document.querySelector('#currency').value;
          request.open('POST', '/convert');

          // Функция обратного вызова, когда запрос завершен
          request.onload = () => {

              // Извлечение данных JSON из запроса
              const data = JSON.parse(request.responseText);

              // Обновите result div
              if (data.success) {
                  const contents = `1 USD is equal to ${data.rate} ${currency}.`
                  document.querySelector('#result').innerHTML = contents;
              }
              else {
                  document.querySelector('#result').innerHTML = 'There was an error.';
              }
          }

          // Добавить данные для отправки с запросом
          const data = new FormData();
          data.append('currency', currency);

          // Послать запрос
          request.send(data);
          return false;
      };

  });
    • XMLHttpRequest — это просто объект, который позволяет выполнять Ajax-запрос.
    • В request.open фактически инициализируется новый запрос с указанием метода HTTP и маршрута.
    • JSON.parse преобразует необработанный ответ (request.responseText) в объект, который можно индексировать по ключам и значениям.
    • Остальная часть обратного вызова просто обновляет HTML, используя литералы шаблона, чтобы отразить результат преобразования.
    • FormData — это просто объект, который содержит любой пользовательский ввод.

WebSockets

До этого взаимодействие клиент-сервер обсуждались до сих пор с позиции HTTP-запросов (модель запрос-ответ). Она полезна, если данные передаются только тогда, когда сделан запрос. Но с «полнодуплексной связью», более просто описываемой как связь в режиме реального времени, существует необходимость сделать новый запрос (чтобы, например, проверить, например, отправил ли кто-то сообщение в чате) без перезагрузки веб-страницы. Websockets — это протокол, который допускает такой тип связи, а Socket.IO — это конкретная библиотека JavaScript, которая поддерживает этот протокол.

Вот пример приложения для голосования на JavaScript и python, которое будет подсчитывать и отображать голоса в режиме реального времени. Вот полный application.py, со всеми инструкциями установки и импорта:

import os
  import requests

  from flask import Flask, jsonify, render_template, request
  from flask_socketio import SocketIO, emit

  app = Flask(__name__)
  app.config["SECRET_KEY"] = os.getenv("SECRET_KEY")
  socketio = SocketIO(app)

  @app.route("/")
  def index():
      return render_template("index.html")

  @socketio.on("submit vote")
  def vote(data):
      selection = data["selection"]
      emit("announce vote", {"selection": selection}, broadcast=True)
      • flask_socketio – это библиотека, которая позволяет использовать веб-сокеты внутри приложения Flask.  Эта библиотека позволяет веб-серверу и клиенту отправлять события всем другим пользователям, а также прослушивать и получать события, передаваемые другими.
      • submit vote — это событие, которое будет транслироваться при каждом голосовании. Код для этого будет в JavaScript.
      • Как только голос получен, голос объявляется всем пользователям (broadcast=True) с функцией emit.

index.html:

<html>
      <head>
          <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.6/socket.io.min.js"></script>
          <script src=""></script>
          <title>Vote</title>
      </head>
      <body>
          <ul id="votes">
          </ul>
          <hr>
          <button data-vote="yes">Yes</button>
          <button data-vote="no">No</button>
          <button data-vote="maybe">Maybe</button>
      </body>
  </html>

index.js:

document.addEventListener('DOMContentLoaded', () => {

      // Подключиться к веб-сокету
      var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port);

      // При подключении настройте кнопки
      socket.on('connect', () => {

          // Каждая кнопка должна создать событие "submit vote"
          document.querySelectorAll('button').forEach(button => {
              button.onclick = () => {
                  const selection = button.dataset.vote;
                  socket.emit('submit vote', {'selection': selection});
              };
          });
      });

      // Когда будет объявлено новое голосование, добавьте в неупорядоченный список
      socket.on('announce vote', data => {
          const li = document.createElement('li');
          li.innerHTML = `Vote recorded: ${data.selection}`;
          document.querySelector('#votes').append(li);
      });
  });
    • Соединение websocket устанавливается с использованием стандартной линии для подключения к тому месту, где в данный момент выполняется приложение.
    • submit vote — это название события, которое отправляется при нажатии кнопки. Это событие просто отправляет, каким бы ни было голосование.
    • announce vote — это событие, полученное от сервера Python, которое инициирует обновление списка голосов.

Усовершенствованием этого приложения на JavaScript с python было бы отображение общего количества голосов, а не просто перечисление каждого отдельного голоса, и обеспечение того, чтобы новые пользователи могли видеть прошедшие голоса.

Изменения в application.py:

votes = {"yes": 0, "no": 0, "maybe": 0}

  @app.route("/")
  def index():
      return render_template("index.html", votes=votes)

  @socketio.on("submit vote")
  def vote(data):
      selection = data["selection"]
      votes[selection] += 1
      emit("vote totals", votes, broadcast=True)
    • Теперь любые предложения о голосовании сначала используются для обновления словаря votes, чтобы вести учет итогов голосования. Затем весь этот словарь транслируется.

Изменения в index.html:

<body>
      <div>Yes Votes: <span id="yes"></span></div>
      <div>No Votes: <span id="no"></span></div>
      <div>Maybe Votes: <span id="maybe"><span></div>
      <hr>
      <button data-vote="yes">Yes</button>
      <button data-vote="no">No</button>
      <button data-vote="maybe">Maybe</button>
  </body>
    • Элементы span выделяют пространство для подсчета голосов, которое будет заполнено позже.

Изменения в index.js:

socket.on('vote totals', data => {
      document.querySelector('#yes').innerHTML = data.yes;
      document.querySelector('#no').innerHTML = data.no;
      document.querySelector('#maybe').innerHTML = data.maybe;
  });

Читайте больше по теме:

Подписаться
Уведомление о
guest
0 Комментарий
Inline Feedbacks
View all comments
Просмотры: 1890

Популярные записи