DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)示例3: 行选择

发布于:2025-03-06 ⋅ 阅读:(13) ⋅ 点赞:(0)

前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕

共同探索软件研发!敬请关注【宝码香车】
关注描述

csdngif标识


📚📗📕📘📖🕮💡📝🗂️✍️🛠️💻🚀🎉🏗️🌐🖼️🔗📊👉🔖⚠️🌟🔐⬇️·正文开始⬇️·🎥😊🎓📩😺🌈🤝🤖📜📋🔍✅🧰❓📄📢📈 🙋0️⃣1️⃣2️⃣3️⃣4️⃣5️⃣6️⃣7️⃣8️⃣9️⃣🔟🆗*️⃣#️⃣

DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)示例3: 行选择

📚前言

DeepSeek 与各大企业的合作不断深化。2 月 3 日,百度智能云宣布 DeepSeek-R1 和 DeepSeek-V3 模型已在百度智能云千帆平台上架,并推出超低价格方案;联通云宣布已基于星罗平台实现国产及主流算力适配多规格 DeepSeek-R1 模型,扩大了模型市场覆盖范围。2 月 4 日,京东云宣布正式上线 DeepSeek-R1 和 DeepSeek-V3 模型,支持公有云在线部署、专混私有化实例部署两种模式;DeepSeek V3 和 R1 模型完成海光 DCU 国产化适配,并正式上线,推动了国产化适配进程。

📚页面效果

DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)示例3:  行选择

📚指令输入

已经创建好了一个基于Vue3的组合式API的项目(Composition API),并能正常运行起来,请帮我用 Vue3的组合式API(Composition API) 生成一个 表格(Table) 的功能组件,所有代码都保存在components/Table 下的文件夹中。功能组件的script标签中只有setup属性,使用普通 JavaScript 实现,不使用TypeScript。
功能要有,如下属性:

定义属性

数据相关
  1. data
    • 作用:表格展示的数据,是一个数组,每个元素代表一行记录。
    • 类型:Array<Object>
    • 默认值:[]
  2. columns
    • 作用:定义表格的列配置,每个元素包含列标题、数据字段名、对齐方式等信息。
    • 类型:Array<Object>
    • 默认值:[]
    • 示例:[{ title: '姓名', dataIndex: 'name', align: 'left' }]
  3. pagination
    • 作用:是否开启分页功能。
    • 类型:Boolean
    • 默认值:false
  4. pageSize
    • 作用:每页显示的记录数。
    • 类型:Number
    • 默认值:10
  5. currentPage
    • 作用:当前显示的页码,支持双向绑定。
    • 类型:Number
    • 默认值:1
样式与布局相关
  1. stripe
    • 作用:是否显示斑马纹效果。
    • 类型:Boolean
    • 默认值:false
  2. border
    • 作用:是否显示表格边框。
    • 类型:Boolean
    • 默认值:false
  3. size
    • 作用:表格的尺寸,如 smallmediumlarge
    • 类型:String
    • 默认值:'medium'
  4. headerAlign
    • 作用:表头内容的对齐方式,如 leftcenterright
    • 类型:String
    • 默认值:'left'
  5. cellAlign
    • 作用:表格单元格内容的对齐方式,如 leftcenterright
    • 类型:String
    • 默认值:'left'
功能相关
  1. rowSelection
    • 作用:是否开启行选择功能。
    • 类型:Boolean
    • 默认值:false
  2. selectedRows
    • 作用:双向绑定当前选中的行数据,支持 v-model 语法。
    • 类型:Array<Object>
    • 默认值:[]
  3. sortable
    • 作用:是否开启列排序功能。
    • 类型:Boolean
    • 默认值:false
  4. sortedColumn
    • 作用:当前排序的列信息,包括列字段名和排序顺序(ascdesc)。
    • 类型:Object
    • 默认值:{ field: null, order: null }

定义事件

  1. update:currentPage
    • 作用:当页码发生变化时触发,用于实现 currentPage 的双向绑定。
    • 参数:Number,新的页码。
  2. update:selectedRows
    • 作用:当选中的行发生变化时触发,用于实现 selectedRows 的双向绑定。
    • 参数:Array<Object>,新的选中行数据。
  3. update:sortedColumn
    • 作用:当排序的列发生变化时触发,用于实现 sortedColumn 的双向绑定。
    • 参数:Object,新的排序列信息。
  4. rowClick
    • 作用:当点击表格某一行时触发。
    • 参数:Object,被点击行的数据。
  5. sortChange
    • 作用:当列排序发生变化时触发。
    • 参数:{ field, order },排序的列字段名和排序顺序。
  6. paginationChange
    • 作用:当分页参数(如页码、每页记录数)发生变化时触发。
    • 参数:{ currentPage, pageSize },新的页码和每页记录数。

