最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

表格Table實(shí)現(xiàn)前端全選所有功能方案示例(包含非當(dāng)前頁(yè))

 更新時(shí)間:2024年02月01日 09:10:15   作者:小皇帝James  
這篇文章主要為大家介紹了表格Table實(shí)現(xiàn)前端全選所有功能,包括非當(dāng)前頁(yè)的方案示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

最近兩家公司都遇到了全選全頁(yè)+批量操作的功能場(chǎng)景,即點(diǎn)擊全選所有的時(shí)候需要勾選所有數(shù)據(jù)包括非當(dāng)前頁(yè)的。

方案

如果純前端分頁(yè)可以參考 antdv.table,一般主流的組件庫(kù)都給封裝好了,全選所有時(shí)設(shè)置pageSize為無窮大并調(diào)用列表接口得到全量數(shù)據(jù)賦值給selectedRowKeys即可。但是這套方案最大的問題在于點(diǎn)擊全選所有時(shí)需要等待后端接口返回,這樣的交互延遲是無法忍受的!且全選所有+批量操作兩次請(qǐng)求的服務(wù)端資源浪費(fèi)也是巨大的。

因此基于后端分頁(yè)的前提,提出了另一套合理解決方案:

通過isAll判斷是否為全選所有,如果是的話配合excludeIds、否則配合includeIds的值完成返顯。最后業(yè)務(wù)中調(diào)用批量操作接口的時(shí)候還需要傳篩選項(xiàng)。

實(shí)現(xiàn)

使用框架 vue3 + antdv

代碼如下,框架為 vue3 + antdv

// CTable
<template>
  <a-table
    v-bind="$attrs"
    :columns="columns"
  >
    <template #headerCell="{ column }" v-if="!$slots.headerCell">
      <template v-if="column.dataIndex === '_checkbox_'">
        <CTableHeaderCheckbox
          ref="cTableHeaderCheckboxRef"
          :rowKey="rowKey"
          :dataSource="dataSource"
          v-model:isAll="isAll"
          v-model:includeIds="includeIds"
          v-model:excludeIds="excludeIds"
          :judgeToggleIsAll="judgeToggleIsAll"
        />
      </template>
    </template>
    <template #bodyCell="{ record, column }" v-if="!$slots.bodyCell">
      <template v-if="column.dataIndex === '_checkbox_'">
        <CTableBodyCheckbox
          :record="record"
          :rowKey="rowKey"
          :isAll="isAll"
          :includeIds="includeIds"
          :excludeIds="excludeIds"
          :judgeToggleIsAll="judgeToggleIsAll"
        />
      </template>
    </template>
    <template v-for="(_, name) in $slots" :key="name" #[name]="slotProps">
      <slot :name="name" v-bind="slotProps" v-if="name === 'headerCell' && slotProps.column.dataIndex === '_checkbox_'">
        <CTableHeaderCheckbox
          ref="cTableHeaderCheckboxRef"
          :rowKey="rowKey"
          :dataSource="dataSource"
          v-model:isAll="isAll"
          v-model:includeIds="includeIds"
          v-model:excludeIds="excludeIds"
          :judgeToggleIsAll="judgeToggleIsAll"
        />
      </slot>
      <slot :name="name" v-bind="slotProps" v-if="name === 'bodyCell' && slotProps.column.dataIndex === '_checkbox_'">
        <CTableBodyCheckbox
          :record="slotProps.record"
          :rowKey="rowKey"
          :isAll="isAll"
          :includeIds="includeIds"
          :excludeIds="excludeIds"
          :judgeToggleIsAll="judgeToggleIsAll"
        />
      </slot>
      <slot :name="name" v-bind="slotProps" v-else></slot>
    </template>
  </a-table>
</template>

<script lang="ts" setup>
import { Table, TableColumnProps } from 'ant-design-vue';
import CTableHeaderCheckbox from './CTableHeaderCheckbox.vue';
import CTableBodyCheckbox from './CTableBodyCheckbox.vue';

const props = withDefaults(
  defineProps<{
    columns: TableColumnProps[],
    allSelection?: {
      onCheckboxChange:(params) => void,
    } | null,
  }>(),
  {
    columns: () => [],
    allSelection: null,
  },
);

