svelte 尝鲜之夏日必备的天气预报🌦️

837 阅读2分钟

我正在参加「初夏创意投稿大赛」详情请看:初夏创意投稿大赛


夏日天气多变,一会雨,一会大太阳。今天,咱们就来尝试自己做一个天气显示页面吧

R-C.abfe92a0fb85e95d000a9b48772c7a8b.gif

用 Vue ?React ?

不不不

用 Svelte !

R-C.805cf01386a4eec1ba2fe20fe748c5eb.png

Svelte ! 是一种全新的构建用户界面的方法。传统框架如 React 和 Vue 在浏览器中需要做大量的工作,而 Svelte 将这些工作放到构建应用程序的编译阶段来处理。

与使用虚拟(virtual)DOM 差异对比不同。Svelte 编写的代码在应用程序的状态更改时就能像做外科手术一样更新 DOM。

构建项目

npx degit sveltejs/template my-svelte-project
cd my-svelte-project
npm install
npm run dev

www.sveltejs.cn/tutorial/ba…

svelte 的官网贴心的为我们准备了基础教程。

相信看这个文章的小伙伴,应该都是学习过 Vue 或者 React 框架的,对于变量的绑定,事件的定义和绑定都比较清楚。这里我们不会特别仔细的讲解。

<script>
  let string = `this string contains some <strong>HTML!!!</strong>`;
  // 代码逻辑部分
</script>

// 页面部分
<p>{string}</p>

// 样式部分
<style>
</style>

是不是和 Vue 一模一样


图片.png

上面输入城市名称,敲击回车,请求数据。数据返回,显示在页面上。

<script>
  let value = "";
  async function handleChange() {
    // 请求数据
  }
</script>

<input type="text" on:change={handleChange} bind:value />

这里请求数据,我们使用

www.tianqiapi.com/api?version…

这个接口

cityCode 为城市编码

appid 和 appsecret 登录账号之后,即可获得。

github.com/baichengzho…

这里我实现的方式比较简单。通过数组的方式,返回需要的数据,即将该数据改造为

图片.png

获取用户输入的城市名称之后,通过数组的 find 方法,返回 code,之后调用请求接口。

<script>
  import { onMount } from "svelte";
  import { cityCodeArr } from "./utils/cityCode";

  let cityName = "";
  let showDate = "";
  let currentTem = "";
  let heightTem1 = "";
  let lowTem2 = "";
  let weather = "";
  let value = "";
  let cityArr = [];
  let cityCode = "";

  onMount(async () => {
    cityArr = cityCodeArr.map((item) => {
      return {
        cityName: item[2],
        code: item[0],
      };
    });
    init();
  });

  async function handleChange() {
    const code = cityArr.find((item) => item.cityName === value).code;
    cityCode = code;
    init();
  }

  async function init() {
    const endpoint = `https://www.tianqiapi.com/api?version=v6&appid=59736232&appsecret=cU5UZ65u&cityid=${cityCode}`;
    const response = await fetch(endpoint);
    const { city, date, tem, tem1, tem2, wea } = await response.json();
    cityName = city;
    weather = wea;
    heightTem1 = tem1;
    lowTem2 = tem2;
    currentTem = tem;
    showDate = date;
  }
</script>

通过不同的 weather 值,渲染不同的天气卡片。

