無星的前端之旅(二十二)—— 自定義CompositionAPI/hook

背景

咱們作的大量都是後臺管理系統,對於這種系統,咱們會發現,裏面的業務其實至關單一。html

大量都是相似這種, 搜索條件,表格,分頁vue

1.png

每一個頁面都要處理上下翻頁,搜索,mounted加載首頁table數據等等邏輯react

雖然不復雜,但很累。ios

所以,咱們須要封裝一些DSL來下降咱們的重複工做量axios

啥是CompositionAPI/hook

看看文檔api

咱們的請求通過封裝,大概是這種格式

// /api/index.js
import API from '@szyx/axios';
// 請求攔截器
API.interceptors.request.use((config) => {
  // xxxx
  return config;
});

// 結果攔截器
API.interceptors.response.use(
  (response) => {
    // 判斷狀態
    if (response.status === '0') {
      return response.data;
    }
    // 不然都是錯了
    throw new Error(JSON.stringify(response));
  },
  (error) => {
    throw error;
  },
);
export default {
  getExample: (params) => API.POSTJSON('/xxx/xxx/xxx', params),
};

複製代碼

提取CompositionAPI

tableCompositions.js數組

import { ref, onMounted } from 'vue';
import API from '@/api/index';

export default function tableCompositon(params, urlName, pageDefault = 1, pageSizeDefault = 10) {
  // 表格數據
  const tableData = ref([]);
  // 總量
  const total = ref(0);
  // 當前頁面,默認1
  const page = ref(pageDefault);
  // 頁面數量,默認10
  const pageSize = ref(pageSizeDefault);

  const getTableData = () => {
    API[urlName]({
      ...params,
      pageNum: page.value,
      pageSize: pageSize.value,
    }).then((data) => {
      tableData.value = data.list;
      page.value = data.pageNum;
      pageSize.value = data.pageSize;
      total.value = data.total;
    });
  };
  // 頁面加載請求
  onMounted(() => { getTableData(); });

  return {
    tableData,
    total,
    page,
    pageSize,
    getTableData,
  };
}

複製代碼

參數解析

  • params入參是指當前頁面除了頁碼分頁數量之外還須要的業務參數
  • urlName是指請求的方法名,上面能夠看到咱們的請求封裝完之後的導出都是一個個的方法,例如調用getExample方法,則傳遞getExample這個字符串便可。

return解析

  • tableData 頁面的表格數據,表格確定是數組類型的數據
  • total 一共多少條數據
  • page 當前頁碼
  • pageSize 當前分頁數
  • getTableData 獲取表格數據的方法

內容解析

應該很簡單,都能看懂,定義了一些數據,一個請求方法,還有onMounted中發起請求,而後return了這些東西出去markdown

使用

好比像這樣的一個頁面flex

2.png

省略掉表單彈窗相關的代碼ui

<template>
  <div class="flex row align-items-center header">
    <div class="flex row align-items-center flex1">
      <p class="title">用戶名:</p>
      <el-input
        v-model="nameState.username"
        placeholder="用戶名稱"
        class="name-input"
        @keyup.enter="getTableData"
      />
    </div>

    <div class="flex row ">
      <el-button type="primary" @click="page.value = 1;
                                        getTableData();">
        搜索
      </el-button>
      <el-button plain @click="nameState.username = '';getTableData();">清空</el-button>
    </div>
  </div>
  <div class="table">
    <el-table :data="tableData" border stripe
              :header-cell-style="tableHeaderStyle" :cell-style="tableCellStyle"
    >
      <el-table-column prop="name" label="用戶名" align="center" />
      <el-table-column prop="roleName" label="角色名稱" align="center" />
      <el-table-column label="操做" align="center">
        <template #default="scope">
          <el-button type="primary" v-permission="'100001002'" @click="editUser(scope.row)">
            修改
          </el-button>
          <el-button type="danger" v-permission="'100001003'" @click="deleteUser(scope.row)">
            刪除
          </el-button>
        </template>
      </el-table-column>
    </el-table>
  </div>
  <Pagination
    class="pagination"
    v-model:total="total"
    v-model:page="page"
    v-model:limit="pageSize"
    @pagination="getTableData"
  />
</template>

<script>
import {
  defineComponent, reactive,
} from 'vue';
import Pagination from '@/components/Pagination/index.vue';
import tableCompositions from '@/compositions/tableCompositions';

export default defineComponent({
  components: { Pagination },
  setup() {
    // 用戶名稱
    const nameState = reactive({
      username: '',
    });
    // 獲取table數據
    const {
      tableData, getTableData, total, pageSize, page,
    } = tableCompositions(
      nameState,
      'getUserList',
    );

    return {
      total,
      pageSize,
      page,
      nameState,
      tableData,
      getTableData,
    };
  },
});
</script>
複製代碼

大概不到100行的代碼,就結束了。

js基本沒什麼邏輯。只須要定義除pagepageSize之外還須要的業務參數

好比我這個頁面還須要一個用戶名

const nameState = reactive({
      username: '',
  });
複製代碼

而後將nameState做爲參數傳遞給tableCompositions,獲取全部的東西

const {
      tableData, getTableData, total, pageSize, page,
    } = tableCompositions(
      nameState,
      'getUserList',
    );
複製代碼

而後tableData直接丟給el-table就好了

pagination

至於pagination,其實直接用el-pagination就能夠了

咱們也只是把一些經常使用的放進去,包了一層而已

Pagination/index.vue

<template>
  <el-pagination
    :background="background"
    v-model:current-page="currentPage"
    v-model:page-size="pageSize"
    :layout="layout"
    :page-sizes="pageSizes"
    :total="total"
    v-bind="$attrs"
    @size-change="handleSizeChange"
    @current-change="handleCurrentChange"
  />
</template>

<script>
export default {
  name: 'Pagination',
  props: {
    total: {
      required: true,
      type: Number,
    },
    page: {
      type: Number,
      default: 1,
    },
    limit: {
      type: Number,
      default: 20,
    },
    pageSizes: {
      type: Array,
      default() {
        return [5, 10, 20, 30, 50];
      },
    },
    layout: {
      type: String,
      default: 'total, sizes, prev, pager, next, jumper',
    },
    background: {
      type: Boolean,
      default: true,
    },

    hidden: {
      type: Boolean,
      default: false,
    },
  },
  computed: {
    currentPage: {
      get() {
        return this.page;
      },
      set(val) {
        this.$emit('update:page', val);
      },
    },
    pageSize: {
      get() {
        return this.limit;
      },
      set(val) {
        this.$emit('update:limit', val);
      },
    },
  },
  methods: {
    handleSizeChange(val) {
      console.log('handleSizeChange', val);
      this.$emit('pagination', { page: this.currentPage, limit: val });
    },
    handleCurrentChange(val) {
      console.log('handleCurrentChange', val);
      this.$emit('pagination', { page: val, limit: this.pageSize });
    },
  },
};
</script>

複製代碼

因此上下頁的邏輯,往上一綁,就結束了

<Pagination class="pagination" v-model:total="total" v-model:page="page" v-model:limit="pageSize" @pagination="getTableData" />
複製代碼

react也同樣,我這裏就不放react代碼了,能夠本身封裝一下

咱們的宗旨只有一個:懶

相關文章
相關標籤/搜索