位置: IT常识 - 正文

分享项目 - Vue3 + TS + element-ui-plus 项目 -- Table表格表单(分享项目成果)

编辑:rootadmin
分享项目 - Vue3 + TS + element-ui-plus 项目 -- Table表格表单 文章目录前言项目地址以及怎么阅读别人的代码整体代码分页数据作者是怎么处理的 usePagination顺藤摸瓜找到 api 接口的封装api 接口再往底层找全局请求封装与请求拦截器 service.ts前言

推荐整理分享分享项目 - Vue3 + TS + element-ui-plus 项目 -- Table表格表单(分享项目成果),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:vue技术分享,分享项目的说说,分享项目话术,分享项目话术,分享项目经验,分享项目经验,分享项目要注意什么,分享项目要注意什么,内容如对您有帮助,希望把文章链接给更多的朋友!

今天看一个 ts 项目的 table 模块,亲身体验这是公司后台管理系统一定会使用到的,也是最常使用到的,这个项目对新手很友好,毕竟是一个相对来说比较空的项目模板,对于我来说就是一个学习的记录,一些技术的分享,手把手告知新手别人的代码怎么读,甚至还能帮该开源项目作者获取一些热度,我很乐于做这样的事情(已经争得原作者许可,感谢 🤓)项目地址:V3 Admin Vite

通过该文章可以学习到 :

element-ui-plus 的表单、表格等组件的使用怎么阅读他人的代码、怎么写出优雅炫酷的代码api 请求以及 api 请求拦截器、api 全局请求封装等知识点项目地址以及怎么阅读别人的代码分享项目 - Vue3 + TS + element-ui-plus 项目 -- Table表格表单(分享项目成果)

我们来看一下具体代码是怎么实现的,我读别人的代码喜欢先看一下大体目录结构、然后从页面功能入手,然后在 html 中找到该组件,然后查看该组件使用的方法等,一直相连关联到底层封装代码(或者直接看脚本逻辑,从脚本逻辑入手,看大家习惯)

功能、底层封装、页面结构等等知道了,自然而然就通了

我一步一步就标注了我对该代码的思考,希望对于大家有所帮助

