Vue 天气应用
一款宠物应用,附有相关文章。
项目设置
yarn install
编译和热重载以进行开发
yarn run serve
编译并压缩以供生产环境使用
yarn run build
运行测试
yarn run test
整理和修复文件
yarn run lint
自定义配置
请参阅配置参考。
大家好!
我最近在学习 Vue。所以我认为,深入理解 Vue 的最佳方法就是写篇文章来分享:]
另外,在开发应用的过程中,我发现了一些缺失的信息,我接下来会谈到这些内容。
我将概述一下我的个人项目 Vue 应用程序,该应用程序使用Weatherbit的公共 API ,并根据城市获取天气信息:温度和描述。
该应用有两个视图:
首页和关于。本文不会详细描述每一行代码,而是重点介绍应用的架构和流程。

您可能需要具备 HTML、CSS 和 JS 的基础知识,以及 Vue.js 的概念,才能完全理解这里发生的事情。
该项目由Vue CLI生成和管理。
我强烈推荐您使用这个工具。它非常适合初学者。
文件夹内容如下src:
src
│
├───assets # Stuff like images are stored here
│ logo.png
│
├── components # Independent "bricks" of app
│ weatherWidget.vue
│
├── services # Code that works with API. Axios gets data from API here
│ service.js
│
├── views # Views are like pages. Router navigates through them
│ About.vue
│ Home.vue
├── App.vue # Root Vue component
├── constants.js # Just some constants that I want to store
├── main.js # Core JS file that imports and mounts our app
├── router.js # Router config is here
├── store.js # Store management with Vuex
现在让我们更深入地研究代码!
从main.js.开始,main.js这是整个项目的根 JavaScript 文件。
在这里,我们导入核心库、配置和组件,然后创建new Vue实例并告诉 Vue 使用router和store。
import Vue from "vue"; // Vue lib
import App from "./App.vue"; // Our root component
import router from "./router"; // Router config
import store from "./store"; // Store config
import "normalize.css"; // Normalize.css lib to reset default styles
Vue.config.productionTip = false;
new Vue({
router,
store,
render: h => h(App)
}).$mount("#app"); // Create Vue instance and mount it in index.html -> #app element
这里存储着我的 API 密钥和 URL。REST
API 可以获取大量数据。请查阅文档深入了解。
在这个项目中,我将获取我所在的城市基辅的当前天气。因此,包含查询语句和密钥的 API 请求 URL 将类似于CURRENT_WEATHER:
const API_KEY = "b60f3577e8eb46f089853e2a9fd7d744";
const CURRENT_WEATHER = `https://api.weatherbit.io/v2.0/current?city=Kiev,UA&key=${API_KEY}`;
export { API_KEY, CURRENT_WEATHER }; // export constant to be able to use them in components
路由配置。该应用有两个视图(页面)——首页和关于。因此,我希望 URL 格式如下:首页https://app和关于https://app/about。我可以在 `<path>` 中定义它们。我只需要在`<path>`router.js中指定每个页面:写入路径,为路由命名,并将其链接到现有组件。注意,视图将采用延迟加载。这意味着路由 URL 中将不包含`<path>`。如果没有这一行,每个 URL 都将如下所示:首页和关于。但请不要忘记配置服务器,使其在历史记录模式下正常工作。routesRouter/aboutmode: "history"#https://app/#route
import Vue from "vue";
import Router from "vue-router";
import Home from "./views/Home.vue"; // import components that you wish to became Routes
Vue.use(Router); // tell Vue to action with Router
export default new Router({
mode: "history",
base: process.env.BASE_URL,
routes: [ // All the routes are described here
{
path: "/",
name: "home",
component: Home
},
{
path: "/about",
name: "about",
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () =>
import(/* webpackChunkName: "about" */ "./views/About.vue")
}
]
});
Store管理部分Store包含全局数据——应用程序的状态。应用程序的设置和定义均
在此处完成。statemutationsactions
简化来说,操作算法Store是:
我们调用一个action动作,调用一个mutation改变mutation动作。state
注意: @路径import指的是从文件夹开始src,也就是我们工作区的根目录。
import Vue from "vue";
import Vuex from "vuex";
import service from "@/services/service.js"; // service.js fetch data from API. We will have a look at it in the next step.
Vue.use(Vuex); // tell Vue to action with Vuex
export default new Vuex.Store({
state: { // define here data that you wish to store
weather: {},
dataIsRecived: false
},
mutations: { // change state from here
UPDATE_WEATHER(state) {
service
.getWeather() // call the function from service.js that returns the data from API
.then(response => { // if the response was get
state.weather = response.data.data[0]; // set weather obj in state to real weather obj
state.dataIsRecived = true; // mark that data was recived
console.log(response); // and log it
})
.catch(error => { // if there was an error
console.log("There was an error:", error.response); // log it
state.dataIsRecived = false; // and mark that data wasn't recived
});
}
},
actions: { // call mutations that change the state here
updateWeather(context) {
context.commit("UPDATE_WEATHER");
}
}
});
这里使用了API 通信。Axios基于 Promise 的 HTTP 请求会发送到 Weatherbit,获取当前天气的真实数据。
import axios from "axios";
import { CURRENT_WEATHER } from "@/constants"; // URL with queries and API key
const apiClient = axios.create({ // create promise
baseURL: CURRENT_WEATHER,
withCredentials: false, // CORS
headers: { // some HTTP headers
Accept: "application/json",
"Content-Type": "application/json"
}
});
export default {
getWeather() { // function that is used in store.js 👆
return apiClient.get();
}
};
现在我们已经具备编写 Vue 组件并在其中使用所有这些功能的全部条件了。
那么,让我们开始吧!
根 Vue 组件。
这里使用路由来添加导航栏,其中包含指向“首页”和“关于”视图的链接。
<template>
<div id="app"> // root
<div class="nav"> // navbar
<router-link to="/" class="nav__link">Home</router-link>
<router-link to="/about" class="nav__link">About</router-link>
</div>
<router-view /> // router views will be rendered here
</div>
</template>
<style lang="scss"> // some styles 🖍️
@import url('https://fonts.googleapis.com/css?family=Montserrat:100,200,300,400&display=swap&subset=cyrillic');
body {
font-family: 'Montserrat', sans-serif;
max-height: 100vh;
}
a {
color: #153B50;
text-decoration-color: rgba($color: #153B50, $alpha: 0.5);
transition: all 0.3s ease;
&:hover {
text-decoration-color: #153B50;
}
}
.nav {
display: flex;
justify-content: center;
align-items: center;
padding: 15px 0;
position: absolute;
top: 0;
left: 0;
width: 100%;
}
.nav__link {
&:not(:last-child) {
margin-right: 15px;
}
}
</style>
仅包含占位符的视图。
<template>
<div class="about">
<p>Thanks <a href="https://www.weatherbit.io/">Weatherbit</a> for public API!</p>
</div>
</template>
<style lang="scss" scoped> // some styles 🖍️
.about {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
</style>
视图中包含 weatherWidget vue 组件。
请在下一部分中查看。
<template>
<div class="home">
<weatherWidget />
</div>
</template>
<script>
import weatherWidget from '@/components/weatherWidget.vue'; // import component
export default {
name: "home",
components: { // and register it
weatherWidget
}
}
</script>
<style lang="scss" scoped> // some styles 🖍️
.home {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
</style>
所以,神奇之处就在这里。
我们已经准备好获取天气数据并将其渲染到组件中。
现在我们只需要dispatch存储数据action(这将调用 mutation,mutation 将调用服务并将从 API 获取的数据写入state)。
通过生命周期钩子,created我们调用 ` get_weather_data()` updateWeather action。这样我们就得到了computed property天气数据,从而保证了状态和组件之间的响应式。
最后一步:我们需要将计算属性值插值到组件中。
此外,还有一个预加载器。当dataIsRecived状态属性为 `weather_data( )` 时false(请查看 store.js),SVG 加载指示器会旋转并等待数据。
<template>
<div>
<div v-if="this.$store.state.dataIsRecived" class="weather-widget"> // widget itself
<p class="weather-widget__city">{{ weather.city_name }}</p>
<h2 class="weather-widget__temp">{{ weather.temp }}<span>°C</span></h2>
<p class="weather-widget__status">{{ weather.weather.description }}</p>
</div>
<div v-else class="weather-widget"> // preloader
<img src="spinner.svg" alt="">
</div>
</div>
</template>
<script>
export default {
computed: {
weather() {
return this.$store.state.weather // gets weather state from Vuex store
}
},
created() {
this.$store.dispatch("updateWeather"); // dispatch "updateWeather" when component is created
}
}
</script>
<style lang="scss" scoped> // some styles 🖍️
.weather-widget {
display: flex;
flex-direction: column;
align-items: center;
color: #429EA6;
}
.weather-widget__city {
font-size: 20px;
margin: 0;
}
.weather-widget__temp {
display: flex;
align-items: flex-start;
color: #16F4D0;
font-size: 200px;
font-weight: 200;
margin: 0;
span {
font-size: 30px;
font-weight: 400;
margin-top: 35px;
}
}
.weather-widget__status {
font-size: 20px;
margin: 0;
}
</style>
我们的 Vue 单页应用运行正常!它从 Weatherbit 获取数据并将其渲染到屏幕上。就这么简单。
完整的源代码可以在我的GitHub仓库中找到。
一款宠物应用,附有相关文章。
yarn install
yarn run serve
yarn run build
yarn run test
yarn run lint
请参阅配置参考。
PS:非常期待大家的反馈,这对我很重要。这是我的第一篇文章,很高兴能为 DEV.to 社区贡献一份力量。希望这篇文章对大家有所帮助 😉
文章来源:https://dev.to/oxyyyyy/simple-weather-app-on-vue-js-1g20