其他

  1. 提供插槽:使用 Vue 的插槽机制,允许用户自定义表头内容、表格单元格内容、分页器样式等,增加组件的灵活性。例如,用户可以自定义某一列的显示格式。
  2. 虚拟列表支持:当数据量很大时,使用虚拟列表技术,只渲染当前可见区域的数据,提高性能。
  3. 搜索与过滤功能:添加搜索框和过滤条件,方便用户快速查找和筛选数据。
  4. 国际化支持:支持不同语言的表头、分页器文字等,方便不同地区的用户使用。
  5. 键盘交互:支持通过键盘操作表格,如使用方向键移动焦点、回车键选中行等,提升用户操作体验。
  6. 样式定制:提供一些样式类名或 CSS 变量,方便用户自定义表格的样式,如颜色、字体、边框等。
  7. 文档和示例:编写详细的文档,说明每个属性和事件的作用,并提供多种使用示例,方便其他开发者使用该组件。例如,展示如何实现分页、排序、行选择等功能。

你有更好的建议也可以添加,要注明。组件定义好后给出5个及以上的调用示例,示例中添加完整的数据和事件,确保每个示例是独立的。
下面是现有目录
DeepSeekAndVue/
├── src/ # 源代码目录
│ ├── assets/ # 静态资源
│ │ ├── base.css
│ │ ├── main.css
│ │ └── logo.svg
│ ├── components/ # 组件目录
│ │ ├── HelloWorld.vue
│ │ ├── TheWelcome.vue
│ │ ├── WelcomeItem.vue
│ │ ├── Progress/
│ │ │ └── Progress.vue
│ │ ├── Accordion/
│ │ ├── BackToTop/
│ │ ├── Card/
│ │ ├── InfiniteScroll/
│ │ ├── Notification/
│ │ ├── Timeline/
│ │ ├── Switch/
│ │ ├── Tabs/
│ │ ├── Sidebar/
│ │ ├── Breadcrumbs/
│ │ ├── MasonryLayout/
│ │ ├── Rating/
│ │ ├── ColorPicker/
│ │ ├── RightClickMenu/
│ │ ├── RangePicker/
│ │ ├── Navbar/
│ │ ├── FormValidation/
│ │ ├── CopyToClipboard/
│ │ ├── ClickAnimations/
│ │ ├── ThumbnailList/
│ │ ├── KeyboardShortcuts/
│ │ ├── CommentSystem/
│ │ ├── QRCode/
│ │ ├── RadioButton/
│ │ ├── Slider/
│ │ ├── ScrollAnimations/
│ │ ├── TextInput/
│ │ ├── Divider/
│ │ ├── Checkbox/
│ │ ├── TagInput/
│ │ ├── DropdownSelect/
│ │ ├── List/
│ │ ├── Header/
│ │ ├── Footer/
│ │ ├── Pagination/
│ │ ├── FloatingActionButton/
│ │ ├── PasswordInput/
│ │ ├── GridLayout/
│ │ ├── Flexbox/
│ │ ├── Modal/
│ │ ├── RichTextEditor/
│ │ ├── TimePicker/
│ │ ├── FileUpload/
│ │ ├── Autocomplete/
│ │ ├── MultistepForm/
│ │ ├── SearchBar/
│ │ ├── DynamicFormFields/
│ │ ├── Table/
│ │ ├── DatePicker/
│ │ └── icons/
│ ├── router/ # 路由配置
│ │ └── index.js
│ ├── stores/ # Pinia 状态管理
│ │ └── counter.js
│ ├── views/ # 页面组件
│ │ ├── ProgressView.vue
│ │ ├── TabsView.vue
│ │ ├── SwitchView.vue
│ │ ├── TimelineView.vue
│ │ ├── NotificationView.vue
│ │ ├── CardView.vue
│ │ ├── InfiniteScrollView.vue
│ │ ├── BackToTopView.vue
│ │ ├── AccordionView.vue
│ │ ├── SidebarView.vue
│ │ ├── BreadcrumbsView.vue
│ │ ├── MasonryLayoutView.vue
│ │ ├── RatingView.vue
│ │ ├── ColorPickerView.vue
│ │ ├── RightClickMenuView.vue
│ │ ├── RangePickerView.vue
│ │ ├── NavbarView.vue
│ │ ├── FormValidationView.vue
│ │ ├── CopyToClipboardView.vue
│ │ ├── ClickAnimationsView.vue
│ │ ├── ThumbnailListView.vue
│ │ ├── KeyboardShortcutsView.vue
│ │ ├── CommentSystemView.vue
│ │ ├── QRCodeView.vue
│ │ ├── RadioButtonView.vue
│ │ ├── SliderView.vue
│ │ ├── ScrollAnimationsView.vue
│ │ ├── TextInputView.vue
│ │ ├── DividerView.vue
│ │ ├── CheckboxView.vue
│ │ ├── TagInputView.vue
│ │ ├── DropdownSelectView.vue
│ │ ├── ListView.vue
│ │ ├── HeaderView.vue
│ │ ├── FooterView.vue
│ │ ├── PaginationView.vue
│ │ ├── FloatingActionButtonView.vue
│ │ ├── GridLayoutView.vue
│ │ ├── PasswordInputView.vue
│ │ ├── FlexboxView.vue
│ │ ├── ModalView.vue
│ │ ├── RichTextEditorView.vue
│ │ ├── TimePickerView.vue
│ │ ├── FileUploadView.vue
│ │ ├── AutocompleteView.vue
│ │ ├── MultistepFormView.vue
│ │ ├── SearchBarView.vue
│ │ ├── DynamicFormFieldsView.vue
│ │ ├── TableView.vue
│ │ ├── DatePickerView.vue
│ │ └── AboutView.vue
│ ├── App.vue # 根组件
│ └── main.js # 应用入口
├── public/ # 公共资源目录
├── index.html # HTML 模板
├── package.json # 项目配置
├── vite.config.js # Vite 配置
└── node_modules/ # 依赖包目录

