JavaScript >> Javascript 文檔 >  >> jQuery

重新審視天氣預報 Webapp

一年前,我發布了一篇關於構建天氣預報 Web 應用程序的教程,該應用程序由 Yahoo 的 API 和瀏覽器的內置地理定位功能提供支持。然而,最近雅虎停止提供這些免費 API,所以今天我們將把網絡應用轉換為不同的服務 - OpenWeatherMap。

OpenWeatherMap API

OpenWeatherMap 不僅可以免費使用,而且還可以返回未來五天的預報,並且只需一個 API 請求即可完成 Yahoo 只能使用兩個 API 請求。 API 直接獲取一組地理坐標並返回天氣數據(無需先找到城市)。這些功能使其使用起來無痛,我很抱歉我之前不知道這項服務。這是一個示例響應:

{
    "cod": "200",
    "message": 0.0074,
    "city": {
        "id": 726048,
        "name": "Varna",
        "coord": {
            "lon": 27.91667,
            "lat": 43.216671
        },
        "country": "BG",
        "population": 0
    },
    "cnt": 41,
    "list": [{
            "dt": 1369224000,
            "main": {
                "temp": 295.15,
                "temp_min": 293.713,
                "temp_max": 295.15,
                "pressure": 1017.5,
                "sea_level": 1023.54,
                "grnd_level": 1017.5,
                "humidity": 94,
                "temp_kf": 1.44
            },
            "weather": [{
                    "id": 800,
                    "main": "Clear",
                    "description": "sky is clear",
                    "icon": "02d"
                }
            ],
            "clouds": {
                "all": 8
            },
            "wind": {
                "speed": 5.11,
                "deg": 155.502
            },
            "sys": {
                "pod": "d"
            },
            "dt_txt": "2013-05-22 12:00:00"
        }

        // 40 more items here..

    ]
}

一個 API 調用即可返回地理信息、城市名稱、國家代碼和詳細的天氣預報。 list 中返回天氣預報 屬性作為一個數組,相隔三個小時。在我們的代碼中,我們將不得不遍歷這個列表,並將預測呈現為一系列幻燈片。好消息是我們在上一個教程中所做的很多工作都可以重複使用。

需要改變的地方

我們不會從頭開始——我們將重用上一教程中的 HTML 和設計。在 HTML 部分,一切都與原始版本幾乎相同,除了我已經升級到最新的 jQuery 版本,並導入了我們將用來展示的 moment.js(快速提示)日期/時間庫預測的時間。

index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>Weather Forecast App Revisited | Tutorialzine Demo</title>

        <!-- The stylesheet -->
        <link rel="stylesheet" href="assets/css/styles.css" />

        <!-- Google Fonts -->
        <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Playball|Open+Sans+Condensed:300,700" />

        <!--[if lt IE 9]>
          <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
        <![endif]-->
    </head>

    <body>

        <header>
            <h1>Weather Forecast</h1>
        </header>

        <div id="weather">

            <ul id="scroller">
                <!-- The forecast items will go here -->
            </ul>

            <a href="#" class="arrow previous">Previous</a>
            <a href="#" class="arrow next">Next</a>

        </div>

        <p class="location"></p>

        <div id="clouds"></div>

        <!-- JavaScript includes - jQuery, moment.js and our own script.js -->
        <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
        <script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.0.0/moment.min.js"></script>
        <script src="assets/js/script.js"></script>

    </body>
</html>

不過需要重寫的是我們的 JavaScript 代碼。 OpenWeatherMap 使用起來更簡單,直接從 geolocation api 獲取坐標,所以我刪除了很多舊代碼。另一個好處是無需在 OpenWeatherMap 上註冊 API 密鑰,這意味著我們可以直接跳轉到源:

assets/js/script.js

