JavaScript >> Javascript 文檔 >  >> Tags >> CSS

App Engine 系列 #5:前端

這是我們 App Engine 系列的第五部分,我們將使用 Google 強大的 App Engine 平台和工具構建正常運行時間儀表板 Web 應用程序。閱讀第四部分,我們在其中創建了控制器,它處理對我們應用程序的 URL 請求。

這是本系列的最後一部分,我們將在其中創建 jQuery / CSS 前端。我們將使用 Flot jquery 插件來構建應用程序收集的正常運行時間數據的實時可視化。您可能希望在選項卡中保持本系列的第三部分打開,因為我們將在此處討論的 HTML 標記的基礎上進行構建。

JSON 請求

正如您上次記得的那樣,我們有一個專門的控制器來處理 AJAX 請求。它處理和輸出 /ajax/24hours/ 的 JSON 響應 , /ajax/7days//ajax/30days/ .

響應具有以下結構:

{
    "chart": {
        "data": [{
            "value": 231,
            "label": "Apr, 10"
        }, {
            "value": 243,
            "label": "Apr, 11"
        }, {
            "value": 330,
            "label": "Apr, 12"
        }, {
            "value": 404,
            "label": "Apr, 13"
        }],
        "tooltip": "Average response time for %1: %2ms"
    },
    "downtime": [{
        "begin": "15:37 on Apr, 11, 2011",
        "end": "15:42 on Apr, 11, 2011",
        "period": "00:05:00"
    }, {
        "begin": "08:16 on Apr, 12, 2011",
        "end": "08:21 on Apr, 12, 2011",
        "period": "00:05:00"
    }, {
        "begin": "08:09 on Apr, 13, 2011",
        "end": "08:14 on Apr, 13, 2011",
        "period": "00:05:00"
    }]
}

數據數組中的屬性對應於給定 ping 的響應時間,選擇過去 24 小時時,或選擇 7 天或 30 天時的天數。

我們將使用此 JSON 數據來構建圖表及其下方的停機時間列表。

jQuery

在本節中,我們將查看 assets/js/scripts.js 中的代碼 .請注意,這不是此應用程序中唯一的 JavaScript 文件。我們也在使用 jQuery 庫 , Flot 插件 , 和 excanvas(僅在較舊的 IE 瀏覽器中要求兼容)。

第一步是監聽 document.ready 事件,以便我們可以訪問底層頁面的 DOM。

