pagination.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  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 > 4 && value < 22 && (value | 0) === value && (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. },
  43. data() {
  44. return {
  45. internalCurrentPage: 1,
  46. internalPageSize: 0,
  47. lastEmittedPage: -1,
  48. userChangePageSize: false
  49. };
  50. },
  51. render(h) {
  52. let template = <div class={['el-pagination', {
  53. 'is-background': this.background,
  54. 'el-pagination--small': this.small
  55. }] }></div>;
  56. const layout = this.layout || '';
  57. if (!layout) return;
  58. const TEMPLATE_MAP = {
  59. prev: <prev></prev>,
  60. jumper: <jumper></jumper>,
  61. pager: <pager currentPage={ this.internalCurrentPage } pageCount={ this.internalPageCount } pagerCount={ this.pagerCount } on-change={ this.handleCurrentChange } disabled={ this.disabled }></pager>,
  62. next: <next></next>,
  63. sizes: <sizes pageSizes={ this.pageSizes }></sizes>,
  64. slot: <my-slot></my-slot>,
  65. total: <total></total>
  66. };
  67. const components = layout.split(',').map((item) => item.trim());
  68. const rightWrapper = <div class="el-pagination__rightwrapper"></div>;
  69. let haveRightWrapper = false;
  70. template.children = template.children || [];
  71. rightWrapper.children = rightWrapper.children || [];
  72. components.forEach(compo => {
  73. if (compo === '->') {
  74. haveRightWrapper = true;
  75. return;
  76. }
  77. if (!haveRightWrapper) {
  78. template.children.push(TEMPLATE_MAP[compo]);
  79. } else {
  80. rightWrapper.children.push(TEMPLATE_MAP[compo]);
  81. }
  82. });
  83. if (haveRightWrapper) {
  84. template.children.unshift(rightWrapper);
  85. }
  86. return template;
  87. },
  88. components: {
  89. MySlot: {
  90. render(h) {
  91. return (
  92. this.$parent.$slots.default
  93. ? this.$parent.$slots.default[0]
  94. : ''
  95. );
  96. }
  97. },
  98. Prev: {
  99. render(h) {
  100. return (
  101. <button
  102. type="button"
  103. class="btn-prev"
  104. disabled={ this.$parent.disabled || this.$parent.internalCurrentPage <= 1 }
  105. on-click={ this.$parent.prev }>
  106. {
  107. this.$parent.prevText
  108. ? <span>{ this.$parent.prevText }</span>
  109. : <i class="el-icon el-icon-arrow-left"></i>
  110. }
  111. </button>
  112. );
  113. }
  114. },
  115. Next: {
  116. render(h) {
  117. return (
  118. <button
  119. type="button"
  120. class="btn-next"
  121. disabled={ this.$parent.disabled || this.$parent.internalCurrentPage === this.$parent.internalPageCount || this.$parent.internalPageCount === 0 }
  122. on-click={ this.$parent.next }>
  123. {
  124. this.$parent.nextText
  125. ? <span>{ this.$parent.nextText }</span>
  126. : <i class="el-icon el-icon-arrow-right"></i>
  127. }
  128. </button>
  129. );
  130. }
  131. },
  132. Sizes: {
  133. mixins: [Locale],
  134. props: {
  135. pageSizes: Array
  136. },
  137. watch: {
  138. pageSizes: {
  139. immediate: true,
  140. handler(newVal, oldVal) {
  141. if (valueEquals(newVal, oldVal)) return;
  142. if (Array.isArray(newVal)) {
  143. this.$parent.internalPageSize = newVal.indexOf(this.$parent.pageSize) > -1
  144. ? this.$parent.pageSize
  145. : this.pageSizes[0];
  146. }
  147. }
  148. }
  149. },
  150. render(h) {
  151. return (
  152. <span class="el-pagination__sizes">
  153. <el-select
  154. value={ this.$parent.internalPageSize }
  155. popperClass={ this.$parent.popperClass || '' }
  156. on-input={ this.handleChange }
  157. disabled={ this.$parent.disabled }>
  158. {
  159. this.pageSizes.map(item =>
  160. <el-option
  161. value={ item }
  162. label={ item + this.t('el.pagination.pagesize') }>
  163. </el-option>
  164. )
  165. }
  166. </el-select>
  167. </span>
  168. );
  169. },
  170. components: {
  171. ElSelect,
  172. ElOption
  173. },
  174. methods: {
  175. handleChange(val) {
  176. if (val !== this.$parent.internalPageSize) {
  177. this.$parent.internalPageSize = val = parseInt(val, 10);
  178. this.$parent.userChangePageSize = true;
  179. this.$parent.$emit('size-change', val);
  180. }
  181. }
  182. }
  183. },
  184. Jumper: {
  185. mixins: [Locale],
  186. data() {
  187. return {
  188. oldValue: null
  189. };
  190. },
  191. components: { ElInput },
  192. watch: {
  193. '$parent.internalPageSize'() {
  194. this.$nextTick(() => {
  195. this.$refs.input.$el.querySelector('input').value = this.$parent.internalCurrentPage;
  196. });
  197. }
  198. },
  199. methods: {
  200. handleFocus(event) {
  201. this.oldValue = event.target.value;
  202. },
  203. handleBlur({ target }) {
  204. this.resetValueIfNeed(target.value);
  205. this.reassignMaxValue(target.value);
  206. },
  207. handleKeyup({ keyCode, target }) {
  208. if (keyCode === 13 && this.oldValue && target.value !== this.oldValue) {
  209. this.handleChange(target.value);
  210. }
  211. },
  212. handleChange(value) {
  213. this.$parent.internalCurrentPage = this.$parent.getValidCurrentPage(value);
  214. this.$parent.emitChange();
  215. this.oldValue = null;
  216. this.resetValueIfNeed(value);
  217. },
  218. resetValueIfNeed(value) {
  219. const num = parseInt(value, 10);
  220. if (!isNaN(num)) {
  221. if (num < 1) {
  222. this.$refs.input.$el.querySelector('input').value = 1;
  223. } else {
  224. this.reassignMaxValue(value);
  225. }
  226. }
  227. },
  228. reassignMaxValue(value) {
  229. if (+value > this.$parent.internalPageCount) {
  230. this.$refs.input.$el.querySelector('input').value = this.$parent.internalPageCount;
  231. }
  232. }
  233. },
  234. render(h) {
  235. return (
  236. <span class="el-pagination__jump">
  237. { this.t('el.pagination.goto') }
  238. <el-input
  239. class="el-pagination__editor is-in-pagination"
  240. min={ 1 }
  241. max={ this.$parent.internalPageCount }
  242. value={ this.$parent.internalCurrentPage }
  243. domPropsValue={ this.$parent.internalCurrentPage }
  244. type="number"
  245. ref="input"
  246. disabled={ this.$parent.disabled }
  247. nativeOnKeyup={ this.handleKeyup }
  248. onChange={ this.handleChange }
  249. onFocus={ this.handleFocus }
  250. onBlur={ this.handleBlur }/>
  251. { this.t('el.pagination.pageClassifier') }
  252. </span>
  253. );
  254. }
  255. },
  256. Total: {
  257. mixins: [Locale],
  258. render(h) {
  259. return (
  260. typeof this.$parent.total === 'number'
  261. ? <span class="el-pagination__total">{ this.t('el.pagination.total', { total: this.$parent.total }) }</span>
  262. : ''
  263. );
  264. }
  265. },
  266. Pager
  267. },
  268. methods: {
  269. handleCurrentChange(val) {
  270. this.internalCurrentPage = this.getValidCurrentPage(val);
  271. this.userChangePageSize = true;
  272. this.emitChange();
  273. },
  274. prev() {
  275. if (this.disabled) return;
  276. const newVal = this.internalCurrentPage - 1;
  277. this.internalCurrentPage = this.getValidCurrentPage(newVal);
  278. this.$emit('prev-click', this.internalCurrentPage);
  279. this.emitChange();
  280. },
  281. next() {
  282. if (this.disabled) return;
  283. const newVal = this.internalCurrentPage + 1;
  284. this.internalCurrentPage = this.getValidCurrentPage(newVal);
  285. this.$emit('next-click', this.internalCurrentPage);
  286. this.emitChange();
  287. },
  288. getValidCurrentPage(value) {
  289. value = parseInt(value, 10);
  290. const havePageCount = typeof this.internalPageCount === 'number';
  291. let resetValue;
  292. if (!havePageCount) {
  293. if (isNaN(value) || value < 1) resetValue = 1;
  294. } else {
  295. if (value < 1) {
  296. resetValue = 1;
  297. } else if (value > this.internalPageCount) {
  298. resetValue = this.internalPageCount;
  299. }
  300. }
  301. if (resetValue === undefined && isNaN(value)) {
  302. resetValue = 1;
  303. } else if (resetValue === 0) {
  304. resetValue = 1;
  305. }
  306. return resetValue === undefined ? value : resetValue;
  307. },
  308. emitChange() {
  309. this.$nextTick(() => {
  310. if (this.internalCurrentPage !== this.lastEmittedPage || this.userChangePageSize) {
  311. this.$emit('current-change', this.internalCurrentPage);
  312. this.lastEmittedPage = this.internalCurrentPage;
  313. this.userChangePageSize = false;
  314. }
  315. });
  316. }
  317. },
  318. computed: {
  319. internalPageCount() {
  320. if (typeof this.total === 'number') {
  321. return Math.ceil(this.total / this.internalPageSize);
  322. } else if (typeof this.pageCount === 'number') {
  323. return this.pageCount;
  324. }
  325. return null;
  326. }
  327. },
  328. watch: {
  329. currentPage: {
  330. immediate: true,
  331. handler(val) {
  332. this.internalCurrentPage = val;
  333. }
  334. },
  335. pageSize: {
  336. immediate: true,
  337. handler(val) {
  338. this.internalPageSize = isNaN(val) ? 10 : val;
  339. }
  340. },
  341. internalCurrentPage: {
  342. immediate: true,
  343. handler(newVal, oldVal) {
  344. newVal = parseInt(newVal, 10);
  345. /* istanbul ignore if */
  346. if (isNaN(newVal)) {
  347. newVal = oldVal || 1;
  348. } else {
  349. newVal = this.getValidCurrentPage(newVal);
  350. }
  351. if (newVal !== undefined) {
  352. this.internalCurrentPage = newVal;
  353. if (oldVal !== newVal) {
  354. this.$emit('update:currentPage', newVal);
  355. }
  356. } else {
  357. this.$emit('update:currentPage', newVal);
  358. }
  359. }
  360. },
  361. internalPageCount(newVal) {
  362. /* istanbul ignore if */
  363. const oldPage = this.internalCurrentPage;
  364. if (newVal > 0 && oldPage === 0) {
  365. this.internalCurrentPage = 1;
  366. } else if (oldPage > newVal) {
  367. this.internalCurrentPage = newVal === 0 ? 1 : newVal;
  368. this.userChangePageSize && this.emitChange();
  369. }
  370. this.userChangePageSize = false;
  371. }
  372. }
  373. };