整体代码<script lang="ts" setup>import { reactive, ref, watch } from "vue"import { createTableDataApi, deleteTableDataApi, updateTableDataApi, getTableDataApi } from "@/api/table"import { type FormInstance, type FormRules, ElMessage, ElMessageBox } from "element-plus"import { Search, Refresh, CirclePlus, Delete, Download, RefreshRight } from "@element-plus/icons-vue"import { usePagination } from "@/hooks/usePagination"// 加载状态,这也是 element-ui-plus 的一种加载方法,可以查看 html 元素并访问 element-ui-plus 官网来找到该变量有什么用处// 定义 loading 为响应式状态值,ts 限制为布尔类型const loading = ref<boolean>(false)// 自己封装的页面功能,可以转到 对应 src目录下 hooks 文件夹中的 usePagination 中查看对应方法的功能// 相应代码在本文章下面,可对应查看或者直接去 GitHub 下载宝藏博主的源码码进行查看const { paginationData, handleCurrentChange, handleSizeChange } = usePagination()//#region 增// 我们在 html 代码中可以看到 是使用在 el-dialog 组件的 v-module 属性上的,我们可以查看 element-ui-plus 文档查看该功能// v-model 控制这该组件是否显示const dialogVisible = ref<boolean>(false)// 表单对象实例 ts限制为表单实例 或 null// 在新增用户判断时需要使用到,被绑定在 表单的 ref 值上const formRef = ref<FormInstance | null>(null)// 表单输入值const formData = reactive({ username: "", password: ""})// 定义表单验证规则并使用 ts 进行类型规范const formRules: FormRules = reactive({ username: [{ required: true, trigger: "blur", message: "请输入用户名" }], password: [{ required: true, trigger: "blur", message: "请输入密码" }]})// 创建新用户/修改用户 方法const handleCreate = () => { // 判断表单实例是否存在 // 因为 validate 是 element-ui-plus 表单上的一个方法,所以需要使用到表单实例才可以使用该方法,现在我们知道了为什么要获取表单实例了 // validate 接收一个回调函数,或返回 Promise,执行之前是有一个前提的,需要表单实例是存在的 formRef.value?.validate((valid: boolean) => { if (valid) { // 如果 valid 存在,那么判断 currentUpdateId 是否为 undefined // currentUpdateId 是否有值决定着用户操作的是新增还是修改 if (currentUpdateId.value === undefined) { // 发起创建 table 请求,携带用户名与用户密码 createTableDataApi({ username: formData.username, password: formData.password }).then(() => { // 数据请求成功之后弹出提示信息 ElMessage.success("新增成功") // 并将弹框设置为不显示 dialogVisible.value = false // 这里的方法在下面 但是从命名就不难看出 这是新增成功之后重新请求一下所有的数据 保证页面数据的最新 getTableData() }) } else { // 前面也有提到 这里是一个炫酷写法,将新增和修改放在一个方法中,执行哪个方法取决于 currentUpdateId 是否有值 // 不得不佩服作者代码写得很棒 updateTableDataApi({ id: currentUpdateId.value, username: formData.username }).then(() => { ElMessage.success("修改成功") dialogVisible.value = false getTableData() }) } // 没有 valid 值,将会退出该方法不执行任何操作 } else { return false } })}// 读到这里就知道 currentUpdateId 是一个关于什么的值了// 我们查到找 html 代码发现当弹窗关闭的时候会触发该方法// 捋一下思路,也就是弹窗关闭,currentUpdateId 值会清空(用户信息也会清空)// 所以我们可以知道用户信息是为了下次打开弹框不会发生之前数据还显示出来的状况// 而 currentUpdateId 则是当前更新 ID ,该值为 undefined 需要执行的是新增,如果当前拥有用户id,那么执行的就是更新const resetForm = () => { currentUpdateId.value = undefined formData.username = "" formData.password = ""}//#endregion//#region 删// row 是当前点击列表项的数据const handleDelete = (row: any) => { ElMessageBox.confirm(`正在删除用户:${row.username},确认删除?`, "提示", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning" }).then(() => { // deleteTableDataApi 是封装好的 request(ajax) 方法 // 我们可以看看作者是怎么封装数据请求的 deleteTableDataApi(row.id).then(() => { ElMessage.success("删除成功") getTableData() }) })}//#endregion//#region 改// 这里的修改方法只是给到了用户数据以及 当前ID 值,当用户点击确认按钮的时候才会发出真在的数据请求,将该值给到服务端处理// 所以这里只是一些简单的数据修改const currentUpdateId = ref<undefined | string>(undefined)const handleUpdate = (row: any) => { currentUpdateId.value = row.id formData.username = row.username formData.password = row.password dialogVisible.value = true}//#endregion//#region 查// 表格列表数据 -- 好的代码命名一看就知道是什么意思,是非常棒的const tableData = ref<any[]>([])// 输入框框实例const searchFormRef = ref<FormInstance | null>(null)// 输入框输入值const searchData = reactive({ username: "", phone: ""})// 获取所有列表数据进行页面的渲染const getTableData = () => { loading.value = true // 获取列表数据的 API getTableDataApi({ // 前俩个看命名也知道是分页相关值 currentPage: paginationData.currentPage, size: paginationData.pageSize, username: searchData.username || undefined, phone: searchData.phone || undefined }) .then((res) => { // 总数以及列表数据 paginationData.total = res.data.total tableData.value = res.data.list }) .catch(() => { // 如果数据请求发生错误,那么不显示数据列表 tableData.value = [] }) .finally(() => { // 无论请求成功或者失败 不显示加载图标 loading.value = false })}// 查询const handleSearch = () => { // 只有当数据处在第一页的时候才会刷新数据 if (paginationData.currentPage === 1) { getTableData() } // 跳转到第一页 paginationData.currentPage = 1}// 重置const resetSearch = () => { // resetFields 重置该表单项,将其值重置为初始值,并移除校验结果,这也是 element-ui-plus 组件实例上的方法 searchFormRef.value?.resetFields() if (paginationData.currentPage === 1) { getTableData() } paginationData.currentPage = 1}// 刷新表格const handleRefresh = () => { getTableData()}//#endregion/** 监听分页参数的变化 */// 看到这里我们就明白为什么查询和重置页面为什么跳转到第一页就不管了,因为这里在监听着分页参数的变化,这样的完美代码看着是很爽的,为作者点一个大赞watch([() => paginationData.currentPage, () => paginationData.pageSize], getTableData, { immediate: true })</script><template> <div class="app-container"> <el-card v-loading="loading" shadow="never" class="search-wrapper"> <el-form ref="searchFormRef" :inline="true" :model="searchData"> <el-form-item prop="username" label="用户名"> <el-input v-model="searchData.username" placeholder="请输入" /> </el-form-item> <el-form-item prop="phone" label="手机号"> <el-input v-model="searchData.phone" placeholder="请输入" /> </el-form-item> <el-form-item> <el-button type="primary" :icon="Search" @click="handleSearch">查询</el-button> <el-button :icon="Refresh" @click="resetSearch">重置</el-button> </el-form-item> </el-form> </el-card> <el-card v-loading="loading" shadow="never"> <div class="toolbar-wrapper"> <div> <el-button type="primary" :icon="CirclePlus" @click="dialogVisible = true">新增用户</el-button> <el-button type="danger" :icon="Delete">批量删除</el-button> </div> <div> <el-tooltip content="下载"> <el-button type="primary" :icon="Download" circle /> </el-tooltip> <el-tooltip content="刷新表格"> <el-button type="primary" :icon="RefreshRight" circle @click="handleRefresh" /> </el-tooltip> </div> </div> <div class="table-wrapper"> <el-table :data="tableData"> <el-table-column type="selection" width="50" align="center" /> <el-table-column prop="username" label="用户名" align="center" /> <el-table-column prop="roles" label="角色" align="center"> <template #default="scope"> <el-tag v-if="scope.row.roles === 'admin'" effect="plain">admin</el-tag> <el-tag v-else type="warning" effect="plain">{{ scope.row.roles }}</el-tag> </template> </el-table-column> <el-table-column prop="phone" label="手机号" align="center" /> <el-table-column prop="email" label="邮箱" align="center" /> <el-table-column prop="status" label="状态" align="center"> <template #default="scope"> <el-tag v-if="scope.row.status" type="success" effect="plain">启用</el-tag> <el-tag v-else type="danger" effect="plain">禁用</el-tag> </template> </el-table-column> <el-table-column prop="createTime" label="创建时间" align="center" /> <el-table-column fixed="right" label="操作" width="150" align="center"> <template #default="scope"> <el-button type="primary" text bg size="small" @click="handleUpdate(scope.row)">修改</el-button> <el-button type="danger" text bg size="small" @click="handleDelete(scope.row)">删除</el-button> </template> </el-table-column> </el-table> </div> <div class="pager-wrapper"> <el-pagination background :layout="paginationData.layout" :page-sizes="paginationData.pageSizes" :total="paginationData.total" :page-size="paginationData.pageSize" :currentPage="paginationData.currentPage" @size-change="handleSizeChange" @current-change="handleCurrentChange" /> </div> </el-card> <!-- 新增/修改 --> <el-dialog v-model="dialogVisible" :title="currentUpdateId === undefined ? '新增用户' : '修改用户'" @close="resetForm" width="30%" > <el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px" label-position="left"> <el-form-item prop="username" label="用户名"> <el-input v-model="formData.username" placeholder="请输入" /> </el-form-item> <el-form-item prop="password" label="密码"> <el-input v-model="formData.password" placeholder="请输入" /> </el-form-item> </el-form> <template #footer> <el-button @click="dialogVisible = false">取消</el-button> <el-button type="primary" @click="handleCreate">确认</el-button> </template> </el-dialog> </div></template><style lang="scss" scoped>.search-wrapper { margin-bottom: 20px; :deep(.el-card__body) { padding-bottom: 2px; }}.toolbar-wrapper { display: flex; justify-content: space-between; margin-bottom: 20px;}.table-wrapper { margin-bottom: 20px;}.pager-wrapper { display: flex; justify-content: flex-end;}</style>分页数据作者是怎么处理的 usePagination