$(function(){

    /* Configuration */

    var DEG = 'c';  // c for celsius, f for fahrenheit

    var weatherDiv = $('#weather'),
        scroller = $('#scroller'),
        location = $('p.location');

    // Does this browser support geolocation?
    if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(locationSuccess, locationError);
    }
    else{
        showError("Your browser does not support Geolocation!");
    }

    // Get user's location, and use OpenWeatherMap
    // to get the location name and weather forecast

    function locationSuccess(position) {

        try{

            // Retrive the cache
            var cache = localStorage.weatherCache && JSON.parse(localStorage.weatherCache);

            var d = new Date();

            // If the cache is newer than 30 minutes, use the cache
            if(cache && cache.timestamp && cache.timestamp > d.getTime() - 30*60*1000){

                // Get the offset from UTC (turn the offset minutes into ms)
                var offset = d.getTimezoneOffset()*60*1000;
                var city = cache.data.city.name;
                var country = cache.data.city.country;

                $.each(cache.data.list, function(){
                    // "this" holds a forecast object

                    // Get the local time of this forecast (the api returns it in utc)
                    var localTime = new Date(this.dt*1000 - offset);

                    addWeather(
                        this.weather[0].icon,
                        moment(localTime).calendar(),   // We are using the moment.js library to format the date
                        this.weather[0].main + ' <b>' + convertTemperature(this.main.temp_min) + '°' + DEG +
                                                ' / ' + convertTemperature(this.main.temp_max) + '°' + DEG+'</b>'
                    );

                });

                // Add the location to the page
                location.html(city+', <b>'+country+'</b>');

                weatherDiv.addClass('loaded');

                // Set the slider to the first slide
                showSlide(0);

            }

            else{

                // If the cache is old or nonexistent, issue a new AJAX request

                var weatherAPI = 'http://api.openweathermap.org/data/2.5/forecast?lat='+position.coords.latitude+
                                    '&lon='+position.coords.longitude+'&callback=?'

                $.getJSON(weatherAPI, function(response){

                    // Store the cache
                    localStorage.weatherCache = JSON.stringify({
                        timestamp:(new Date()).getTime(),   // getTime() returns milliseconds
                        data: response
                    });

                    // Call the function again
                    locationSuccess(position);
                });
            }

        }
        catch(e){
            showError("We can't find information about your city!");
            window.console && console.error(e);
        }
    }

    function addWeather(icon, day, condition){

        var markup = '<li>'+
            '<img src="assets/img/icons/'+ icon +'.png" />'+
            ' <p class="day">'+ day +'</p> <p class="cond">'+ condition +
            '</p></li>';

        scroller.append(markup);
    }

    /* Handling the previous / next arrows */

    var currentSlide = 0;
    weatherDiv.find('a.previous').click(function(e){
        e.preventDefault();
        showSlide(currentSlide-1);
    });

    weatherDiv.find('a.next').click(function(e){
        e.preventDefault();
        showSlide(currentSlide+1);
    });

    // listen for arrow keys

    $(document).keydown(function(e){
        switch(e.keyCode){
            case 37: 
                weatherDiv.find('a.previous').click();
            break;
            case 39:
                weatherDiv.find('a.next').click();
            break;
        }
    });

    function showSlide(i){
        var items = scroller.find('li');

        if (i >= items.length || i < 0 || scroller.is(':animated')){
            return false;
        }

        weatherDiv.removeClass('first last');

        if(i == 0){
            weatherDiv.addClass('first');
        }
        else if (i == items.length-1){
            weatherDiv.addClass('last');
        }

        scroller.animate({left:(-i*100)+'%'}, function(){
            currentSlide = i;
        });
    }

    /* Error handling functions */

    function locationError(error){
        switch(error.code) {
            case error.TIMEOUT:
                showError("A timeout occured! Please try again!");
                break;
            case error.POSITION_UNAVAILABLE:
                showError('We can\'t detect your location. Sorry!');
                break;
            case error.PERMISSION_DENIED:
                showError('Please allow geolocation access for this to work.');
                break;
            case error.UNKNOWN_ERROR:
                showError('An unknown error occured!');
                break;
        }

    }

    function convertTemperature(kelvin){
        // Convert the temperature to either Celsius or Fahrenheit:
        return Math.round(DEG == 'c' ? (kelvin - 273.15) : (kelvin*9/5 - 459.67));
    }

    function showError(msg){
        weatherDiv.addClass('error').html(msg);
    }

});

大部分更改是針對 locationSuccess() 函數,我們向 API 發出請求並調用 addWeather() .後者還需要進行一些更改,以便它使用包含在天氣數據中的圖標代碼來顯示 assets/img/icons 文件夾中的正確圖像。請參閱 OpenWeatherMap 文檔中的圖標列表(白天和夜間版本)和天氣代碼。

另一件值得注意的事是我使用持久化 localStorage 的方式 對象將來自 API 的結果緩存 30 分鐘,這限制了轉到 OpenWeatherMap 的請求數量,以便每個人都可以得到公平的份額。

有了這個,我們的天氣網絡應用程序就準備好了! 有任何問題嗎?點擊下方評論區。


Tutorial JavaScript 教程
  1. JavaScript 面試問題 #26:這些日期是否相等?

  2. 哦,是你 jQuery

  3. 如何使用 Nx 輕鬆創建具有與 ES/AMD/UMD/CJS 模塊系統兼容的捆綁依賴項的 JS 庫

  4. 使用 javascript 深度克隆對象

  5. 8 個令人驚嘆的 jQuery 頁面佈局插件

  6. 在 10 分鐘內使用 node.js 構建 Telegram Bot

  7. 宣布 N|Solid 4.3.0 - 導入/導出設置

  1. CSS 黑客 101

  2. JavaScript 正則表達式中的前瞻(和後瞻)

  3. 創建您的第一個 Angular 應用程序:組件,第 2 部分

  4. 使用 JpegCamera 和 Canvas 訪問用戶的相機

  5. 如何為跨 API 創建代理中間件。

  6. VeeValidate 對於 Vue.js 前端驗證很有用

  7. 在 1 行中將 Typescript 添加到您的 JS 項目中

  1. 幹、濕還是啊哈?

  2. 10 個 jQuery 酷炫菜單效果插件

  3. 使用 FlatList 創建 ViewPager

  4. 一個使用 Socket.io 與 NodeJS 和 ReactJS 的簡單聊天應用程序