Skip to content
on this page

扫码联系

编程学习&& IT

tian

Weather

数据来源

weather来源于openweather网站 需要密钥 aki-key

示例数据

下面给出三组数据进行展示 image.png

image.png

image.png

json数据详情如下

json
{
    "coord": {
        "lon": 108.9286,
        "lat": 34.2583
    },
    "weather": [
        {
            "id": 804,
            "main": "Clouds",
            "description": "overcast clouds",
            "icon": "04d"
        }
    ],
    "base": "stations",
    "main": {
        "temp": 7.45,
        "feels_like": 7.45,
        "temp_min": 7.45,
        "temp_max": 7.45,
        "pressure": 1028,
        "humidity": 100,
        "sea_level": 1028,
        "grnd_level": 977
    },
    "visibility": 27,
    "wind": {
        "speed": 0.16,
        "deg": 111,
        "gust": 0.25
    },
    "clouds": {
        "all": 100
    },
    "dt": 1682232424,
    "sys": {
        "type": 1,
        "id": 9645,
        "country": "CN",
        "sunrise": 1682201049,
        "sunset": 1682248857
    },
    "timezone": 28800,
    "id": 1790630,
    "name": "Xi'an",
    "cod": 200
}

天气类型说明

      800         ---- 晴天  

  200 ~ 232       ---- 雷电天气

  600 ~ 622       ---- 下雪天气

  701 ~ 781       ---- 雾霾天气

  801 ~ 804       ---- 多云天气

  500 ~ 531        ---- 雨天 

  300 ~ 321        ---- 雨天 

布局

js
<!DOCTYPE html>
<html lang="zh-cn" dir="ltr">

<head>
    <meta charset="utf-8">
    <title>Weather App made in xiao tian~</title>
    <link rel="stylesheet" href="style.css">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- Linking BoxIcon for Icon -->
    <link href='https://unpkg.com/boxicons@2.0.9/css/boxicons.min.css' rel='stylesheet'>
</head>

<body>
    <div class="wrapper">
        <header><i class='bx bx-left-arrow-alt'></i>Weather App</header>
        <section class="input-part">
            <p class="info-txt"></p>
            <div class="content">
                <input type="text" spellcheck="false" placeholder="Enter city name" required>
                <div class="separator"></div>
                <button>Get Device Location</button>
            </div>
        </section>
        <section class="weather-part">
            <img src="#" alt="Weather Icon">
            <div class="temp">
                <span class="numb">_</span>
                <span class="deg">°</span>C
            </div>
            <div class="weather">_ _</div>
            <div class="location">
                <i class='bx bx-map'></i>
                <span>_, _</span>
            </div>
            <div class="bottom-details">
                <div class="column feels">
                    <i class='bx bxs-thermometer'></i>
                    <div class="details">
                        <div class="temp">
                            <span class="numb-2">_</span>
                            <span class="deg">°</span>C
                        </div>
                        <p>Feels like</p>
                    </div>
                </div>
                <div class="column humidity">
                    <i class='bx bxs-droplet-half'></i>
                    <div class="details">
                        <span>_</span>
                        <p>Humidity</p>
                    </div>
                </div>
            </div>
        </section>
    </div>

    <script src="weather.js"></script>

</body>

</html>

js 功能实现

js
// 获取DOM节点 
const wrapper = document.querySelector(".wrapper"),
    inputPart = document.querySelector(".input-part"),
    infoTxt = inputPart.querySelector(".info-txt"),
    inputField = inputPart.querySelector("input"),
    locationBtn = inputPart.querySelector("button"),
    weatherPart = wrapper.querySelector(".weather-part"),
    wIcon = weatherPart.querySelector("img"),
    arrowBack = wrapper.querySelector("header i");

let api;

/**
 * input 添加Keyup  如果key === enter && != '' 时,发起请求 requestApi 
 */
inputField.addEventListener("keyup", e => {
    if (e.key == "Enter" && inputField.value != "") {
        requestApi(inputField.value);
    }
});