这是分页数据接口规范以及方法定义导出

import { reactive } from "vue"// ts 定义接口 -- 分页数据接口规范interface IDefaultPaginationData { total: number currentPage: number pageSizes: number[] pageSize: number layout: string}// ts 定义接口 -- 合并数据接口规范interface IPaginationData { total?: number currentPage?: number pageSizes?: number[] pageSize?: number layout?: string}/** 默认的分页参数 */const defaultPaginationData: IDefaultPaginationData = { total: 0, currentPage: 1, pageSizes: [10, 20, 50], pageSize: 10, layout: "total, sizes, prev, pager, next, jumper"}export function usePagination(_paginationData: IPaginationData = {}) { /** 合并分页参数 */ // Object.assign()是对象的静态方法,可以用来复制对象的可枚举属性到目标对象,利用这个特性可以实现对象属性的合并 // 意思就是传过来的值有的话就覆盖,没有就使用默认分页数据,这个处理很完美 const paginationData = reactive(Object.assign({ ...defaultPaginationData }, _paginationData)) /** 改变当前页码 */ const handleCurrentChange = (value: number) => { paginationData.currentPage = value } /** 改变每页显示数据数量 */ const handleSizeChange = (value: number) => { paginationData.pageSize = value } return { paginationData, handleCurrentChange, handleSizeChange }}}顺藤摸瓜找到 api 接口的封装

