UniApp 状态管理:Vuex 在 UniApp 中的实践

一、引言

在 UniApp 开发的过程中,你是否曾为组件间的数据共享与传递而烦恼?当项目逐渐庞大,各个页面和组件之间的状态变得错综复杂,传统的状态管理方式往往使得代码的可维护性大打折扣,数据流向难以追踪,容易引发各种难以排查的 Bug。

比如说,在一个电商应用中,购物车组件、商品列表组件以及用户信息组件可能分布在不同页面,但它们都需要共享用户登录状态、商品数量、总价等数据。若缺乏有效的状态管理,每个组件各自为政,不仅代码冗余,一旦数据需要更新,同步过程极易出错,严重影响用户体验。

而 Vuex 作为 Vue.js 官方的状态管理工具,为这些问题提供了一套完善的解决方案。它能够将应用中的共享状态集中管理,确保数据的一致性,并且遵循单向数据流的规则,让状态的变更清晰可预测。无论是小型项目的简洁架构搭建,还是大型复杂应用的状态维护,Vuex 都展现出了强大的优势,极大地提升开发效率与代码质量,接下来就让我们深入探索 Vuex 在 UniApp 中的实践之道。

二、Vuex 简介与在 UniApp 中的定位

Vuex 是 Vue.js 的状态管理库,它采用集中式存储管理应用的所有组件状态,为复杂的应用提供了清晰、可维护的状态管理方案。在 UniApp 项目里,它担当着至关重要的角色,负责管理跨页面以及组件之间的共享状态。

当我们开发 UniApp 应用时,随着功能的不断增加,组件之间的数据交互愈发频繁。例如,在一个集社交、资讯于一体的应用中,用户登录状态、偏好设置、文章列表数据等诸多信息,都可能被多个不同页面的组件所需要。若没有 Vuex,我们可能不得不通过复杂的组件间传值方式,如 props 层层传递、事件总线(Event Bus)等,来实现数据共享。但这样一来,数据的流向会变得错综复杂,一旦出现问题,调试成本极高,而且代码的可维护性大打折扣。

Vuex 通过定义一系列严格的规则,如单向数据流,确保状态的读取与修改都必须通过预定义的途径进行。这使得状态变更更加可预测,任何状态的改变都能有据可查,极大地提高了多个组件间交互的可维护性。我们能够清晰地知道数据从哪里来,在何处被修改,又流向了哪些组件,让整个应用的数据管理如同有条不紊的精密仪器,高效且稳定地运行。

三、Vuex 核心概念在 UniApp 中的应用

(一)State:数据核心

在 UniApp 的 Vuex 体系里,State 无疑是数据的核心所在,它就像是应用的 “数据心脏”,负责存储那些被多个组件共享的关键数据。比如在一个在线教育类 UniApp 中,课程列表数据、用户的学习进度、登录状态等信息,都需要被不同页面的组件频繁访问与使用,这些数据统一存放在 State 中进行集中管理,能够确保数据的一致性,避免各个组件持有不一致的副本,造成数据混乱。

为了保障数据的规范与可控,我们必须通过官方提供的特定方法来访问和修改 State 中的数据。在组件内,可以通过 this.$store.state.属性名 的方式直接获取 State 中的数据,例如:

 

export default {

computed: {

courseList() {

return this.$store.state.courseList;

}

}

}

当需要修改 State 时,绝不能直接对其赋值,而是要借助接下来会讲到的 Mutations 来完成,这一点至关重要,它保证了状态变更的可追溯性,使得任何数据的改动都有迹可循,方便排查问题,维护整个应用数据的稳定与健康。

(二)Getters:派生状态

Getters 在 UniApp 的 Vuex 应用中,扮演着 “数据加工厂” 的角色,它能够依据 State 中的原始数据,派生出一些新的状态供组件使用,这与 Vue 组件中的计算属性极为相似,却又服务于整个应用的多个组件。

想象一个社交应用,State 中存储了用户发布的所有动态列表数据,而不同的页面组件可能需要展示不同筛选条件下的动态,如仅显示图片动态、或是按照点赞数排序后的动态。此时,Getters 就能发挥强大作用,通过定义相应的函数,从原始动态列表中过滤、排序出符合需求的数据,提供给组件。

在代码层面,定义 Getters 就像在 store 的配置中添加一个新的对象属性:

 

