Golang模板中如何操作DOM添加/删除属性

Golang模板中如何操作DOM添加/删除属性 在我的代码中,我想根据用户认证级别禁用某些输入字段。我可以用 JavaScript 实现,但这不是推荐的做法,我希望从服务器端来实现。

以下是我的 Go 代码:

package main

import (
	"context"
	"html/template"
	"net/http"
	"strings"
	"time"
)

type User struct {
	Flags string
	Title string
}

type UsersPageData struct {
	PageTitle string
	Users     []User
}

func requestTime(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ctx := r.Context()
		ctx = context.WithValue(ctx, "requestTime", time.Now().Format(time.RFC3339))
		r = r.WithContext(ctx)
		next.ServeHTTP(w, r)
	})
}

func helloHandler(name string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		var title string
		if requestTime := r.Context().Value("requestTime"); requestTime != nil {
			if str, ok := requestTime.(string); ok {
				title = "\ngenerated at: " + str
			}
		}

		master := strings.Join([]string{"admin", "user", "superuser", "read"}, " ")
		admin := strings.Join([]string{"admin"}, " ")
		user := strings.Join([]string{"user"}, " ")

		tmpl := template.Must(template.ParseFiles("index.html"))
		data := UsersPageData{
			PageTitle: "Users list: " + title,
			Users: []User{
				{Flags: master, Title: "Everything"},
				{Flags: admin, Title: "Administrator"},
				{Flags: user, Title: "Normal user"},
			},
		}
		tmpl.Execute(w, data)
	})
}

func main() {
	http.Handle("/john", requestTime(helloHandler("John")))
	http.ListenAndServe(":8080", nil)
}

这是我的模板,包含 JS 代码:

<style>
.admin {
    color: green;
}

.user {
    color: red;
    --btn-disable: 0;
}


[data-authorized="no"] { 
  /* Attribute has this exact value */
        cursor: not-allowed;
        pointer-events: none;

        /*Button disabled - CSS color class*/
        color: #c0c0c0;
        background-color: rgb(229, 229, 229) !important;
}

</style>
<h1>{{.PageTitle}}</h1>
<ul>
    {{range .Users}}
            <input type="text" data-permissions={{.Flags}} data-authorized="no">{{.Title}}</s>
    {{end}}
</ul>

<script>
  var flags = ["admin", "super user"]
  var elements = document.querySelectorAll("input");
  elements.forEach((element, index, array) => { 
        if(element.hasAttribute("data-permissions")){
            console.log(element.dataset.permissions)
            var perm = element.dataset.permissions.split(" ");
                    var found = false;
                    for (var i = 0; i < perm.length; i++) {
                        if (flags.indexOf(perm[i]) > -1) {
                            element.dataset.authorized = "yes"
                            element.removeAttribute("data-permissions")
                            break;
                        }
                    } 
        }
  });
</script>

以下是输出结果:

enter image description here

有什么想法吗?


更多关于Golang模板中如何操作DOM添加/删除属性的实战教程也可以访问 https://www.itying.com/category-94-b0.html

11 回复

如果你有已授权的用户,只需从应用程序发送不同的HTML代码即可。

更多关于Golang模板中如何操作DOM添加/删除属性的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


只需渲染另一个模板

关键就在这里,我希望能使用同一个模板。

没明白,你能用一些代码详细说明一下吗,谢谢

@Sibert 说得对。@hyousef 你可以在视图中使用逻辑区分,或者在 Go 代码中使用相同的方法(只需渲染另一个模板)。

我想在服务器端实现它。

一种方法是在 Go 模板中隐藏/显示元素

{{if and .User .User.Admin}}
  You are an admin user!
{{else}}
  Access denied!
{{end}}

Sibert:

一种方法是在 Go 模板中隐藏/显示元素

谢谢,但这意味着要使用不同的模板。实际上,我有两种认证情况:

  1. 每种权限对应不同的视图,这可以通过您提供的代码在 GO 中控制。
  2. 单一视图,其中某些字段对某些权限级别禁用,而对其他权限级别开放。这正是我试图实现的功能。
  1. 对于某些权限级别,单一视图中的某些字段被禁用,而对其他权限级别则开放,这正是我试图实现的功能。

你可以使用一个带有内置条件的模板。

<form>
{{if .SuperAdmin}}
  <input type="text" name="subject" placeholder="For Superadmin" required>
{{else if .Admin}}
  <input type="text" name="subject" placeholder="For Admin" required>
{{else}}
  <input type="text" name="subject" placeholder="For Normal Users" required>
{{end}}
//outside if statement:
<input type="text" name="subject" placeholder="For all users" required>
</form>