我们顺着上面发起请求的导出方法找到了这里(这里位于 src 下的 api 文件夹),这是一些简单的接口定义以及 api 接口的封装,等等,好像有一个奇怪的东西,在依赖包中使用的是 axios ,怎么出现了 request ,肯定还有一个整体封装层,并且应该在那里会有一个请求响应拦截器,我们去看看

import { request } from "@/utils/service"interface ICreateTableRequestData { username: string password: string}interface IUpdateTableRequestData { id: string username: string password?: string}interface IGetTableRequestData { /** 当前页码 */ currentPage: number /** 查询条数 */ size: number /** 查询参数 */ username?: string phone?: string}type GetTableResponseData = IApiResponseData<{ list: { createTime: string email: string id: string phone: string roles: string status: boolean username: string }[] total: number}>/** 增 */export function createTableDataApi(data: ICreateTableRequestData) { return request({ url: "table", method: "post", data })}/** 删 */export function deleteTableDataApi(id: string) { return request({ url: `table/${id}`, method: "delete" })}/** 改 */export function updateTableDataApi(data: IUpdateTableRequestData) { return request({ url: "table", method: "put", data })}/** 查 */export function getTableDataApi(params: IGetTableRequestData) { return request<GetTableResponseData>({ url: "table", method: "get", params })}api 接口再往底层找全局请求封装与请求拦截器 service.ts

果然是 😎