const store = new Vuex.Store({

state: {

posts: [

{ id: 1, content: '这是一条文字动态', type: 'text', likes: 10 },

{ id: 2, content: '一张美丽的风景图', type: 'image', likes: 50 },

{ id: 3, content: '生活小趣事分享', type: 'text', likes: 30 }

]

},

getters: {

imagePosts(state) {

return state.posts.filter(post => post.type === 'image');

},

sortedPostsByLikes(state) {

return state.posts.sort((a, b) => b.likes - a.likes);

}

}

})

在组件中使用这些 Getters,和使用 State 类似,既可以直接通过 this.$store.getters.属性名 访问:

 

export default {

computed: {

shownPosts() {

return this.$store.getters.sortedPostsByLikes;

}

}

}

也可以借助 mapGetters 辅助函数,将 Getters 映射为组件内的计算属性,进一步简化代码,让数据获取更加优雅高效,为组件提供清晰、便捷的数据片段访问方式。

(三)Mutations:同步变更

Mutations 在 UniApp 的 Vuex 架构里,是保证状态修改有序且可追踪的 “纪律委员”。它规定,所有对 State 的同步变更操作,都必须通过它来执行,这就像是在数据变更的关键路径上设置了一道严格的关卡,使得任何状态的修改都被记录在案。

考虑一个电商应用,当用户在购物车中点击增加商品数量按钮时,这个操作需要同步更新购物车中商品的数量数据,而这一更新过程就必须通过 Mutations 来完成。在 store 的定义中,Mutations 是一个包含多个修改方法的对象:

 

const store = new Vuex.Store({

state: {

cartItems: [

{ id: 1, name: '商品A', quantity: 2 },

{ id: 2, name: '商品B', quantity: 1 }

]

},

mutations: {

incrementItemQuantity(state, payload) {

const item = state.cartItems.find(item => item.id === payload.id);

if (item) {

item.quantity++;

}

}

}

})

在组件中,当触发增加商品数量的操作时,需要使用 this.$store.commit('mutation方法名', 参数) 来提交变更:

 

export default {

methods: {

addItemQuantity(itemId) {

this.$store.commit('incrementItemQuantity', { id: itemId });

}

}

}

如此一来,在调试复杂的状态变更问题时,开发人员能够清晰地回溯每一次数据是在何处、因何操作而改变,极大地降低了排查问题的难度,确保应用状态始终处于可控状态。

(四)Actions:异步处理

在 UniApp 开发中,当涉及到与后端 API 交互、定时器操作等异步场景时,Actions 就成为了处理这些复杂异步逻辑的 “得力助手”。它允许我们在其中执行异步操作,待获取到数据或异步任务完成后,再通过触发 Mutations 来更新 State,从而确保数据的一致性与可追踪性。

以一个新闻资讯类 UniApp 为例,当页面加载时,需要从后端服务器获取最新的新闻列表数据,并更新到 State 中以供组件展示。此时,在 Actions 中可以发起网络请求:

 

const store = new Vuex.Store({

state: {

newsList: []

},

mutations: {

setNewsList(state, payload) {

state.newsList = payload;

}

},

actions: {

fetchNewsList({ commit }) {

uni.request({

url: 'https://api.example.com/news',

success: (res) => {

commit('setNewsList', res.data);

}

});

}

}

})

在组件的生命周期钩子函数(如 onLoad)中,通过 this.$store.dispatch('action方法名', 参数) 来触发这个异步操作:

 

export default {

onLoad() {

this.$store.dispatch('fetchNewsList');

}

}

这样,组件无需陷入复杂的异步逻辑处理,只需专注于自身的交互逻辑,而数据的获取与更新则由 Vuex 的 Actions 与 Mutations 协同完成,使得代码职责更加清晰,提高了整个应用的可维护性与开发效率。

四、模块化 Vuex 的优势与实施策略

(一)模块内聚性

随着 UniApp 项目规模的不断扩大,功能日益复杂,传统的单一 store 模式会使得 Vuex 的代码变得臃肿不堪,难以维护。此时,模块化 Vuex 的优势便凸显出来。

模块化能够将功能相关的状态管理代码紧密聚集在一起,形成一个个独立的 “小单元”。以一个包含社交、商城、资讯等多功能的 UniApp 为例,我们可以将用户模块、商品模块、文章模块分别拆分成独立的 Vuex 模块。在用户模块中,集中管理用户的登录状态、个人信息、好友列表等相关状态;商品模块则专注于处理商品列表、购物车、订单等与商品交互紧密相关的数据;文章模块负责文章的分类、列表展示、阅读状态等状态管理。

