Как создать приложение для отслеживания прогноза погоды

Как создать приложение для отслеживания прогноза погоды

Рассказываем, как с помощью Vue 3 и Vite создать простое приложение, которое показывает прогноз погоды.

Введение

Привет! Меня зовут Анна Блок, я автор одноименного YouTube-канала о программировании. Представьте, что вы — веб-разработчик и хотите пополнить портфолио новыми работами. Самое лучше решение — попробовать написать то, что будет охватывать несколько технологий. 

В инструкции покажу, как сделать простое приложение для прогноза погоды. Так мы сможем отработать несколько технологий: HTML, CSS, JavaScript, Vue, Vite и подключение API. После — задеплоить проект на облачный сервер Selectel.

Начало работы с Vite

В качестве инструмента сборки будем использовать Vite. С его помощью легко запустим любой JavaScript-фреймворк. 

Первым шагом установим Vite. Создаем папку на компьютере, которая будет сохранять данные проекта, и переносим ее в редактор кода VS Code. Далее открываем терминал и вводим код, чтобы создать проект из шаблона:


    npm create vite@latest

Теперь добавим в проект необходимые пакеты. Для этого нужно дать согласие системе — пишем «y» и нажимаем Enter

В ответ получаем конфигурационные файлы и строку Project name. В ней указываем имя будущего проекта. У меня — weather, но можно назвать по-другому. Нажимаем Enter, чтобы продолжить установку. 

Далее выбираем необходимый фреймворк и язык программирования. В нашем случае — Vue и JavaScript.

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


    cd weather
npm install
npm run dev

В результате получаем ссылку localhost. Переходим по ней и видим стандартную страницу:

Верстка приложения

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

Сейчас проект состоит из следующих файлов и папок:

Обратите внимание на папку src — именно с ней мы будем работать. При этом все изменения данных будут отражаться в браузере в момент разработки. 

Внутри src есть две папки — assets и components. Поскольку мы делаем простое приложение, предлагаю удалить последнюю папку и ее содержимое. На реальных проектах этого делать не рекомендую, но в нашем случае она ни на что не повлияет. 

В assets удаляем лишнее изображение формата svg. Саму папку не трогаем.

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

Теперь переходим к созданию разметки. Указываем основные теги <template>, внутрь добавляем <div> с классом weather и ниже размещаем <script>:


    <template>
   <div class="weather"></div>
</template>

<script>

</script>

В <div> добавляем класс с контейнером, чтобы разместить поисковую строку, кнопку и информацию о погоде. Ниже — класс weather-bg для хранения изображений. 


    <template>
 <div class="weather">
   <div class="container">

     <div class="card weather-form">
       <input type="text" class="weather-form__input" placeholder="Enter city">
       <button class="weather-form__btn">Search</button>
     </div>

     <div class="weather-info">

       <div class="weather-info__text">
         <p class="card">Phuket</p>
         <p class="card">30°C</p>
         <p class="card">Sunny</p>
       </div>
     </div>

   </div>

   <div class="weather-bg">
     <div>
       <img class="weather-bg__img bg" src="./assets/bg.jpg" alt="App Background">
       <img class="weather-bg__img overcast" src="./assets/overcast.jpg" alt="App Background">
       <img class="weather-bg__img partly-cloudy" src="./assets/partly-cloudy.jpg" alt="Partly Cloudy">
       <img class="weather-bg__img sunny" src="./assets/sunny.jpg" alt="Sunny">
     </div>
   </div>

 </div>
</template>

Заранее сохраняем картинку, которая будет отображаться при загрузке приложения. Для остальных описываем разные состояния погоды. За основу возьмем overcats (пасмурно), partly cloudy (переменная облачность) и sunny (солнечно). Подходящие фоны можно найти на любом сервисе стоковых изображений. 

Все изображения переносим в папку assets. В файл style.css добавляем основные стили. Подключаем шрифт, прописываем переменные и указываем стандартные сбросы.


    @import url('https://fonts.googleapis.com/css2?family=Karla:ital,wght@0,200..800;1,200..800&display=swap');

:root {
 --font: "Karla", sans-serif;

 --accent: #12C0DD;
 --accent-rgb: 18, 192, 221;
 --light: #FFFFFF;

 --border-radius: 10px;
 --width-line: 2px;
 --tr: .3s;
}

* {
 margin: 0;
 padding: 0;
}

body, html {
 height: 100vh;
}

body {
 font-family: var(--font);
 height: 100%;
}

input, button {
 font-family: var(--font);
}