const $attrs = useAttrs() as any;
const $slots = useSlots();

const cTableHeaderCheckboxRef = ref();
const columns = computed(() => {
  if (props.allSelection) {
    return [
      {
        title: '多選',
        dataIndex: '_checkbox_',
        fixed: 'left',
        width: 48,
        customHeaderCell: () => ({ class: 'ant-table-checkbox-column' }),
      },
      ...props.columns,
    ];
  }
  return props.columns;
});
// 是否全選所有
const isAll = ref(false);
// 未全選所有時(shí)勾選數(shù)據(jù)
const includeIds = ref<string[]>([]);
// 全選所有時(shí)反選數(shù)據(jù)
const excludeIds = ref<string[]>([]);
const rowKey = computed(() => $attrs.rowKey || $attrs['row-key']);
const dataSource = computed(() => $attrs.dataSource || $attrs['data-source']);
// 表單數(shù)據(jù)可能存在disabled不可選擇狀態(tài),此時(shí)需要后端返回enabledTotal幫助判斷
const total = computed(() => $attrs.pagination?.enabledTotal || $attrs.pagination?.total || $attrs.enabledTotal || $attrs.total);
// 已勾選總數(shù),幫助業(yè)務(wù)展示
const checkedTotal = computed(() => (isAll.value ? total.value - excludeIds.value.length : includeIds.value.length));
// 當(dāng)選擇數(shù)據(jù)發(fā)生改變時(shí),需要判斷是否切換全選狀態(tài)
const judgeToggleIsAll = () => {
  if (isAll.value && excludeIds.value.length && excludeIds.value.length === total.value) {
    isAll.value = false;
    includeIds.value = [];
    excludeIds.value = [];
  }
  if (!isAll.value && includeIds.value.length && includeIds.value.length === total.value) {
    isAll.value = true;
    includeIds.value = [];
    excludeIds.value = [];
  }
};
// 當(dāng)源數(shù)據(jù)發(fā)生改變時(shí),手動(dòng)重置選擇框狀態(tài)
const onResetCheckbox = () => {
  cTableHeaderCheckboxRef.value.handleMenu({ key: Table.SELECTION_NONE });
};

// 有任何選擇變化時(shí),同步回傳給父組件
watch(
  [isAll, includeIds, excludeIds],
  () => {
    props.allSelection?.onCheckboxChange?.({
      isAll: isAll.value,
      includeIds: includeIds.value,
      excludeIds: excludeIds.value,
      checkedTotal: checkedTotal.value,
    });
  },
  { deep: true },
);

defineExpose({
  onResetCheckbox,
});
</script>

判斷slots是否存在headerCell和bodyCell

vue 模版里需要額外判斷slots是否存在headerCell和bodyCell,如果存在的話需要透?jìng)鲃?dòng)態(tài)插槽,否則通過具名插槽傳入。

// CTableHeaderCheckbox
<template>
  <a-checkbox
    :checked="isCurrentChecked"
    :indeterminate="isCurrentIndeterminate"
    :disabled="isCurrentDisabled"
    @change="onCheckboxChange"
  />
  <a-dropdown
    :disabled="isCurrentDisabled"
  >
    <CIcon
      class="ml-2 cursor-pointer"
      icon="triangle-down-o"
      :size="12"
      color="#C9CCD0"
    />
    <template #overlay>
      <a-menu @click="handleMenu">
        <a-menu-item :key="Table.SELECTION_ALL">全選所有</a-menu-item>
        <a-menu-item :key="Table.SELECTION_INVERT">反選當(dāng)頁(yè)</a-menu-item>
        <a-menu-item :key="Table.SELECTION_NONE">清空所有</a-menu-item>
      </a-menu>
    </template>
  </a-dropdown>
</template>

<script lang="ts" setup>
import { Table } from 'ant-design-vue';

const props = withDefaults(
  defineProps<{
    rowKey: string,
    dataSource: any[],
    isAll: boolean,
    includeIds: string[],
    excludeIds: string[],
    judgeToggleIsAll:() => void,
  }>(),
  {},
);
const emit = defineEmits(['update:isAll', 'update:includeIds', 'update:excludeIds']);

