文件结构
基础功能搭建好了之后,剩下的就简单了,建立组件设置模板、控件、组件和使用状态即可。总体结构如下:
文件结构
列表状态的使用
基础工作做好之后我们来看看,在各个组件里面是如何使用状态的。
1查询
首先看看查询,用户设置查询条件后,查询控件把查询条件记入状态里面。然后调用状态管理里的 reloadFirstPager ,获取列表数据。查询控件支持防抖功能。
<template> <!--查询--> <nf-el-find v-model="listState.query" v-bind="findProps" @my-change="myChange" /> </template>
直接使用查询控件,模板内容是不是很简单了?
import { reactive } from'vue' // 加载json import loadJson from'./control/loadjson.js' // 状态 import VueDS from'vue-data-state' // 组件 import nfElFind from'/ctrl/nf-el-find/el-find-div.vue' // 属性:模块ID、查询条件 const props = defineProps({ moduleId: [Number, String] }) // 设置 查询的 meta const findProps = reactive({reload: true}) loadJson(props.moduleId, 'find', findProps) // 访问状态 const { get } = VueDS.useStore() // 获取状态 const listState = get.dataListState() // 用户设置查询条件后触发 const myChange = (query) => { // 获取第一页的数据,并且重新统计总数 listState.reloadFirstPager() }
2分页
分页就很简单了,查询条件由查询控件搞定,所以这里只需要按照 el-pagination 的要求,把分页状态设置给 el-pagination 的属性即可。
<template> <!--分页--> <el-pagination background layout="prev, pager, next" v-model:currentPage="pager.pageIndex" :page-size="pager.pageSize" :total="pager.pageTotal"> </el-pagination> </template>
直接把状态作为属性值。
// 状态 import VueDS from'vue-data-state' // 访问状态 const { get } = VueDS.useStore() // 获取分页信息 const pager = get.dataListState().pager
直接获取分页状态设置 el-pagination 的属性即可。翻页的时候 el-pagination 会自动修改 pager.pageIndex 的值,而状态管理里面会监听其变化,然后获取对应的列表数据。
3添加、修改
添加完成之后,总记录数会增加,所以需要重新统计总记录数,然后翻到第一页。而修改之后,一般总记录数并不会变化,所以只需要重新获取当前页号的数据即可。
<template> <div> <!--表单--> <el-form ref="formControl" v-model="model" :partModel="partModel" v-bind="formProps" > </el-form> <span class="dialog-footer"> <el-button @click="">取 消</el-button> <el-button type="primary" @click="mysubmit">确 定</el-button> </span> </div> </template>
使用表单控件和两个按钮。
import { computed, reactive, watch } from'vue' import { ElMessage } from'element-plus' // 加载json import loadJson from'./control/loadjson.js' // 状态 import VueDS from'vue-data-state' // 仿后端API import service from'./api/data-service.js' // 表单组件 import elForm from'/ctrl/nf-el-form/el-form-div.vue' // 访问状态 const { get } = VueDS.useStore() // 定义属性 const props = defineProps({ moduleId: [Number, String], // 模块ID formMetaId: [Number, String], // 表单的ID dataId: Number, // 修改或者显示的记录的ID type: String// 类型:添加、修改、查看 }) // 模块ID + 表单ID = 自己的标志 const modFormId = computed(() => props.moduleId + props.formMetaId) // 子组件里面获取状态 const dataListState = get.dataListState(modFormId.value) // 表单控件的 model const model = reactive({}) // 表单控件需要的属性 const formProps = reactive({reload:false}) // 加载需要的 json loadJson(props.moduleId, 'form_' + props.formMetaId, formProps) // 仿后端API const { getData, addData, updateData } = service(modFormId.value) // 监听记录ID的变化,加载数据便于修改 watch(() => props.dataId, (id) => { if (props.type !== 'add') { // 加载数据 getData( id ).then((data) => { Object.assign(model, data[0]) formProps.reload = !formProps.reload }) } }, {immediate: true}) // 提交数据 const mysubmit = () => { // 判断是添加还是修改 if (props.type === 'add'){ // 添加数据 addData(model).then(() => { ElMessage({ type: 'success', message: '添加数据成功!' }) // 重新加载第一页的数据 dataListState.reloadFirstPager() }) } elseif (props.type === 'update') { // 修改数据 updateData(model, props.dataId).then(() => { ElMessage({ type: 'success', message: '修改数据成功!' }) // 重新加载当前页号的数据 dataListState.reloadCurrentPager() }) } }
代码稍微多了一些,基本上就是在合适的时机调用状态里的重新加载数据的事件。
4删除
删除之后也会影响总记录数,所以需要重新统计,然后刷新当前页号的列表数据。删除的代码写在了操作按钮的组件里面,对应删除按钮触发的事件:
case'delete': dialogInfo.show = false // 删除 ElMessageBox.confirm('此操作将删除该记录, 是否继续?', '温馨提示', { confirmButtonText: '删除', cancelButtonText: '后悔了', type: 'warning' }).then(() => { // 后端API const { deleteData } = service(props.moduleId + meta.formMetaId) deleteData(dataListState.choice.dataId).then(() => { ElMessage({ type: 'success', message: '删除成功!' }) dataListState.reloadPager() // 刷新列表数据 }) }).catch(() => { ElMessage({ type: 'info', message: '已经取消了。' }) }) break
5快捷键
我是喜欢用快捷键实现一些操作的,比如翻页、添加等操作。用鼠标去找到“上一页”、“下一页”或者需要的页号,这个太麻烦。如果通过键盘操作就能翻页,是不是可以更方便一些呢?比如 w、a、s、d,分别表示上一页、下一页、首页、末页;数字键就是要翻到的页号。
是不是有一种打游戏的感觉?
实现方式也比较简单,一开始打算用 Vue 的键盘事件,但是发现似乎不太好用,于是改用监听document 的键盘事件。
/** * 列表页面的快捷键 */ const setHotkey = (dataListState) => { // 设置分页、操作按钮等快捷键 // 计时器做一个防抖 let timeout let tmpIndex = 0// 页号 document.onkeydown = (e) => { if (!(e.target instanceof HTMLBodyElement)) return// 表单触发,退出 if (e.altKey) { // alt + 的快捷键,调用操作按钮的事件 dataListState.hotkey(e.key) } else { // 翻页 const maxPager = parseInt(dataListState.pager.pageTotal / dataListState.pager.pageSize) + 1 switch (e.key) { case'ArrowLeft': // 左箭头 上一页 case'PageUp': case'a': dataListState.pager.pageIndex -= 1 if (dataListState.pager.pageIndex <= 0) { dataListState.pager.pageIndex = 1 } break case'ArrowRight': // 右箭头 下一页 case'PageDown': case'd': dataListState.pager.pageIndex += 1 if (dataListState.pager.pageIndex >= maxPager) { dataListState.pager.pageIndex = maxPager } break case'ArrowUp': // 上箭头 case'Home': // 首页 case'w': dataListState.pager.pageIndex = 1 break case'ArrowDown': // 下箭头 case'End': // 末页 case's': dataListState.pager.pageIndex = maxPager break default: // 判断是不是数字 if (!isNaN(parseInt(e.key))) { // 做一个防抖 tmpIndex = tmpIndex * 10 + parseInt(e.key) clearTimeout(timeout) // 清掉上一次的计时 timeout = setTimeout(() => { // 修改 modelValue 属性 if (tmpIndex === 0) { dataListState.pager.pageIndex = 10 } else { if (tmpIndex >= maxPager) { tmpIndex = maxPager } dataListState.pager.pageIndex = tmpIndex } tmpIndex = 0 }, 500) } } } e.stopPropagation() } }
这段代码,其实是放在状态管理类里面的,拿出来单独介绍一下,避免混淆。
- document.onkeydown 监听键盘按下的事件,这个 e 并不是原生的 e,而是Vue封装之后的 e。首先要判断一下事件来源,如果是 input 等触发的需要跳过,以免影响正常的数据输入。然后是判断按了哪个按键,根据需求调用对应的函数。
e 的样子
- altKey 是否按下了 alt 键。有些快捷键可以是组合方式,本来想用 ctrl 键的,但是发现在网页里面 ctrl 开头的快捷键实在太多,抢不过,所以只好 用 alt。
- alt + a 相当于按 添加按钮
- alt + s 相当于按 修改按钮
- alt + d 相当于按 删除按钮
你觉得 a 代表 add,d 代表 delete吗?其实不是的,a、s、d 的键位可以对应操作按钮里面前三个按钮。就酱。
- 数字翻页的防抖 如果不做防抖的话,只能实现 1-9 的页号翻页,如果做了防抖的话,基本可以做到三位数页号的翻页。所以手欠做了个防抖。
开源
https://gitee.com/naturefw/nf-vite2-element
在线演示
https://naturefw.gitee.io/nf-vue-cdn/elecontrol/
nf-vite2-element 的仓库没来得及开通pager服务,所以放在另一个仓库里面了。
本文作者:自然框架
个人网址:jyk.cnblogs.com
声明:本文为 脚本之家专栏作者 投稿,未经允许请勿转载。