用 JavaScript 在網頁中加入動態行為

    前言

    HTML 和 CSS 都是靜態的內容,透過 JavaScript 則可在網頁客戶端加上動態的行為。由於 JavaScript 的內容相當多,我們無法在短短的文章中詳細說明,請讀者自行觀看其他學習資料

    我們的範例程式分為網頁程式和計算機兩部分,主要的內容為前者,後者是一個純網頁前端的程式,和 Go 無關,有興趣可參考這個專案。本範例程式完整的程式碼放在這裡,有需要的讀者可自行追蹤,本文僅節錄部分內容。

    程式展示

    我們的程式是一個電子計算機,示意圖如下:

    以 TypeScript 實作的電子計算機

    眼尖的讀者可發現,我們的計算機可以處理數學運算式,和一般實體的計算機略有不同。

    主程式的部分

    我們來看實作內容。先看 Go 程式的部分:

    package main
    
    import (
    	"github.com/julienschmidt/httprouter"
    	"html/template"
    	"net/http"
    )
    
    func main() {
    	// Set a new HTTP request multiplexer
    	mux := httprouter.New()
    
    	// Listen to root path
    	mux.GET("/", index)
    
    	// Listen to CSS assets
    	mux.ServeFiles("/css/*filepath", http.Dir("public/css"))
    
    	// Listen to JavaScript assets
    	mux.ServeFiles("/js/*filepath", http.Dir("public/js"))
    
    	// Custom 404 page
    	mux.NotFound = http.HandlerFunc(notFound)
    
    	// Custom 500 page
    	mux.PanicHandler = errorHandler
    
    	// Set the parameters for a HTTP server
    	server := http.Server{
    		Addr:    "127.0.0.1:8080",
    		Handler: mux,
    	}
    
    	// Listen requests
    	server.ListenAndServe()
    }
    
    // Implement the handlers here.
    

    由這段程式碼可知,Go 網頁程式和電子計算機的行為無關。在本範例中,電子計算機的行為是用 JavaScript 寫在前端,Go 網頁程式的部分只是用來托管前端代碼。

    為什麼不直接寫純網頁前端程式呢?以這個例子來說,其實可以寫成純網頁前端程式,我們這個範例的目的是練習如何以 Golang 網頁程式掛載這些資源。

    本程式的介面

    接著來看佈局的部分 (節錄):

    <body>
        <div class="container-fluid">
            <div class="row">
                <div class="col-sm-4 col-xs-1"></div>
                <div class="col-sm-4 col-xs-10">
                    <div class="page-header">
                        <h1>Calculator</h1>
                    </div>
                 {{ template "content" . }}
                 </div>
                <div class="col-sm-4 col-xs-1"></div>
            </div>
        </div>
    
        <!-- Load related JavaScript files -->
    </body>
    

    我們在主要的 UI 之外,另外引入兩段空的欄 (column),避免在桌機上觀看該頁面時,UI 過於拉長較不美觀。實際的內容會在 "content" 區塊中。

    我們節錄一部分的 UI 來看:

    <div>
        <!-- Omit some parts -->
        <div class="row">
            <div class="col-xs-3 nopadding">
                <button type="button" class="btn btn-default btn-calc" id="ltparen">(</button>
            </div>
            <div class="col-xs-3 nopadding">
                <button type="button" class="btn btn-default btn-calc" id="rtparen">)</button>
            </div>
            <div class="col-xs-3 nopadding">
                <button type="button" class="btn btn-default btn-calc" id="pow">**</button>
            </div>
            <div class="col-xs-3 nopadding">
                <button type="button" class="btn btn-default btn-calc" id="mod">%</button>
            </div>
        </div>
        <!-- Omit some parts -->
    </div>
    

    我們的按鈕是用欄分隔開來,原本的欄預設會有一些空間,這樣會導致間距過寬,故我們用 nopadding 移除額外的間距。實際的按鈕是用 <button> 標籤來製作。

    在我們的程式中,我們將字串存在 #calc-text 這個文字區塊中,並且將編輯的功能鎖住:

    <div class="input-group col-xs-12 div-calc">
        <textarea disabled class="form-control text-calc" rows="5" id="calc-text"></textarea>
    </div>
    

    我們的網頁程式設計成只能透過 UI 所提供的按鈕來更動字串內容。

    程式邏輯的部分

    接著,我們來看 UI 元件的處理器的部分的代碼。數字 0 按鈕的事件處理器如下:

    jQuery('#zero').click(function() {
        jQuery('#calc-text').prop('disabled', false);
    
        let text = jQuery('#calc-text').val();
        if (!isNumberLast(text)) {
            text += ' ';
        }
        text += '0';
        jQuery('#calc-text').val(text);
    
        jQuery('#calc-text').prop('disabled', true);
    });
    

    在按下按鈕時,會暫時打開 <textarea> 的編輯功能,就可以新增內容。我們先偵測 <textarea> 的內容,如果最後一個字元不是數字,代表可能是括號或運算符號,這時候我們就插入一個空白字元 ' '。然後,我們插入數字 0,並更新 <textarea> 的內容,最後,我們將 <textarea> 的編輯功能關掉,防止使用者直接編輯文字區塊。

    實際執行運算行為的事件處理器如下:

    jQuery('#calc').click(function() {
        jQuery('#calc-text').prop('disabled', false);
        let text = jQuery('#calc-text').val();
    
        try {
            var evaluator = new calc.Evaluator(text);
            let result = evaluator.run();
            jQuery('#calc-text').val(result);
        }
        catch (err) {
            jQuery('#msg').empty();
            jQuery('#msg').append("<div class=\"alert alert-warning alert-dismissable center-block\"><a href=\"#\" class=\"close\" data-dismiss=\"alert\" aria-label=\"close\">&times;</a><strong>Error</strong> " + err + " </div>");
        }
    
        jQuery('#calc-text').prop('disabled', true);
    });
    

    呼叫計算機的程式碼其實相當簡短:

    var evaluator = new calc.Evaluator(text);
    let result = evaluator.run();
    jQuery('#calc-text').val(result);
    

    我們將運算式字串輸入 evaluator 物件中,執行該物件即會得到結果。當然程式內部運作沒那麼簡短,這隻程式的專案在這裡,有興趣的讀者可自行閱讀。

    運算的結果不一定正確,運算發生錯誤時會吐出錯誤訊息:

    jQuery('#msg').empty();
    jQuery('#msg').append("<div class=\"alert alert-warning alert-dismissable center-block\"><a href=\"#\" class=\"close\" data-dismiss=\"alert\" aria-label=\"close\">&times;</a><strong>Error</strong> " + err + " </div>");
    

    在這裡我們先清空舊內容,接著用 Bootstrap 的警示框來顯示錯誤訊息。

    結語

    嚴格說來,我們的範例程式是純網頁前端程式。本範例的目的是觀看如何在 Golang 網頁程式中加入 JavaScript 命令稿。在現階段的實務中,網頁前端仍然要用 JavaScript 來寫,所以我們的專案實際上是由網頁前端和網頁後端兩隻程式合併在一起,這是傳統的網頁程式的專案架構。

    【分享本文】
    Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Yahoo
    【追蹤本站】
    Facebook Facebook Twitter