<main>
  <div class="content">
    <input type="text" on:change={handleChange} bind:value />
    {#if weather === "晴"}
      <Sunny />
    {:else if weather === "多云"}
      <Cloudy />
    {:else if weather === "阴"}
      <Overcast />
    {:else if weather.includes("雨")}
      <Rainy />
    {:else if weather.includes("雪")}
      <Snowy />
    {/if}
    <div />
    <div>当前城市:{cityName}</div>
    <div>当前日期:{showDate}</div>
    <div>当前气温:{currentTem}</div>
    <div class="">最高气温:{heightTem1}</div>
    <div class="">最低气温:{lowTem2}</div>
  </div>
</main>

外边框

<style>
  .weather {
    position: relative;
    display: inline-block;
    width: 180px;
    height: 240px;
    background: #23b7e5;
    border-radius: 8px;
    margin-left: 20px;
  }
</style>

太阳🌞

图片.png

<style>
  .sunny::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 60px;
    height: 60px;
    background: #f6d963;
    border-radius: 50%;
    box-shadow: 0 0 20px #ff0;
    z-index: 2;
  }

  .sunny::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    margin: -45px 0 0 -45px;
    width: 90px;
    height: 90px;
    background: #ffeb3b;
    clip-path: polygon(
      50% 0%,
      64.43% 25%,
      93.3% 25%,
      78.87% 50%,
      93.3% 75%,
      64.43% 75%,
      50% 100%,
      35.57% 75%,
      6.7% 75%,
      21.13% 50%,
      6.7% 25%,
      35.57% 25%
    );
    z-index: 1;
    animation: sunScale 2s linear infinite;
  }

  @keyframes sunScale {
    0% {
      transform: scale(1);
    }

    50% {
      transform: scale(1.1);
    }

    100% {
      transform: scale(1);
    }
  }
</style>

云☁️

图片.png

<style>
  .overcast::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 25%;
    transform: translate(-50%, -50%);
    width: 36px;
    height: 36px;
    background: #fff;
    border-radius: 50%;
    box-shadow: #fff 22px -15px 0 6px, #fff 57px -6px 0 2px,
      #fff 87px 4px 0 -4px, #fff 33px 6px 0 6px, #fff 61px 6px 0 2px,
      #ccc 29px -23px 0 6px, #ccc 64px -14px 0 2px, #ccc 94px -4px 0 -4px;
    z-index: 2;
    animation: cloudMove 2s linear infinite;
  }

  @keyframes cloudMove {
    0% {
      transform: translate(-50%, -50%);
    }

    50% {
      transform: translate(-50%, -60%);
    }

    100% {
      transform: translate(-50%, -50%);
    }
  }
</style>

雨🌧️

图片.png

<style>
  .rainy::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 25%;
    transform: translate(-50%, -50%);
    width: 36px;
    height: 36px;
    background: #fff;
    border-radius: 50%;
    box-shadow: #fff 22px -15px 0 6px, #fff 57px -6px 0 2px,
      #fff 87px 4px 0 -4px, #fff 33px 6px 0 6px, #fff 61px 6px 0 2px,
      #ccc 29px -23px 0 6px, #ccc 64px -14px 0 2px, #ccc 94px -4px 0 -4px;
    z-index: 2;
  }

  .rainy::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 25%;
    width: 4px;
    height: 14px;
    background: #fff;
    border-radius: 2px;
    box-shadow: #fff 25px -10px 0, #fff 50px 0 0, #fff 75px -10px 0,
      #fff 0 25px 0, #fff 25px 15px 0, #fff 50px 25px 0, #fff 75px 15px 0,
      #fff 0 50px 0, #fff 25px 40px 0, #fff 50px 50px 0, #fff 75px 40px 0;
    animation: rainDrop 2s linear infinite;
  }

  @keyframes rainDrop {
    0% {
      transform: translate(0, 0) rotate(10deg);
    }

    100% {
      transform: translate(-4px, 24px) rotate(10deg);
      box-shadow: #fff 25px -10px 0, #fff 50px 0 0, #fff 75px -10px 0,
        #fff 0 25px 0, #fff 25px 15px 0, #fff 50px 25px 0, #fff 75px 15px 0,
        rgba(255, 255, 255, 0) 0 50px 0, rgba(255, 255, 255, 0) 25px 40px 0,
        rgba(255, 255, 255, 0) 50px 50px 0, rgba(255, 255, 255, 0) 75px 40px 0;
    }
  }
</style>

雪❄️

图片.png

