pagination.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. import Pager from './pager.vue';
  2. import ElSelect from 'element-ui/packages/select';
  3. import ElOption from 'element-ui/packages/option';
  4. import ElInput from 'element-ui/packages/input';
  5. import Locale from 'element-ui/src/mixins/locale';
  6. import { valueEquals } from 'element-ui/src/utils/util';
  7. export default {
  8. name: 'ElPagination',
  9. props: {
  10. pageSize: {
  11. type: Number,
  12. default: 10
  13. },
  14. small: Boolean,
  15. total: Number,
  16. pageCount: Number,
  17. pagerCount: {
  18. type: Number,
  19. validator(value) {
  20. return (value | 0) === value && value > 4 && value < 22 && (value % 2) === 1;
  21. },
  22. default: 7
  23. },
  24. currentPage: {
  25. type: Number,
  26. default: 1
  27. },
  28. layout: {
  29. default: 'prev, pager, next, jumper, ->, total'
  30. },
  31. pageSizes: {
  32. type: Array,
  33. default() {
  34. return [10, 20, 30, 40, 50, 100];
  35. }
  36. },
  37. popperClass: String,
  38. prevText: String,
  39. nextText: String,
  40. background: Boolean,
  41. disabled: Boolean,
  42. hideOnSinglePage: Boolean
  43. },
  44. data() {
  45. return {
  46. internalCurrentPage: 1,
  47. internalPageSize: 0,
  48. lastEmittedPage: -1,
  49. userChangePageSize: false
  50. };
  51. },
  52. render(h) {
  53. const layout = this.layout;
  54. if (!layout) return null;
  55. if (this.hideOnSinglePage && (!this.internalPageCount || this.internalPageCount === 1)) return null;
  56. let template = <div class={['el-pagination', {
  57. 'is-background': this.background,
  58. 'el-pagination--small': this.small
  59. }] }></div>;
  60. const TEMPLATE_MAP = {
  61. prev: <prev></prev>,
  62. jumper: <jumper></jumper>,
  63. pager: <pager currentPage={ this.internalCurrentPage } pageCount={ this.internalPageCount } pagerCount={ this.pagerCount } on-change={ this.handleCurrentChange } disabled={ this.disabled }></pager>,
  64. next: <next></next>,
  65. sizes: <sizes pageSizes={ this.pageSizes }></sizes>,
  66. slot: <slot>{ this.$slots.default ? this.$slots.default : '' }</slot>,
  67. total: <total></total>
  68. };
  69. const components = layout.split(',').map((item) => item.trim());
  70. const rightWrapper = <div class="el-pagination__rightwrapper"></div>;
  71. let haveRightWrapper = false;
  72. template.children = template.children || [];
  73. rightWrapper.children = rightWrapper.children || [];
  74. components.forEach(compo => {
  75. if (compo === '->') {
  76. haveRightWrapper = true;
  77. return;
  78. }
  79. if (!haveRightWrapper) {
  80. template.children.push(TEMPLATE_MAP[compo]);
  81. } else {
  82. rightWrapper.children.push(TEMPLATE_MAP[compo]);
  83. }
  84. });
  85. if (haveRightWrapper) {
  86. template.children.unshift(rightWrapper);
  87. }
  88. return template;
  89. },
  90. components: {
  91. Prev: {
  92. render(h) {
  93. return (
  94. <button
  95. type="button"
  96. class="btn-prev"
  97. disabled={ this.$parent.disabled || this.$parent.internalCurrentPage <= 1 }
  98. on-click={ this.$parent.prev }>
  99. {
  100. this.$parent.prevText
  101. ? <span>{ this.$parent.prevText }</span>
  102. : <i class="el-icon el-icon-arrow-left"></i>
  103. }
  104. </button>
  105. );
  106. }
  107. },
  108. Next: {
  109. render(h) {
  110. return (
  111. <button
  112. type="button"
  113. class="btn-next"
  114. disabled={ this.$parent.disabled || this.$parent.internalCurrentPage === this.$parent.internalPageCount || this.$parent.internalPageCount === 0 }
  115. on-click={ this.$parent.next }>
  116. {
  117. this.$parent.nextText
  118. ? <span>{ this.$parent.nextText }</span>
  119. : <i class="el-icon el-icon-arrow-right"></i>
  120. }
  121. </button>
  122. );
  123. }
  124. },
  125. Sizes: {
  126. mixins: [Locale],
  127. props: {
  128. pageSizes: Array
  129. },
  130. watch: {
  131. pageSizes: {
  132. immediate: true,
  133. handler(newVal, oldVal) {
  134. if (valueEquals(newVal, oldVal)) return;
  135. if (Array.isArray(newVal)) {
  136. this.$parent.internalPageSize = newVal.indexOf(this.$parent.pageSize) > -1
  137. ? this.$parent.pageSize
  138. : this.pageSizes[0];
  139. }
  140. }
  141. }
  142. },
  143. render(h) {
  144. return (
  145. <span class="el-pagination__sizes">
  146. <el-select
  147. value={ this.$parent.internalPageSize }
  148. popperClass={ this.$parent.popperClass || '' }
  149. size="mini"
  150. on-input={ this.handleChange }
  151. disabled={ this.$parent.disabled }>
  152. {
  153. this.pageSizes.map(item =>
  154. <el-option
  155. value={ item }
  156. label={ item + this.t('el.pagination.pagesize') }>
  157. </el-option>
  158. )
  159. }
  160. </el-select>
  161. </span>
  162. );
  163. },
  164. components: {
  165. ElSelect,
  166. ElOption
  167. },
  168. methods: {
  169. handleChange(val) {
  170. if (val !== this.$parent.internalPageSize) {
  171. this.$parent.internalPageSize = val = parseInt(val, 10);
  172. this.$parent.userChangePageSize = true;
  173. this.$parent.$emit('update:pageSize', val);
  174. this.$parent.$emit('size-change', val);
  175. }
  176. }
  177. }
  178. },
  179. Jumper: {
  180. mixins: [Locale],
  181. components: { ElInput },
  182. data() {
  183. return {
  184. userInput: null
  185. };
  186. },
  187. watch: {
  188. '$parent.internalCurrentPage'() {
  189. this.userInput = null;
  190. }
  191. },
  192. methods: {
  193. handleKeyup({ keyCode, target }) {
  194. // Chrome, Safari, Firefox triggers change event on Enter
  195. // Hack for IE: https://github.com/ElemeFE/element/issues/11710
  196. // Drop this method when we no longer supports IE
  197. if (keyCode === 13) {
  198. this.handleChange(target.value);
  199. }
  200. },
  201. handleInput(value) {
  202. this.userInput = value;
  203. },
  204. handleChange(value) {
  205. this.$parent.internalCurrentPage = this.$parent.getValidCurrentPage(value);
  206. this.$parent.emitChange();
  207. this.userInput = null;
  208. }
  209. },
  210. render(h) {
  211. return (
  212. <span class="el-pagination__jump">
  213. { this.t('el.pagination.goto') }
  214. <el-input
  215. class="el-pagination__editor is-in-pagination"
  216. min={ 1 }
  217. max={ this.$parent.internalPageCount }
  218. value={ this.userInput !== null ? this.userInput : this.$parent.internalCurrentPage }
  219. type="number"
  220. disabled={ this.$parent.disabled }
  221. nativeOnKeyup={ this.handleKeyup }
  222. onInput={ this.handleInput }
  223. onChange={ this.handleChange }/>
  224. { this.t('el.pagination.pageClassifier') }
  225. </span>
  226. );
  227. }
  228. },
  229. Total: {
  230. mixins: [Locale],
  231. render(h) {
  232. return (
  233. typeof this.$parent.total === 'number'
  234. ? <span class="el-pagination__total">{ this.t('el.pagination.total', { total: this.$parent.total }) }</span>
  235. : ''
  236. );
  237. }
  238. },
  239. Pager
  240. },
  241. methods: {
  242. handleCurrentChange(val) {
  243. this.internalCurrentPage = this.getValidCurrentPage(val);
  244. this.userChangePageSize = true;
  245. this.emitChange();
  246. },
  247. prev() {
  248. if (this.disabled) return;
  249. const newVal = this.internalCurrentPage - 1;
  250. this.internalCurrentPage = this.getValidCurrentPage(newVal);
  251. this.$emit('prev-click', this.internalCurrentPage);
  252. this.emitChange();
  253. },
  254. next() {
  255. if (this.disabled) return;
  256. const newVal = this.internalCurrentPage + 1;
  257. this.internalCurrentPage = this.getValidCurrentPage(newVal);
  258. this.$emit('next-click', this.internalCurrentPage);
  259. this.emitChange();
  260. },
  261. getValidCurrentPage(value) {
  262. value = parseInt(value, 10);
  263. const havePageCount = typeof this.internalPageCount === 'number';
  264. let resetValue;
  265. if (!havePageCount) {
  266. if (isNaN(value) || value < 1) resetValue = 1;
  267. } else {
  268. if (value < 1) {
  269. resetValue = 1;
  270. } else if (value > this.internalPageCount) {
  271. resetValue = this.internalPageCount;
  272. }
  273. }
  274. if (resetValue === undefined && isNaN(value)) {
  275. resetValue = 1;
  276. } else if (resetValue === 0) {
  277. resetValue = 1;
  278. }
  279. return resetValue === undefined ? value : resetValue;
  280. },
  281. emitChange() {
  282. this.$nextTick(() => {
  283. if (this.internalCurrentPage !== this.lastEmittedPage || this.userChangePageSize) {
  284. this.$emit('current-change', this.internalCurrentPage);
  285. this.lastEmittedPage = this.internalCurrentPage;
  286. this.userChangePageSize = false;
  287. }
  288. });
  289. }
  290. },
  291. computed: {
  292. internalPageCount() {
  293. if (typeof this.total === 'number') {
  294. return Math.max(1, Math.ceil(this.total / this.internalPageSize));
  295. } else if (typeof this.pageCount === 'number') {
  296. return Math.max(1, this.pageCount);
  297. }
  298. return null;
  299. }
  300. },
  301. watch: {
  302. currentPage: {
  303. immediate: true,
  304. handler(val) {
  305. this.internalCurrentPage = this.getValidCurrentPage(val);
  306. }
  307. },
  308. pageSize: {
  309. immediate: true,
  310. handler(val) {
  311. this.internalPageSize = isNaN(val) ? 10 : val;
  312. }
  313. },
  314. internalCurrentPage: {
  315. immediate: true,
  316. handler(newVal) {
  317. this.$emit('update:currentPage', newVal);
  318. this.lastEmittedPage = -1;
  319. }
  320. },
  321. internalPageCount(newVal) {
  322. /* istanbul ignore if */
  323. const oldPage = this.internalCurrentPage;
  324. if (newVal > 0 && oldPage === 0) {
  325. this.internalCurrentPage = 1;
  326. } else if (oldPage > newVal) {
  327. this.internalCurrentPage = newVal === 0 ? 1 : newVal;
  328. this.userChangePageSize && this.emitChange();
  329. }
  330. this.userChangePageSize = false;
  331. }
  332. }
  333. };