📚think

📘组件代码

我将按照您的要求创建一个功能完善的Table组件,并给出多个使用示例。以下是实现步骤:

  1. 首先创建组件文件:components/Table/Table.vue
<!-- components/Table/Table.vue -->
<template>
  <div class="ds-table" :class="[`table-size-${size}`, { 'table-stripe': stripe, 'table-border': border }]">
    <!-- 搜索框 -->
    <div v-if="showSearch" class="table-search">
      <input
        v-model="searchKeyword"
        placeholder="搜索..."
        @input="handleSearch"
        class="search-input"
      />
    </div>

    <!-- 表格主体 -->
    <div class="table-container">
      <table>
        <thead>
          <tr>
            <!-- 选择列 -->
            <th 
              v-if="rowSelection" 
              :class="headerAlignClass"
              class="selection-column"
            >
              <input
                type="checkbox"
                :checked="allSelected"
                @change="toggleAllSelection"
              />
            </th>
            
            <!-- 数据列 -->
            <th
              v-for="col in columns"
              :key="col.dataIndex"
              :class="[headerAlignClass, { sortable: sortable && col.sortable }]"
              @click="handleSort(col)"
            >
              <slot :name="`header-${col.dataIndex}`" :column="col">
                {{ col.title }}
                <span v-if="sortable && col.sortable" class="sort-icon">
                  {{ sortedColumn.field === col.dataIndex ? 
                    (sortedColumn.order === 'asc' ? '↑' : '↓') : '' }}
                </span>
              </slot>
            </th>
          </tr>
        </thead>
        
        <tbody>
          <!-- 虚拟列表占位 -->
          <template v-if="virtualScroll">
            <tr
              v-for="row in visibleData"
              :key="rowKey ? row[rowKey] : row.id"
              :class="{ 'selected-row': isRowSelected(row) }"
              @click="handleRowClick(row)"
            >
              <!-- 选择列 -->
              <td v-if="rowSelection" :class="cellAlignClass">
                <input
                  type="checkbox"
                  :checked="isRowSelected(row)"
                  @change="toggleRowSelection(row)"
                />
              </td>
              
              <!-- 数据列 -->
              <td
                v-for="col in columns"
                :key="col.dataIndex"
                :class="cellAlignClass"
              >
                <slot :name="`cell-${col.dataIndex}`" :row="row" :value="row[col.dataIndex]">
                  {{ row[col.dataIndex] }}
                </slot>
              </td>
            </tr>
          </template>
          
          <!-- 普通列表 -->
          <template v-else>
            <tr
              v-for="(row, index) in processedData"
              :key="rowKey ? row[rowKey] : index"
              :class="{ 'selected-row': isRowSelected(row), 'stripe-row': stripe && index % 2 === 0 }"
              @click="handleRowClick(row)"
            >
              <!-- 同上 -->
            </tr>
          </template>
        </tbody>
      </table>
    </div>

    <!-- 分页 -->
    <div v-if="pagination" class="table-pagination">
      <button 
        :disabled="currentPage === 1"
        @click="changePage(currentPage - 1)"
      >
        上一页
      </button>
      <span>第 {{ currentPage }} 页 / 共 {{ totalPages }} 页</span>
      <button
        :disabled="currentPage >= totalPages"
        @click="changePage(currentPage + 1)"
      >
        下一页
      </button>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, watch, toRefs } from 'vue'