import axios, { type AxiosInstance, type AxiosRequestConfig } from "axios"import { useUserStoreHook } from "@/store/modules/user"import { ElMessage } from "element-plus"import { get } from "lodash-es"import { getToken } from "./cache/cookies"/** 创建请求实例 */function createService() { // 创建一个 Axios 实例 const service = axios.create() // 请求拦截 service.interceptors.request.use( (config) => config, // 发送失败 (error) => Promise.reject(error) ) // 响应拦截(可根据具体业务作出相应的调整) service.interceptors.response.use( (response) => { // apiData 是 API 返回的数据 const apiData = response.data as any // 这个 Code 是和后端约定的业务 Code const code = apiData.code // 如果没有 Code, 代表这不是项目后端开发的 API if (code === undefined) { ElMessage.error("非本系统的接口") return Promise.reject(new Error("非本系统的接口")) } else { switch (code) { case 0: // code === 0 代表没有错误 return apiData default: // 不是正确的 Code ElMessage.error(apiData.message || "Error") return Promise.reject(new Error("Error")) } } }, (error) => { // Status 是 HTTP 状态码 const status = get(error, "response.status") switch (status) { case 400: error.message = "请求错误" break case 401: // Token 过期时,直接退出登录并强制刷新页面(会重定向到登录页) useUserStoreHook().logout() location.reload() break case 403: error.message = "拒绝访问" break case 404: error.message = "请求地址出错" break case 408: error.message = "请求超时" break case 500: error.message = "服务器内部错误" break case 501: error.message = "服务未实现" break case 502: error.message = "网关错误" break case 503: error.message = "服务不可用" break case 504: error.message = "网关超时" break case 505: error.message = "HTTP 版本不受支持" break default: break } ElMessage.error(error.message) return Promise.reject(error) } ) return service}/** 创建请求方法 */function createRequestFunction(service: AxiosInstance) { return function <T>(config: AxiosRequestConfig): Promise<T> { const configDefault = { headers: { // 携带 Token Authorization: "Bearer " + getToken(), "Content-Type": get(config, "headers.Content-Type", "application/json") }, timeout: 5000, baseURL: import.meta.env.VITE_BASE_API, data: {} } return service(Object.assign(configDefault, config)) }}/** 用于网络请求的实例 */export const service = createService()/** 用于网络请求的方法 */export const request = createRequestFunction(service)
本文链接地址:https://www.jiuchutong.com/zhishi/297764.html 转载请保留说明!

上一篇:WGAN(Wasserstein GAN)看这一篇就够啦,WGAN论文解读

下一篇:uniapp中获取dom元素的方法,更改dom元素颜色(遇坑记录)(uniapp dom操作)

  • 5crnimo模具钢(5c 5s)(5crnimo模具钢的用途)

    5crnimo模具钢(5c 5s)(5crnimo模具钢的用途)

  • 小米文件夹下面的广告怎么取消(小米文件夹下面的应用推荐怎么关闭)

    小米文件夹下面的广告怎么取消(小米文件夹下面的应用推荐怎么关闭)

  • 华为vr glass支持外置片源吗(华为vrglass支持鸿蒙3.0吗)

    华为vr glass支持外置片源吗(华为vrglass支持鸿蒙3.0吗)

  • 麒麟980跟骁龙855差距大吗(麒麟980跟骁龙855哪个好)

    麒麟980跟骁龙855差距大吗(麒麟980跟骁龙855哪个好)

  • oppoa92s后盖是什么材质(oppoa92s后盖怎么拆)

    oppoa92s后盖是什么材质(oppoa92s后盖怎么拆)

  • 苹果6s换电池的坏处(苹果6s手机电池更换)

    苹果6s换电池的坏处(苹果6s手机电池更换)

  • 3400g核显相当于什么(3400g核显相当于什么cpu)

    3400g核显相当于什么(3400g核显相当于什么cpu)

  • 笔记本电脑发送键是那个(笔记本电脑发送键)

    笔记本电脑发送键是那个(笔记本电脑发送键)

  • ipad如何快速截长图(ipad如何快速截图到笔记)

    ipad如何快速截长图(ipad如何快速截图到笔记)

  • wps权限设置在哪里解除(wps权限设置在哪里)

    wps权限设置在哪里解除(wps权限设置在哪里)

  • 闲鱼重新编辑有影响吗(闲鱼重新编辑有影响曝光吗)

    闲鱼重新编辑有影响吗(闲鱼重新编辑有影响曝光吗)

  • word2007找回未保存文档(word2007找回未保存)

    word2007找回未保存文档(word2007找回未保存)

  • 华为手机从哪下载东西(华为手机从哪下软件)

    华为手机从哪下载东西(华为手机从哪下软件)

  • 拼多多如何绑支付宝(拼多多如何绑定支付)

    拼多多如何绑支付宝(拼多多如何绑定支付)

  • 企业微信怎么添加部门(企业微信怎么添加人)

    企业微信怎么添加部门(企业微信怎么添加人)

  • airpods2代红叹号是坏了吗(airpods2感叹号什么意思)

    airpods2代红叹号是坏了吗(airpods2感叹号什么意思)

  • 微信怎么扫码坐公交车(微信怎么扫码坐地铁成都)

    微信怎么扫码坐公交车(微信怎么扫码坐地铁成都)

  • 苹果手机接电话录音在哪里(苹果手机接电话时怎么录音)

    苹果手机接电话录音在哪里(苹果手机接电话时怎么录音)

  • 拼多多签到50元提现怎么使用(拼多多签到50元能领吗)

    拼多多签到50元提现怎么使用(拼多多签到50元能领吗)

  • arcgis是做什么的(arcgis是做什么的软件)

    arcgis是做什么的(arcgis是做什么的软件)

  • 陌陌为什么发不了视频(陌陌为什么发不出信息)

    陌陌为什么发不了视频(陌陌为什么发不出信息)

  • airports耳机怎么切歌(airpods耳机操作方法)

    airports耳机怎么切歌(airpods耳机操作方法)

  • 手机人像模式怎么设置(手机人像模式怎么调倍数)

    手机人像模式怎么设置(手机人像模式怎么调倍数)

  • 陌陌实名认证能解除吗(陌陌实名认证能卖吗)

    陌陌实名认证能解除吗(陌陌实名认证能卖吗)

  • 爱沙尼亚波罗的海 (© fotoman-kharkov/Getty Images)(爱沙尼亚的故事)

    爱沙尼亚波罗的海 (© fotoman-kharkov/Getty Images)(爱沙尼亚的故事)

  • 营业税加收滞纳金的规定
  • 企业重组的特殊性税务处理比例
  • 包装物押金计入成本吗
  • 佣金开什么发票内容
  • 开票地址开错有什么后果
  • 小规模纳税人季度超过45万怎么交税
  • 员工一次性补偿要缴纳个税吗
  • 对方公司注销用现金还货款怎么入帐?
  • 制造费用工资结转怎么算
  • 广告公司可以开维修费吗
  • 结转上年度的企业所得税会计分录?
  • 建筑安装工程承包合同
  • 购置税交了发票能作废吗
  • 土地使用税怎么征收标准
  • 某公司为了更好的开展业务
  • 企业的资金怎么使用
  • 企业收到要发放给员工的补贴
  • 个体户需要申报工资薪金吗
  • 研发费用发票怎么入账
  • 非居民纳税人享受协定待遇办理方式
  • 已经折旧完的固定资产怎么处理
  • 精英主板设置u盘启动
  • macos big sur最新版本
  • 攀岗的企业性质有哪些
  • 施工企业内部往来核算方法包括( )
  • win11怎么让任务栏不重叠
  • MacOS Big Sur 11.3网页怎么设置时间限制?
  • php 静态
  • hhupd.exe
  • php扩展ffmpeg教程
  • 酒店加盟管理费多少
  • 销售货物价格明显偏低且无正当理由
  • php操作redis
  • 金碟软件如何查看明细账
  • vue如何实现打印
  • php如何实现
  • js栈堆的区别
  • 进口设备退税如何计算
  • 记账凭证后面附发票吗
  • 跨年度多计提的附加税怎么做分录
  • 个税赡养老人专项扣除 多人
  • 古腾堡中文官网
  • sql server中变量声明的命令是什么
  • 绿化养护合同交不交印花税
  • 营业外支出的内容包括
  • 员工工资是哪个会计科目
  • 工资发放凭证原件指什么意思
  • 股东捐赠资产要纳税吗
  • 存货报废进项税转出分录
  • 以前年度损益调整是什么意思
  • 坏账准备是什么凭证
  • 尚未使用或出租而待售的商品房需要交房产税吗
  • 公司水电费分摊怎么算
  • 建筑公司工程按什么收费
  • 股权转让账务咋处理
  • 有限公司结业清算
  • 公司分期付款买车怎么抵税
  • 软件开发过程中,一个错误发现的越晚
  • 新公司建账流程及日常业务处理
  • sql语句递归
  • 配置是什么意思
  • win10 rs5
  • windows共享功能
  • win7系统怎么更改桌面图标大小
  • win8应用程序没有响应
  • WIN7如何关闭自动关机
  • linux中find命令用法
  • 错误日志项数
  • android打包原理
  • js selectionchange
  • json转复杂对象
  • android 开源
  • javascript bug
  • 深圳电子税务局app
  • "贴现"是什么业务,都涉及哪些费用?
  • 企业登录密码是几位数
  • 出口退税的企业货币要回国内吗
  • 南宁税务局进面分数线
  • 税务24号公告
  • 怎样通过发票号码查询电子发票
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设