const isAll = computed({
  get: () => props.isAll,
  set: (val) => {
    emit('update:isAll', val);
  },
});
const includeIds = computed({
  get: () => props.includeIds,
  set: (val) => {
    emit('update:includeIds', val);
  },
});
const excludeIds = computed({
  get: () => props.excludeIds,
  set: (val) => {
    emit('update:excludeIds', val);
  },
});
const isCurrentChecked = computed(() => {
  const ids = props.dataSource?.map((item) => item[props.rowKey]);
  if (!ids.length) return false;
  return isAll.value ? !ids.some((id) => excludeIds.value.includes(id)) : ids.every((id) => includeIds.value.includes(id));
});
const isCurrentIndeterminate = computed(() => {
  const ids = props.dataSource?.map((item) => item[props.rowKey]);
  if (!ids.length) return false;
  if (isAll.value) {
    return !ids.every((id) => excludeIds.value.includes(id)) && !isCurrentChecked.value;
  } else {
    return ids.some((id) => includeIds.value.includes(id)) && !isCurrentChecked.value;
  }
});
const isCurrentDisabled = computed(() => !props.dataSource?.map((item) => item[props.rowKey]).length);
const handleMenu = ({ key }) => {
  const ids = props.dataSource?.map((item) => item[props.rowKey]);
  if (key === Table.SELECTION_INVERT) {
    // 數(shù)學(xué)意義的補(bǔ)集
    if (isAll.value) {
      excludeIds.value = [
        ...excludeIds.value.filter((id) => !ids.includes(id)),
        ...ids.filter((id) => !excludeIds.value.includes(id)),
      ];
    } else {
      includeIds.value = [
        ...includeIds.value.filter((id) => !ids.includes(id)),
        ...ids.filter((id) => !includeIds.value.includes(id)),
      ];
    }
    props.judgeToggleIsAll();
  } else {
    isAll.value = key === Table.SELECTION_ALL;
    includeIds.value = [];
    excludeIds.value = [];
  }
};
const onCheckboxChange = (e) => {
  const ids = props.dataSource?.map((item) => item[props.rowKey]);
  const { checked } = e.target;
  if (isAll.value) {
    excludeIds.value = checked ? excludeIds.value.filter((id) => !ids.includes(id)) : Array.from(new Set([...excludeIds.value, ...ids]));
  } else {
    includeIds.value = checked ? Array.from(new Set([...includeIds.value, ...ids])) : includeIds.value.filter((id) => !ids.includes(id));
  }
  props.judgeToggleIsAll();
};

defineExpose({
  handleMenu,
});
</script>

CTableBodyCheckbox 

// CTableBodyCheckbox
<template>
  <a-checkbox
    :checked="isAll ? !excludeIds.includes(record[rowKey]) : includeIds.includes(record[rowKey])"
    :disabled="record.disabled"
    @change="onCheckboxChange(record[rowKey])"
  />
</template>

<script lang="ts" setup>
const props = withDefaults(
  defineProps<{
    record: any,
    rowKey: string,
    isAll: boolean,
    includeIds: string[],
    excludeIds: string[],
    judgeToggleIsAll:() => void,
  }>(),
  {},
);

const onCheckboxChange = (keyId) => {
  const ids = props.isAll ? props.excludeIds : props.includeIds;
  const index = ids.indexOf(keyId);
  if (~index) {
    ids.splice(index, 1);
  } else {
    ids.push(keyId);
  }
  props.judgeToggleIsAll();
};
</script>

結(jié)論

如此一來,展示和交互邏輯就全部收攏在前端了,對(duì)于交互體驗(yàn)和服務(wù)端負(fù)載都是極大的改善。

以上就是表格Table實(shí)現(xiàn)前端全選所有功能方案示例的詳細(xì)內(nèi)容,更多關(guān)于Table表格全選功能的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

