github.com/zhongdalu/gf@v1.0.0/g/util/gpage/gpage.go (about) 1 // Copyright 2018 gf Author(https://github.com/zhongdalu/gf). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/zhongdalu/gf. 6 7 // Package gpage provides useful paging functionality for web pages. 8 package gpage 9 10 import ( 11 "fmt" 12 "github.com/zhongdalu/gf/g/net/ghttp" 13 "github.com/zhongdalu/gf/g/text/gregex" 14 "github.com/zhongdalu/gf/g/text/gstr" 15 "github.com/zhongdalu/gf/g/util/gconv" 16 "math" 17 url2 "net/url" 18 "strings" 19 ) 20 21 // 分页对象 22 type Page struct { 23 Url *url2.URL // 当前页面的URL对象 24 Router *ghttp.Router // 当前页面的路由对象(与gf框架耦合,在静态分页下有效) 25 UrlTemplate string // URL生成规则,内部可使用{.page}变量指定页码 26 TotalSize int // 总共数据条数 27 TotalPage int // 总页数 28 CurrentPage int // 当前页码 29 PageName string // 分页参数名称(GET参数) 30 NextPageTag string // 下一页标签 31 PrevPageTag string // 上一页标签 32 FirstPageTag string // 首页标签 33 LastPageTag string // 尾页标签 34 PrevBar string // 上一分页条 35 NextBar string // 下一分页条 36 PageBarNum int // 控制分页条的数量 37 AjaxActionName string // AJAX方法名,当该属性有值时,表示使用AJAX分页 38 } 39 40 // 创建一个分页对象,输入参数分别为: 41 // 总数量、每页数量、当前页码、当前的URL(URI+QUERY)、(可选)路由规则(例如: /user/list/:page、/order/list/*page、/order/list/{page}.html) 42 func New(TotalSize, perPage int, CurrentPage interface{}, url string, router ...*ghttp.Router) *Page { 43 u, _ := url2.Parse(url) 44 page := &Page{ 45 PageName: "page", 46 PrevPageTag: "<", 47 NextPageTag: ">", 48 FirstPageTag: "|<", 49 LastPageTag: ">|", 50 PrevBar: "<<", 51 NextBar: ">>", 52 TotalSize: TotalSize, 53 TotalPage: int(math.Ceil(float64(TotalSize) / float64(perPage))), 54 CurrentPage: 1, 55 PageBarNum: 10, 56 Url: u, 57 } 58 curPage := gconv.Int(CurrentPage) 59 if curPage > 0 { 60 page.CurrentPage = curPage 61 } 62 if len(router) > 0 { 63 page.Router = router[0] 64 } 65 return page 66 } 67 68 // 启用AJAX分页 69 func (page *Page) EnableAjax(actionName string) { 70 page.AjaxActionName = actionName 71 } 72 73 // 设置URL生成规则模板,模板中可使用{.page}变量指定页码位置 74 func (page *Page) SetUrlTemplate(template string) { 75 page.UrlTemplate = template 76 } 77 78 // 获取显示"下一页"的内容. 79 func (page *Page) NextPage(styles ...string) string { 80 var curStyle, style string 81 if len(styles) > 0 { 82 curStyle = styles[0] 83 } 84 if len(styles) > 1 { 85 style = styles[0] 86 } 87 if page.CurrentPage < page.TotalPage { 88 return page.GetLink(page.GetUrl(page.CurrentPage+1), page.NextPageTag, "下一页", style) 89 } 90 return fmt.Sprintf(`<span class="%s">%s</span>`, curStyle, page.NextPageTag) 91 } 92 93 /// 获取显示“上一页”的内容 94 func (page *Page) PrevPage(styles ...string) string { 95 var curStyle, style string 96 if len(styles) > 0 { 97 curStyle = styles[0] 98 } 99 if len(styles) > 1 { 100 style = styles[0] 101 } 102 if page.CurrentPage > 1 { 103 return page.GetLink(page.GetUrl(page.CurrentPage-1), page.PrevPageTag, "上一页", style) 104 } 105 return fmt.Sprintf(`<span class="%s">%s</span>`, curStyle, page.PrevPageTag) 106 } 107 108 /** 109 * 获取显示“首页”的代码 110 * 111 * @return string 112 */ 113 func (page *Page) FirstPage(styles ...string) string { 114 var curStyle, style string 115 if len(styles) > 0 { 116 curStyle = styles[0] 117 } 118 if len(styles) > 1 { 119 style = styles[0] 120 } 121 if page.CurrentPage == 1 { 122 return fmt.Sprintf(`<span class="%s">%s</span>`, curStyle, page.FirstPageTag) 123 } 124 return page.GetLink(page.GetUrl(1), page.FirstPageTag, "第一页", style) 125 } 126 127 // 获取显示“尾页”的内容 128 func (page *Page) LastPage(styles ...string) string { 129 var curStyle, style string 130 if len(styles) > 0 { 131 curStyle = styles[0] 132 } 133 if len(styles) > 1 { 134 style = styles[0] 135 } 136 if page.CurrentPage == page.TotalPage { 137 return fmt.Sprintf(`<span class="%s">%s</span>`, curStyle, page.LastPageTag) 138 } 139 return page.GetLink(page.GetUrl(page.TotalPage), page.LastPageTag, "最后页", style) 140 } 141 142 // 获得分页条列表内容 143 func (page *Page) PageBar(styles ...string) string { 144 var curStyle, style string 145 if len(styles) > 0 { 146 curStyle = styles[0] 147 } 148 if len(styles) > 1 { 149 style = styles[0] 150 } 151 plus := int(math.Ceil(float64(page.PageBarNum / 2))) 152 if page.PageBarNum-plus+page.CurrentPage > page.TotalPage { 153 plus = page.PageBarNum - page.TotalPage + page.CurrentPage 154 } 155 begin := page.CurrentPage - plus + 1 156 if begin < 1 { 157 begin = 1 158 } 159 ret := "" 160 for i := begin; i < begin+page.PageBarNum; i++ { 161 if i <= page.TotalPage { 162 if i != page.CurrentPage { 163 ret += page.GetLink(page.GetUrl(i), gconv.String(i), style, "") 164 } else { 165 ret += fmt.Sprintf(`<span class="%s">%d</span>`, curStyle, i) 166 } 167 } else { 168 break 169 } 170 } 171 return ret 172 } 173 174 // 获取基于select标签的显示跳转按钮的代码 175 func (page *Page) SelectBar() string { 176 ret := `<select name="gpage_select" onchange="window.location.href=this.value">` 177 for i := 1; i <= page.TotalPage; i++ { 178 if i == page.CurrentPage { 179 ret += fmt.Sprintf(`<option value="%s" selected>%d</option>`, page.GetUrl(i), i) 180 } else { 181 ret += fmt.Sprintf(`<option value="%s">%d</option>`, page.GetUrl(i), i) 182 } 183 } 184 ret += "</select>" 185 return ret 186 } 187 188 // 预定义的分页显示风格内容 189 func (page *Page) GetContent(mode int) string { 190 switch mode { 191 case 1: 192 page.NextPageTag = "下一页" 193 page.PrevPageTag = "上一页" 194 return fmt.Sprintf( 195 `%s <span class="current">%d</span> %s`, 196 page.PrevPage(), 197 page.CurrentPage, 198 page.NextPage(), 199 ) 200 201 case 2: 202 page.NextPageTag = "下一页>>" 203 page.PrevPageTag = "<<上一页" 204 page.FirstPageTag = "首页" 205 page.LastPageTag = "尾页" 206 return fmt.Sprintf( 207 `%s%s<span class="current">[第%d页]</span>%s%s第%s页`, 208 page.FirstPage(), 209 page.PrevPage(), 210 page.CurrentPage, 211 page.NextPage(), 212 page.LastPage(), 213 page.SelectBar(), 214 ) 215 216 case 3: 217 page.NextPageTag = "下一页" 218 page.PrevPageTag = "上一页" 219 page.FirstPageTag = "首页" 220 page.LastPageTag = "尾页" 221 pageStr := page.FirstPage() 222 pageStr += page.PrevPage() 223 pageStr += page.PageBar("current") 224 pageStr += page.NextPage() 225 pageStr += page.LastPage() 226 pageStr += fmt.Sprintf( 227 `<span>当前页%d/%d</span> <span>共%d条</span>`, 228 page.CurrentPage, 229 page.TotalPage, 230 page.TotalSize, 231 ) 232 return pageStr 233 234 case 4: 235 page.NextPageTag = "下一页" 236 page.PrevPageTag = "上一页" 237 page.FirstPageTag = "首页" 238 page.LastPageTag = "尾页" 239 pageStr := page.FirstPage() 240 pageStr += page.PrevPage() 241 pageStr += page.PageBar("current") 242 pageStr += page.NextPage() 243 pageStr += page.LastPage() 244 return pageStr 245 } 246 return "" 247 } 248 249 // 为指定的页面返回地址值 250 func (page *Page) GetUrl(pageNo int) string { 251 // 复制一个URL对象 252 url := *page.Url 253 if len(page.UrlTemplate) == 0 && page.Router != nil { 254 page.UrlTemplate = page.makeUrlTemplate(url.Path, page.Router) 255 } 256 if len(page.UrlTemplate) > 0 { 257 // 指定URL生成模板 258 url.Path = gstr.Replace(page.UrlTemplate, "{.page}", gconv.String(pageNo)) 259 return url.String() 260 } 261 262 values := page.Url.Query() 263 values.Set(page.PageName, gconv.String(pageNo)) 264 url.RawQuery = values.Encode() 265 return url.String() 266 } 267 268 // 根据当前URL以及注册路由信息计算出对应的URL模板 269 func (page *Page) makeUrlTemplate(url string, router *ghttp.Router) (tpl string) { 270 if page.Router != nil && len(router.RegNames) > 0 { 271 if match, err := gregex.MatchString(router.RegRule, url); err == nil && len(match) > 0 { 272 if len(match) > len(router.RegNames) { 273 tpl = router.Uri 274 hasPageName := false 275 for i, name := range router.RegNames { 276 rule := fmt.Sprintf(`[:\*]%s|\{%s\}`, name, name) 277 if !hasPageName && strings.Compare(name, page.PageName) == 0 { 278 hasPageName = true 279 tpl, _ = gregex.ReplaceString(rule, `{.page}`, tpl) 280 } else { 281 tpl, _ = gregex.ReplaceString(rule, match[i+1], tpl) 282 } 283 } 284 if !hasPageName { 285 tpl = "" 286 } 287 } 288 } 289 } 290 return 291 } 292 293 // 获取链接地址 294 func (page *Page) GetLink(url, text, title, style string) string { 295 if len(style) > 0 { 296 style = fmt.Sprintf(`class="%s" `, style) 297 } 298 if len(page.AjaxActionName) > 0 { 299 return fmt.Sprintf(`<a %shref='#' onclick="%s('%s')">%s</a>`, style, page.AjaxActionName, url, text) 300 } else { 301 return fmt.Sprintf(`<a %shref="%s" title="%s">%s</a>`, style, url, title, text) 302 } 303 }