$(document).ready(function(){

    // Caching some of the selectors for better performance
    var periodDropDown = $('#periodDropDown'),
        dropDownUL = $('ul',periodDropDown),
        currentPeriod = $('.currentPeriod',periodDropDown),
        performancePlot = $('#plot'),
        cache = {};

    // Listening for clicks on the dropdown:
    periodDropDown.find('li').click(function(){
        var li = $(this);
        currentPeriod.text(li.text());
        loadPeriod(li.data('action'));
    });

    // Disabling the dropdown when an AJAX request is active:
    periodDropDown.ajaxStart(function(){
        periodDropDown.addClass('inactive');
    }).ajaxComplete(function(){
        periodDropDown.removeClass('inactive');
    });

如您所見,我們將最常使用的一些選擇器分配給變量,這對性能有積極影響。另外,我正在使用 ajaxStart()ajaxComplete() 綁定事件的方法,一旦發起 AJAX 請求就會執行。在上面的代碼中,inactive 類被添加到 periodDropDown ,這可以防止它在懸停時展開。

接下來我們將綁定一個自定義事件到 plot div,這將幫助我們更好地組織我們的代碼。在後面的代碼中,我們將能夠通過簡單地觸發 render 創建一個新的繪圖 方法。

  // Binding a custom "render" event to the plot div:

    performancePlot.bind('render',function(e,plotData,labels){

        var ticksLength = 7;

        // Using the Flot jQuery plugin to generate
        // the performance graph:

        var plot = $.plot(performancePlot,
            [{
                // Passing the datapoints received as a parameter
                // and setting the color and legend label.

                data: plotData,
                color:'#86c9ff',
                label: "Response Time"
            }], {
                series: {
                    // Setting additional options for the styling.
                    lines: {
                        show:true,
                        fill:true,
                        fillColor:'rgba(237,247,255,0.4)',
                        lineWidth:1
                    },
                    shadowSize: 0,
                    points: { show: (labels.length == 1) }
                },
                grid: {
                    tickColor:'#e0e0e0',
                    hoverable: true,
                    borderWidth:1,
                    borderColor:'#cccccc'
                },
                xaxis:{

                    // This function is called by the plugin
                    // which passes a "range" object. The function
                    // must generate an array with the divisions ticks:

                    ticks:function(range){

                        ticksLength = range.max-range.min;
                        var dv = 1;

                        // Trying to find a suitable number of ticks,
                        // given the varying number of data points in the
                        // graph:

                        while(ticksLength>12){
                            ticksLength = Math.floor(ticksLength/++dv);
                            if(dv>30) break;
                        }

                        var ratio = (range.max-range.min)/ticksLength,
                            ret = [];

                        ticksLength++;

                        for(var i=0;i<ticksLength;i++){
                            ret.push(Math.floor(i*ratio));
                        }

                        return ret;
                    }
                }

        });

        // The Flot plugin has some limitations. In the snippet below
        // we are replacing the ticks with proper, more descriptive labels:

        var elem = $('div.tickLabel').slice(0,ticksLength).each(function(){
            var l = $(this);
            l.text(labels[parseInt(l.text())]);
        }).last().next().hide();

        // Displaying a tooltip over the points of the plot:

        var prev = null;
        performancePlot.bind("plothover", function (e,pos,item) {

            if (item) {

                if(item.datapoint.toString() == prev){
                    return;
                }

                prev = item.datapoint.toString();

                // Calling the show method of the tooltip object,
                // with X and Y coordinates, and a tooltip text:

                tooltip.show(
                    item.pageX,
                    item.pageY,
                    currentData.chart.tooltip.replace('%2',item.datapoint[1])
                                             .replace('%1',currentData.chart.data[item.dataIndex].label)
                );
            }
            else {
                tooltip.hide();
                prev = null;
            }

        });

    }).bind("mouseleave",function(){
        tooltip.hide();
        prev = null;
    });

我們用來顯示漂亮圖形的 Flot jQuery 插件支持廣泛的 api。這裡用到了很多選項,雖然代碼有註釋,但我會進一步解釋其中的一些。

該插件將 jQuery 對象(或 DOM 節點)作為其第一個參數,將在圖表中顯示的數據點排在第二位,第三個是帶有附加選項的對象。 jQuery 對象決定了繪圖的顯示位置(繪圖採用元素的全寬和全高)。

稍後您將看到,數據點是通過 AJAX 請求的。作為插件調用的第三個參數,我們傳遞了一個具有三個屬性的對象 - series ,它決定了數據點的樣式,gridxaxis .

最後一個屬性 - xaxis - 是在生成繪圖的水平分割之前由插件調用的回調函數。我們正在使用它來覆蓋和減少它們的默認分區數,因此它們的間距適當。否則,當圖表上顯示一整天的 ping 時,x 軸會變得雜亂無章。

我們還為 plothover 綁定了一個事件監聽器 當用戶將鼠標懸停在插件上方時,由插件觸發的事件。我們使用它來顯示一個簡單的工具提示,使用 tooltip 的方法 對象,如下所示:

// This object provides methods for hiding and showing the tooltip:

    var tooltip = {
        show : function(x, y, str) {

            if(!this.tooltipObj){
                this.tooltipObj = $('<div>',{
                    id      : 'plotTooltip',
                    html    : str,
                    css     : {
                        opacity : 0.75
                    }
                }).appendTo("body");
            }

            this.tooltipObj.hide().html(str);
            var width = this.tooltipObj.outerWidth();

            this.tooltipObj.css({left: x-width/2, top: y+15}).fadeIn(200);
        },
        hide : function(){
            $("#plotTooltip").hide();
        }
    }

    // Loading the data for the last 24hours on page load:
    loadPeriod('24hours');

在代碼片段的底部,您可以看到我們正在調用 loadPeriod 函數。它處理 AJAX 請求,並通過從下拉列表中選擇不同的時間段來觸發。但是,在加載時,我們需要手動觸發它。你可以在下面看到它的代碼。

  var currentData;

    // This function fetches and caches AJAX data.
    function loadPeriod(period){

        // If the period exists in cache, return it.
        if(cache[period]){
            render(cache[period]);
        }
        else{

            // Otherwise initiate an AJAX request:
            $.get('/ajax/'+period+'/',function(r){
                cache[period] = r;
                render(r);
            },'json');
        }

        function render(obj){

            var plotData = [],
                labels = [],
                downtimeData = $('#downtimeData');

            // Generating plotData and labels arrays.
            $.each(obj.chart.data,function(i){
                plotData.push([i,this.value]);
                labels.push(this.label);
            });

            // They are passed with our custom "render" event to the plot:
            performancePlot.trigger('render',[plotData, labels]);

            // Formatting the downtime:
            if(obj.downtime.length){

                $('#noDowntime').hide();

                if(!obj.processed){
                    // Adding the heading for the downtime list:
                    obj.downtime.push({begin: 'FROM',end:'TO',period:'DURATION'});
                    obj.downtime = obj.downtime.reverse();
                }
                obj.processed = true;

                var tmp = $('<div class="dtContainer">'),
                    className = '';

                $.each(obj.downtime,function(){
                    if(this.end == 'NOW'){
                        className = ' ongoing';
                    }
                    else className = '';

                    tmp.append(
                        '<div class="row'+className+'">'+
                            '<span class="from">'+this.begin+'</span>'+
                            '<span class="to">'+this.end+'</span>'+
                            '<span class="period">'+this.period+'</span>'
                        +'</div>'
                    );
                });

                downtimeData.html(tmp)
            }
            else {
                downtimeData.empty();
                $('#noDowntime').show();
            }

            currentData = obj;
        }
    }
});