<style>
  .snowy::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 25%;
    transform: translate(-50%, -50%);
    width: 36px;
    height: 36px;
    background: #fff;
    border-radius: 50%;
    box-shadow: #fff 22px -15px 0 6px, #fff 57px -6px 0 2px,
      #fff 87px 4px 0 -4px, #fff 33px 6px 0 6px, #fff 61px 6px 0 2px,
      #ccc 29px -23px 0 6px, #ccc 64px -14px 0 2px, #ccc 94px -4px 0 -4px;
    z-index: 2;
  }

  .snowy::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 25%;
    width: 8px;
    height: 8px;
    background: #fff;
    border-radius: 50%;
    box-shadow: #fff 25px -10px 0, #fff 50px 0 0, #fff 75px -10px 0,
      #fff 0 25px 0, #fff 25px 15px 0, #fff 50px 25px 0, #fff 75px 15px 0,
      #fff 0 50px 0, #fff 25px 40px 0, #fff 50px 50px 0, #fff 75px 40px 0;
    animation: snowDrop 2s linear infinite;
  }

  @keyframes snowDrop {
    0% {
      transform: translateY(0);
    }

    100% {
      transform: translateY(25px);
      box-shadow: #fff 25px -10px 0, #fff 50px 0 0, #fff 75px -10px 0,
        #fff 0 25px 0, #fff 25px 15px 0, #fff 50px 25px 0, #fff 75px 15px 0,
        rgba(255, 255, 255, 0) 0 50px 0, rgba(255, 255, 255, 0) 25px 40px 0,
        rgba(255, 255, 255, 0) 50px 50px 0, rgba(255, 255, 255, 0) 75px 40px 0;
    }
  }
</style>

多云

图片.png

<style>
  .weather {
    position: relative;
    display: inline-block;
    width: 180px;
    height: 240px;
    background: #23b7e5;
    border-radius: 8px;
    margin-left: 20px;
  }

  .sunny:before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 60px;
    height: 60px;
    background: #f6d963;
    border-radius: 50%;
    box-shadow: 0 0 20px #ff0;
    z-index: 2;
  }

  .sunny:after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    margin: -45px 0 0 -45px;
    width: 90px;
    height: 90px;
    background: #ffeb3b;
    clip-path: polygon(
      50% 0%,
      64.43% 25%,
      93.3% 25%,
      78.87% 50%,
      93.3% 75%,
      64.43% 75%,
      50% 100%,
      35.57% 75%,
      6.7% 75%,
      21.13% 50%,
      6.7% 25%,
      35.57% 25%
    );
    z-index: 1;
    animation: sunScale 2s linear infinite;
  }

  @keyframes sunScale {
    0% {
      transform: scale(1);
    }

    50% {
      transform: scale(1.1);
    }

    100% {
      transform: scale(1);
    }
  }

  .cloudy::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 25%;
    transform: translate(-50%, -50%);
    width: 36px;
    height: 36px;
    background: #fff;
    border-radius: 50%;
    box-shadow: #fff 22px -15px 0 6px, #fff 57px -6px 0 2px,
      #fff 87px 4px 0 -4px, #fff 33px 6px 0 6px, #fff 61px 6px 0 2px,
      #ccc 29px -23px 0 6px, #ccc 64px -14px 0 2px, #ccc 94px -4px 0 -4px;
    z-index: 2;
    animation: cloudMove 2s linear infinite;
  }

  @keyframes cloudMove {
    0% {
      transform: translate(-50%, -50%);
    }

    50% {
      transform: translate(-50%, -60%);
    }

    100% {
      transform: translate(-50%, -50%);
    }
  }
</style>

导入页面中

<script>
  import Sunny from "./components/Sunny.svelte";
  import Cloudy from "./components/Cloudy.svelte";
  import Overcast from "./components/Overcast.svelte";
  import Rainy from "./components/Rainy.svelte";
  import Snowy from "./components/Snowy.svelte";
</script>

总体来说,语法其实相差不大。如果是学过框架的小伙伴,其实还是很容易上手的。

尝鲜就这么多啦,剩下的,多多参考官网

图片.png