/**
 * @param geolocation    - 获取
 * 点击获取当前location时, button -添加click事件, 
 * 如果 浏览器有geolocation时, 则进行获取当前位置getCurrentPosition方法 
 *   - 成功   获取数据,进行响应 显示   
 *   - 失败   进行报错显示
 * 如果浏览器没有该属性时,则alert提醒 浏览器不支持该功能 
 */
locationBtn.addEventListener("click", () => {
    if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(onSuccess, onError);
    } else {
        alert("Your browser not support geolocation api");
    }
});

/**
 * @param  requestApi()   请求api方法
 * @param  city           请求的城市
 * @param  fetchData()    发起请求 
 */
function requestApi(city) {
    api = `https://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=a017e6cba7dc219a9338d233e37a9ae3`;
    fetchData();
}

/**
 * @param  onSuccess()  成功的方法 
 * @param  latitude     维度
 * @param  longitude    经度
 * 
 * 成功回调的函数, 将经纬度给api 然后发起请求数据 
 */
function onSuccess(position) {
    const { latitude, longitude } = position.coords;
    api = `https://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&units=metric&appid=a017e6cba7dc219a9338d233e37a9ae3`;
    fetchData();
}


/**
 * @param onError()  失败的方法
 *  失败了 则进行对应的错误报错
 */
function onError(error) {
    infoTxt.innerText = error.message;
    infoTxt.classList.add("error");
}

/**
 * @param fetchData()   请求数据的方法 
 * @param api           openweather---apikey 
 * 
 * 请求数据的过程中,进行文字提示
 * 使用fetch() 传入api地址,该方法会返回一个Promise
 * 使用then进行响应处理  
 * 第一个then 将响应体解析为JSON格式 然后调用weatherDetail()处理解析后的数据 
 * 若出错则catch 将文字替换为错误提醒  并将pending更新为error
 */
function fetchData() {
    infoTxt.innerText = "Getting weather details...";
    infoTxt.classList.add("pending");
    fetch(api).then(res => res.json()).then(result => weatherDetails(result)).catch(() => {
        infoTxt.innerText = "Something went wrong";
        infoTxt.classList.replace("pending", "error");
    });
}

/**
 * @param info        Txt of weather details  
 * @param info.code   不同天气类型对应的code状态码 
 * @param wIcon       天气图标
 */
function weatherDetails(info) {
    // once we received data from api then we'll hide pendging message and show weather
    if (info.cod == "404") {
        infoTxt.classList.replace("pending", "error");
        infoTxt.innerText = `${inputField.value} isn't a valid city name`;
    } else {
        const city = info.name;
        const country = info.sys.country;
        const { description, id } = info.weather[0];
        console.log(info);
        const { temp, feels_like, humidity } = info.main;
        // using custom icon according to the id  which api return us
        if (id == 800) {
            wIcon.src = "icons/clear.svg";
        } else if (id >= 200 && id <= 232) {
            wIcon.src = "icons/storm.svg";
        } else if (id >= 600 && id <= 622) {
            wIcon.src = "icons/snow.svg";
        } else if (id >= 701 && id <= 781) {
            wIcon.src = "icons/haze.svg";
        } else if (id >= 801 && id <= 804) {
            wIcon.src = "icons/cloud.svg";
        } else if ((id >= 500 && id <= 531) || (id >= 300 && id <= 321)) {
            wIcon.src = "icons/rain.svg";
        }

        // 进行天气详情数据的替换 
        weatherPart.querySelector(".temp .numb").innerText = Math.floor(temp);
        weatherPart.querySelector(".weather").innerText = description;
        weatherPart.querySelector(".location span").innerText = `${city}, ${country}`;
        weatherPart.querySelector(".temp .numb-2").innerText = Math.floor(feels_like);
        weatherPart.querySelector(".humidity span").innerText = `${humidity}%`;
        infoTxt.classList.remove("pending", "error");
        infoTxt.innerText = "";
        inputField.value = "";
        wrapper.classList.add("active");
    }
}


/**
 * @param arrowBack    返回上一页  
 *   触发click  移除active状态  返回首页 
 */
arrowBack.addEventListener("click", () => {
    wrapper.classList.remove("active");
});