該函數發出AJAX請求,觸發render plot div 的方法,並生成停機日誌。另外它還使用了一種簡單的緩存機制,使得請求只在第一次發出。

我們剩下要做的就是添加一些 CSS 光澤。

CSS

我們的正常運行時間儀表板使用的樣式位於 assets/css/styles.css .該文件處理從正文樣式到圖形工具提示的所有內容。

首先,我們將為下拉菜單設置樣式。這是包含我們提供停機時間報告的不同時期的元素。

/*===============================
*   Styling the dropdown:
================================*/

#periodDropDown{
    background: url("../img/sprite.png") repeat-x 0 -7px;
    bottom: 0;
    cursor: pointer;
    height: 38px;
    padding: 0 25px 0 12px;
    position: absolute;
    right: 0;
    text-indent: 37px;
    width: 150px;
    text-shadow: 1px 1px 0 #95999D;
}

#periodDropDown ul{
    display:none;
    background-color: #9FA2A8;
    left: 1px;
    list-style: none outside none;
    padding-bottom: 10px;
    position: absolute;
    right: 1px;
    top: 36px;

    -moz-border-radius:0 0 3px 3px;
    -webkit-border-radius:0 0 3px 3px;
    border-radius:0 0 3px 3px;
}

#periodDropDown:hover ul{
    display:block;
}

#periodDropDown.inactive ul{
    display:none !important;
}

#periodDropDown.inactive{
    cursor:default;
}

#periodDropDown li{
    padding:2px;
    text-indent: 47px;
}
#periodDropDown li:hover{
    background-color:#b0b2b7
}

#periodDropDown .left,
#periodDropDown .right,
#periodDropDown .arrow{
    background: url("../img/sprite.png") repeat-x 0 -45px;
    position:absolute;
    top:0;
    left:0;
    height:38px;
    width:11px;
}

#periodDropDown .right{
    left:auto;
    right:0;
    background-position:0 -83px;
}

#periodDropDown .arrow{
    background-position:0 0;
    width:10px;
    height:7px;
    top:50%;
    margin-top:-2px;
    left:auto;
    right:15px;
}

#periodDropDown .currentPeriod{
    line-height: 34px;
}

您可以看到我們正在使用 CSS 精靈作為下拉菜單的左、右和箭頭跨度。所有這些元素的通用樣式都放在一個聲明組中,稍後分配單獨的樣式。