const props = defineProps({
  // 数据相关
  data: {
    type: Array,
    default: () => []
  },
  columns: {
    type: Array,
    default: () => []
  },
  pagination: {
    type: Boolean,
    default: false
  },
  pageSize: {
    type: Number,
    default: 10
  },
  currentPage: {
    type: Number,
    default: 1
  },
  
  // 样式相关
  stripe: Boolean,
  border: Boolean,
  size: {
    type: String,
    default: 'medium',
    validator: v => ['small', 'medium', 'large'].includes(v)
  },
  headerAlign: {
    type: String,
    default: 'left',
    validator: v => ['left', 'center', 'right'].includes(v)
  },
  cellAlign: {
    type: String,
    default: 'left',
    validator: v => ['left', 'center', 'right'].includes(v)
  },
  
  // 功能相关
  rowSelection: Boolean,
  selectedRows: {
    type: Array,
    default: () => []
  },
  sortable: Boolean,
  sortedColumn: {
    type: Object,
    default: () => ({ field: null, order: null })
  },
  
  // 其他
  rowKey: String,
  virtualScroll: Boolean,
  showSearch: Boolean
})

const emit = defineEmits([
  'update:currentPage',
  'update:selectedRows',
  'update:sortedColumn',
  'rowClick',
  'sortChange',
  'paginationChange'
])

const { data, pageSize } = toRefs(props)

// 搜索相关
const searchKeyword = ref('')
const filteredData = computed(() => {
  if (!searchKeyword.value) return props.data
  const keyword = searchKeyword.value.toLowerCase()
  return props.data.filter(row =>
    props.columns.some(col => 
      String(row[col.dataIndex]).toLowerCase().includes(keyword)
  )
})

// 排序处理
const sortedData = computed(() => {
  if (!props.sortable || !props.sortedColumn.field) return filteredData.value
  
  return [...filteredData.value].sort((a, b) => {
    const field = props.sortedColumn.field
    const order = props.sortedColumn.order === 'asc' ? 1 : -1
    return a[field] > b[field] ? order : -order
  })
})

// 分页处理
const totalPages = computed(() => Math.ceil(sortedData.value.length / props.pageSize))
const processedData = computed(() => {
  if (!props.pagination) return sortedData.value
  const start = (props.currentPage - 1) * props.pageSize
  const end = start + props.pageSize
  return sortedData.value.slice(start, end)
})

// 选择功能
const allSelected = computed(() => 
  props.selectedRows.length === processedData.value.length && processedData.value.length > 0
)

function toggleRowSelection(row) {
  const selected = [...props.selectedRows]
  const index = selected.findIndex(r => r === row)
  if (index > -1) {
    selected.splice(index, 1)
  } else {
    selected.push(row)
  }
  emit('update:selectedRows', selected)
}

function toggleAllSelection(e) {
  const checked = e.target.checked
  emit('update:selectedRows', checked ? [...processedData.value] : [])
}

function isRowSelected(row) {
  return props.selectedRows.includes(row)
}

// 分页控制
function changePage(page) {
  if (page < 1 || page > totalPages.value) return
  emit('update:currentPage', page)
  emit('paginationChange', { currentPage: page, pageSize: props.pageSize })
}

// 排序处理
function handleSort(col) {
  if (!props.sortable || !col.sortable) return
  
  let order = 'asc'
  if (props.sortedColumn.field === col.dataIndex) {
    order = props.sortedColumn.order === 'asc' ? 'desc' : null
  }
  
  const newSort = order ? 
    { field: col.dataIndex, order } : 
    { field: null, order: null }
  
  emit('update:sortedColumn', newSort)
  emit('sortChange', newSort)
}

// 事件处理
function handleRowClick(row) {
  emit('rowClick', row)
}

function handleSearch() {
  if (props.pagination) {
    emit('update:currentPage', 1)
  }
}

// 样式类
const headerAlignClass = computed(() => `align-${props.headerAlign}`)
const cellAlignClass = computed(() => `align-${props.cellAlign}`)

// 虚拟列表相关(简化实现)
const visibleData = computed(() => processedData.value)
</script>

<style scoped>
.ds-table {
  --header-bg: #f5f7fa;
  --border-color: #ebeef5;
  --hover-bg: #f5f7fa;
}

table {
  width: 100%;
  border-collapse: collapse;
}

th, td {
  padding: 12px;
  border-bottom: 1px solid var(--border-color);
}

/* 对齐样式 */
.align-left { text-align: left; }
.align-center { text-align: center; }
.align-right { text-align: right; }

/* 斑马纹 */
.table-stripe tr:nth-child(even) {
  background-color: var(--header-bg);
}

/* 边框 */
.table-border {
  border: 1px solid var(--border-color);
}

/* 尺寸 */
.table-size-small th, 
.table-size-small td {
  padding: 8px;
}

.table-size-large th,
.table-size-large td {
  padding: 16px;
}

/* 悬停效果 */
tr:hover {
  background-color: var(--hover-bg);
}

.selected-row {
  background-color: #e6f7ff !important;
}

.sort-icon {
  margin-left: 4px;
}

.sortable {
  cursor: pointer;
  user-select: none;
}

.table-pagination {
  margin-top: 16px;
  display: flex;
  gap: 12px;
  align-items: center;
}

.search-input {
  margin-bottom: 16px;
  padding: 8px;
  width: 200px;
}
</style>

接下来是5个使用示例:

<!-- 示例1: 基础表格 -->
<template>
  <Table
    :data="users"
    :columns="[
      { title: 'ID', dataIndex: 'id' },
      { title: '姓名', dataIndex: 'name' },
      { title: '年龄', dataIndex: 'age' }
    ]"
  />
