arco-design / arco-design-vue

A Vue.js 3 UI Library based on Arco Design
https://arco.design/vue
MIT License
2.75k stars 539 forks source link

min-width 有bug啊,arco和antd没一个做的好的,学习一下element ui的吧 #3275

Open grasilife opened 3 months ago

grasilife commented 3 months ago

Basic Info

What is expected?

{ dataIndex: 'appKey', slotName: 'appKey', title: 'AppKey', minWidth: 100, ellipsis: true, tooltip: true, }, { dataIndex: 'name', slotName: 'name', title: '应用名', minWidth: 100, ellipsis: true, tooltip: true, }, { dataIndex: 'domain', slotName: 'domain', title: '应用域名1', minWidth: 10, ellipsis: true, tooltip: true, }, { dataIndex: 'description', slotName: 'description', title: '描述', minWidth: 100, ellipsis: true, tooltip: true, }, 列宽有问题,根本和设置的不一样

grasilife commented 3 months ago
      <CubeTable
        :columns="columns"
        :data="dataSource"
        :loading="loading"
        :pagination="pagination"
        @page-change="changePage"
        @page-size-change="pageSizeChange"
      >
        <template #name="{ record }">
          <Link @click="toApps(record)"> {{ record.name }}</Link>
        </template>
        <template #domain="{ record }">
          <Link :href="record.domain"> {{ record.domain }}</Link>
        </template>
        <template #description="{ record }">
          {{ record.description || '-' }}
        </template>
        <template #actions="{ record }">
          <Button type="text" @click="edit(record)">编辑</Button>
          <Popconfirm content="你确定要删除吗?" @ok="remove(record)">
            <Button type="text" status="danger"> 删除 </Button>
          </Popconfirm>
        </template>
      </CubeTable>
grasilife commented 3 months ago

给你们一个好用的minWidth的demo

grasilife commented 3 months ago
const columns: TableColumnData[] = [
  {
    dataIndex: 'appKey',
    slotName: 'appKey',
    title: 'AppKey',
    ellipsis: true,
    tooltip: true,
  },
  {
    dataIndex: 'name',
    slotName: 'name',
    title: '应用名',

    ellipsis: true,
    tooltip: true,
  },
  {
    dataIndex: 'domain',
    slotName: 'domain',
    title: '应用域名',
    width: 200,
    ellipsis: true,
    tooltip: true,
  },
  {
    dataIndex: 'description',
    slotName: 'description',
    title: '描述',
    ellipsis: true,
    tooltip: true,
  },
  ...commonColumns,
  {
    dataIndex: 'actions',
    slotName: 'actions',
    title: '操作',
    width: 160,
    fixed: 'right',
  },
];
grasilife commented 3 months ago
<template>
  <div class="CubeTableCom">
    <Spin :loading="props.loading" tip="数据加载中">
      <div class="tableContain">
        <table>
          <!-- 表头 -->
          <thead>
            <tr class="tableRow">
              <th
                v-for="(columnsItem, index) in props.columns"
                :key="index"
                :class="{
                  fixed: columnsItem.fixed,
                  fixedBackground: columnsItem.fixed,
                  lastBorder: !columnsItem.fixed,
                }"
                :style="{
                  minWidth: `${columnsItem.minWidth}px`,
                  width: `${columnsItem.width}px`,
                }"
              >
                <Ellipsis :switch="columnsItem.ellipsis">
                  {{ columnsItem.title }}
                </Ellipsis>
              </th>
            </tr>
          </thead>

          <!-- 表格内容 -->
          <tbody>
            <tr
              v-for="(dataSourceItem, dataSourceIndex) in props.data"
              :key="dataSourceIndex"
              class="tableRow"
              :class="{ trListHover: dataSourceIndex === activeKey }"
              @mouseenter="mouseenter(dataSourceIndex)"
              @mouseleave="mouseleave(dataSourceIndex)"
            >
              <td
                v-for="(columnsItem, columnsIndex) in props.columns"
                :key="columnsIndex"
                :class="{
                  fixed: columnsItem.fixed,
                  trListHover: dataSourceIndex === activeKey,
                  lastBorder: !columnsItem.fixed,
                  ellipsis: columnsItem.ellipsis,
                }"
                :style="{
                  minWidth: `${columnsItem.minWidth}px`,
                  width: `${columnsItem.width}px`,
                }"
              >
                <Ellipsis :switch="columnsItem.ellipsis">
                  <template v-if="hasSlot(columnsItem.slotName)">
                    <slot
                      :name="columnsItem.slotName"
                      :record="dataSourceItem"
                    ></slot>
                  </template>
                  <template v-else>
                    <Tooltip
                      v-if="columnsItem.tooltip"
                      :content="getValue(dataSourceItem, columnsItem.dataIndex)"
                      position="bottom"
                    >
                      <span>{{
                        getValue(dataSourceItem, columnsItem.dataIndex)
                      }}</span>
                    </Tooltip>
                    <template v-else>
                      {{ getValue(dataSourceItem, columnsItem.dataIndex) }}
                    </template>
                  </template>
                </Ellipsis>
              </td>
            </tr>
          </tbody>
        </table>

        <div class="contain" v-if="props.data.length === 0">
          <Empty v-if="props.data.length === 0" />
        </div>
      </div>
      <div class="pagination">
        <Pagination
          v-if="props.pagination"
          v-model="props.pagination.current"
          :total="props.pagination?.total || 0"
          :pageSize="pagination.pageSize"
          :showTotal="pagination.showTotal"
          :showJumper="pagination.showJumper"
          :showPageSize="pagination.showPageSize"
          @change="change"
          @page-size-change="pageSizeChange"
        />
      </div>
    </Spin>
  </div>
