🌐 AI搜索 & 代理 主页
Skip to content

Commit 3874470

Browse files
committed
feat(b-pagination): add page button class props and option to show first/last page numbers
1 parent 56ed34b commit 3874470

File tree

4 files changed

+114
-62
lines changed

4 files changed

+114
-62
lines changed

src/components/dropdown/dropdown.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,15 @@ export const props = {
2929
default: false
3030
},
3131
menuClass: {
32-
type: [String, Array],
32+
type: [String, Array, Object],
3333
default: null
3434
},
3535
toggleTag: {
3636
type: String,
3737
default: 'button'
3838
},
3939
toggleClass: {
40-
type: [String, Array],
40+
type: [String, Array, Object],
4141
default: null
4242
},
4343
noCaret: {
@@ -61,7 +61,7 @@ export const props = {
6161
default: () => getComponentConfig(NAME, 'splitVariant')
6262
},
6363
splitClass: {
64-
type: [String, Array],
64+
type: [String, Array, Object],
6565
default: null
6666
},
6767
splitButtonType: {

src/mixins/dropdown.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ export default {
213213
if (!this.inNavbar) {
214214
if (typeof Popper === 'undefined') {
215215
/* istanbul ignore next */
216-
warn('b-dropdown: Popper.js not found. Falling back to CSS positioning.')
216+
warn('Popper.js not found. Falling back to CSS positioning', 'BDropdown')
217217
} else {
218218
// for dropup with alignment we use the parent element as popper container
219219
let element = (this.dropup && this.right) || this.split ? this.$el : this.$refs.toggle

src/mixins/pagination.js

Lines changed: 106 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ export const props = {
5555
type: [Number, String],
5656
default: null,
5757
validator(value) /* istanbul ignore next */ {
58-
const num = toInteger(value)
59-
if (!isNull(value) && (isNaN(num) || num < 1)) {
60-
warn('pagination: v-model value must be a number greater than 0')
58+
const number = toInteger(value)
59+
if (!isNull(value) && (isNaN(number) || number < 1)) {
60+
warn('"v-model" value must be a number greater than "0"', 'BPagination')
6161
return false
6262
}
6363
return true
@@ -67,9 +67,9 @@ export const props = {
6767
type: [Number, String],
6868
default: DEFAULT_LIMIT,
6969
validator(value) /* istanbul ignore next */ {
70-
const num = toInteger(value)
71-
if (isNaN(num) || num < 1) {
72-
warn('pagination: prop "limit" must be a number greater than 0')
70+
const number = toInteger(value)
71+
if (isNaN(number) || number < 1) {
72+
warn('Prop "limit" must be a number greater than "0"', 'BPagination')
7373
return false
7474
}
7575
return true
@@ -99,6 +99,14 @@ export const props = {
9999
type: String,
100100
default: '\u00AB' // '«'
101101
},
102+
firstNumber: {
103+
type: Boolean,
104+
default: false
105+
},
106+
firstClass: {
107+
type: [String, Array, Object],
108+
default: null
109+
},
102110
labelPrevPage: {
103111
type: String,
104112
default: 'Go to previous page'
@@ -107,6 +115,10 @@ export const props = {
107115
type: String,
108116
default: '\u2039' // '‹'
109117
},
118+
prevClass: {
119+
type: [String, Array, Object],
120+
default: null
121+
},
110122
labelNextPage: {
111123
type: String,
112124
default: 'Go to next page'
@@ -115,6 +127,10 @@ export const props = {
115127
type: String,
116128
default: '\u203A' // '›'
117129
},
130+
nextClass: {
131+
type: [String, Array, Object],
132+
default: null
133+
},
118134
labelLastPage: {
119135
type: String,
120136
default: 'Go to last page'
@@ -123,17 +139,33 @@ export const props = {
123139
type: String,
124140
default: '\u00BB' // '»'
125141
},
142+
lastNumber: {
143+
type: Boolean,
144+
default: false
145+
},
146+
lastClass: {
147+
type: [String, Array, Object],
148+
default: null
149+
},
126150
labelPage: {
127151
type: [String, Function],
128152
default: 'Go to page'
129153
},
154+
pageClass: {
155+
type: [String, Array, Object],
156+
default: null
157+
},
130158
hideEllipsis: {
131159
type: Boolean,
132160
default: false
133161
},
134162
ellipsisText: {
135163
type: String,
136164
default: '\u2026' // '…'
165+
},
166+
ellipsisClass: {
167+
type: [String, Array, Object],
168+
default: null
137169
}
138170
}
139171

@@ -165,8 +197,8 @@ export default {
165197
} else if (align === 'end' || align === 'right') {
166198
return 'justify-content-end'
167199
} else if (align === 'fill') {
168-
// The page-items will also have 'flex-fill' added.
169-
// We ad text centering to make the button appearance better in fill mode.
200+
// The page-items will also have 'flex-fill' added
201+
// We add text centering to make the button appearance better in fill mode
170202
return 'text-center'
171203
}
172204
return ''
@@ -289,14 +321,13 @@ export default {
289321
},
290322
methods: {
291323
handleKeyNav(evt) {
292-
const keyCode = evt.keyCode
293-
const shift = evt.shiftKey
324+
const { keyCode, shiftKey } = evt
294325
if (keyCode === KeyCodes.LEFT || keyCode === KeyCodes.UP) {
295326
evt.preventDefault()
296-
shift ? this.focusFirst() : this.focusPrev()
327+
shiftKey ? this.focusFirst() : this.focusPrev()
297328
} else if (keyCode === KeyCodes.RIGHT || keyCode === KeyCodes.DOWN) {
298329
evt.preventDefault()
299-
shift ? this.focusLast() : this.focusNext()
330+
shiftKey ? this.focusLast() : this.focusNext()
300331
}
301332
},
302333
getButtons() {
@@ -307,7 +338,7 @@ export default {
307338
btn.focus()
308339
},
309340
focusCurrent() {
310-
// We do this in next tick to ensure buttons have finished rendering
341+
// We do this in `$nextTick()` to ensure buttons have finished rendering
311342
this.$nextTick(() => {
312343
const btn = this.getButtons().find(
313344
el => toInteger(getAttr(el, 'aria-posinset')) === this.computedCurrentPage
@@ -321,7 +352,7 @@ export default {
321352
})
322353
},
323354
focusFirst() {
324-
// We do this in next tick to ensure buttons have finished rendering
355+
// We do this in `$nextTick()` to ensure buttons have finished rendering
325356
this.$nextTick(() => {
326357
const btn = this.getButtons().find(el => !isDisabled(el))
327358
if (btn && btn.focus && btn !== document.activeElement) {
@@ -330,7 +361,7 @@ export default {
330361
})
331362
},
332363
focusLast() {
333-
// We do this in next tick to ensure buttons have finished rendering
364+
// We do this in `$nextTick()` to ensure buttons have finished rendering
334365
this.$nextTick(() => {
335366
const btn = this.getButtons()
336367
.reverse()
@@ -341,7 +372,7 @@ export default {
341372
})
342373
},
343374
focusPrev() {
344-
// We do this in next tick to ensure buttons have finished rendering
375+
// We do this in `$nextTick()` to ensure buttons have finished rendering
345376
this.$nextTick(() => {
346377
const buttons = this.getButtons()
347378
const idx = buttons.indexOf(document.activeElement)
@@ -351,7 +382,7 @@ export default {
351382
})
352383
},
353384
focusNext() {
354-
// We do this in next tick to ensure buttons have finished rendering
385+
// We do this in `$nextTick()` to ensure buttons have finished rendering
355386
this.$nextTick(() => {
356387
const buttons = this.getButtons()
357388
const idx = buttons.indexOf(document.activeElement)
@@ -365,19 +396,20 @@ export default {
365396
render(h) {
366397
const buttons = []
367398
const numberOfPages = this.localNumberOfPages
399+
const pageNumbers = this.pageList.map(p => p.number)
368400
const disabled = this.disabled
369401
const { showFirstDots, showLastDots } = this.paginationParams
370402
const currentPage = this.computedCurrentPage
371403
const fill = this.align === 'fill'
372404

373405
// Helper function and flag
374406
const isActivePage = pageNum => pageNum === currentPage
375-
const noCurrPage = this.currentPage < 1
407+
const noCurrentPage = this.currentPage < 1
376408

377409
// Factory function for prev/next/first/last buttons
378-
const makeEndBtn = (linkTo, ariaLabel, btnSlot, btnText, pageTest, key) => {
410+
const makeEndBtn = (linkTo, ariaLabel, btnSlot, btnText, btnClass, pageTest, key) => {
379411
const isDisabled =
380-
disabled || isActivePage(pageTest) || noCurrPage || linkTo < 1 || linkTo > numberOfPages
412+
disabled || isActivePage(pageTest) || noCurrentPage || linkTo < 1 || linkTo > numberOfPages
381413
const pageNum = linkTo < 1 ? 1 : linkTo > numberOfPages ? numberOfPages : linkTo
382414
const scope = { disabled: isDisabled, page: pageNum, index: pageNum - 1 }
383415
const btnContent = this.normalizeSlot(btnSlot, scope) || toString(btnText) || h()
@@ -409,7 +441,7 @@ export default {
409441
{
410442
key,
411443
staticClass: 'page-item',
412-
class: { disabled: isDisabled, 'flex-fill': fill },
444+
class: [{ disabled: isDisabled, 'flex-fill': fill }, btnClass],
413445
attrs: {
414446
role: 'presentation',
415447
'aria-hidden': isDisabled ? 'true' : null
@@ -426,7 +458,7 @@ export default {
426458
{
427459
key: `ellipsis-${isLast ? 'last' : 'first'}`,
428460
staticClass: 'page-item',
429-
class: ['disabled', 'bv-d-xs-down-none', fill ? 'flex-fill' : ''],
461+
class: ['disabled', 'bv-d-xs-down-none', fill ? 'flex-fill' : '', this.ellipsisClass],
430462
attrs: { role: 'separator' }
431463
},
432464
[
@@ -437,33 +469,47 @@ export default {
437469
)
438470
}
439471

440-
// Goto First Page button bookend
441-
buttons.push(
442-
this.hideGotoEndButtons
472+
// Goto first page button bookend
473+
// Don't render button when `hideGotoEndButtons` is set or when
474+
// `firstNumber` is enabled and the first page is in the page list
475+
const $firstPageBtn =
476+
this.hideGotoEndButtons || (this.firstNumber && pageNumbers.indexOf(1) !== -1)
443477
? h()
444-
: makeEndBtn(1, this.labelFirstPage, 'first-text', this.firstText, 1, 'bookend-goto-first')
478+
: makeEndBtn(
479+
1,
480+
this.labelFirstPage,
481+
'first-text',
482+
this.firstNumber ? '1' : this.firstText,
483+
this.firstClass,
484+
1,
485+
'bookend-goto-first'
486+
)
487+
488+
// Goto previous page button bookend
489+
const $prevPageBtn = makeEndBtn(
490+
currentPage - 1,
491+
this.labelPrevPage,
492+
'prev-text',
493+
this.prevText,
494+
this.prevClass,
495+
1,
496+
'bookend-goto-prev'
445497
)
446498

447-
// Goto Previous page button bookend
499+
// When `firstNumber` prop is set we move the previous page button
500+
// before the first page button
448501
buttons.push(
449-
makeEndBtn(
450-
currentPage - 1,
451-
this.labelPrevPage,
452-
'prev-text',
453-
this.prevText,
454-
1,
455-
'bookend-goto-prev'
456-
)
502+
...(this.firstNumber ? [$prevPageBtn, $firstPageBtn] : [$firstPageBtn, $prevPageBtn])
457503
)
458504

459505
// First Ellipsis Bookend
460506
buttons.push(showFirstDots ? makeEllipsis(false) : h())
461507

462-
// Individual Page links
508+
// Individual page links
463509
this.pageList.forEach((page, idx) => {
464-
const active = isActivePage(page.number) && !noCurrPage
510+
const active = isActivePage(page.number) && !noCurrentPage
465511
// Active page will have tabindex of 0, or if no current page and first page button
466-
const tabIndex = disabled ? null : active || (noCurrPage && idx === 0) ? '0' : '-1'
512+
const tabIndex = disabled ? null : active || (noCurrentPage && idx === 0) ? '0' : '-1'
467513
const attrs = {
468514
role: 'menuitemradio',
469515
'aria-disabled': disabled ? 'true' : null,
@@ -508,42 +554,47 @@ export default {
508554
{
509555
key: `page-${page.number}`,
510556
staticClass: 'page-item',
511-
class: [{ disabled, active, 'flex-fill': fill }, page.classes],
557+
class: [{ disabled, active, 'flex-fill': fill }, page.classes, this.pageClass],
512558
attrs: { role: 'presentation' }
513559
},
514560
[inner]
515561
)
516562
)
517563
})
518564

519-
// Last Ellipsis Bookend
565+
// Last ellipsis bookend
520566
buttons.push(showLastDots ? makeEllipsis(true) : h())
521567

522-
// Goto Next page button bookend
523-
buttons.push(
524-
makeEndBtn(
525-
currentPage + 1,
526-
this.labelNextPage,
527-
'next-text',
528-
this.nextText,
529-
numberOfPages,
530-
'bookend-goto-next'
531-
)
568+
// Goto next page button bookend
569+
const $nextPageBtn = makeEndBtn(
570+
currentPage + 1,
571+
this.labelNextPage,
572+
'next-text',
573+
this.nextText,
574+
this.nextClass,
575+
numberOfPages,
576+
'bookend-goto-next'
532577
)
533578

534-
// Goto Last Page button bookend
535-
buttons.push(
536-
this.hideGotoEndButtons
579+
// Goto last page button bookend
580+
// Don't render button when `hideGotoEndButtons` is set or when
581+
// `lastNumber` is enabled and the last page is in the page list
582+
const $lastPageBtn =
583+
this.hideGotoEndButtons || (this.lastNumber && pageNumbers.indexOf(numberOfPages) !== -1)
537584
? h()
538585
: makeEndBtn(
539586
numberOfPages,
540587
this.labelLastPage,
541588
'last-text',
542-
this.lastText,
589+
this.lastNumber ? toString(numberOfPages) : this.lastText,
590+
this.lastClass,
543591
numberOfPages,
544592
'bookend-goto-last'
545593
)
546-
)
594+
595+
// When `lastNumber` prop is set we move the next page button
596+
// after the last page button
597+
buttons.push(...(this.lastNumber ? [$lastPageBtn, $nextPageBtn] : [$nextPageBtn, $lastPageBtn]))
547598

548599
// Assemble the pagination buttons
549600
const pagination = h(

0 commit comments

Comments
 (0)