在上面的例子中,用户有两个标志,Admin 授予了对该元素的访问权限,而 Viewer 阻止了对同一元素的访问,我该如何处理这种情况?

在我看来,这不是一个 Go 语言的问题,而是一个逻辑问题。这就像扑克牌游戏。Admin 拥有最好的牌,所以它赢了游戏!😊

但我认为,当你解决了逻辑问题后,操作符 “and” 是另一个选项。据我理解,它某种程度上可以替代 switch 语句。

Go Playground - The Go Programming Language

引用 Sibert:

您可以使用一个带有内置条件的模板。

如果每个用户只有一个标志,这个方法对我有效,例如:

type Flag int

const (
	Admin Flag = iota + 1 // iota = 0
	Editer
	Superuser
	Viewer
)

type User struct {
	Flags Flag
	Title string
}

模板如下:

<h1>{{.PageTitle}}</h1>
<ul>
    {{range .Users}}
            <span>{{.Title}}</span>
            {{if eq .Flags 1}}
                 <input type="text" name="subject" placeholder= {{.Flags}} required>
                 {{else if eq .Flags 4}}
                 <input type="text" name="subject" placeholder= {{.Flags}} disabled>
            {{end}}
    {{end}}
</ul>

但是,如果我的标志是数组形式,该怎么办?其中:

  1. 每个用户可能拥有多个标志
  2. 如果同一个用户的一个标志对元素有权限,而另一个标志不允许此权限,那么我该如何为更高优先级的标志开放权限?

一个例子是:

type User struct {
	Flags []Flag
	Title string
}

master := User{
 Flags: []string{Admin, Viewer},
Title: "Abnormal user",
}

在上面的例子中,用户有两个标志:Admin 授予了对元素的访问权限,而 Viewer 则阻止了对同一元素的访问权限,我该如何处理这种情况?

更新 经过搜索,我尝试了下面的方法,但问题仍未解决。如果同一个用户有多个标志,并且它们都没有权限,那么同一个字段会重复多次;

		master := []flag{Admin, Editer, Superuser, Viewer}
		admin := []flag{Admin, Superuser}
		user := []flag{Viewer, Dummy}

// template
<h1>{{.PageTitle}}</h1>
<ul>
    {{range .Users}}
        <span>{{.Title}}</span>
        {{ $done := false }}
        {{range $i, $v := .Flags}}
            {{ if $done }}
            {{ else }}
                {{if or (eq $v 1) (eq $v 3)}} 
                    <input type="text" name="subject" placeholder= {{$v}} required>
                    {{ $done = true }}
                {{else}}
                     <input type="text" name="subject" placeholder= {{$v}} disabled>
                {{end}}
            {{end}}
        {{end}}
    {{end}}
</ul>

image

谢谢

package main

import (
	"html/template"
	"net/http"
)

type User struct {
	Flags []flag //string
	Title string
}

type UsersPageData struct {
	PageTitle string
	Users     []User
}

type flag int

const (
	Admin flag = iota + 1 // iota = 0
	Editer
	Superuser
	Viewer
	Dummy
)

func subtract(arg1, arg2 int) int {
	return arg1 - arg2
}

func helloHandler(name string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// 在模板中映射自定义的 `subtract` 函数
		funcMap := map[string]interface{}{"subtract": subtract}

		master := []flag{Admin, Editer, Superuser, Viewer}
		admin := []flag{Admin, Superuser, Viewer}
		user := []flag{Viewer, Dummy}

		tmpl := template.New("").Funcs(template.FuncMap(funcMap))
		template.Must(tmpl.ParseFiles("index.html"))
		data := UsersPageData{
			PageTitle: "Users list: ",
			Users: []User{
				{Flags: master, Title: "Everything"},
				{Flags: admin, Title: "Administrator"},
				{Flags: user, Title: "Normal user"},
			},
		}
		tmpl.ExecuteTemplate(w, "index.html", data)
	})
}

func main() {
	fs := http.StripPrefix("/www/", http.FileServer(http.Dir("./www")))
	http.Handle("/www/", fs)

	http.Handle("/", helloHandler("John"))
	http.ListenAndServe(":8080", nil)
}

index.html 文件内容如下:

<html>
{{/* This is a comment 
{{$flags := []flag{Admin, Editer, Superuser, Viewer};}}	
    Admin Flag = iota + 1 // iota = 0
	Editer
	Superuser
	Viewer
    }}
*/}}