</template>

<script setup lang="ts">
import {
  TableColumnData,
  Empty,
  PaginationProps,
  Pagination,
  Spin,
  Tooltip,
} from '@arco-design/web-vue';
import { PropType, ref, useSlots, VNode } from 'vue';
import Ellipsis from '~/components/Ellipsis.vue';
import { beautifyJSON } from '~/utils';
type Slots = Record<string, () => VNode[]>;
const activeKey = ref(-1);
const emit = defineEmits([
  'mouseenter',
  'mouseleave',
  'pageChange',
  'pageSizeChange',
]);
const change = (currentPage: number) => {
  console.log(currentPage, 'currentPage');
  emit('pageChange', currentPage);
};
const pageSizeChange = (pageSize: number) => {
  console.log(pageSize, 'pageSize');
  emit('pageSizeChange', pageSize);
};
const props = defineProps({
  loading: {
    type: Boolean,
    required: false,
    default: () => false,
  },
  bordered: {
    type: Boolean,
    required: false,
    default: () => true,
  },
  data: {
    type: Array as PropType<any[]>,
    required: true,
    default: () => [],
  },
  pagination: {
    type: Object as PropType<PaginationProps>,
    required: false,
    default: () => null,
  },
  columns: {
    type: Array as PropType<TableColumnData[]>,
    required: true,
    default: () => [],
  },
});

function hasSlot(slotName: string | undefined): boolean {
  const slots = useSlots() as Slots;
  return slotName ? !!slots[slotName] : false;
}

function getValue(dataSourceItem: any, dataIndex: string | undefined): string {
  if (dataIndex) {
    const value = dataSourceItem[dataIndex as keyof typeof dataSourceItem];

    // 如果值是对象或数组,使用 beautifyJSON 进行美化处理
    if (typeof value === 'object' && value !== null) {
      return beautifyJSON(value);
    }

    // 如果值是布尔值或数字,将其转换为字符串
    if (typeof value === 'boolean' || typeof value === 'number') {
      return value.toString();
    }

    // 默认情况,直接返回值,确保其为字符串
    return value !== undefined && value !== null ? value.toString() : '-';
  }

  // 如果没有 dataIndex 或值为空,返回占位符 '-'
  return '-';
}

function mouseenter(dataSourceIndex: number) {
  activeKey.value = dataSourceIndex;
  emit('mouseenter', dataSourceIndex);
}

function mouseleave(dataSourceIndex: number) {
  activeKey.value = -1;
  emit('mouseleave', dataSourceIndex);
}
</script>

<style scoped>
.CubeTableCom {
  display: flex;
  flex-direction: column;
  flex: 1;
}
.tableContain {
  display: flex;
  flex-direction: column;
  flex: 1;
  font-size: 14px;
  border-top: 1px solid var(--color-border);
  border-left: 1px solid var(--color-border);
  border-right: 1px solid var(--color-border);
  overflow-x: auto;
  overflow-y: hidden;
}
table {
  border-collapse: collapse;
  width: 100%;
}
tr {
  width: 100%;
}
th,
td {
  text-align: left;
  padding: 12px 16px;
}
th {
  background-color: var(--color-fill-2);
  color: var(--color-text);
  border-bottom: 1px solid var(--color-border);
}
.borderedRight {
  border-right: 1px solid var(--color-border);
}
td {
  color: var(--color-text-secondary);
  border-bottom: 1px solid var(--color-border);
}

