import { HorizontalLayout, Widget, shortcut, extend, emptyFn, result, isKey, createWidget, map, stripEL, formatEL, Controller, Events, MIN, MAX } from "@/core"; import { Label } from "../single"; import { ButtonGroup } from "../combination"; /** * 分页控件 * * Created by GUY on 2015/8/31. * @class Pager * @extends Widget */ @shortcut() export class Pager extends Widget { _defaultConfig() { return extend(super._defaultConfig(...arguments), { baseCls: "bi-pager", behaviors: {}, layouts: [ { type: HorizontalLayout.xtype, hgap: 10, vgap: 0, } ], dynamicShow: true, // 是否动态显示上一页、下一页、首页、尾页, 若为false,则指对其设置使能状态 // dynamicShow为false时以下两个有用 dynamicShowFirstLast: false, // 是否动态显示首页、尾页 dynamicShowPrevNext: false, // 是否动态显示上一页、下一页 pages: false, // 总页数 curr: () => 1, // 初始化当前页 groups: 0, // 连续显示分页数 jump: emptyFn, // 分页的回调函数 first: false, // 是否显示首页 last: false, // 是否显示尾页 prev: "上一页", next: "下一页", firstPage: 1, lastPage: () => // 在万不得已时才会调用这个函数获取最后一页的页码, 主要作用于setValue方法 1, hasPrev: emptyFn, // pages不可用时有效 hasNext: emptyFn, // pages不可用时有效 }); } static xtype = "bi.pager"; static EVENT_CHANGE = "EVENT_CHANGE"; static EVENT_AFTER_POPULATE = "EVENT_AFTER_POPULATE"; render() { this.currPage = result(this.options, "curr"); // 翻页太灵敏 // this._lock = false; // this._debouce = debounce(function () { // self._lock = false; // }, 300); this._populate(); } _populate() { const o = this.options, view = [], dict = {}; const { dynamicShow, dynamicShowPrevNext, hasPrev, dynamicShowFirstLast, hasNext, behaviors, layouts, jump } = this.options; this.empty(); const pages = result(o, "pages"); const curr = result(this, "currPage"); let groups = result(o, "groups"); let first = result(o, "first"); let last = result(o, "last"); const prev = result(o, "prev"); const next = result(o, "next"); if (pages === false) { groups = 0; first = false; last = false; } else { groups > pages && (groups = pages); } // 计算当前组 dict.index = Math.ceil((curr + (groups > 1 && groups !== pages ? 1 : 0)) / (groups === 0 ? 1 : groups)); // 当前页非首页,则输出上一页 if (((!dynamicShow && !dynamicShowPrevNext) || curr > 1) && prev !== false) { if (isKey(prev)) { view.push({ text: prev, value: "prev", disabled: pages === false ? hasPrev(curr) === false : !(curr > 1 && prev !== false), }); } else { view.push({ el: extend( { disabled: pages === false ? hasPrev(curr) === false : !(curr > 1 && prev !== false), }, prev ), }); } } // 当前组非首组,则输出首页 if (((!dynamicShow && !dynamicShowFirstLast) || (dict.index > 1 && groups !== 0)) && first) { view.push({ text: first, value: "first", disabled: !(dict.index > 1 && groups !== 0), }); if (dict.index > 1 && groups !== 0 && groups !== pages - 1) { view.push({ type: Label.xtype, cls: "page-ellipsis", text: "\u2026", }); } } // 输出当前页组 dict.poor = Math.floor((groups - 1) / 2); dict.start = dict.index > 1 ? curr - dict.poor : 1; dict.end = dict.index > 1 ? (function () { const max = curr + (groups - dict.poor - 1); return max > pages ? pages : max; }()) : groups; if (dict.end - dict.start < groups - 1) { // 最后一组状态 dict.start = dict.end - groups + 1; } let s = dict.start, e = dict.end; if (first && last && dict.index > 1 && groups !== 0 && pages > groups && dict.end < pages && groups !== 0) { s++; e--; } for (; s <= e; s++) { if (s === curr) { view.push({ text: s, value: s, selected: true, }); } else { view.push({ text: s, value: s, }); } } // 总页数大于连续分页数,且当前组最大页小于总页,输出尾页 if (((!dynamicShow && !dynamicShowFirstLast) || (pages > groups && dict.end < pages && groups !== 0)) && last) { if (pages > groups && dict.end < pages && groups !== 0 && groups !== pages - 1) { view.push({ type: Label.xtype, cls: "page-ellipsis", text: "\u2026", }); } view.push({ text: last, value: "last", disabled: !(pages > groups && dict.end < pages && groups !== 0), }); } // 当前页不为尾页时,输出下一页 dict.flow = !prev && groups === 0; if ((!dynamicShow && !dynamicShowPrevNext && next) || (curr !== pages && next) || dict.flow) { view.push( (function () { if (isKey(next)) { if (pages === false) { return { text: next, value: "next", disabled: hasNext(curr) === false }; } return dict.flow && curr === pages ? { text: next, value: "next", disabled: true } : { text: next, value: "next", disabled: !((curr !== pages && next) || dict.flow) }; } return { el: extend( { disabled: pages === false ? hasNext(curr) === false : !((curr !== pages && next) || dict.flow), }, next ), }; })() ); } this.button_group = createWidget({ type: ButtonGroup.xtype, element: this, items: map(view, (idx, v) => { v = extend( { cls: "bi-list-item-select bi-border-radius", height: 23, hgap: v.el ? 0 : 10, stopPropagation: true, }, stripEL(v) ); return formatEL(v); }), behaviors, layouts, }); this.button_group.on(Controller.EVENT_CHANGE, (type, value, obj, ...args) => { // if (self._lock === true) { // return; // } // self._lock = true; // self._debouce(); if (type === Events.CLICK) { const v = this.button_group.getValue()[0]; switch (v) { case "first": this.currPage = 1; break; case "last": this.currPage = pages; break; case "prev": this.currPage--; break; case "next": this.currPage++; break; default: this.currPage = v; break; } jump.apply(this, [ { pages, curr: this.currPage, } ]); this._populate(); this.fireEvent(Pager.EVENT_CHANGE, obj); } this.fireEvent(Controller.EVENT_CHANGE, type, value, obj, ...args); }); this.fireEvent(Pager.EVENT_AFTER_POPULATE); } getCurrentPage() { return this.currPage; } setAllPages(pages) { this.options.pages = pages; this._populate(); } hasPrev(v) { v || (v = 1); const { pages, hasPrev } = this.options; return pages === false ? hasPrev(v) : v > 1; } hasNext(v) { v || (v = 1); const { pages, hasNext } = this.options; return pages === false ? hasNext(v) : v < pages; } setValue(v) { const o = this.options; const { pages } = this.options; v = v || 0; v = v < 1 ? 1 : v; if (pages === false) { const lastPage = result(o, "lastPage"); let firstPage = 1; this.currPage = v > lastPage ? lastPage : ((firstPage = result(o, "firstPage")), v < firstPage ? firstPage : v); } else { v = v > pages ? pages : v; this.currPage = v; } this._populate(); } getValue() { const val = this.button_group.getValue()[0]; switch (val) { case "prev": return -1; case "next": return 1; case "first": return MIN; case "last": return MAX; default: return val; } } attr(key, value) { super.attr(...arguments); if (key === "curr") { this.currPage = result(this.options, "curr"); } } populate() { this._populate(); } }