这样一来,在开发与维护过程中,开发人员只需关注特定模块内的状态逻辑,代码的可读性与可理解性大幅提升。当需要对用户模块进行功能扩展,如添加新的社交互动方式,只需深入了解该模块内部的 state、mutations、actions 和 getters,而不会被其他无关功能的代码干扰,极大地提高了开发效率,降低了出错的概率,让代码维护工作变得更加得心应手。

(二)模块的重用与扩展

在 UniApp 项目成长的过程中,需求变更与功能拓展是常有的事。模块化 Vuex 为应对这些变化提供了强大的支撑,使得项目具备出色的可扩展性。

当项目需要引入新的功能模块时,比如在原有的基础上添加一个用户权限管理模块,我们可以轻松创建一个新的 Vuex 模块,独立定义其 state 用于存储用户权限数据,mutations 负责同步更新权限状态,actions 处理诸如从后端获取权限信息的异步操作,getters 提供对外暴露经过处理后的权限相关派生状态。

将这个新模块集成到现有项目中,不会对已有的其他模块造成任何影响,原有模块的功能依旧稳定运行。而且,若在其他项目中也有类似的权限管理需求,我们能够直接重用这一模块,避免了重复开发,节省了大量的时间与精力。这种高度的可重用性与扩展性,使得 Vuex 模块化成为大型 UniApp 项目持续迭代、不断优化的得力工具,确保项目在复杂多变的业务需求下依然保持清晰、灵活的架构。

五、Vuex 配合 UniApp 页面生命周期的策略

(一)初始化和重置状态

在 UniApp 的开发旅程中,页面的生命周期如同一个个关键节点,而 Vuex 与之配合,能让状态管理更加精准高效。当页面加载时,我们通常需要为页面准备好初始数据,这时候,onLoad生命周期钩子就成为了 Vuex 施展身手的绝佳时机。

想象一个电商详情页,页面加载时需要获取商品详情数据、用户评价数据等,并将这些数据填充到 Vuex 的 State 中,以便组件展示。在 onLoad 钩子函数里,我们可以轻松地结合 Vuex 的 Actions 来完成这一复杂的数据初始化工作:

 

export default {

onLoad() {

this.$store.dispatch('fetchProductDetails', { productId: this.$route.params.id });

this.$store.dispatch('fetchProductReviews', { productId: this.$route.params.id });

}

}

上述代码中,通过 dispatch 触发了两个 Actions,分别用于获取商品详情和用户评价,这些 Actions 内部会发起网络请求,在获取到数据后通过 Mutations 更新 State。

而当页面关闭或隐藏时,比如用户从商品详情页离开,跳转至其他页面,为了节省资源、避免数据冲突或保持下次进入页面时的状态一致性,我们可能需要重置或保存页面相关的状态。在 onUnload 或 onHide 生命周期钩子中,就可以添加相应逻辑:

 

export default {

onUnload() {

// 重置商品详情相关状态

this.$store.commit('resetProductDetails');

// 保存用户在当前页面的浏览记录等信息到本地存储或后端

this.$store.dispatch('savePageHistory');

},

onHide() {

// 若页面隐藏时不需要重置某些状态,仅保存关键信息

this.$store.dispatch('saveSelectedOptions');

}

}

通过这种在页面生命周期关键节点与 Vuex 紧密配合的方式,无论是页面初次加载时的数据就绪,还是页面切换时的状态清理与保存,都能有条不紊地进行,为用户带来流畅且符合预期的交互体验。

(二)持久化状态处理

在一些应用场景下,我们希望用户的某些状态能够跨会话保持,比如用户登录后的身份信息、应用的主题设置等,这时候 Vuex 状态的持久化就显得尤为重要。借助 vuex-persistedstate 等强大的插件,我们能够轻松实现这一需求。

以用户登录信息为例,在用户首次登录成功后,我们将登录令牌(token)、用户 ID 等关键信息存储到 Vuex 的 State 中,为了确保用户下次打开应用时无需重新登录,就需要让这些信息持久化。首先,安装 vuex-persistedstate 插件:

 

npm install vuex-persistedstate --save

然后在 Vuex 的 store 配置文件中引入并配置该插件:

 