.fixed {
  position: sticky;
  right: 0;
  background: #fff;
  z-index: 2;
  display: inline-block;
  border-left: 1px solid var(--color-border);
}
.fixedBackground {
  background-color: var(--color-fill-2);
}
.lastBorder {
  border-left: 1px solid var(--color-border);
}

.trListHover {
  transition: background-color 0.2s;
  background-color: var(--color-fill-2);
}
.contain {
  display: flex;
  height: 200px;
  align-items: center;
  justify-content: center;
  border-bottom: 1px solid var(--color-border);
}
.pagination {
  display: flex;
  flex: 1;
  justify-content: flex-end;
  margin-top: 12px;
}

/* 选择除最后两个子元素之外的所有子元素 */
.tableRow > :not(:nth-last-child(-n + 2)) {
  border-right: 1px solid var(--color-border);
}
</style>
grasilife commented 3 months ago
<template>
  <div ref="ellipsisContainer" :style="ellipsisStyle">
    <slot></slot>
  </div>
</template>

<script lang="ts" setup>
import { onMounted, onBeforeUnmount, ref, computed } from 'vue';

const props = defineProps({
  switch: {
    type: Boolean,
    required: false,
    default: () => false,
  },
});

const ellipsisContainer = ref<HTMLElement | null>(null);

const ellipsisStyle = computed(() => {
  if (props.switch) {
    if (ellipsisContainer.value && ellipsisContainer.value) {
      const parentWidth = ellipsisContainer.value.clientWidth;
      return {
        maxWidth: `${parentWidth}px`,
        whiteSpace: 'nowrap',
        overflow: 'hidden',
        textOverflow: 'ellipsis',
      };
    }
  } else {
    return {};
  }
});

const setEllipsisWidth = () => {
  if (props.switch && ellipsisContainer.value) {
    const parentWidth = ellipsisContainer.value.clientWidth;
    ellipsisContainer.value.style.maxWidth = `${parentWidth}px`;
  }
};

onMounted(() => {
  if (props.switch) {
    setEllipsisWidth();
    window.addEventListener('resize', setEllipsisWidth);
  }
});

onBeforeUnmount(() => {
  if (props.switch) {
    window.removeEventListener('resize', setEllipsisWidth);
  }
});
</script>

<style scoped>
.ellipsis {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
</style>
lin-97 commented 3 months ago

为了点小问题,写这堆屎山代码,又不是不能用

grasilife commented 3 months ago

为了点小问题,写这堆屎山代码,又不是不能用 我只是想要一个好用的minwidth而已,代码你可以写的比我好,相信你,太常用了,其他功能需要不是很大,这个太大了

mingbai2006 commented 1 month ago

为了点小问题,写这堆屎山代码,又不是不能用

经典的“又不是不能用”,那太好了,BUG也别修了,项目也别维护了,张嘴闭嘴就屎山代码,你又不是维护者,别人提个意见碍着你啥事了?什么毛病都带到这里来了,污染环境

lin-97 commented 1 month ago

为了点小问题,写这堆屎山代码,又不是不能用

经典的“又不是不能用”,那太好了,BUG也别修了,项目也别维护了,张嘴闭嘴就屎山代码,你又不是维护者,别人提个意见碍着你啥事了?什么毛病都带到这里来了,污染环境

arco-table的min-width用这没问题啊,反正我测了没问题,而且就算要弄td的min-width,也有个td插槽,封装这么麻烦干嘛,arco的灵活度不是那么差的,不会用怪组件库呗

lin-97 commented 1 month ago

为了点小问题,写这堆屎山代码,又不是不能用

经典的“又不是不能用”,那太好了,BUG也别修了,项目也别维护了,张嘴闭嘴就屎山代码,你又不是维护者,别人提个意见碍着你啥事了?什么毛病都带到这里来了,污染环境

如果你接手一个项目,看到这个二次封装的,一没有文档,要你看源码,行如果你厉害你看得懂了,可以往下做,如果要扩展需求,a-table能实现,这个不能,你要咋弄,继续给源码加props是吧,到时候你别骂街就行,你不骂街,下个人就要骂你

lin-97 commented 1 month ago

为了点小问题,写这堆屎山代码,又不是不能用

经典的“又不是不能用”,那太好了,BUG也别修了,项目也别维护了,张嘴闭嘴就屎山代码,你又不是维护者,别人提个意见碍着你啥事了?什么毛病都带到这里来了,污染环境

楼主的也不是基于a-table二次封装,而是自己封装的,这样会导致什么呢,样式不统一,风格不统一,你告诉我这不是变成屎山的节奏吗以后,而且也没有文档,我宁愿用着组件库的table,也不会搞这么复杂