</template>

<script setup>
import { ref } from 'vue'
import Table from '@/components/Table/Table.vue'

const users = ref([
  { id: 1, name: '张三', age: 25 },
  { id: 2, name: '李四', age: 30 },
  { id: 3, name: '王五', age: 28 }
])
</script>

<!-- 示例2: 分页和排序 -->
<template>
  <Table
    :data="dataList"
    :columns="columns"
    :pagination="true"
    :page-size="5"
    v-model:current-page="currentPage"
    :sortable="true"
    v-model:sorted-column="sortedCol"
    @sort-change="handleSort"
  />
</template>

<script setup>
import { ref } from 'vue'

const dataList = ref([/* 50条数据 */])
const currentPage = ref(1)
const sortedCol = ref({ field: null, order: null })

const columns = [
  { title: '日期', dataIndex: 'date', sortable: true },
  { title: '销售额', dataIndex: 'amount', sortable: true }
]

function handleSort({ field, order }) {
  console.log('排序变化:', field, order)
}
</script>

<!-- 示例3: 行选择 -->
<template>
  <Table
    :data="products"
    :columns="columns"
    :row-selection="true"
    v-model:selected-rows="selected"
    @row-click="showDetail"
  />
</template>

<script setup>
import { ref } from 'vue'

const products = ref([/* ... */])
const selected = ref([])
const columns = [
  { title: '产品名称', dataIndex: 'name' },
  { title: '价格', dataIndex: 'price' }
]

function showDetail(row) {
  console.log('查看详情:', row)
}
</script>

<!-- 示例4: 自定义插槽 -->
<template>
  <Table :data="orders" :columns="columns">
    <template #header-status="{ column }">
      <span style="color: blue">{{ column.title }}</span>
    </template>
    
    <template #cell-status="{ row }">
      <span :style="{ color: row.status === '完成' ? 'green' : 'red' }">
        {{ row.status }}
      </span>
    </template>
  </Table>
</template>

<script setup>
// 数据定义...
</script>

<!-- 示例5: 搜索和过滤 -->
<template>
  <Table
    :data="customers"
    :columns="columns"
    :show-search="true"
    stripe
    border
    size="small"
  />
</template>

<script setup>
// 数据定义...
</script>

优化建议:

  1. 添加表格空状态提示
  2. 增加加载状态指示器
  3. 支持列宽调整
  4. 添加表头固定功能
  5. 支持导出数据功能
  6. 添加行拖拽排序功能
  7. 支持列固定(冻结列)
  8. 添加树形表格支持
  9. 支持单元格合并
  10. 添加详细的键盘导航支持

每个功能都可以通过组合式API逐步实现,建议根据实际需求优先级逐步添加这些功能。

📚代码测试

页面有一个报错,原因是代码中少了一个结束的括号")"。修正后还不显示,是因为生成的代码中省略了一部分代码在Table组件中。展示的示例要加 :virtualScroll="true"才可以。virtualScroll是完整模式。

📚示例3,整理后主要代码

📘定义组件 \src\views\TableView3.vue