import Vue from 'vue';

import Vuex from 'vuex';

import createPersistedState from 'vuex-persistedstate';

Vue.use(Vuex);

export default new Vuex.Store({

state: {

user: {

token: '',

userId: ''

}

},

mutations: {

setUserToken(state, token) {

state.user.token = token;

},

setUserId(state, userId) {

state.user.userId = userId;

}

},

actions: {

login({ commit }, { token, userId }) {

commit('setUserToken', token);

commit('setUserId', userId);

}

},

plugins: [createPersistedState({

storage: window.localStorage,

key: 'app_user_state',

paths: ['user.token', 'user.userId']

})]

});

在上述配置中,插件会将指定路径( paths )下的 State 数据存储到本地存储(这里指定为 localStorage ),并在应用下次启动时自动从本地存储中读取数据,恢复到 Vuex 的 State 中,使得用户登录状态得以无缝延续,极大地提升了用户体验,让应用的使用更加便捷、连贯。

六、性能优化:Vuex 在 UniApp 中的最佳实践

(一)避免过度使用 Vuex

在 UniApp 项目中,并非所有的状态都适合放在 Vuex 中进行管理。Vuex 虽然强大,但如果滥用,可能会引入不必要的复杂性,甚至影响性能。

例如,对于一些仅在单个组件内部使用的临时状态,如组件内的弹窗显示与否的控制变量、临时的表单输入缓存等,完全可以通过组件自身的 data 或者 computed 属性来管理。这些状态的生命周期与组件紧密相关,若放入 Vuex,不仅增加了代码的跳转路径,还使得组件的独立性减弱,不利于代码的维护与调试。

再考虑一些简单的页面级配置,像某个特定页面的背景颜色切换状态,若只有这一个页面会用到,并且不需要在页面间共享或持久化,使用组件内的局部状态更加合适。只有那些需要在多个组件之间共享、频繁更新,并且对数据一致性要求较高,尤其是涉及到异步操作更新的数据,才是 Vuex 发挥优势的场景,我们需要依据实际情况仔细权衡,避免将 Vuex 变成一个臃肿的 “数据大杂烩”。

(二)利用 Vuex 模块的命名空间

随着 UniApp 项目的不断壮大,Vuex 模块日益增多,模块之间的名字冲突风险也随之加大。此时,合理利用 Vuex 模块的命名空间就显得至关重要。

命名空间能够为每个模块划定清晰的 “势力范围”,有效避免不同模块中的 state、mutations、actions 和 getters 发生名字冲突。例如,在一个同时拥有用户管理模块和权限管理模块的项目中,两个模块都可能有 isLoading 状态用于标识数据加载状态,若不使用命名空间,极易造成混乱。

通过为模块开启命名空间,在定义模块时设置 namespaced: true:

 

const userModule = {

namespaced: true,

state: {

userInfo: {},

isLoading: false

},

mutations: {

setUserInfo(state, payload) {

state.userInfo = payload;

},

setLoading(state, flag) {

state.isLoading = flag;

}

},

actions: {

fetchUserInfo({ commit }) {

// 发起网络请求获取用户信息

commit('setLoading', true);

uni.request({

url: 'https://api.example.com/user',

success: (res) => {

commit('setUserInfo', res.data);

commit('setLoading', false);

}

});

}

}

}

const permissionModule = {

namespaced: true,

state: {

permissions: [],

isLoading: false

},

mutations: {

setPermissions(state, payload) {

state.permissions = payload;

},

setLoading(state, flag) {

state.isLoading = flag;

}

},

actions: {

fetchPermissions({ commit }) {

// 发起网络请求获取权限信息

commit('setLoading', true);

uni.request({

url: 'https://api.example.com/permissions',

success: (res) => {

commit('setPermissions', res.data);

commit('setLoading', false);

}

});

}

}

}

const store = new Vuex.Store({

modules: {

user: userModule,

permission: permissionModule

}

})

在组件中使用时,通过特定的命名空间前缀来访问模块内的状态、触发变更等操作,例如:

 

export default {

computed: {

userInfo() {

return this.$store.state.user.userInfo;

},

isUserLoading() {

return this.$store.state.user.isLoading;

}

},

methods: {

updateUserInfo() {

this.$store.dispatch('user/fetchUserInfo');

}

}

}