#app {
 height: 100%;
}

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

Основные стили:


    .weather {
 width: 100%;
 height: 100%;
 display: flex;
 flex-direction: column;
 align-items: center;
 justify-content: center;
 position: relative;
 overflow: hidden;
}

.weather-bg {
 position: absolute;
 left: 0;
 right: 0;
 top: 0;
 margin: 0 auto;
 width: 100%;
 height: 100%;
 z-index: -1;
}

.weather-bg > div {
 width: 100%;
 height: 100%;
 position: relative;
 overflow: hidden;
}

Основные стили для изображений:


    .weather-bg__img {
 width: 100%;
 height: 100%;
 position: absolute;
 top: 50%;
 left: 50%;
 transform: translate(-50%, -50%);
 object-fit: cover;
 opacity: 0;
 transition: var(--tr) ease-in-out;
}

Стиль для основного фона:


    .weather .weather-bg__img.bg {
 opacity: 1;
}

Стиль для разных типов погоды. Для примера рассмотрим солнечную (sunny), но вы можете установить несколько вариантов и подобрать несколько состояний — вместо sunny нужно будет записать другие варианты:


    .weather.sunny .weather-bg__img:not(.sunny) {
 opacity: 0;
}

.weather.sunny .weather-bg__img.sunny {
 opacity: 1;
}

    .container {
 width: 100%;
 max-width: 1000px;
 margin: 0 auto;
 padding-left: 15px;
 padding-right: 15px;
 display: grid;
 grid-template-columns: 1fr 100px 200px;
 gap: 20px;
 box-sizing: border-box;
}

.card {
 background-color: var(--light);
 border-radius: var(--border-radius);
 padding: 20px 30px;
 box-sizing: border-box;
}

.weather-form {
 display: flex;
 align-items: stretch;
 gap: 20px;
}

    .weather-form__input {
 flex-grow: 1;
 font-size: 20px;
 border: var(--width-line) solid rgba(var(--accent-rgb), .3);
 border-radius: var(--border-radius);
 padding: 10px 15px;
 box-sizing: border-box;
 transition: var(--tr);
}

.weather-form__input:focus {
 outline: none;
 border-color: var(--accent);
}

.weather-form__btn {
 flex-basis: 180px;
 font-size: 20px;
 background-color: rgba(var(--accent-rgb), .3);
 border: none;
 border-radius: var(--border-radius);
 padding: 10px 15px;
 box-sizing: border-box;
 cursor: pointer;
 transition: var(--tr);
}

.weather-form__btn:hover {
 background-color: var(--accent);
}

    .weather-form,
.weather-load,
.weather-info {
 grid-column: 1 / 4;
}

.weather-load {
 display: flex;
 align-items: center;
 height: 87px;
}

.weather-info__text {
 display: grid;
 grid-template-columns: 1fr auto auto;
 gap: 20px;
 font-size: 40px;
}

Подготовка фреймворка Vue

Ранее мы запустили инструмент сборки Vite. Вся структура приложения уже подготовлена за нас. Осталось внести изменения в разметку и дописать скрипты.

Информацию о погоде будем получать из реальных источников. Для этого воспользуемся любым бесплатным API. В нашем случае — Weather API.

Переходим на сайт и авторизируемся, чтобы получить ключ для работы с API. Открываем файл App.vue. Нас интересует блок <script>...</script>


    <script>

export default {
 data() {
   return {

   };
 },
 computed: {
   weatherClass() {
    
   }
 },
 methods: {
   weatherSearch() {
    
   },
   resetSearchQuery() {
    
   }
 }
};

</script>

В нем прописываем основную структуру кода.

  • В data будем управлять полученными данными.
  • В computed пропишем изменения фона приложений, в зависимости от типа погоды.
  • В methods подключим API и изменения в работе приложения.

Чтобы передавать приложению погодные характеристики из API, нужно открыть доступ к изменению данных. Для этого используем интерполяцию. В <div> указываем названия необходимых значений, а в <script> добавляем функцию, которая возвращает их в объект данных, data().


    <div class="weather-info__text">
         <p class="card">{{ location }}</p>
         <p class="card">{{ temperature }}°C</p>
         <p class="card">{{ description }}</p>
</div>

    data() {
   return {
     location: '',
     temperature: 0,
     description: '',
   };
 }

Указываем в элементах интерфейса input и button связь функций. В директиву v-model добавляем переменную searchQuery.


    <input type="text" class="weather-form__input" v-model="searchQuery" @keyup.enter="weatherSearch" placeholder="Enter city">