以上就是表格Table實(shí)現(xiàn)前端全選所有功能方案示例(包括非當(dāng)前頁(yè))的詳細(xì)內(nèi)容,更多關(guān)于Table表格全選功能的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 解決vue2.0動(dòng)態(tài)綁定圖片src屬性值初始化時(shí)報(bào)錯(cuò)的問題

    解決vue2.0動(dòng)態(tài)綁定圖片src屬性值初始化時(shí)報(bào)錯(cuò)的問題

    下面小編就為大家分享一篇解決vue2.0動(dòng)態(tài)綁定圖片src屬性值初始化時(shí)報(bào)錯(cuò)的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-03-03
  • 前端+接口請(qǐng)求實(shí)現(xiàn)vue動(dòng)態(tài)路由

    前端+接口請(qǐng)求實(shí)現(xiàn)vue動(dòng)態(tài)路由

    在Vue應(yīng)用中,結(jié)合前端和后端接口請(qǐng)求實(shí)現(xiàn)動(dòng)態(tài)路由,可根據(jù)用戶權(quán)限動(dòng)態(tài)生成路由,提高安全性與靈活性,本文就來介紹一下前端+接口請(qǐng)求實(shí)現(xiàn)vue動(dòng)態(tài)路由,感興趣的可以了解一下
    2024-09-09
  • vue3中實(shí)現(xiàn)異步組件的方法實(shí)例

    vue3中實(shí)現(xiàn)異步組件的方法實(shí)例

    前端開發(fā)經(jīng)常遇到異步的問題,請(qǐng)求函數(shù)、鏈接庫(kù)等,下面這篇文章主要給大家介紹了關(guān)于vue3中實(shí)現(xiàn)異步組件的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-06-06
  • 詳解vue slot插槽的使用方法

    詳解vue slot插槽的使用方法

    本篇文章主要介紹了詳解vue slot插槽的使用方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-06-06
  • vant-ui組件調(diào)用Dialog彈窗異步關(guān)閉操作

    vant-ui組件調(diào)用Dialog彈窗異步關(guān)閉操作

    這篇文章主要介紹了vant-ui組件調(diào)用Dialog彈窗異步關(guān)閉操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • 詳解Vue如何手寫一個(gè)虛擬列表

    詳解Vue如何手寫一個(gè)虛擬列表

    虛擬列表是一種優(yōu)化長(zhǎng)列表渲染的技術(shù),它可以在保持流暢性的同時(shí),渲染大量的數(shù)據(jù),本文主要介紹了如何使用vue手寫一個(gè)虛擬列表,感興趣的可以了解下
    2024-04-04
  • 解決vue cli4升級(jí)sass-loader(v8)后報(bào)錯(cuò)問題

    解決vue cli4升級(jí)sass-loader(v8)后報(bào)錯(cuò)問題

    這篇文章主要介紹了解決vue cli4升級(jí)sass-loader(v8)后報(bào)錯(cuò)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-07-07
  • Vue實(shí)現(xiàn)懸浮框自由移動(dòng)+錄音功能的示例代碼

    Vue實(shí)現(xiàn)懸浮框自由移動(dòng)+錄音功能的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何利用Vue實(shí)現(xiàn)懸浮框自由移動(dòng)+錄音功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以動(dòng)手嘗試一下
    2022-07-07
  • Vue中rem與postcss-pxtorem的應(yīng)用詳解

    Vue中rem與postcss-pxtorem的應(yīng)用詳解

    這篇文章主要介紹了Vue中rem與postcss-pxtorem的應(yīng)用詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • vue源碼nextTick使用及原理解析

    vue源碼nextTick使用及原理解析

    這篇文章主要介紹了vue源碼nextTick使用及原理解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-08-08

最新評(píng)論

长泰县| 汝阳县| 会昌县| 公主岭市| 清苑县| 泗水县| 景谷| 扎赉特旗| 墨竹工卡县| 登封市| 靖边县| 拉孜县| 大渡口区| 合水县| 且末县| 鄂尔多斯市| 惠州市| 元阳县| 含山县| 台东市| 同江市| 禹州市| 兰西县| 娄底市| SHOW| 祁门县| 商洛市| 团风县| 云龙县| 湘西| 六安市| 云浮市| 伊春市| 泸溪县| 射洪县| 台南市| 莱州市| 台江县| 丹寨县| 富宁县| 汨罗市|