在此之後,我們為繪圖和繪圖工具提示設置樣式。

/*===============================
*   Styling the plot:
================================*/

#plot{
    height:400px;
    margin:30px;
    position:relative;
}

#plot .preloader{
    background: url('../img/preloader.gif') no-repeat center center;
    position:absolute;
    width:100%;
    height:100%;
    left:0;
    top:0;
}

#plotTooltip{
    position: absolute;
    display: none;
    border: 1px solid #a1d0f6;
    padding: 2px 5px;
    background-color: #c5e2f9;
    color:#2a4f6d;
    font-size:11px;
    text-shadow:0 0 1px rgba(255,255,255,0.3);

    -moz-box-shadow:2px 2px 0 rgba(0,0,0,0.1),1px 1px 0 #fff;
    -webkit-box-shadow:2px 2px 0 rgba(0,0,0,0.1),1px 1px 0 #fff;
    box-shadow:2px 2px 0 rgba(0,0,0,0.1),1px 1px 0 #fff;
}

最後是部分和停機時間數據列表。

/*===============================
*   The sections:
================================*/

#page h3{
    font-size: 15px;
    line-height: 34px;
    padding: 0 15px;
}

#page .section{
    background: url("../img/sprite.png") repeat-x 0 -121px #FAFAFA;
    border: 1px solid #D1D3D5;
    min-height: 300px;
    margin: 40px 0;
    overflow-x: hidden;

    -moz-border-radius: 4px;
    -webkit-border-radius: 4px;
    border-radius: 4px;

    -moz-box-shadow: 0 0 1px #fff inset;
    -webkit-box-shadow: 0 0 1px #fff inset;
    box-shadow: 0 0 1px #fff inset;
}

/*===============================
*   Downtime styles:
================================*/

#noDowntime{
    color: #999999;
    line-height: 160px;
    text-align: center;
    display:none;
}

.dtContainer{
    color:#777;
}

.row{
    border-bottom: 1px solid #DDDDDD;
    overflow: hidden;
    padding: 6px 0;
}

.row.ongoing{
    color:#C30;
}

#downtimeData .row span{
    float:left;
}

#downtimeData .row:first-child{
    font-size:10px;
}

#downtimeData .from,
#downtimeData .to{
    margin-left: 10px;
    width:40%;
}

#downtimeData{
    margin: 50px 100px;
}

到此我們的應用程序和這個系列的前端就完成了!

總結

在本系列課程中,我們使用 Python 和 jQuery 創建了一個簡單的 App Engine Web 應用程序,同時演示了各種 Google API 以及如何使用它們來構建友好的停機時間報告,並附有實時圖表。您可以使用生成的應用程序來跟踪您網站的性能,甚至可以對其進行修改以包含更多有用的功能。

請務必在下面的評論部分分享您的想法和建議!


Tutorial JavaScript 教程
  1. 低代碼 React Native 後端

  2. 2013 年 100 大 jQuery 插件(第 3/5 部分)

  3. Nest JS 微服務 || 12 因素應用程序

  4. 如何在 Firebase 上免費託管 React 或 Angular 應用程序

  5. JavaScript 不變性——用示例解釋 JS 中的凍結對象

  6. Evan You 的 Vue 3.0 設計原則

  7. 使用 Node.js 構建 React 文件上傳組件

  1. react-keyboard-key NPM 包

  2. 節點與 Python。下面介紹如何使用 Spawn 在項目中運行這兩者!

  3. 為樂趣和利潤而進行的 Dom 遍歷

  4. 在 Monorepo 中使用 ESLint 和 Prettier 強制 Husky 預提交

  5. 構建一個 React Native 應用程序。第 1 部分:開發

  6. 如何使用正則表達式獲取特定字符之後的所有字符,例如逗號 (,)

  7. 像程序員一樣思考💭💻

  1. 在 ReactJS 中創建提及和標籤

  2. [zh-CN] 我們如何使用 Vue 和 Webpack 創建 Pará de Minas 玩家會議的網站和 CMS

  3. 受未來啟發:Vision UI Dashboard React(開源版)

  4. 什麼是 WalletConnect?