Wiidede's blog Wiidede's blog
  • 前端
  • Python
  • 算法
  • 生活
  • 其他
  • 分类
  • 标签
  • 归档
  • 关于我
  • 赞赏
  • 我的小站 (opens new window)
GitHub (opens new window)

Wiidede

小的的写前端
  • 前端
  • Python
  • 算法
  • 生活
  • 其他
  • 分类
  • 标签
  • 归档
  • 关于我
  • 赞赏
  • 我的小站 (opens new window)
GitHub (opens new window)
  • 整理一些css样式
  • vue隔代组件层层动态插槽并且附带数据
  • vue判断字符串是否溢出来显示弹窗、解决el-table tooltip 内过多导致无法显示,内容闪烁
  • 整理一些js写法
  • ElementUI timePicker 增加此刻按钮 引发的dom操作的学习
  • 毕业设计(水表识别)前端知识整理
  • html小知识
  • axios请求api然后下载文件
  • vue3+ts根据高度改变元素的透明度
  • vue3 + ElementPlus 换肤方案(Css变量)
  • Moment的一些使用方法
  • echarts基础vue组件
  • element UI el-date-picker 年月日切换组件
  • 可以不选择的el-radio单选框
  • vue的小技巧总结
  • 全局动态权限判断(Vue指令)
  • vue-anchor 探索
  • Deep Dive with Evan You 笔记
  • 前端基础知识查漏补缺
  • WebPack 知识总结
  • 我写的一些可以日后参考的代码
  • 接口变化后,封装接口函数,改变返回内容
  • 项目组件整理
  • 前端框架设计想发
  • 全局进度条
  • 带有token的图片vue组件:authImg,使用axios下载图片
  • 前端npm包推荐
  • 给ElInputNumber添加prefix
  • ElPagination添加页数总数
  • el-tab做成chrome类似的tab样式
  • vue-grid-layout-组件配置
  • 项目数据字典封装
  • 图表组件响应式探索
  • ElementPlus表格table列自动合并composition
  • 简单的curd组件封装
    • utils
    • 基于这个想法,我觉得el-form可以同样的封装,但是为了灵活,我把el-form-item做了一个组件
  • ElementPlus表格自定义合计列composition
  • 一些处理表格数据composition api
  • div内容溢出后,内容向左悬浮,vue组件封装
  • 文本数字溢出后,按比例缩小,vue组件封装
  • 表格使用async-validator检验composition
  • ElementPlus Form一些简单的组件整合
  • arco-design快速使用tailwind的颜色、unocss动态颜色
  • 前端
wiidede
2022-12-31

简单的curd组件封装

# 简单的curd组件封装

特性:主要是合并表格、分页,然后其他内容自己通过slot插入,表格column也使用对象的形式定义

<template>
  <div class="curd-container h-full flex flex-col">
    <div class="header-line">
      <slot name="header" />
    </div>
    <div class="table-container flex-auto">
      <el-table
        ref="tableRef"
        :data="tableData"
        class="flex-auto"
        stripe
        border
      >
        <template
          v-for="(column, index) in columns"
          :key="column.prop || index"
        >
          <el-table-column
            :class-name="column.className || (column.slot && `${column.slot}-column`)"
            v-bind="column"
            #="scope"
          >
            <span v-if="column.prop && column.map">{{ column.map.value[scope.row[column.prop]] ?? scope.row[column.prop] }}</span>
            <slot v-if="column.slot" :name="column.slot" v-bind="scope" />
          </el-table-column>
        </template>
      </el-table>
      <el-pagination
        v-if="pageModel"
        v-model:page-size="pageModel.pageSize"
        v-model:current-page="pageModel.pageNum"
        :total="pageModel.total"
        :page-sizes="[15, 30, 50]"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        background
        layout="->, total, sizes, prev, pager, next, jumper"
        h-80px
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import type { CurdColumn, IPage } from '@/typings/common';
import type { ElTableColumn, ElTable } from 'element-plus/es';

const props = defineProps<{
  columns: CurdColumn[]
  tableData: unknown[]
  page?: IPage
}>();

type IEmit = {
  (event: 'update:page', value: typeof props.page): void;
  (event: 'search'): void;
}
const emit = defineEmits<IEmit>();

const tableRef = ref<InstanceType<typeof ElTable>>();

const pageModel = computed({
  get: () => props.page,
  set: (value) => emit('update:page', value),
});

const handleSizeChange = (val: number) => {
  if (!pageModel.value) return;
  pageModel.value.pageSize = val;
  pageModel.value.pageNum = 1;
  emit('search');
};
const handleCurrentChange = (val: number) => {
  if (!pageModel.value) return;
  pageModel.value.pageNum = val;
  emit('search');
};

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

<style lang="scss" scoped>
.curd-container{
  box-sizing: border-box;
}