<button class="weather-form__btn" @click="weatherSearch">Search</button>

    data() {
   return {
     location: '',
     temperature: 0,
     description: '',
     searchQuery: '',
   };
 }

Подключаем API для сбора данных о погоде и добавляем два условия. Сначала необходимо обработать поисковый запрос, затем — сбросить введенную фразу из <input>.


    methods: {
   weatherSearch() {
     this.loading = true;
     this.error = false;
     fetch(`https://api.weatherapi.com/v1/current.json?key=69ed7b91ab4b4d4f9f282327242604&q=${this.searchQuery}`)
       .then(response => response.json())
       .then(data => {
         this.loading = false;
         this.location = data.location.name;
         this.temperature = data.current.temp_c;
         this.description = data.current.condition.text;
         this.resetSearchQuery();
       })
       .catch(error => {
         this.loading = false;
         this.error = true;
         console.error(error);
       });
   },
   resetSearchQuery() {
     this.searchQuery = '';
   }
 }

Поскольку в catch указаны значения loading и error, их также необходимо добавить в ветку data(). Это позволит отображать строку загрузки и планировать вывод ошибок на случай, если API перестанет обрабатывать данные через поиск.


    data() {
   return {
     location: '',
     temperature: 0,
     description: '',
     searchQuery: '',
     loading: false,
     error: false,
   };
 }

    <div class="card weather-load" v-if="loading">...</div>

<div class="weather-info" v-show="!error && location && temperature !== 0 && description">

       <div class="card" v-if="error">...</div>

       <div class="weather-info__text">
       ...
       </div>
</div>

Для изменения фона добавим :class в <div>, куда установлен класс weather. 


    <div class="weather" :class="weatherClass">

Далее пишем функцию, после которой появятся дополнительные классы напротив <div>. И это только в том случае, если в {{ description }} отображается соответствующее описание.

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


    computed: {
   weatherClass() {
     if (this.description.includes('Sunny')) {
       return 'sunny';
     } else if (this.description.includes('Overcast')) {
       return 'overcast';
     } else if (this.description.includes('Partly cloudy')) {
       return 'partly-cloudy';
     } else {
       return '';
     }
   }
 },

Финальный шаг — создаем приложение:


    npm run build

Готово, мы сделали простое приложение по прогнозу погоды с нуля! 

Деплой проекта

Сейчас готовый результат не увидит никто, кроме нас. Чтобы это исправить, перенесем его на облачный сервер Selectel.

В файле vite.config.js добавляем строку base: './' внутри export default defineConfig({ … }). Это позволит в build проекта отразить верные пути файлов.

Вводим в терминале команду npm run build, после которой появится папка dist. В ней будут формироваться итоговые данные проекта. Файлы оттуда выгрузим на облачный сервер.

В панели управления нужно создать аккаунт или авторизоваться, если у вас уже есть учетная запись. Внутри выбираем Облачная платформа и нажимаем Создать сервер.

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

После установки конфигурации спускаемся вниз и нажимаем Создать

Возвращаемся в панель управления и переходим в консоль созданного сервера. Для входа нужен логин (root) и пароль. Нажимаем ЛКМ по иконке Горячие клавиши и добавляем сгенерированный пароль. 

В терминале вводим набор команд, чтобы загружать файлы на облачный сервер по FTP-протоколу.

  1. Устанавливаем FTP-сервер (vsftpd):

    sudo apt update
sudo apt install vsftpd
  1. Настраиваем доступ. Для этого редактируем файл конфигурации FTP-сервера:

    sudo nano /etc/vsftpd.conf
  1. Проверяем параметры конфигурации. Они должны быть установлены или раскомментированы и иметь указанные значения:

    anonymous_enable=NO
local_enable=YES
write_enable=YES
chroot_local_user=YES
  1. Перезапускаем сервис:

    sudo systemctl restart vsftpd
  1. Открываем порты в файрволе, если необходимо:

    sudo ufw allow ftp
  1. Проверяем статус сервиса:

    sudo systemctl status vsftpd

С помощью IP-адреса, имени пользователя и пароля вы можете войти в FTP-клиент, чтобы подключить приложение к FTP-серверу. Остается только перенести туда готовые файлы из папки dist. 

Готово! Сайт доступен по адресу 46.148.229.29:

Заключение

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

А чтобы снизить затраты на обслуживание приложения, советуем присмотреться к виртуальному серверу линейки Shared Line. Оплата производится только за потребленные мощности — по модели pay-as-you-go.

Автор: Анна Блок, автор YouTube-канала.