<template>
  <Table
      :data="products"
      :columns="columns"
      :virtualScroll="true"
      :row-selection="true"
      v-model:selected-rows="selected"
      @row-click="showDetail"
  />
</template>

<script setup>
import { ref } from 'vue'
import Table from '@/components/Table/Table.vue'

// 模拟产品数据
const products = ref([
  { id: 1, name: 'iPhone 15', price: 6999, stock: 100, category: '手机' },
  { id: 2, name: 'MacBook Pro', price: 12999, stock: 50, category: '笔记本' },
  { id: 3, name: 'iPad Air', price: 4799, stock: 80, category: '平板' },
  { id: 4, name: 'AirPods Pro', price: 1999, stock: 200, category: '耳机' },
  { id: 5, name: 'Apple Watch', price: 3299, stock: 150, category: '智能手表' },
  { id: 6, name: 'iMac', price: 15999, stock: 30, category: '台式机' },
  { id: 7, name: 'Magic Keyboard', price: 999, stock: 120, category: '配件' },
  { id: 8, name: 'Magic Mouse', price: 699, stock: 180, category: '配件' },
  { id: 9, name: 'HomePod', price: 2499, stock: 60, category: '智能音箱' },
  { id: 10, name: 'Mac mini', price: 5999, stock: 40, category: '台式机' }
])

const selected = ref([])

// 扩展列配置,添加更多有用的信息
const columns = [
  { title: '产品名称', dataIndex: 'name' },
  { title: '价格', dataIndex: 'price', 
    render: (price) => `¥${price.toLocaleString()}` },
  { title: '库存', dataIndex: 'stock' },
  { title: '分类', dataIndex: 'category' }
]

function showDetail(row) {
  console.log('查看详情:', row)
}
</script>

<style scoped>
.table-container {
  padding: 20px;
}
</style>

📚测试代码正常跑通,附其他基本代码

  • 添加路由
  • 页面展示入口

📘编写路由 src\router\index.js

\router\index.js

import { createRouter, createWebHistory } from 'vue-router'
import RightClickMenuView from '../views/RightClickMenuView.vue'
import RangePickerView from '../views/RangePickerView.vue'