.table-container {
  box-sizing: border-box;
  width: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
export interface IPage extends IPagination {
  total: number
}

export type CurdColumn = ElTableColumnProps & {
  slot?: string
  map?: Ref<Record<string, string>>
}
1
2
3
4
5
6
7
8

# utils

如果想指定props,我也写了一个工具类

export type DefinedKeys<O, Key extends string, Keys> = O & {
  [k in Key]?: Keys
}
1
2
3

用法:

const columns: DefinedKeys<CurdColumn, 'prop', keyof IData>[] = []
1

# 基于这个想法,我觉得el-form可以同样的封装,但是为了灵活,我把el-form-item做了一个组件

但这个组件用到现在我感觉设计上还是有点问题, 如果能使用type,props的方式可能会更好,这样类型就定义起来比较麻烦, 不同的type,对应element-plus不同组件的props, 这样整个el-form的自定义程度会更高,但是一开始写的时候没有考虑到这些, 现在重构也不太好了。。。

<template>
  <template
    v-for="item in formItems"
    :key="item.prop"
  >
    <el-form-item v-bind="item">
      <!--这里可以是一些通用的固定组件,不然就直接放到slot里面就行-->
      <el-date-picker
        v-if="item.date && ['datetime', 'date', 'week', 'month', 'year'].includes(item.date)"
        v-model="formModel[item.prop]"
        :size="inputSize"
        :type="item.date"
        value-format="YYYY-MM-DD HH:mm:ss"
        clearable
        @change="emit('change')"
      />
      <WddUpload v-else-if="item.upload" v-model:file-list="(formModel[item.prop])" />
      <!--基础的一些表单-->
      <el-select
        v-else-if="item.map" v-model="formModel[item.prop]" :size="inputSize" placeholder="请选择" clearable
        filterable @change="emit('change')"
      >
        <el-option
          v-for="(value, key) in unref(item.map)"
          :key="key"
          :label="value"
          :value="key"
        />
      </el-select>
      <slot v-else-if="item.slot" :name="item.slot" />
      <div v-else-if="item.multi" class="flex gap4 w-full">
        <div v-for="subItem in item.multi" :key="subItem.prop" class="flex flex-1 min-w-0 items-center">
          <span mr1>{{ subItem.label }}</span>
          <el-input v-if="subItem.number" v-model.number="formModel[subItem.prop]" type="number" :size="inputSize" v-bind="subItem.inputProps">
            <template v-if="subItem.unit" #suffix>{{ subItem.unit }}</template>
          </el-input>
          <el-input v-else v-model="formModel[subItem.prop]" :size="inputSize" v-bind="subItem.inputProps">
            <template v-if="subItem.unit" #suffix>{{ subItem.unit }}</template>
          </el-input>
        </div>
      </div>
      <el-input v-else-if="item.textarea" type="textarea" :rows="item.textarea" v-model="formModel[item.prop]" v-bind="item.inputProps" />
      <el-input
        v-else-if="item.number" v-model.number="formModel[item.prop]" type="number" :size="inputSize" v-bind="item.inputProps"
        @keyup.enter="emit('change')"
      >
        <template v-if="item.unit" #suffix>{{ item.unit }}</template>
      </el-input>
      <el-input
        v-else v-model="formModel[item.prop]" :size="inputSize" v-bind="item.inputProps"
        @keyup.enter="emit('change')"
      >
        <template v-if="item.unit" #suffix>{{ item.unit }}</template>
      </el-input>
    </el-form-item>
  </template>
</template>

<script setup lang="ts">
import type { CurdFormItems } from '@/typings/common';
import { unref } from 'vue';
import WddUpload from './WddUpload.vue';

const props = defineProps<{
  formItems: CurdFormItems[]
  form: Record<string, unknown>
  inputSize?: string
}>();

type IEmit = {
  (event: 'update:form', value: typeof props.form): void;
  (event: 'change'): void;
}
const emit = defineEmits<IEmit>();

const formModel = computed({
  get: () => props.form,
  set: (value) => emit('update:form', value),
});
</script>

<style lang="scss" scoped>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

类型:

type ElFormItemProps = InstanceType<typeof ElFormItem>['$props']
type ElInputProps = InstanceType<typeof ElInput>['$props']
type ElUploadProps = InstanceType<typeof ElUpload>['$props']
export type CurdFormItems = ElFormItemProps & {
  prop: string,
  slot?: string
  map?: Ref<Record<string, string>>
  number?: boolean
  unit?: string
  inputProps?: ElInputProps
  multi?: CurdFormItems[]
  date?: 'datetime' | 'date' | 'week' | 'month' | 'year'
  upload?: boolean
  textarea?: number
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#Vue#Vue组件
上次更新: 2023/06/01, 12:40:50

← ElementPlus表格table列自动合并composition ElementPlus表格自定义合计列composition→

Theme by Vdoing | Copyright © 2021-2023 Wiidede | Website use MIT License | Article content & logo use CC-BY-SA-4.0 License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式