gf/util/gpage/gpage.go

301 lines
8.4 KiB
Go
Raw Normal View History

// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
2018-04-22 10:07:24 +08:00
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
2018-04-22 10:07:24 +08:00
2019-01-15 23:27:47 +08:00
// Package gpage provides useful paging functionality for web pages.
2018-04-22 10:07:24 +08:00
package gpage
import (
2019-06-19 09:06:52 +08:00
"fmt"
"math"
url2 "net/url"
"strings"
2019-07-29 21:01:19 +08:00
"github.com/gogf/gf/net/ghttp"
"github.com/gogf/gf/text/gregex"
"github.com/gogf/gf/text/gstr"
"github.com/gogf/gf/util/gconv"
2018-04-22 10:07:24 +08:00
)
// 分页对象
2018-04-22 10:07:24 +08:00
type Page struct {
2019-06-19 09:06:52 +08:00
Url *url2.URL // 当前页面的URL对象
Router *ghttp.Router // 当前页面的路由对象(与gf框架耦合在静态分页下有效)
UrlTemplate string // URL生成规则内部可使用{.page}变量指定页码
TotalSize int // 总共数据条数
TotalPage int // 总页数
CurrentPage int // 当前页码
PageName string // 分页参数名称(GET参数)
NextPageTag string // 下一页标签
PrevPageTag string // 上一页标签
FirstPageTag string // 首页标签
LastPageTag string // 尾页标签
PrevBar string // 上一分页条
NextBar string // 下一分页条
PageBarNum int // 控制分页条的数量
AjaxActionName string // AJAX方法名当该属性有值时表示使用AJAX分页
2018-04-22 10:07:24 +08:00
}
// 创建一个分页对象,输入参数分别为:
// 总数量、每页数量、当前页码、当前的URL(URI+QUERY)、(可选)路由规则(例如: /user/list/:page、/order/list/*page、/order/list/{page}.html)
2019-06-19 09:06:52 +08:00
func New(TotalSize, perPage int, CurrentPage interface{}, url string, router ...*ghttp.Router) *Page {
u, _ := url2.Parse(url)
page := &Page{
PageName: "page",
PrevPageTag: "<",
NextPageTag: ">",
FirstPageTag: "|<",
LastPageTag: ">|",
PrevBar: "<<",
NextBar: ">>",
TotalSize: TotalSize,
TotalPage: int(math.Ceil(float64(TotalSize) / float64(perPage))),
CurrentPage: 1,
PageBarNum: 10,
Url: u,
}
curPage := gconv.Int(CurrentPage)
if curPage > 0 {
page.CurrentPage = curPage
}
if len(router) > 0 {
page.Router = router[0]
}
return page
2018-04-22 10:07:24 +08:00
}
2018-04-22 11:26:19 +08:00
// 启用AJAX分页
func (page *Page) EnableAjax(actionName string) {
2019-06-19 09:06:52 +08:00
page.AjaxActionName = actionName
2018-04-22 10:07:24 +08:00
}
// 设置URL生成规则模板模板中可使用{.page}变量指定页码位置
func (page *Page) SetUrlTemplate(template string) {
2019-06-19 09:06:52 +08:00
page.UrlTemplate = template
}
2018-04-22 11:26:19 +08:00
// 获取显示"下一页"的内容.
2019-06-19 09:06:52 +08:00
func (page *Page) NextPage(styles ...string) string {
var curStyle, style string
if len(styles) > 0 {
curStyle = styles[0]
}
if len(styles) > 1 {
style = styles[0]
}
if page.CurrentPage < page.TotalPage {
return page.GetLink(page.GetUrl(page.CurrentPage+1), page.NextPageTag, "下一页", style)
}
return fmt.Sprintf(`<span class="%s">%s</span>`, curStyle, page.NextPageTag)
2018-04-22 10:07:24 +08:00
}
2019-08-22 23:30:28 +08:00
// 获取显示“上一页”的内容
2019-06-19 09:06:52 +08:00
func (page *Page) PrevPage(styles ...string) string {
var curStyle, style string
if len(styles) > 0 {
curStyle = styles[0]
}
if len(styles) > 1 {
style = styles[0]
}
if page.CurrentPage > 1 {
return page.GetLink(page.GetUrl(page.CurrentPage-1), page.PrevPageTag, "上一页", style)
}
return fmt.Sprintf(`<span class="%s">%s</span>`, curStyle, page.PrevPageTag)
2018-04-22 10:07:24 +08:00
}
2019-08-22 23:30:28 +08:00
// 获取显示“首页”的代码
2019-06-19 09:06:52 +08:00
func (page *Page) FirstPage(styles ...string) string {
var curStyle, style string
if len(styles) > 0 {
curStyle = styles[0]
}
if len(styles) > 1 {
style = styles[0]
}
if page.CurrentPage == 1 {
return fmt.Sprintf(`<span class="%s">%s</span>`, curStyle, page.FirstPageTag)
}
return page.GetLink(page.GetUrl(1), page.FirstPageTag, "第一页", style)
2018-04-22 11:26:19 +08:00
}
// 获取显示“尾页”的内容
2019-06-19 09:06:52 +08:00
func (page *Page) LastPage(styles ...string) string {
var curStyle, style string
if len(styles) > 0 {
curStyle = styles[0]
}
if len(styles) > 1 {
style = styles[0]
}
if page.CurrentPage == page.TotalPage {
return fmt.Sprintf(`<span class="%s">%s</span>`, curStyle, page.LastPageTag)
}
return page.GetLink(page.GetUrl(page.TotalPage), page.LastPageTag, "最后页", style)
2018-04-22 11:26:19 +08:00
}
// 获得分页条列表内容
2019-06-19 09:06:52 +08:00
func (page *Page) PageBar(styles ...string) string {
var curStyle, style string
if len(styles) > 0 {
curStyle = styles[0]
}
if len(styles) > 1 {
style = styles[0]
}
plus := int(math.Ceil(float64(page.PageBarNum / 2)))
if page.PageBarNum-plus+page.CurrentPage > page.TotalPage {
plus = page.PageBarNum - page.TotalPage + page.CurrentPage
}
begin := page.CurrentPage - plus + 1
if begin < 1 {
begin = 1
}
ret := ""
for i := begin; i < begin+page.PageBarNum; i++ {
if i <= page.TotalPage {
if i != page.CurrentPage {
ret += page.GetLink(page.GetUrl(i), gconv.String(i), style, "")
} else {
ret += fmt.Sprintf(`<span class="%s">%d</span>`, curStyle, i)
}
} else {
break
}
}
return ret
2018-04-22 10:07:24 +08:00
}
2019-06-19 09:06:52 +08:00
// 获取基于select标签的显示跳转按钮的代码
func (page *Page) SelectBar() string {
2019-06-19 09:06:52 +08:00
ret := `<select name="gpage_select" onchange="window.location.href=this.value">`
for i := 1; i <= page.TotalPage; i++ {
if i == page.CurrentPage {
ret += fmt.Sprintf(`<option value="%s" selected>%d</option>`, page.GetUrl(i), i)
} else {
ret += fmt.Sprintf(`<option value="%s">%d</option>`, page.GetUrl(i), i)
}
}
ret += "</select>"
return ret
2018-04-22 10:07:24 +08:00
}
// 预定义的分页显示风格内容
func (page *Page) GetContent(mode int) string {
2019-06-19 09:06:52 +08:00
switch mode {
case 1:
page.NextPageTag = "下一页"
page.PrevPageTag = "上一页"
return fmt.Sprintf(
`%s <span class="current">%d</span> %s`,
page.PrevPage(),
page.CurrentPage,
page.NextPage(),
)
2019-06-19 09:06:52 +08:00
case 2:
page.NextPageTag = "下一页>>"
page.PrevPageTag = "<<上一页"
page.FirstPageTag = "首页"
page.LastPageTag = "尾页"
return fmt.Sprintf(
`%s%s<span class="current">[第%d页]</span>%s%s第%s页`,
page.FirstPage(),
page.PrevPage(),
page.CurrentPage,
page.NextPage(),
page.LastPage(),
page.SelectBar(),
)
2019-06-19 09:06:52 +08:00
case 3:
page.NextPageTag = "下一页"
page.PrevPageTag = "上一页"
page.FirstPageTag = "首页"
page.LastPageTag = "尾页"
pageStr := page.FirstPage()
pageStr += page.PrevPage()
pageStr += page.PageBar("current")
pageStr += page.NextPage()
pageStr += page.LastPage()
pageStr += fmt.Sprintf(
`<span>当前页%d/%d</span> <span>共%d条</span>`,
page.CurrentPage,
page.TotalPage,
page.TotalSize,
)
return pageStr
2019-06-19 09:06:52 +08:00
case 4:
page.NextPageTag = "下一页"
page.PrevPageTag = "上一页"
page.FirstPageTag = "首页"
page.LastPageTag = "尾页"
pageStr := page.FirstPage()
pageStr += page.PrevPage()
pageStr += page.PageBar("current")
pageStr += page.NextPage()
pageStr += page.LastPage()
return pageStr
}
return ""
2018-04-22 11:26:19 +08:00
}
// 为指定的页面返回地址值
func (page *Page) GetUrl(pageNo int) string {
2019-06-19 09:06:52 +08:00
// 复制一个URL对象
url := *page.Url
if len(page.UrlTemplate) == 0 && page.Router != nil {
page.UrlTemplate = page.makeUrlTemplate(url.Path, page.Router)
}
if len(page.UrlTemplate) > 0 {
// 指定URL生成模板
url.Path = gstr.Replace(page.UrlTemplate, "{.page}", gconv.String(pageNo))
return url.String()
}
2018-08-06 22:38:55 +08:00
2019-06-19 09:06:52 +08:00
values := page.Url.Query()
values.Set(page.PageName, gconv.String(pageNo))
url.RawQuery = values.Encode()
return url.String()
2018-08-06 22:38:55 +08:00
}
// 根据当前URL以及注册路由信息计算出对应的URL模板
func (page *Page) makeUrlTemplate(url string, router *ghttp.Router) (tpl string) {
2019-06-19 09:06:52 +08:00
if page.Router != nil && len(router.RegNames) > 0 {
if match, err := gregex.MatchString(router.RegRule, url); err == nil && len(match) > 0 {
if len(match) > len(router.RegNames) {
tpl = router.Uri
hasPageName := false
for i, name := range router.RegNames {
rule := fmt.Sprintf(`[:\*]%s|\{%s\}`, name, name)
if !hasPageName && strings.Compare(name, page.PageName) == 0 {
hasPageName = true
tpl, _ = gregex.ReplaceString(rule, `{.page}`, tpl)
} else {
tpl, _ = gregex.ReplaceString(rule, match[i+1], tpl)
}
}
if !hasPageName {
tpl = ""
}
}
}
}
return
2018-04-22 11:26:19 +08:00
}
// 获取链接地址
func (page *Page) GetLink(url, text, title, style string) string {
2019-06-19 09:06:52 +08:00
if len(style) > 0 {
style = fmt.Sprintf(`class="%s" `, style)
}
if len(page.AjaxActionName) > 0 {
return fmt.Sprintf(`<a %shref='#' onclick="%s('%s')">%s</a>`, style, page.AjaxActionName, url, text)
} else {
return fmt.Sprintf(`<a %shref="%s" title="%s">%s</a>`, style, url, title, text)
}
2018-04-22 10:07:24 +08:00
}