const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: 'progress',
      component:  () => import('../views/ProgressView.vue'),
    },
    {
      path: '/tabs',
      name: 'tabs',
      // route level code-splitting
      // this generates a separate chunk (About.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      // 标签页(Tabs)
      component: () => import('../views/TabsView.vue'),
    },
    {
      path: '/accordion',
      name: 'accordion',
      // 折叠面板(Accordion)
      component: () => import('../views/AccordionView.vue'),
    },
    {
      path: '/timeline',
      name: 'timeline',
      // 时间线(Timeline)
      component: () => import('../views/TimelineView.vue'),
    },
    {
      path: '/backToTop',
      name: 'backToTop',
      component: () => import('../views/BackToTopView.vue')
    },
    {
      path: '/notification',
      name: 'notification',
      component: () => import('../views/NotificationView.vue')
    },
    {
      path: '/card',
      name: 'card',
      component: () => import('../views/CardView.vue')
    },
    {
      path: '/infiniteScroll',
      name: 'infiniteScroll',
      component: () => import('../views/InfiniteScrollView.vue')
    },
    {
      path: '/switch',
      name: 'switch',
      component: () => import('../views/SwitchView.vue')
    },
    {
      path: '/sidebar',
      name: 'sidebar',
      component: () => import('../views/SidebarView.vue')
    },
    {
      path: '/breadcrumbs',
      name: 'breadcrumbs',
      component: () => import('../views/BreadcrumbsView.vue')
    },
    {
      path: '/masonryLayout',
      name: 'masonryLayout',
      component: () => import('../views/MasonryLayoutView.vue')
    },
    {
      path: '/rating',
      name: 'rating',
      component: () => import('../views/RatingView.vue')
    },
    {
      path: '/datePicker',
      name: 'datePicker',
      component: () => import('../views/DatePickerView.vue')
    },
    {
      path: '/colorPicker',
      name: 'colorPicker',
      component: () => import('../views/ColorPickerView.vue')
    },
    {
      path: '/rightClickMenu',
      name: 'rightClickMenu',
      component: RightClickMenuView
    },
    {
      path: '/rangePicker',
      name: 'rangePicker',
      component: () => import('../views/RangePickerView.vue')
    },
    {
      path: '/navbar',
      name: 'navbar',
      component: () => import('../views/NavbarView.vue')
    },
    {
      path: '/formValidation',
      name: 'formValidation',
      component: () => import('../views/FormValidationView.vue')
    },
    {
      path: '/copyToClipboard',
      name: 'copyToClipboard',
      component: () => import('../views/CopyToClipboardView.vue')
    },
    {
      path: '/clickAnimations',
      name: 'clickAnimations',
      component: () => import('../views/ClickAnimationsView.vue')
    },
    {
      path: '/thumbnailList',
      name: 'thumbnailList',
      component: () => import('../views/ThumbnailListView.vue')
    },
    {
      path: '/keyboardShortcuts',
      name: 'keyboardShortcuts',
      component: () => import('../views/KeyboardShortcutsView.vue')
    },
    {
      path: '/commentSystem',
      name: 'commentSystem',
      component: () => import('../views/CommentSystemView.vue')
    },
    {
      path: '/qRCode',
      name: 'qRCode',
      component: () => import('../views/QRCodeView.vue')
    },
    {
      path: '/radioButton',
      name: 'radioButton',
      component: () => import('../views/RadioButtonView.vue')
    },
    {
      path: '/slider',
      name: 'slider',
      component: () => import('../views/SliderView.vue')
    },
    {
      path: '/scrollAnimations',
      name: 'scrollAnimations',
      component: () => import('../views/ScrollAnimationsView.vue')
    },
    {
      path: '/textInputView',
      name: 'textInputView',
      component: () => import('../views/TextInputView.vue')
    },
    {
      path: '/divider',
      name: 'divider',
      component: () => import('../views/DividerView.vue')
    },
    {
      path: '/checkbox',
      name: 'checkbox',
      component: () => import('../views/CheckboxView.vue')
    },
    {
      path: '/tagInput',
      name: 'tagInput',
      component: () => import('../views/TagInputView.vue')
    },
    {
      path: '/dropdownSelect',
      name: 'dropdownSelect',
      component: () => import('../views/DropdownSelectView.vue')
    },
    {
      path: '/list',
      name: 'list',
      component: () => import('../views/ListView.vue')
    },
    {
      path: '/header',
      name: 'header',
      component: () => import('../views/HeaderView.vue')
    },
    {
      path: '/footer',
      name: 'footer',
      component: () => import('../views/FooterView.vue')
    },
    {
      path: '/pagination',
      name: 'pagination',
      component: () => import('../views/PaginationView.vue')
    },
    {
      path: '/floatingActionButton',
      name: 'floatingActionButton',
      component: () => import('../views/FloatingActionButtonView.vue')
    },
    {
      path: '/gridLayout',
      name: 'gridLayout',
      component: () => import('../views/GridLayoutView.vue')
    },
    {
      path: '/passwordInput',
      name: 'passwordInput',
      component: () => import('../views/PasswordInputView.vue')
    },
    {
      path: '/flexbox',
      name: 'flexbox',
      component: () => import('../views/FlexboxView.vue')
    },
    {
      path: '/modal',
      name: 'modal',
      component: () => import('../views/ModalView.vue')
    },
    {
      path: '/richTextEditor',
      name: 'richTextEditor',
      component: () => import('../views/RichTextEditorView.vue')
    },
    {
      path: '/timePickerView',
      name: 'timePickerView',
      component: () => import('../views/TimePickerView.vue')
    },
    {
      path: '/multistepForm',
      name: 'multistepForm',
      component: () => import('../views/MultistepFormView.vue')
    },
    {
      path: '/table1',
      name: 'table1',
      component: () => import('../views/TableView1.vue')
    },
    {
      path: '/table2',
      name: 'table2',
      component: () => import('../views/TableView2.vue')
    },
    {
      path: '/table3',
      name: 'table3',
      component: () => import('../views/TableView3.vue')
    },
    {
      path: '/table4',
      name: 'table4',
      component: () => import('../views/TableView4.vue')
    },
    {
      path: '/table5',
      name: 'table5',
      component: () => import('../views/TableView5.vue')
    }
  ],
})

export default router

📘编写展示入口 src\App.vue

 src\App.vue

<script setup>
import { RouterLink, RouterView } from 'vue-router'
import HelloWorld from './components/HelloWorld.vue'
</script>

<template>
  <header>
    <img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="125" height="125" />

    <div class="wrapper">
      <HelloWorld msg="You did it!" />
      <nav>
        <RouterLink to="/">Progress</RouterLink>
        <RouterLink to="/tabs">Tabs</RouterLink>
        <RouterLink to="/accordion">Accordion</RouterLink>
        <RouterLink to="/timeline">Timeline</RouterLink>
        <RouterLink to="/backToTop">BackToTop</RouterLink>
        <RouterLink to="/notification">Notification</RouterLink>
        <RouterLink to="/card">Card</RouterLink>
        <RouterLink to="/infiniteScroll">InfiniteScroll</RouterLink>
        <RouterLink to="/switch">Switch</RouterLink>
        <RouterLink to="/sidebar">Sidebar</RouterLink>
        <RouterLink to="/breadcrumbs">Breadcrumbs</RouterLink>
        <RouterLink to="/masonryLayout">MasonryLayout</RouterLink>
        <RouterLink to="/rating">Rating</RouterLink>
        <RouterLink to="/datePicker">DatePicker</RouterLink>
        <RouterLink to="/colorPicker">ColorPicker</RouterLink>
        <RouterLink to="/rightClickMenu">RightClickMenu</RouterLink>
        <RouterLink to="/rangePicker">RangePicker</RouterLink>
        <RouterLink to="/navbar">Navbar</RouterLink>
        <RouterLink to="/formValidation">FormValidation</RouterLink>
        <RouterLink to="/copyToClipboard">CopyToClipboard</RouterLink>
        <RouterLink to="/clickAnimations">ClickAnimations</RouterLink>
        <RouterLink to="/thumbnailList">ThumbnailList</RouterLink>
        <RouterLink to="/keyboardShortcuts">KeyboardShortcuts</RouterLink>
        <RouterLink to="/commentSystem">CommentSystem</RouterLink>
        <RouterLink to="/qRCode">QRCode</RouterLink>
        <RouterLink to="/radioButton">RadioButton</RouterLink>
        <RouterLink to="/slider">Slider</RouterLink>
        <RouterLink to="/scrollAnimations">ScrollAnimations</RouterLink>
        <RouterLink to="/textInputView">TextInput</RouterLink>
        <RouterLink to="/divider">Divider</RouterLink>
        <RouterLink to="/checkbox">Checkbox</RouterLink>
        <RouterLink to="/tagInput">TagInput</RouterLink>
        <RouterLink to="/dropdownSelect">DropdownSelect</RouterLink>
        <RouterLink to="/list">List</RouterLink>
        <RouterLink to="/header">Header</RouterLink>
        <RouterLink to="/footer">Footer</RouterLink>
        <RouterLink to="/pagination">Pagination</RouterLink>
        <RouterLink to="/floatingActionButton">FloatingActionButton</RouterLink>
        <RouterLink to="/gridLayout">GridLayout</RouterLink>
        <RouterLink to="/passwordInput">PasswordInput</RouterLink>
        <RouterLink to="/flexbox">Flexbox</RouterLink>
        <RouterLink to="/modal">Modal</RouterLink>
        <RouterLink to="/richTextEditor">RichTextEditor</RouterLink>
        <RouterLink to="/timePickerView">TimePickerView</RouterLink>
        <RouterLink to="/multistepForm">MultistepFormView</RouterLink>
        <RouterLink to="/table1">Table1</RouterLink>
        <RouterLink to="/table2">Table2</RouterLink>
        <RouterLink to="/table3">Table3</RouterLink>
        <RouterLink to="/table4">Table4</RouterLink>
        <RouterLink to="/table5">Table5</RouterLink>
      </nav>
    </div>
  </header>
  <RouterView />
</template>

<style scoped>
header {
  line-height: 1.5;
  max-height: 100vh;
}

.logo {
  display: block;
  margin: 0 auto 2rem;
}

nav {
  width: 100%;
  font-size: 12px;
  text-align: center;
  margin-top: 2rem;
}

nav a.router-link-exact-active {
  color: var(--color-text);
}

nav a.router-link-exact-active:hover {
  background-color: transparent;
}

nav a {
  display: inline-block;
  padding: 0 1rem;
  border-left: 1px solid var(--color-border);
}

nav a:first-of-type {
  border: 0;
}

@media (min-width: 1024px) {
  header {
    display: flex;
    place-items: center;
    padding-right: calc(var(--section-gap) / 2);
  }

  .logo {
    margin: 0 2rem 0 0;
  }

  header .wrapper {
    display: flex;
    place-items: flex-start;
    flex-wrap: wrap;
  }

  nav {
    text-align: left;
    margin-left: -1rem;
    font-size: 1rem;

    padding: 1rem 0;
    margin-top: 1rem;
  }
}
</style>

📚页面效果

DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)示例3

到此这篇文章就介绍到这了,更多精彩内容请关注本人以前的文章或继续浏览下面的文章,创作不易,如果能帮助到大家,希望大家多多支持宝码香车~💕,若转载本文,一定注明本文链接。


整理不易,点赞关注宝码香车