本专栏为了还在Vue2x的广大同胞提供一点升级3X的借鉴思路
适用人群
- Vue前端开发者
阅读条件
- 撸一遍Vue3文档
收获
- 纯净的Vue3-admin框架
如果你是一名成熟的开发工程师,可以直接访问成品
【admin-mini】封装table列表
一个标准的列表页,至少需要包含,搜索条件、分页配置、列表数据、分页切换函数、分页长度切换函数等等
如果在加上各种新增、删除、编辑、绑定等等操作
维护难度可想而知
示例
<template>
<div class="admin-view">
<div class="admin-view-header">
<admin-bread></admin-bread>
</div>
<div class="admin-view-search">
<el-form ref="queryFrom" @submit.prevent="$table.search" :inline="true" :model="$table.query">
<el-form-item label="帐号" prop="username" :rules="[$rules.required]">
<el-input v-model="$table.query.username"></el-input>
</el-form-item>
<el-form-item label="下拉">
<select-dict :dict="$dict.userType" show-all></select-dict>
</el-form-item>
<el-form-item label="时间范围">
<date-picker-range v-model:begin="$table.query.beginTime"
v-model:end="$table.query.endTime"></date-picker-range>
</el-form-item>
<el-form-item>
<el-button native-type="submit" type="primary" :loading="$table.loading">搜索</el-button>
</el-form-item>
</el-form>
</div>
<div class="admin-view-body">
<div class="admin-table-btns">
<el-button @click="openAdd" type="primary" icon="plus">新增</el-button>
</div>
<div class="admin-table-list">
<el-table border :data="$table.data" :empty-text="$table.emptyText" v-loading="$table.loading"
table-layout="auto">
<el-table-column prop="username" label="帐号" />
<el-table-column prop="userType" label="类型">
<template #default="scope">
<el-tag :type="scope.row.userTypeObj.color">
{{ scope.row.userTypeObj.label }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="nickName" label="用户姓名" />
<el-table-column prop="userType" label="类型" :formatter="$formatter.dict($dict.userType)" />
<el-table-column prop="loginTime" label="登陆时间" :formatter="$formatter.date(true)" />
<el-table-column prop="createTime" label="登陆时间" :formatter="$formatter.date()" />
<el-table-column label="操作" width="400px">
<template #default="scope">
<el-space spacer="|">
<el-link :disabled="scope.row.loading" type="primary"
@click="openEdit(scope.row)">编辑</el-link>
<el-link :disabled="scope.row.loading" type="primary"
@click="openDel(scope.row)">删除</el-link>
<el-link :disabled="scope.row.loading" type="primary"
@click="openPassword(scope.row)">修改密码</el-link>
</el-space>
</template>
</el-table-column>
</el-table>
<div class="admin-pager-container">
<el-pagination :layout="$table.pageLayout" background v-model:current-page="$table.query.page"
:page-size="$table.query.size" :total="$table.total" @size-change="$table.handleSizeChange"
@current-change="$table.handleCurrentChange" />
</div>
</div>
</div>
</div>
</template>
<script setup>
import { userList } from '@/api'
import { reactive, onMounted } from 'vue'
import { ElMessage, } from 'element-plus'
const rules = reactive({});
const $table = reactive({
pageLayout: 'total, sizes, prev, pager, next, jumper',
emptyText: '暂无数据',
data: [],
total: 0,
loading: false,
query: {
page: 1,
size: 20
},
handleCurrentChange: handleCurrentChange,
handleSizeChange: handleSizeChange,
getTable: getTable,
search: search,
rules: rules,
ref: null, //如果指定会自动执行validate校验表单
parse: (data) => data.data, //格式化返回数据
parseQuery: (query) => query //格式化请求数据
})
onMounted(function () {
search()
})
function handleSizeChange(size) {
$table.query.size = size
search()
}
function handleCurrentChange(p) {
$table.query.page = p
getTable()
}
function getTable() {
if ($table.ref) {
$table.ref.validate((valid) => {
if (valid) {
_getTable()
}
})
} else {
_getTable()
}
}
function _getTable() {
$table.loading = true
$table.emptyText = '加载中...'
let query = $table.parseQuery(JSON.parse(JSON.stringify($table.query)))
userList(query)
.then((res) => {
if (res.data.code == 0) {
let rows = res.data.data
$table.data = rows
$table.total = parseInt(res.data.total) || 0
} else {
throw new Error('接口错误')
}
})
.catch((err) => {
console.error(err)
ElMessage.error(err || '接口错误')
})
.finally(() => {
$table.loading = false
$table.emptyText = '暂无数据'
})
}
function search() {
$table.query.page = 1
getTable()
}
</script>
<style></style>
精简!
把通用逻辑封装成一个VUE3插件,即可完成蜕变
示例
<template>
...html部分同上
</template>
<script setup>
import { userList } from '@/api'
import useAdminTable from '@/plugins/use-admin-table'
import dict from "@/utils/dict"
const $table = useAdminTable({api:userList})
</script>
<style></style>
封装后,仅需一行代码即可实现简单的列表页
当然,为了保证灵活性,还提需要提供一些可配置项
- $table.parse 用于格式化响应数据
- $table.parseQuery 用于格式化请求数据
- $table.api 修改列表api函数
- $table下所有属性均可diy
实现代码
import { reactive, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
export default function useAdminTable(options) {
const rules = reactive({})
const $table = reactive({
pageLayout: 'total, sizes, prev, pager, next, jumper',
emptyText: '暂无数据',
data: [],
total: 0,
loading: false,
api: undefined,
query: {
page: 1,
size: 20
},
handleCurrentChange: handleCurrentChange,
handleSizeChange: handleSizeChange,
getTable: getTable,
search: search,
rules: rules,
ref: null, //如果指定会自动执行validate校验表单
parse: (data) => data.data, //格式化返回数据
parseQuery: (query) => query, //格式化请求数据
autoSearch: true //是否在mounted周期中自动调用search
})
Object.assign($table, options)
onMounted(function () {
if (!$table.autoSearch) {
return false
}
if ($table.api) {
search()
}
})
function handleSizeChange(size) {
$table.query.size = size
search()
}
function handleCurrentChange(p) {
$table.query.page = p
getTable()
}
function getTable() {
if ($table.ref) {
$table.ref.validate((valid) => {
if (valid) {
_getTable()
}
})
} else {
_getTable()
}
}
function _getTable() {
if (!$table.api) {
return false
}
$table.loading = true
$table.emptyText = '加载中...'
let query = $table.parseQuery(JSON.parse(JSON.stringify($table.query)))
$table
.api(query)
.then((res) => {
if (res.data.code == 0) {
let rows = res.data.data
rows = $table.parse(res.data)
$table.data = rows
$table.total = parseInt(res.data.total) || 0
} else {
throw new Error('接口错误')
}
})
.catch((err) => {
console.error(err)
ElMessage.error(err || '接口错误')
})
.finally(() => {
$table.loading = false
$table.emptyText = '暂无数据'
})
}
function search() {
$table.query.page = 1
getTable()
}
return $table
}
useAdminTable.install = function (app) {
void app
}