这样,模块间的通信更加明确,代码的可读性与可维护性大幅提升,让多人协作开发大型 UniApp 项目时,不同开发者负责的模块之间能够井水不犯河水,协同高效地推进项目进展。

七、总结与展望

通过本文的深入探讨,我们清晰地认识到 Vuex 在 UniApp 状态管理中的关键作用与强大功能。从核心概念的精准运用,到模块化策略提升架构扩展性,再到与页面生命周期的默契配合以及性能优化的精细打磨,每一个环节都紧密相扣,为构建高效、健壮的 UniApp 应用筑牢根基。合理运用 Vuex,能够让数据流向明晰可辨,状态变更有条不紊,极大地提升项目的可维护性与可扩展性,避免随着项目规模扩大而陷入代码 “泥沼”。

然而,技术的发展永不止步,前端领域更是日新月异。新的状态管理理念与工具或许会不断涌现,UniApp 自身也在持续进化,未来我们需要时刻关注行业动态,不断学习、实践,将 Vuex 与其他前沿技术融合创新,探索出更适配复杂业务场景、更能提升用户体验的状态管理模式,为跨平台应用开发注入源源不断的活力,在数字化浪潮中乘风破浪,打造出更多优质、惊艳的应用产品。愿各位开发者在 UniApp 与 Vuex 的结合之旅中,持续精进,收获满满,让代码绽放无限魅力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/948529.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

微信流量主挑战:用户破16!新增文档转换(新纪元3)

朋友们,报告好消息!我的小程序用户数量已经涨到16个了!没错,真没拉朋友圈亲戚好友来撑场子,全靠实力(和一点点运气)吸引了16位陌生小伙伴光临!这波进步,连我自己都感动了…

Python:交互式物质三态知识讲解小工具

学着物理写着Python 以下是一个使用Python的Tkinter库实现的简单示例程序,通过图形界面展示并讲解固态、液态、气态的一些特点,代码中有详细的注释来帮助你理解各部分功能: 完整代码 import tkinter as tk from tkinter import ttk import …

ESP32-S3遇见OpenAI:OpenAI官方发布ESP32嵌入式实时RTC SDK

目录 OpenAI RTC SDK简介应用场景详解智能家居控制系统个人健康助手教育玩具 技术亮点解析低功耗设计快速响应高精度RTC安全性保障开发者指南 最近,OpenAI官方发布了一款针对ESP32-S3的嵌入式实时RTC(实时时钟)SDK,这标志着ESP32-…

Windows 11 关闭 VBS(基于虚拟化的安全性)

注:本文为 “Windows 11 关闭 VBS” 相关方法文章合辑。 重传部分 csdn 转储异常图片,未整理去重。 Win11 关闭 VBS 的几种方法 适用机型:台式 / ThinkCentre / 笔记本 / ThinkPad 分析 Virtualization-based Security (VBS) 基于虚拟化的…

小程序租赁系统的优势与应用探索

内容概要 小程序租赁系统,听起来很高大上,但实际上它比你想象的要实用得多!设想一下,几乎所有的租赁需求都能通过手机轻松解决。这种系统的便捷性体现在让用户随时随地都能发起租赁请求,而不再受制于传统繁琐的手续。…

简历_专业技能_熟悉Redis常用数据结构及其操作命令

系列博客目录 文章目录 系列博客目录1.Redis通用命令2.String类型3.Hash类型4.List类型5.Set类型6.Sorted类型7.StringRedisTemplate 1.Redis通用命令 通用指令是部分数据类型的,都可以使用的指令,常见的有: KEYS:查看符合模板的…

USB 驱动开发 --- Gadget 设备连接 Windows 免驱

环境信息 测试使用 DuoS(Arm CA53, Linux 5.10) 搭建方案验证环境,使用 USB sniff Wirekshark 抓包分析,合照如下: 注:左侧图中设备:1. 蓝色,USB sniff 非侵入工 USB 抓包工具;2. …

2025年1月4日蜻蜓q旗舰版st完整开源·包含前后端所有源文件·开源可商用可二开·优雅草科技·优雅草kir|优雅草星星|优雅草银满|优雅草undefined

2025年1月4日蜻蜓q旗舰版st完整开源包含前后端所有源文件开源可商用可二开优雅草科技优雅草kir|优雅草星星|优雅草银满|优雅草undefined 产品介绍: 本产品主要贡献者优雅草科技优雅草kir|优雅草星星|优雅草银满|优雅草undefined-青史留名,时光如川浪淘…

