vue 点击分页滚动到头部

162 阅读3分钟

1.新建 scroll-to.js文件 代码如下

Math.easeInOutQuad = function (t, b, c, d) {
  t /= d / 2;
  if (t < 1) {
    return (c / 2) * t * t + b;
  }
  t--;
  return (-c / 2) * (t * (t - 2) - 1) + b;
};

// requestAnimationFrame for Smart Animating http://goo.gl/sx5sts
let requestAnimFrame = (function () {
  return (
    window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    function (callback) {
      window.setTimeout(callback, 1000 / 60);
    }
  );
})();

/**
 * Because it's so fucking difficult to detect the scrolling element, just move them all
 * @param {number} amount
 */
function move(amount) {
  document.documentElement.scrollTop = amount;
  document.body.parentNode.scrollTop = amount;
  document.body.scrollTop = amount;
}

function position() {
  return (
    document.documentElement.scrollTop ||
    document.body.parentNode.scrollTop ||
    document.body.scrollTop
  );
}

/**
 * @param {number} to
 * @param {number} duration
 * @param {Function} callback
 */
export function scrollTo(to, duration, callback) {
  const start = position();
  const change = to - start;
  const increment = 20;
  let currentTime = 0;
  duration = typeof duration === "undefined" ? 500 : duration;
  let animateScroll = function () {
    // increment the time
    currentTime += increment;
    // find the value with the quadratic in-out easing function
    let val = Math.easeInOutQuad(currentTime, start, change, duration);
    // move the document.body
    move(val);
    // do the animation unless its over
    if (currentTime < duration) {
      requestAnimFrame(animateScroll);
    } else {
      if (callback && typeof callback === "function") {
        // the animation is done so lets callback
        callback();
      }
    }
  };
  animateScroll();
}

2.pagination页面代码

<template>
  <div :class="{ hidden: hidden }" class="pagination-container">
    <el-pagination
      :background="background"
      v-model:current-page="currentPage"
      v-model:page-size="pageSize"
      :layout="layout"
      :page-sizes="pageSizes"
      :total="total"
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
    />
  </div>
</template>

<script setup>
import { computed } from "vue";
import { scrollTo } from "@/utils/scroll-to";
const emit = defineEmits(["pagination", "update:page", "update:limit"]);
const props = defineProps({
  total: {
    required: true,
    type: Number
  },
  page: {
    type: Number,
    default: 1
  },
  limit: {
    type: Number,
    default: 10
  },
  pageSizes: {
    type: Array,

    default: () => [10, 20, 30, 40, 50, 60, 100, 200, 300, 400]
  },

  layout: {
    type: String,
    default: "total, sizes, prev, pager, next, jumper"
  },
  background: {
    type: Boolean,
    default: true
  },
  autoScroll: {
    type: Boolean,
    default: true
  },
  hidden: {
    type: Boolean,
    default: false
  }
});

const currentPage = computed({
  get() {
    return props.page;
  },
  set(val) {
    emit("update:page", val);
  }
});
const pageSize = computed({
  get() {
    return props.limit;
  },
  set(val) {
    emit("update:limit", val);
  }
});
function handleSizeChange(val) {
  // console.log("==", val);
  if (currentPage.value * val > props.total) {
    currentPage.value = 1;
  }
  // console.log("currentPage", currentPage.value);
  emit("pagination", { page: currentPage.value, limit: val });
  if (props.autoScroll) {
    scrollTo(0, 800);
  }
}
function handleCurrentChange(val) {
  // console.log("==1==", val);
  emit("pagination", { page: val, limit: pageSize.value });
  if (props.autoScroll) {
    scrollTo(0, 800);
  }
}
</script>

<style scoped lang="less">
.pagination-container {
  // background: #fff;
  padding: 20px 16px 0 16px;
  display: flex;
  justify-content: flex-end;
}
:deep(.el-pagination .el-select .el-input) {
  width: 100px;
}
:deep(.el-pagination button) {
  width: 28px;
  height: 28px;
}
:deep(.el-pager li) {
  width: 28px;
  height: 28px;
}
:deep(.el-input__wrapper) {
  height: 28px;
}
</style>

3.table封装的页面

<template>
  <section class="table-box">
    <!-- :default-sort="{ prop: 'name', order: 'descending' }" -->
    <el-table
      :data="tableData"
      :height="height"
      border
      ref="multipleTableRef"
      @selection-change="handleSelectionChange"
      :header-cell-style="{
        background: '#F0F0F0',
        color: '#333333',
        fontSize: '15px',
        height: '45px',
        lineHeight: '45px',
        borderColor: '#E4E4E4'
      }"
      :row-style="{ cursor: 'pointer' }"
      @row-click="fnRowClick"
    >
      <!-- :header-cell-style="{
        background: '#F6F6F6',
        color: '#333333',
        fontSize: '14px',
        height: '45px',
        lineHeight: '45px'
      }" -->
      <el-table-column fixed type="selection" width="55" v-if="selection" />
      <el-table-column
        fixed
        type="index"
        label="序号"
        width="120"
        v-if="serialNumber"
      />
      <el-table-column
        :prop="item.prop"
        :sortable="item?.sortable ?? false"
        :label="item.label"
        :width="item.width"
        v-for="(item, i) in tableTitle"
        :key="i"
      >
        <template #default="scope">
          <!-- 图片 -->
          <img
            v-if="item.sign === 'pic'"
            class="pic"
            :src="scope?.row[item?.prop] || tool.getUrl('noCompany.png')"
          />
          <!-- 时间 -->
          <span v-else-if="item.sign === 'timer'">{{
            // HH:mm:ss
            item.hasShow
              ? dayjs(scope.row[item.prop]).format("YYYY-MM")
              : dayjs(scope.row[item.prop]).format("YYYY-MM-DD")
          }}</span>
          <!-- 里面有嵌套的对象取值 -->
          <section v-else-if="item.sign === 'children'">
            <!-- 是数组 -->
            <section v-if="Array.isArray(scope.row[item.arrayName])">
              <span v-for="(v, j) in scope.row[item.arrayName]" :key="j">
                {{ v[item.childrenKey]
                }}{{ j !== scope.row[item.arrayName].length - 1 ? "," : "" }}
              </span>
            </section>
            <!-- 是对象 -->
            <span v-else>{{ scope.row[item?.sign]?.[item.prop] || "-" }}</span>
          </section>
          <!-- 过滤常量 -->
          <span v-else-if="item.sign === 'filter'">{{
            $commonFilter(scope.row[item.prop], item.spec)
          }}</span>
          <!-- 注册地址 -->
          <span v-else-if="item.sign === 'area'">{{
            scope.row.provinceCode != 0
              ? codeToText[scope.row.provinceCode] +
                "," +
                codeToText[scope.row.cityCode] +
                "," +
                codeToText[scope.row.countyCode]
              : "-"
          }}</span>
          <!-- 对象里面名字 -->
          <span v-else-if="item.sign === 'obj'">{{
            scope.row[item.prop][item.objKey] || "-"
          }}</span>
          <span v-else>{{ scope.row[item.prop] }}</span>
        </template>
      </el-table-column>
      <slot></slot>

      <!-- <el-table-column
        fixed="right"
        label="操作"
        :width="operationWidth"
        v-if="operation"
      >
        <template #default
          ><el-button v-if="operationObj.see" link type="primary" size="small"
            >查看</el-button
          >
          <el-button v-if="operationObj.edit" link type="primary" size="small"
            >编辑</el-button
          >
          <el-button v-if="operationObj.add" link type="primary" size="small"
            >添加</el-button
          >
          <el-button v-if="operationObj.del" link type="danger" size="small"
            >删除</el-button
          >
        </template>
      </el-table-column> -->
    </el-table>

    <pagination
      v-if="total > 0"
      :total="total"
      :page="currentPage"
      :limit="limit"
      @pagination="fnChangePage"
    ></pagination>
  </section>
</template>
<script setup>
import { ref, defineProps, nextTick, watch, defineEmits } from "vue";
import tool from "@/utils/tool";
import { codeToText } from "element-china-area-data";
import dayjs from "dayjs";
// console.log(CodeToText(110000));
// const Pagination = defineAsyncComponent(() =>
//   import("@c/Pagination/index.vue")
// );
const emit = defineEmits([
  "handleSelectionChange",
  "fnRowClick",
  "fnChangePage"
]);
const props = defineProps({
  tableTitle: {
    type: Array,
    default: () => {
      return [];
    }
  },
  tableData: {
    type: Array,
    default: () => {
      return [];
    }
  },
  height: {
    type: String,
    default: "auto"
  },
  //是否显示复选框
  selection: {
    type: Boolean,
    default: false
  },
  //序号是否显示
  serialNumber: {
    type: Boolean,
    default: false
  },
  operation: {
    type: Boolean,
    default: false
  },
  operationWidth: {
    type: Number,
    default: 120
  },
  total: Number, // 总数
  currentPage: {
    type: Number,
    default: 1
  },
  limit: {
    type: Number,
    default: 10
  }
  // 增删改查按钮 可增加
  // operationObj: {
  //   type: Object,
  //   default: () => {
  //     return {
  //       add: {
  //         type: Boolean,
  //         default: false
  //       },
  //       edit: {
  //         type: Boolean,
  //         default: false
  //       },
  //       del: {
  //         type: Boolean,
  //         default: false
  //       },
  //       see: {
  //         type: Boolean,
  //         default: false
  //       }
  //     };
  //   }
  // }
});
const multipleTableRef = ref([]);
// table数据
let tableData = ref(props.tableData);
let tableTitle = ref(props.tableTitle);
// 监听table数据变化,达到实时更新
watch(props, () => {
  tableData.value = props.tableData;
  if (props.selection) {
    // 处理选中的
    nextTick(() => {
      props.tableData.map((v, i) => {
        if (v.status && v.status == 20) {
          multipleTableRef.value.toggleRowSelection(props.tableData[i], true);
        }
      });
    });
  }
});

const fnChangePage = (val) => {
  emit("fnChangePage", val);
};
// 多选
const handleSelectionChange = (val) => {
  emit("handleSelectionChange", val);
};
const fnRowClick = (row) => {
  emit("fnRowClick", row);
};
</script>
<style lang="less" scoped>
.table-box {
  // width: 100%;
  // // margin: 20px auto;
  // padding: 20px 0;
  // margin-top: 20px;
}
.pic {
  width: 100px;
  height: 100%;
}

:deep(.el-table--enable-row-hover .el-table__body tr:hover > td) {
  // background-color: #effff9 !important;
}
:deep(.el-scrollbar) {
  background: #fff;
}
.el-table tr {
  color: #333;
}
:deep(.el-table .cell) {
  font-size: 14px !important;
}
// :deep(.el-table thead th) {
//   border-bottom: 2px solid rgba(2, 165, 74, 0.5) !important;
// }
</style>