使用局部状态(轻量级状态)优化博客代码
ccwgpt 2024-10-22 10:22 18 浏览 0 评论
上两篇介绍了如何用vite2 + Vue3 搭建一个博客网站,以及轻量级状态的基础使用,那么二者结合起来会发生什么呢?
做个开源博客学习Vite2 + Vue3 (四)实现博客功能
https://www.toutiao.com/i6954556824670487054/
制作一个轻量级的状态管理插件:Vue-data-state
回顾博客代码
博客代码里面有三个列表:首页的博文列表、编辑博文里面的博文列表以及讨论列表。
三个列表的写了三份代码,但是对比看一下就会发现,这三份代码大同小异嘛。
其共同点就是:查询条件、分页要求、数据容器。
那么是不是可以针对这几个共同点抽象一下,做成一个共用的函数呢?
这个就需要用到轻量级状态里面的局部状态了。
为啥一定要用状态管理呢?那是因为可以把不同的功能分布到不同的组件里面,而不用拘泥在一个组件内实现全部功能。
比如把查询条件的表单放在单独的组件里面,这样可以简化列表组件的代码,更容易进行管理。
定义用于列表需求的局部状态
// store-ds/index.js
import VuexDataState from 'vue-data-state'
// 设置全局状态和局部状态
export default VuexDataState.createStore({
global: { // 全局状态
onlineUser: { // 当前登录用户
name:'jyk' //
}
},
local: { // 局部状态
// 数据列表,使用前需要先注册
dataListState() { // 显示数据列表的状态
return { // 确保不会重复
findKind: {}, // 查询方式,仅容器,不用写具体的查询字段
find: {}, // 查询关键字,还是容器
page: { // 分页参数
pageTotal: 100,
pageSize: 2,
pageIndex: 1, // 其实主要是用这个
orderBy: { id: false } // 排序字段,可以写多个
},
_query: {}, // 缓存的查询条件,翻页的时候使用
isReload: false // 重新加载数据,需要统计总数
}
}
},
init(state) {
// 初始化
}
})
- dataListState
定义一个数据列表用的状态,局部状态的优点就是可以在“多套”业务组件里复用,而且可以保证局部状态不会相互影响,博文列表组件、讨论列表组件都可以用这个状态,而不用定义多个。 - findKind
查询方式,这个只定义一个容器,具体的内容在后面的代码里面实现。 - find
查询关键字,记录用户输入的查询内容。具体内容还是在后面的代码里面实现。 - Page
分页信息,这里主要使用 pageIndex,其他的算是附赠吧,毕竟一般都是配套出现的。 - _query
缓存查询条件,用户进行查询的时候需要记录查询条件,然后翻页的时候就可以直接拿出来使用了。
缓存起来也便于确定需要哪些查询条件。 - init
初始化状态,这个是给全局状态用的。
MVC 的 Control
然后我们可以借鉴MVC的思路,做一个control,控制model的加载、状态的变化等功能。
建立一个 src/control 文件夹,统一管理相关的代码。
// control/data-list.js
import { watch, reactive } from 'vue'
// 状态
import VueDS from 'vue-data-state'
// webSQL
import { webSQLVue } from 'nf-web-storage'
// 获取配置
// eslint-disable-next-line import/no-absolute-path
import blogListInfo from '/config/bloglist.config.json'
/**
* 数据列表的通用管理类
* * 查询条件
* * 分页信息
* * 加载数据
* * 注入局部状态
*/
export default function dataListControl (jsonFlag) {
// 显示数据列表的数组
const _dataList = reactive([])
// 访问 webSQL
const { help } = webSQLVue.useHelp()
// 访问状态
const { reg, get } = VueDS.useStore()
// 子组件里面获取状态
const dataListState = get.dataListState()
// 父组件注册状态
const regDataListState = () => {
// 注入获取列表需要的状态,便于查询、分页里面修改
const state = reg.dataListState()
// 需要的配置信息
const listInfo = blogListInfo[jsonFlag]
if (typeof listInfo === 'undefined') {
// 没有设置对应的信息
return state
}
// 设置具体的查询条件和查询方式
state.find = listInfo.find
state.findKind = listInfo.findKind
state.page = listInfo.page
// 重新加载数据
watch(() => state.isReload, () => {
const _query = {}
// 设置查询条件
for (const key in state.find) {
const value = state.find[key]
const kind = state.findKind[key]
if (value && value.length > 0 && value > 0) {
_query[key] = [kind, value]
}
}
// 缓存查询条件,分页的时候可以直接使用
state._query = _query
state.page.pageIndex = 1 // 显示第一页
// 统计总数
help.selectCount(listInfo.tableName, _query).then((count) => {
// 设置分页
state.page.pageTotal = count
})
// 获取数据
help.select(listInfo.tableName, listInfo.listCol, _query, state.page).then((data) => {
_dataList.length = 0
_dataList.push(...data)
})
})
// 翻页,依据缓存的查询条件,获取其他页号的数据
watch(() => state.page.pageIndex, () => {
// 获取数据
help.select(listInfo.tableName, listInfo.listCol, state._query, state.page).then((data) => {
_dataList.length = 0
_dataList.push(...data)
})
})
return state
}
return {
regDataListState, // 父组件注册状态
dataList: _dataList, // 父组件获得列表
dataListState // 子组件获得状态
}
}
虽然代码多了一点,但是这里处理好各种需求,组件里面就可以轻松使用了。
- 读取配置信息 blogListInfo
因为博文列表、讨论列表需要的信息都是不一样的,所以不同的信息都放在了一个json文件里面,这里用了vite2 的 import 方式读取,然后按照参数(jsonFlag)获取对应的信息。 - VueDS.useStore
获取轻量级状态的注册等函数。 - 子组件里面获取状态
因为 vue 的 inject 必须在 vue 的 setup 的进程里面才可以获取,而在事件的进程里面无法获取,所以只好在这里先把需要的状态获取出来,如果是父组件的话,当然取不出来。 - regDataListState
父组件注册局部状态的函数。从配置信息里面提取对应的信息,设置给 find、findKind、query。 - 监听 state.isReload
isReload 主要针对查询需求,设置好查询条件后对 isReload 取反,就会触发watch,然后这里执行获取数据的操作。在线演示用的是webSQL,正式项目可以使用 axios 向后端申请数据。然后获取数据设置给 dataList。
这里需要统计总记录数,而下面的翻页事件里就不需要统计总记录数了。 - 监听 page.pageIndex
这个是应对翻页的需求的。分成两个来监听,目的是区分要不要统计总记录数。
如果数据量不大的话,统计总数没啥问题,每次翻页都统计一下用户也不会有啥感觉。
但是如果数据量大的话,还是每次翻页都去统计一下总数,那么就太浪费性能了。
所以这里做了一下区分,翻页的时候不统计总数,重置查询条件的时候才会统计总数。
父组件的使用方法
我们先来看一个简单情况,讨论列表的使用方式:
<template>
<el-card shadow="hover"
v-for="(item, index) in dataList"
:key="'discusslist_' + index"
:id="'discuss_'+ item.ID"
>
<template #header>
<div class="card-header">
{{item.discusser}}
<span class="button">({{dateFormat(item.addTime).format('YYYY-MM-DD')}})</span>
</div>
</template>
<!--简介-->
<div class="text item" v-html="item.concent" :id="'discuss1_'+ item.ID"></div>
<hr>
<i class="el-icon-circle-check"></i> {{item.agreeCount}}
</el-card>
<!--没有找到数据-->
<el-empty description="没有讨论呢,抢个沙发呗。" v-if="dataList.length === 0"></el-empty>
<!--分页-->
<pager/>
<!--讨论表单-->
<discussForm :id="id"/>
</template>
把分页和讨论的表单都分布出去做成了单独的组件,这样模板里面可以专注讨论列表的设置了。
集中目标不分心。
// 组件
import { ref } from 'vue'
// 组件
import discussForm from '../components/discuss-form.vue'
import pager from '../components/pager.vue'
// 数据列表的状态
import dataListControl from '../control/data-list'
// 日期格式化
const dateFormat = dayjs
// 组件的属性,获取博文ID
const props = defineProps({
id: String
})
// 获取注册函数和数据容器,
const { regDataListState, dataList } = dataListControl('discussList')
// 注册状态,设置博文ID为查询条件,获取博文的讨论数据。
const discussState = regDataListState()
discussState.find.blogId = props.id
discussState.isReload = !discussState.isReload
怎么样?是不是很简洁。
- 父组件里面使用
首先引入 control/data-list,然后获取状态,根据需求设置好查询条件。
最后别忘了使用 dataList 绑定模板。 - 分页控件使用
分页做成了单独且可以共享的组件,在组件里面可以直接获取局部状态,给 el-pagination 设置属性,这样就不需要父组件操心了。
/src/components/pager.vue
<template>
<el-pagination
background
layout="prev, pager, next"
v-model:currentPage="dataListState.page.pageIndex"
:page-size="dataListState.page.pageSize"
:total="dataListState.page.pageTotal">
</el-pagination>
</template>
获取状态,绑定模板。
// 统一的数据列表的分页组件
import { defineProps } from 'vue'
// 数据列表的状态
import dataListControl from '../control/data-list'
// 获取列表的局部状态
const { dataListState } = dataListControl()
翻页的时候页号会变化,触发 watch 的监听,从而实现翻页获取数据的效果。
子组件的使用方法
也是一样的步骤,只是不需要注册,而是获取父组件注册的状态,得到状态后,在需要的地方修改即可。
这样组件里面的代码就非常简单了。比如上面那个分页组件。
我们来看一下讨论表单的组件,模板部分就是一个普通的表单,跳过直接看js部分:
import { reactive, watch } from 'vue'
// 数据列表的状态
import dataListControl from '../control/data-list'
// 表单管理
import discussFromControl from '../control/data-form'
// 获取讨论列表的状态
const { dataListState } = dataListControl('discussList')
// 表单管理
const { discussModel, addNewDiscuss } = discussFromControl()
// 日期格式化
const dateFormat = dayjs
// 组件的属性
const props = defineProps({
id: String
})
// 发布讨论
const submit = () => {
discussModel.blogId = props.id
addNewDiscuss().then((id) => {
// 通知列表
dataListState.isReload = !dataListState.isReload
})
}
先获取讨论列表的状态,然后发布讨论成功后,调用讨论列表的状态,从而触发讨论列表重新加载讨论数据。
其他代码就不一一介绍了,感兴趣的话可以到 gitee 看源码。
轻量级状态 vue-data-state
轻量级状态已经发布到 npm ,可以使用yarn add vue-data-state 来安装。
源码
- 轻量级状态 vue-data-state
https://gitee.com/naturefw/vue-data-state - 博客
https://gitee.com/naturefw/vue3-blog
在线演示
状态
https://naturefw.gitee.io/vue-data-state/
博客
https://naturefw.gitee.io/vue3-blog
相关推荐
- NestJS入门教程系列一
-
介绍Nest(NestJS)是用于构建高效,可扩展的Node.js服务器端应用程序的框架。它使用渐进式JavaScript,内置并完全支持TypeScript(但开发人员仍然能够使用JavaScrip...
- 【推荐】一个网盘资源搜索与转存工具,支持移动端与PC端!
-
如果您对源码&技术感兴趣,请点赞+收藏+转发+关注,大家的支持是我分享最大的动力!!!项目介绍CloudSaver是一个基于Vue3和Express的网盘资源搜索与转存开源实用工具。它支持...
- Appium原理精讲
-
目前使用Appium新版本和旧版本的企业数目都很多,而两个版本的安装过程和api的使用又有较大的区别。但是无论表面上的东东如何变化,内部原理都是一样的。在这里我给大家介绍一下appium的核心,增进大...
- Kubernetes最小部署单元Pod
-
一、Kubernetes与Pod简介在当今云计算和容器化技术盛行的时代,Kubernetes已然成为容器编排领域的中流砥柱。它是一个开源的容器编排平台,由Google基于其内部使用的Bo...
- 最常用的四种跨域解决方案
-
前置知识什么是跨域?浏览器发送的请求地址(URL)与所在页面的地址不同(端口/协议/域名其一不同)。简言之,浏览器发出的请求url,与其所在页面的url不一样。此时,同源策略会让浏览器拒收服务器...
- Bolt.New —— 全栈AI Web自动编程
-
Bolt.New是由StackBlitz公司推出的,全栈AI工具,代码编辑、运行、部署,通通一站式搞定。它使用WebContainers技术,无需任何本地安装或配置,在浏览器中,就可以运行完整的No...
- Nodejs Express新手教程&高手进阶
-
NodejsExpress新手教程&高手进阶Express是一个NodeJS平台的框架,主要用于构于Web服务器项目。本文将通过示例介绍适合新手入门的Express基础使用,以及高手进阶知识,如:c...
- Express.js 创建Node.js Web应用
-
Express.js是一个基于Node.js的Web应用框架,框架的设计目的是构建应用的架构和简化应用的开发。框架会解决一些通用的问题,在Express.js中,Express框架会处理如:中间件、代...
- JavaScript 的 Express.js 功能及应用场景详解
-
Express.js是一个基于Node.js的轻量级Web应用框架,主要用于快速构建服务器端应用和API。它的核心功能包括以下关键点:1.路由管理URL路径与HTTP方法映射:通过...
- nodejs的express4文件下载
-
在nodejs的express框架中,下载变得非常简单,就一个方法,res.download()首先express命令行生成项目基本框架:不会的看这里:http://blog.csdn.net/zz...
- Express 系列:快速生成一个项目
-
系列预告本系列将以一个项目入手结合相关技术细节来带领大家一起学习Express这个基于Node.js的后端框架。本文首先将介绍:如何快速的生成一个具有一定结构的Express项目。Express项目结...
- nodejs的express自动生成项目框架
-
nodejs版本为:4.X,express版本为4.X1.全局安装2个模块express、express-generator在命令行输入:npminstall-gexpressnpminsta...
- express开发(一)简介与搭建
-
上周末去了趟上海书城,不愧是上海数得上号的书城,流行的科技书应有尽有,话不多说直接上图。最经典的C语言O(∩_∩)O最流行的java(づ ̄3 ̄)づ超酷的R语言/(ㄒoㄒ)/~~然而,身为一个坚定的前...
- Vue+Echarts可视化大屏系统后端框架搭建(附代码)
-
各位同学,大家好。上节课,前面我们讲解了Vue+Echarts前端部分的设计方法。这节课程,我们开始讲解使用Express进行后端设计的方法。01项目相关理论介绍什么是expressExpress是...
- Shopify电商API接口开发
-
Shopify电商API接口开发上线流程主要包括以下步骤。北京木奇移动技术有限公司,专业的软件外包开发公司,欢迎洽谈合作。前期准备-注册Shopify账号:在Shopify官网注册,用于后续开发测试...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- MVC框架 (46)
- spring框架 (46)
- 框架图 (58)
- bootstrap框架 (43)
- flask框架 (53)
- quartz框架 (51)
- abp框架 (47)
- jpa框架 (47)
- laravel框架 (46)
- express框架 (43)
- scrapy框架 (52)
- beego框架 (42)
- java框架spring (43)
- grpc框架 (55)
- 前端框架bootstrap (42)
- orm框架有哪些 (43)
- ppt框架 (48)
- 内联框架 (52)
- winform框架 (46)
- gui框架 (44)
- cad怎么画框架 (58)
- ps怎么画框架 (47)
- ssm框架实现登录注册 (49)
- oracle字符串长度 (48)
- oracle提交事务 (47)