【文献精读笔记】Explainability for Large Language Models: A Survey (大语言模型的可解释性综述)(三)

****非斜体正文为原文献内容(也包含笔者的补充),灰色块中是对文章细节的进一步详细解释! 3.2 全局解释(Global Explanation) 与旨在解释模型个体预测的局部解释不同,全局解释提供了对语言模型…

体验谷歌最新Gemini 2.0 Flash原生多模态音视频对话桌面分享功能

Gemini 2.0是谷歌最新推出的原生多模态输入输出的AI模型。Gemini 2.0 Flash是2.0家族第一个模型,以多模态输入输出和Agent技术为核心,速度比 1.5 Pro快两倍,关键性能指标超过 1.5 Pro。模型支持原生工具调用和实时音视频流输入,提…

Leecode刷题C语言之我的日程安排表③

执行结果:通过 执行用时和内存消耗如下: typedef struct {int size;int maxIntersection;int** books;// #ifdef DEBUG// int runCount;// #endif } MyCalendarThree;void insert(MyCalendarThree*, int, int, int, int); int* binarySearch(int*, int, int);MyCal…

C++ 函数名字后面带const

C++中,在函数名后面加上const关键字表示该函数是一个常量成员函数。 常量成员函数,可以在const对象上被调用,并且不会修改对象的状态。 VC6新建一个单文档工程;添加一个一般类; 把类的代码做好; // MyClass.h: interface for the MyClass class. // //#if !defined(AFX_…

SMTP发送邮件的过程

(1)SMTP客户端首先请求与服务器端的25号端口建立TCP连接(1分)。(2)连接建立成功后,客户端和服务器通过握手阶段验证双方身份(1分)。(3)验证成功后,客户端首先向服务器端通告邮件发送…

qml Rectangle详解

1、概述 Rectangle是Qt Quick中的一个基础图形元素,用于在QML界面上绘制一个可带边框和可填充的矩形区域。它继承自Item类,因此具有Item的所有属性和功能,如位置、尺寸、变换等。通过Rectangle,可以创建各种矩形形状,…

软件工程实验-实验2 结构化分析与设计-总体设计和数据库设计

一、实验内容 1. 绘制工资支付系统的功能结构图和数据库 在系统设计阶段,要设计软件体系结构,即是确定软件系统中每个程序是由哪些模块组成的,以及这些模块相互间的关系。同时把模块组织成良好的层次系统:顶层模块通过调用它的下层…

Innodisk iSMART V6使用说明_SSD还能用多久?已经读写了多少次数?……

Innodisk iSMART是一款SSD健康数据读取软件。它能轻松获取大部分SSD内部寄存器中的健康数据,并以简洁的图形界面展示给用户。在程序界面的顶部,是页面标签,点击页面标签就能切换到相应的页面。页面标签的下面是磁盘选择栏。点击磁盘编号&…

windows11(或centos7)安装nvidia显卡驱动、CUDA、cuDNN

本文是我瞎搞时写的问题汇总及参考文献,记录了一些问题解决的进度及对问题的思考。 最近一次更新时间:2025年1月4日 一、安装或更新nvidia显卡驱动 首先,需要确保你的设备安装了最新的显卡驱动。 (1)centos7安装显…

2、蓝牙打印机点灯-GPIO输出控制

1、硬件 1.1、看原理图 初始状态位高电平. 需要驱动PA1输出高低电平控制PA1. 1.2、看手册 a、系统架构图 GPIOA在APB2总线上。 b、RCC使能 GPIOA在第2位。 c、GPIO寄存器配置 端口:PA1 模式:通用推挽输出模式 -- 输出0、1即可 速度:5…

WPS表格技巧01-项目管理中的基本功能-计划和每日记录的对应

前言: 在项目管理中,一般就是用些项目管理工具来管理这个任务和 task,但是就是要学这些工具很麻烦,比较好的方法,通用的方法就是用 Excel 表格去做(这非常适合松散的团队组织),然后…

Vue 项目中实现打印功能:基于目标 ID 的便捷打印方案

一、引言 在 Vue 项目开发中,实现打印功能是一个常见的需求。本文将介绍如何封装一个打印方法,使得用户只需传入需要打印的目标 ID 名称,即可轻松实现预览并打印的功能。这种方法不仅简单易用,还具有一定的通用性,适合…