百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

使用局部状态(轻量级状态)优化博客代码

ccwgpt 2024-10-22 10:22 29 浏览 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

相关推荐

FastUI:用Python构建高性能React应用,告别JavaScript

在现代Web开发中,前后端分离已经成为主流趋势。然而,前端开发往往需要深入掌握JavaScript和各种框架,这对于许多Python开发者来说是一个不小的挑战。今天,我们要介绍一个革命性的UI框架——...

Python + Flet 开发网站的最佳数据库模块组合

对于使用Python和Flet开发网站并需要数据库支持的应用,以下是推荐的模块组合方案。方案一:SQLite+SQLAlchemy(推荐轻量级方案)**适用场景**:中小型应用、单用户或...

前端程序员应该往全栈方向发展吗?还是坚守前端?

这是一个非常经典且重要的问题,几乎每一位走到职业生涯十字路口的前端程序员都会思考。它没有一个绝对的“正确答案”,但我们可以从多个维度来分析,帮你找到最适合你的那条路。简单来说,这不是一个“要不要”的...

Python交互仪表盘工具:Panel 进阶学习路线图

Panel作为Python生态系统中最强大的交互式仪表盘工具之一,其学习曲线既平缓又深远。这里我将为您构建一个系统化的进阶学习框架,包含实战项目和关键学习节点。1.现代化Web集成开发1....

PuePy:将Python带入浏览器的革命性框架

在现代网络开发中,JavaScript无疑是主导地位的编程语言。但最近,随着WebAssembly和PyScript的崛起,Python的使用场景逐渐扩展到了前端开发领域。PuePy应运而生,作为一...

不容易!找到一个python的超简易网站搭建神器

作者:清香客来源:Python技术相信很多学习python的酱友们,大部分和我一样是为了提升工作效率,但是在提升自己的工作效率时,也会想着做同样工作的同事能不能也用上自己写的脚本(视工作环境而定)...

PyWebView:用 Python 构建桌面应用的神器

作为一个Python开发者,我一直希望能找到一种简便的方法来构建桌面应用,而不是去学习诸如Electron这种重度依赖JavaScript的技术栈。就在我为桌面应用开发寻找替代方案时,遇到...

Python Django框架中级教程:深入探索Django的核心功能

在Python的Web开发领域中,Django框架以其强大的功能和高效的开发模式占据着重要地位。对于已经掌握了Django基础的开发者来说,进一步深入学习中级知识能让我们开发出更复杂、更强大的Web应...

【Python程序开发系列】使用Flask实现前后端分离(案例)

这是我的第398篇原创文章。一、引言随着web开发的不断发展,前后端分离已成为越来越流行的架构设计。Flask是一个轻量级的Pythonweb框架,非常适合用于构建API,然后配合前端框...

每天一个Python库:Flask超轻量Web框架,灵活高效!

为什么要学Flask?Flask是一个「微型但强大的」Web框架:极简上手,几行代码即可跑起来灵活扩展,想加啥加啥(RESTful、JWT、数据库…)文档齐全,适合入门API开发或快...

Python个人量化投资系统:后台搭建

独立搞量化系统的程序员最烦啥?重复造权限管理的轮子绝对排前三。技术老手用Python+PearAdminFlask两天搭出量化后台,实测开源框架真能省下80%基础工作量。开源后台框架选对,一人项目...

python后端学什么(python后端好找工作吗)

在当今数字化的时代,Python后端开发成为了众多开发者追逐的热门领域。那么,想要在这个领域崭露头角,我们究竟应该学些什么呢?学习Python后端开发需要掌握全栈技术栈,涵盖从基础语法到分布式...

Motia:重新定义后端与智能体整合的未来平台

在AIagent技术飞速发展的今天,我们拥有了诸如Dify、RAGFlow、LangChain等一系列优秀平台。然而,随着场景复杂度增加,开发者正面临一个共同问题:后端越来越碎片化,Agen...

Python数据校验不再难:Pydantic库的工程化实践指南

在FastAPI框架横扫Python后端开发领域的今天,其默认集成的Pydantic库正成为处理数据验证的黄金标准。这个看似简单的库究竟隐藏着哪些让开发者爱不释手的能力?本文将通过真实项目案例,带您解...

Python Flask 建站框架实操教程(flask框架网页)

下面我将带您从零开始构建一个完整的Flask网站,包含用户认证、数据库操作和前端模板等核心功能。##第一部分:基础项目搭建###1.创建项目环境```bash#创建项目目录mkdirfl...

取消回复欢迎 发表评论: