Golang中MVM的实现与应用

Golang中MVM的实现与应用 大家好下午好。 朋友们,请告诉我如何使用 html/template 来持续向 HTML 模板传输数据,例如计时器或已下载的数据量? 提前感谢您的帮助。

4 回复

您无法做到。模板只会被精确渲染一次。

如果您想在不触发手动请求的情况下动态更新一个值,您需要在客户端使用 JavaScript 来实现这一点。

更多关于Golang中MVM的实现与应用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


也就是说,我有一个方法返回下载文件的值,它不会实时在客户端显示信息?也就是说,没有属性包装器?真遗憾。

嗯,这是一个前端问题。对于这类应用,我仍然使用AngularJS,但它有点……过时了。不过,你可以使用AjaxVue.js或其他类似的方法来实现。

在Go语言中,可以使用html/template包结合服务器推送技术来实现持续向HTML模板传输数据,例如计时器或下载进度。以下是一个使用Server-Sent Events (SSE) 的示例:

首先,创建一个HTML模板文件 index.html

<!DOCTYPE html>
<html>
<head>
    <title>实时数据更新</title>
</head>
<body>
    <h1>实时数据监控</h1>
    <div id="timer">计时器: 0秒</div>
    <div id="download">下载进度: 0%</div>

    <script>
        const eventSource = new EventSource('/events');
        
        eventSource.onmessage = function(event) {
            const data = JSON.parse(event.data);
            document.getElementById('timer').textContent = `计时器: ${data.timer}秒`;
            document.getElementById('download').textContent = `下载进度: ${data.download}%`;
        };
        
        eventSource.onerror = function() {
            console.log('连接错误');
        };
    </script>
</body>
</html>

然后,创建Go服务器程序:

package main

import (
    "encoding/json"
    "html/template"
    "log"
    "net/http"
    "time"
)

type UpdateData struct {
    Timer    int `json:"timer"`
    Download int `json:"download"`
}

func main() {
    // 解析模板
    tmpl := template.Must(template.ParseFiles("index.html"))
    
    // 首页路由
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        tmpl.Execute(w, nil)
    })
    
    // SSE事件流路由
    http.HandleFunc("/events", func(w http.ResponseWriter, r *http.Request) {
        // 设置SSE相关头部
        w.Header().Set("Content-Type", "text/event-stream")
        w.Header().Set("Cache-Control", "no-cache")
        w.Header().Set("Connection", "keep-alive")
        w.Header().Set("Access-Control-Allow-Origin", "*")
        
        flusher, ok := w.(http.Flusher)
        if !ok {
            http.Error(w, "Streaming unsupported", http.StatusInternalServerError)
            return
        }
        
        // 模拟计时器和下载进度
        timer := 0
        download := 0
        
        for {
            select {
            case <-r.Context().Done():
                log.Println("客户端断开连接")
                return
            case <-time.After(1 * time.Second):
                timer++
                if download < 100 {
                    download += 10
                }
                
                data := UpdateData{
                    Timer:    timer,
                    Download: download,
                }
                
                jsonData, err := json.Marshal(data)
                if err != nil {
                    log.Printf("JSON编码错误: %v", err)
                    continue
                }
                
                // 发送SSE格式数据
                fmt.Fprintf(w, "data: %s\n\n", jsonData)
                flusher.Flush()
                
                if download >= 100 {
                    fmt.Fprintf(w, "event: close\ndata: 下载完成\n\n")
                    flusher.Flush()
                    return
                }
            }
        }
    })
    
    log.Println("服务器启动在 :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

如果需要使用WebSocket实现更复杂的双向通信,可以使用gorilla/websocket库:

package main

import (
    "html/template"
    "log"
    "net/http"
    "time"
    
    "github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{
    CheckOrigin: func(r *http.Request) bool {
        return true
    },
}

func main() {
    tmpl := template.Must(template.ParseFiles("index_ws.html"))
    
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        tmpl.Execute(w, nil)
    })
    
    http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
        conn, err := upgrader.Upgrade(w, r, nil)
        if err != nil {
            log.Println("WebSocket升级失败:", err)
            return
        }
        defer conn.Close()
        
        timer := 0
        download := 0
        
        for {
            timer++
            if download < 100 {
                download += 10
            }
            
            data := map[string]interface{}{
                "timer":    timer,
                "download": download,
            }
            
            if err := conn.WriteJSON(data); err != nil {
                log.Println("发送数据失败:", err)
                break
            }
            
            time.Sleep(1 * time.Second)
            
            if download >= 100 {
                break
            }
        }
    })
    
    log.Println("服务器启动在 :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

对应的WebSocket HTML模板 index_ws.html

<!DOCTYPE html>
<html>
<head>
    <title>WebSocket实时数据</title>
</head>
<body>
    <h1>实时数据监控</h1>
    <div id="timer">计时器: 0秒</div>
    <div id="download">下载进度: 0%</div>

    <script>
        const ws = new WebSocket('ws://' + window.location.host + '/ws');
        
        ws.onmessage = function(event) {
            const data = JSON.parse(event.data);
            document.getElementById('timer').textContent = `计时器: ${data.timer}秒`;
            document.getElementById('download').textContent = `下载进度: ${data.download}%`;
        };
        
        ws.onclose = function() {
            console.log('连接关闭');
        };
    </script>
</body>
</html>

运行前需要安装WebSocket库:

go get github.com/gorilla/websocket

这些示例展示了如何使用SSE和WebSocket技术实现持续向HTML模板传输实时数据。SSE适用于服务器向客户端单向推送数据的场景,而WebSocket支持双向通信。

回到顶部