<template>
    <div class="vui-pagination">
        <span :class="['vui-pagination-btn',{'vui-pagination-disabled':value===1}]"
              @click="value>1&&goto(value-1)">上一页</span>
        <ul>
            <li v-for="(page,index) in list" :key="index" @click="page!=='...'&&goto(page)"
                :class="{'vui-pagination-disabled':page==='...','vui-pagination-active':page===value}">{{page}}
            </li>
        </ul>
        <span :class="['vui-pagination-btn',{'vui-pagination-disabled':value===total}]"
              @click="value<total&&goto(value+1)">下一页
        </span>
        <template v-if="showGoto">
            <span class="vui-pagination-prompt">共{{total}}页，跳转至<input type="text" :value="num" @input="input"
                                                                      @keyup.enter="goto(num)"/>页</span>
            <span :class="['vui-pagination-btn',{'vui-pagination-disabled':!num}]" @click="num&&goto(num)">确定</span>
        </template>
    </div>
</template>

<style>
    .vui-pagination {
        display: inline-block;
        color: #333;
        font-size: 14px;
        line-height: 26px;
        text-align: center;
        user-select: none;
    }

    .vui-pagination-btn,
    .vui-pagination li:not(.vui-pagination-disabled),
    .vui-pagination input {
        border: 1px solid #e5e5e5;
    }

    .vui-pagination-btn {
        display: inline-block;
        margin-left: 6px;
        min-width: 64px;
    }

    .vui-pagination-btn:first-of-type,
    .vui-pagination-btn:nth-of-type(4) {
        margin-left: 0;
    }

    .vui-pagination ul {
        list-style-type: none;
        display: inline-block;
        margin: 0;
        padding: 0;
    }

    .vui-pagination li {
        display: inline-block;
        box-sizing: border-box;
        margin-left: 6px;
        padding: 0 5px;
        min-width: 28px;
        cursor: pointer;
    }

    .vui-pagination-prompt {
        margin: 0 15px;
    }

    .vui-pagination input {
        margin: 0 5px;
        padding: 0 5px;
        width: 40px;
        height: 26px;
        line-height: inherit;
        text-align: center;
        outline: none;
    }

    .vui-pagination li.vui-pagination-active,
    .vui-pagination li:not(.vui-pagination-disabled):hover,
    .vui-pagination-btn:not(.vui-pagination-disabled):hover {
        color: #000;
        border-color: #000;
    }

    .vui-pagination-disabled,
    .vui-pagination-active {
        cursor: not-allowed !important;
    }

    .vui-pagination-btn.vui-pagination-disabled {
        color: #ccc;
    }
</style>

<script>
  export default {
    name: 'vui-pagination',
    props: {
      total: { // 总页数
        type: Number,
        required: true
      },
      value: { // 当前页
        type: Number,
        default: 1
      },
      size: { // 最多显示几个按钮，要求为>=5的奇数
        type: Number,
        default: 7
      },
      showGoto: { // 是否显示goto区域
        type: Boolean,
        default: true
      }
    },
    data () {
      return {
        num: undefined // 输入的页码
      }
    },
    computed: {
      list () {
        let pages = []
        let type
        let start
        let end

        // 根据当前页码和总页数动态渲染
        if (this.value <= (this.size + 1) / 2) { // 左边没省略号
          if (this.total <= this.size) { // 右边没省略号
            type = 0
          } else {
            type = 1
          }
        } else {
          if (this.value + (this.size - 1) / 2 >= this.total) { // 右边没省略号
            type = 2
          } else {
            type = 3
          }
        }
        switch (type) {
          case 0: // 左右两边都没有省略号
            start = 0
            end = this.total
            while (start < end) {
              pages.push(++start)
            }
            break
          case 1: // 右边有省略号，左边没有
            start = 0
            end = this.size - 2
            while (start < end) {
              pages.push(++start)
            }
            pages.push('...', this.total)
            break
          case 2: // 左边有省略号，右边没有
            start = this.total - this.size + 2
            end = this.total
            pages.push(1, '...')
            while (start < end) {
              pages.push(++start)
            }
            break
          case 3: // 左右两边都有省略号
            start = this.value - (this.size - 3) / 2
            end = this.value + (this.size - 5) / 2
            pages.push(1, '...')
            while (start < end) {
              pages.push(++start)
            }
            pages.push('...', this.total)
            break
        }

        return pages
      }
    },
    methods: {
      input (event) { // 限定输入值在页码范围内
        let value = Number(event.target.value.replace(/\D/g, ''))

        if (value) {
          value = value > this.total ? this.total : value
          event.target.value = value // 必须要手动设置值，因为当this.num=this.total后，再输入大于this.total的value时，vue不会去更新input元素
          this.num = value
        } else {
          event.target.value = ''
          this.num = undefined
        }
      },
      goto (num) {
        this.$emit('input', num)
      }
    }
  }
</script>