<ul>
    {{range .Users}}
        <span>{{.Title}}</span>
        {{ $done := false}} {{$length := len .Flags}}
        {{range $i, $v := .Flags}}
            {{ if $done }}
            {{ else }}
                {{if or (eq $v 1) (eq $v 3)}} 
                    <input type="text" name="subject" placeholder= {{$v}} required>
                    {{ $done = true }}
                {{else}}
                    {{ if eq $i (subtract $length 1)}}
                        <input type="text" name="subject" placeholder= {{$v}} disabled>
                    {{ end }}
                {{end}}
            {{end}}
        {{end}}
    {{end}}
</ul>
</html>

enter image description here

在Go模板中直接操作DOM添加/删除属性是可行的,可以通过模板函数和条件逻辑实现。以下是修改后的示例:

package main

import (
    "context"
    "html/template"
    "net/http"
    "strings"
    "time"
)

type User struct {
    Flags string
    Title string
}

type UsersPageData struct {
    PageTitle string
    Users     []User
    UserFlags []string // 当前用户权限
}

// 模板函数检查权限
func hasPermission(userFlags []string, requiredFlags string) bool {
    required := strings.Fields(requiredFlags)
    for _, req := range required {
        found := false
        for _, userFlag := range userFlags {
            if userFlag == req {
                found = true
                break
            }
        }
        if !found {
            return false
        }
    }
    return true
}

func requestTime(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        ctx := r.Context()
        ctx = context.WithValue(ctx, "requestTime", time.Now().Format(time.RFC3339))
        r = r.WithContext(ctx)
        next.ServeHTTP(w, r)
    })
}

func helloHandler(name string) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        var title string
        if requestTime := r.Context().Value("requestTime"); requestTime != nil {
            if str, ok := requestTime.(string); ok {
                title = "\ngenerated at: " + str
            }
        }

        // 模拟当前用户权限
        currentUserFlags := []string{"admin", "superuser"}
        
        // 创建模板函数映射
        funcMap := template.FuncMap{
            "hasPermission": func(requiredFlags string) bool {
                return hasPermission(currentUserFlags, requiredFlags)
            },
        }

        tmpl := template.Must(template.New("index.html").Funcs(funcMap).ParseFiles("index.html"))
        data := UsersPageData{
            PageTitle: "Users list: " + title,
            UserFlags: currentUserFlags,
            Users: []User{
                {Flags: "admin user superuser read", Title: "Everything"},
                {Flags: "admin", Title: "Administrator"},
                {Flags: "user", Title: "Normal user"},
            },
        }
        tmpl.Execute(w, data)
    })
}

func main() {
    http.Handle("/john", requestTime(helloHandler("John")))
    http.ListenAndServe(":8080", nil)
}

模板文件修改为:

<style>
.admin {
    color: green;
}

.user {
    color: red;
}

.disabled { 
    cursor: not-allowed;
    pointer-events: none;
    color: #c0c0c0;
    background-color: rgb(229, 229, 229) !important;
}

</style>
<h1>{{.PageTitle}}</h1>
<ul>
    {{range .Users}}
        {{if hasPermission .Flags}}
            <input type="text" class="admin" value="{{.Title}}">
        {{else}}
            <input type="text" class="disabled user" value="{{.Title}}" disabled>
        {{end}}
    {{end}}
</ul>

<!-- 或者使用属性条件设置 -->
<h2>方法二:动态设置属性</h2>
<ul>
    {{range .Users}}
        <input type="text" 
               value="{{.Title}}" 
               {{if not (hasPermission .Flags)}}disabled{{end}}
               {{if not (hasPermission .Flags)}}class="disabled"{{else}}class="enabled"{{end}}>
    {{end}}
</ul>

另一种更灵活的方式是使用自定义模板函数生成属性:

// 添加模板函数生成属性字符串
funcMap := template.FuncMap{
    "hasPermission": func(requiredFlags string) bool {
        return hasPermission(currentUserFlags, requiredFlags)
    },
    "inputAttrs": func(flags string) template.HTMLAttr {
        if hasPermission(currentUserFlags, flags) {
            return `class="enabled" type="text"`
        }
        return `class="disabled" type="text" disabled`
    },
}

模板中使用:

<h2>方法三:使用属性生成函数</h2>
<ul>
    {{range .Users}}
        <input {{inputAttrs .Flags}} value="{{.Title}}">
    {{end}}
</ul>

对于data属性的操作,可以在模板中直接生成:

<h2>方法四:控制data属性</h2>
<ul>
    {{range .Users}}
        <input type="text" 
               value="{{.Title}}"
               {{if hasPermission .Flags}}
                   data-authorized="yes"
               {{else}}
                   data-authorized="no"
               {{end}}
               data-permissions="{{.Flags}}">
    {{end}}
</ul>

这样完全在服务器端处理权限逻辑,无需客户端JavaScript。模板会根据用户权限动态生成正确的HTML属性和类名。

回到顶部