当前位置: 首页 > article >正文

鸿蒙OSUniApp 制作自定义弹窗与模态框组件#三方框架 #Uniapp

UniApp 制作自定义弹窗与模态框组件

前言

在移动应用开发中,弹窗和模态框是用户交互的重要组成部分,它们用于显示提示信息、收集用户输入或确认用户操作。尽管 UniApp 提供了基础的交互组件如 uni.showModal()uni.showToast(),但这些原生组件的样式和交互方式往往难以满足设计师的要求和复杂的业务需求。

本文将详细介绍如何在 UniApp 中实现自定义弹窗和模态框组件,从基础弹窗到复杂的可交互模态框,全面提升你的应用交互体验。通过本文,你将学会如何打造灵活、美观且功能强大的弹窗组件。

弹窗组件设计思路

在开始编码前,我们需要明确自定义弹窗组件的设计目标和核心功能:

  1. 灵活性:支持不同的弹窗类型(提示、确认、输入等)
  2. 可配置性:可自定义样式、动画效果和内容
  3. 易用性:简单的调用方式,丰富的事件回调
  4. 性能优化:合理的组件复用机制,避免重复创建

基于以上设计思路,我们将实现两个核心组件:

  1. 基础弹窗组件(BasePopup):处理弹窗的显示、隐藏、动画等基础功能
  2. 高级模态框组件(Modal):在基础弹窗基础上,实现更复杂的交互和布局

基础弹窗组件实现

首先,我们来实现一个基础的弹窗组件(BasePopup),它将作为所有弹窗类型的基础:

<!-- components/base-popup/base-popup.vue -->
<template><view class="popup-mask" :class="{ 'popup-show': showPopup }" :style="{ backgroundColor: maskColor }"@tap="handleMaskClick"@touchmove.stop.prevent="preventTouchMove"><view class="popup-container" :class="[`popup-${position}`, showContent ? 'popup-content-show' : '',customClass]":style="customStyle"@tap.stop="() => {}"><slot></slot></view></view>
</template><script>
export default {name: 'BasePopup',props: {// 是否显示弹窗show: {type: Boolean,default: false},// 弹窗位置:center, top, bottom, left, rightposition: {type: String,default: 'center'},// 是否允许点击遮罩关闭maskClosable: {type: Boolean,default: true},// 遮罩背景色maskColor: {type: String,default: 'rgba(0, 0, 0, 0.5)'},// 弹窗内容动画时长(ms)duration: {type: Number,default: 300},// 自定义弹窗样式customStyle: {type: Object,default: () => ({})},// 自定义弹窗类customClass: {type: String,default: ''},// 是否阻止页面滚动preventScroll: {type: Boolean,default: true}},data() {return {showPopup: false,showContent: false}},watch: {show: {handler(val) {if (val) {this.open();} else {this.close();}},immediate: true}},methods: {// 打开弹窗open() {this.showPopup = true;// 渐入动画setTimeout(() => {this.showContent = true;}, 50);},// 关闭弹窗close() {this.showContent = false;// 等待内容关闭动画结束后再关闭整个弹窗setTimeout(() => {this.showPopup = false;this.$emit('close');}, this.duration);},// 处理遮罩点击handleMaskClick() {if (this.maskClosable) {this.$emit('update:show', false);}},// 阻止页面滚动preventTouchMove() {if (this.preventScroll) {return;}}}
}
</script><style scoped>
.popup-mask {position: fixed;top: 0;left: 0;right: 0;bottom: 0;z-index: 999;opacity: 0;visibility: hidden;transition: all 0.3s ease-in-out;display: flex;justify-content: center;align-items: center;
}.popup-show {opacity: 1;visibility: visible;
}.popup-container {position: relative;opacity: 0;transform: scale(0.9);transition: all 0.3s ease-in-out;max-width: 90%;max-height: 90%;overflow: auto;background-color: #fff;border-radius: 12rpx;box-shadow: 0 0 20rpx rgba(0, 0, 0, 0.1);
}.popup-content-show {opacity: 1;transform: scale(1);
}/* 不同位置的弹窗样式 */
.popup-center {/* 默认已居中 */
}.popup-top {position: absolute;top: 0;left: 0;width: 100%;transform: translateY(-100%);border-radius: 0 0 12rpx 12rpx;
}.popup-bottom {position: absolute;bottom: 0;left: 0;width: 100%;transform: translateY(100%);border-radius: 12rpx 12rpx 0 0;
}.popup-top.popup-content-show,
.popup-bottom.popup-content-show {transform: translateY(0);
}.popup-left {position: absolute;top: 0;left: 0;height: 100%;transform: translateX(-100%);border-radius: 0 12rpx 12rpx 0;
}.popup-right {position: absolute;top: 0;right: 0;height: 100%;transform: translateX(100%);border-radius: 12rpx 0 0 12rpx;
}.popup-left.popup-content-show,
.popup-right.popup-content-show {transform: translateX(0);
}
</style>

这个基础弹窗组件具有以下特点:

  1. 支持多种弹出位置(中间、顶部、底部、左侧、右侧)
  2. 支持自定义背景色、样式和过渡动画
  3. 可配置点击遮罩是否关闭
  4. 阻止页面滚动,提升用户体验

高级模态框组件实现

在基础弹窗组件之上,我们可以实现一个功能更完善的模态框组件:

<!-- components/modal/modal.vue -->
<template><base-popup:show="show":position="position":mask-closable="maskClosable":mask-color="maskColor":duration="duration":custom-style="customStyle":custom-class="customClass"@update:show="$emit('update:show', $event)"@close="$emit('close')"><view class="modal-content"><!-- 标题区域 --><view v-if="showHeader" class="modal-header"><text class="modal-title">{{ title }}</text><view v-if="showClose" class="modal-close" @tap.stop="$emit('update:show', false)">✕</view></view><!-- 内容区域 --><view class="modal-body" :style="bodyStyle"><!-- 使用默认插槽或展示传入的内容 --><slot><text class="modal-message">{{ message }}</text></slot></view><!-- 按钮区域 --><view v-if="showFooter" class="modal-footer"><slot name="footer"><view v-if="showCancel" class="modal-btn modal-cancel-btn" :style="cancelBtnStyle"@tap.stop="handleCancel">{{ cancelText }}</view><view v-if="showConfirm" class="modal-btn modal-confirm-btn" :style="confirmBtnStyle"@tap.stop="handleConfirm">{{ confirmText }}</view></slot></view></view></base-popup>
</template><script>
import BasePopup from '../base-popup/base-popup.vue';export default {name: 'Modal',components: {BasePopup},props: {// 是否显示模态框show: {type: Boolean,default: false},// 标题title: {type: String,default: '提示'},// 内容文本message: {type: String,default: ''},// 是否显示头部showHeader: {type: Boolean,default: true},// 是否显示关闭按钮showClose: {type: Boolean,default: true},// 是否显示底部showFooter: {type: Boolean,default: true},// 是否显示取消按钮showCancel: {type: Boolean,default: true},// 是否显示确认按钮showConfirm: {type: Boolean,default: true},// 取消按钮文本cancelText: {type: String,default: '取消'},// 确认按钮文本confirmText: {type: String,default: '确认'},// 弹窗位置position: {type: String,default: 'center'},// 是否允许点击遮罩关闭maskClosable: {type: Boolean,default: true},// 遮罩背景色maskColor: {type: String,default: 'rgba(0, 0, 0, 0.5)'},// 动画时长duration: {type: Number,default: 300},// 自定义样式customStyle: {type: Object,default: () => ({})},// 自定义内容区域样式bodyStyle: {type: Object,default: () => ({})},// 自定义取消按钮样式cancelBtnStyle: {type: Object,default: () => ({})},// 自定义确认按钮样式confirmBtnStyle: {type: Object,default: () => ({})},// 自定义类名customClass: {type: String,default: ''}},methods: {// 处理取消事件handleCancel() {this.$emit('update:show', false);this.$emit('cancel');},// 处理确认事件handleConfirm() {this.$emit('update:show', false);this.$emit('confirm');}}
}
</script><style scoped>
.modal-content {min-width: 560rpx;box-sizing: border-box;
}.modal-header {position: relative;padding: 30rpx 30rpx 20rpx;border-bottom: 1rpx solid #f0f0f0;display: flex;justify-content: center;align-items: center;
}.modal-title {font-size: 32rpx;font-weight: bold;color: #333;text-align: center;flex: 1;
}.modal-close {position: absolute;right: 30rpx;top: 30rpx;width: 40rpx;height: 40rpx;font-size: 32rpx;color: #999;display: flex;justify-content: center;align-items: center;
}.modal-body {padding: 40rpx 30rpx;max-height: 60vh;overflow-y: auto;
}.modal-message {font-size: 28rpx;color: #333;line-height: 1.5;text-align: center;word-break: break-all;
}.modal-footer {display: flex;padding: 20rpx 30rpx 30rpx;border-top: 1rpx solid #f0f0f0;
}.modal-btn {flex: 1;height: 80rpx;line-height: 80rpx;text-align: center;font-size: 30rpx;border-radius: 80rpx;margin: 0 20rpx;
}.modal-cancel-btn {background-color: #f5f5f5;color: #666;
}.modal-confirm-btn {background-color: #07c160;color: #fff;
}
</style>

这个模态框组件在基础弹窗之上增加了以下功能:

  1. 标题栏和关闭按钮
  2. 自定义内容区域(支持插槽或文本)
  3. 底部按钮区域(支持自定义样式和文本)
  4. 完善的事件处理(确认、取消、关闭)

使用示例

1. 基础弹窗示例

<template><view class="container"><button @tap="showBasicPopup = true">显示基础弹窗</button><base-popup :show.sync="showBasicPopup" position="bottom"><view style="padding: 30rpx;"><text>这是一个基础弹窗</text></view></base-popup></view>
</template><script>
import BasePopup from '@/components/base-popup/base-popup.vue';export default {components: {BasePopup},data() {return {showBasicPopup: false}}
}
</script>

2. 模态框组件示例

<template><view class="container"><button @tap="showConfirmModal">显示确认模态框</button><button @tap="showCustomModal">显示自定义模态框</button><!-- 确认模态框 --><modal:show.sync="confirmModal"title="操作确认"message="确定要删除这个项目吗?此操作不可恢复。"@confirm="handleConfirm"@cancel="handleCancel"></modal><!-- 自定义模态框 --><modal:show.sync="customModal"title="自定义内容":show-footer="false"><view class="custom-content"><image src="/static/images/success.png" class="success-icon"></image><text class="success-text">操作成功</text><text class="success-tip">将在3秒后自动关闭</text></view></modal></view>
</template><script>
import Modal from '@/components/modal/modal.vue';export default {components: {Modal},data() {return {confirmModal: false,customModal: false}},methods: {showConfirmModal() {this.confirmModal = true;},showCustomModal() {this.customModal = true;// 3秒后自动关闭setTimeout(() => {this.customModal = false;}, 3000);},handleConfirm() {console.log('用户点击了确认');// 执行确认操作uni.showToast({title: '已确认操作',icon: 'success'});},handleCancel() {console.log('用户点击了取消');}}
}
</script><style>
.container {padding: 40rpx;
}button {margin-bottom: 30rpx;
}.custom-content {display: flex;flex-direction: column;align-items: center;padding: 30rpx;
}.success-icon {width: 120rpx;height: 120rpx;margin-bottom: 20rpx;
}.success-text {font-size: 32rpx;color: #07c160;font-weight: bold;margin-bottom: 10rpx;
}.success-tip {font-size: 24rpx;color: #999;
}
</style>

高级应用:表单输入模态框

在实际应用中,我们经常需要通过模态框收集用户输入。下面是一个表单输入模态框的示例:

<template><modal:show.sync="show"title="用户信息":mask-closable="false":confirm-text="'保存'"@confirm="handleSave"><view class="form-container"><view class="form-item"><text class="form-label">姓名</text><input class="form-input" v-model="form.name" placeholder="请输入姓名" /></view><view class="form-item"><text class="form-label">手机号</text><input class="form-input" v-model="form.phone" type="number" placeholder="请输入手机号" /></view><view class="form-item"><text class="form-label">地址</text><textarea class="form-textarea" v-model="form.address" placeholder="请输入地址"></textarea></view></view></modal>
</template><script>
import Modal from '@/components/modal/modal.vue';export default {name: 'FormModal',components: {Modal},props: {show: {type: Boolean,default: false},// 初始表单数据initData: {type: Object,default: () => ({})}},data() {return {form: {name: '',phone: '',address: ''}}},watch: {show(val) {if (val) {// 打开模态框时,初始化表单数据this.form = {name: this.initData.name || '',phone: this.initData.phone || '',address: this.initData.address || ''};}}},methods: {// 保存表单数据handleSave() {// 表单验证if (!this.form.name) {uni.showToast({title: '请输入姓名',icon: 'none'});return;}if (!this.form.phone) {uni.showToast({title: '请输入手机号',icon: 'none'});return;}// 验证通过,发出保存事件this.$emit('save', {...this.form});}}
}
</script><style scoped>
.form-container {padding: 10rpx 0;
}.form-item {margin-bottom: 30rpx;
}.form-label {display: block;font-size: 28rpx;color: #333;margin-bottom: 10rpx;
}.form-input {width: 100%;height: 80rpx;border: 1rpx solid #eee;border-radius: 8rpx;padding: 0 20rpx;box-sizing: border-box;font-size: 28rpx;
}.form-textarea {width: 100%;height: 160rpx;border: 1rpx solid #eee;border-radius: 8rpx;padding: 20rpx;box-sizing: border-box;font-size: 28rpx;
}
</style>

在页面中使用表单模态框:

<template><view class="container"><button @tap="showFormModal">编辑用户信息</button><form-modal :show.sync="formModalVisible" :init-data="userData"@save="handleSaveUserData"></form-modal></view>
</template><script>
import FormModal from '@/components/form-modal/form-modal.vue';export default {components: {FormModal},data() {return {formModalVisible: false,userData: {name: '张三',phone: '13800138000',address: '北京市朝阳区'}}},methods: {showFormModal() {this.formModalVisible = true;},handleSaveUserData(data) {console.log('保存的用户数据:', data);this.userData = {...data};uni.showToast({title: '保存成功',icon: 'success'});}}
}
</script>

实现一个全局弹窗管理器

为了更方便地调用弹窗,我们可以实现一个全局弹窗管理器,让弹窗的使用更像系统函数调用:

// utils/popup-manager.js
import Vue from 'vue';
import Modal from '@/components/modal/modal.vue';class PopupManager {constructor() {// 创建一个Vue实例来管理模态框this.modalInstance = null;this.initModalInstance();}// 初始化模态框实例initModalInstance() {const ModalConstructor = Vue.extend(Modal);this.modalInstance = new ModalConstructor({el: document.createElement('div')});document.body.appendChild(this.modalInstance.$el);}// 显示提示框alert(options = {}) {return new Promise(resolve => {const defaultOptions = {title: '提示',message: '',confirmText: '确定',showCancel: false,maskClosable: false};const mergedOptions = {...defaultOptions, ...options};this.modalInstance.title = mergedOptions.title;this.modalInstance.message = mergedOptions.message;this.modalInstance.confirmText = mergedOptions.confirmText;this.modalInstance.showCancel = mergedOptions.showCancel;this.modalInstance.maskClosable = mergedOptions.maskClosable;this.modalInstance.show = true;// 监听确认事件this.modalInstance.$once('confirm', () => {resolve(true);});// 处理取消事件this.modalInstance.$once('cancel', () => {resolve(false);});});}// 显示确认框confirm(options = {}) {const defaultOptions = {title: '确认',showCancel: true,cancelText: '取消',confirmText: '确认'};return this.alert({...defaultOptions, ...options});}// 关闭所有弹窗closeAll() {if (this.modalInstance) {this.modalInstance.show = false;}}
}export default new PopupManager();

在页面中使用弹窗管理器:

import popupManager from '@/utils/popup-manager.js';// 显示一个提示框
popupManager.alert({title: '操作成功',message: '您的操作已完成'
}).then(() => {console.log('用户点击了确定');
});// 显示一个确认框
popupManager.confirm({title: '删除确认',message: '确定要删除这条记录吗?',confirmText: '删除'
}).then(result => {if (result) {console.log('用户确认了删除');// 执行删除操作} else {console.log('用户取消了删除');}
});

注意:上面的全局弹窗管理器代码主要适用于H5环境,在App和小程序环境中可能需要不同的实现方式。

最佳实践与优化建议

  1. 避免过多嵌套:弹窗内部尽量避免再打开多层弹窗,这会导致用户体验下降。

  2. 合理使用动画:动画可以提升用户体验,但过多或过于复杂的动画可能导致性能问题。

  3. 适配不同设备:确保弹窗在不同设备上都有良好的表现,尤其是在小屏幕设备上。

  4. 考虑无障碍访问:为弹窗添加适当的ARIA属性,提高无障碍体验。

  5. 性能优化

    • 避免在弹窗中放置过多复杂内容
    • 使用条件渲染(v-if)而不是隐藏显示(v-show)来完全移除不显示的弹窗DOM
    • 在关闭弹窗时及时清理资源
  6. 错误处理:添加适当的错误处理机制,确保弹窗显示和关闭的稳定性。

总结

本文详细介绍了如何在UniApp中实现自定义弹窗和模态框组件,从基础的弹窗到功能丰富的模态框,再到实用的表单输入模态框,全面覆盖了移动应用中常见的弹窗交互需求。通过这些组件,你可以大大提升应用的交互体验和美观度。

在实际项目中,你可以根据具体业务需求对这些组件进行扩展和优化,例如添加更多的动画效果、支持更复杂的布局、实现特定的交互逻辑等。希望本文对你的UniApp开发有所帮助!

在面对移动应用开发中各种弹窗交互的挑战时,拥有一套灵活、可定制的弹窗组件库将是你的得力助手。愿你能基于本文提供的思路和代码,打造出更加出色的用户体验。

相关文章:

鸿蒙OSUniApp 制作自定义弹窗与模态框组件#三方框架 #Uniapp

UniApp 制作自定义弹窗与模态框组件 前言 在移动应用开发中&#xff0c;弹窗和模态框是用户交互的重要组成部分&#xff0c;它们用于显示提示信息、收集用户输入或确认用户操作。尽管 UniApp 提供了基础的交互组件如 uni.showModal() 和 uni.showToast()&#xff0c;但这些原…...

Spring Security与Spring Boot集成原理

Spring Security依赖的是过滤器机制&#xff0c;首先是web容器例如tomcat作为独立的产品&#xff0c;本身有自己的一套过滤器机制用来处理请求&#xff0c;那么如何将tomcat接收到的请求转入到Spring Security的处理逻辑呢&#xff1f;spring充分采用了tomcat的拓展机制提供了t…...

VScode各文件转化为PDF的方法

文章目录 代码.py文件.ipynb文本和代码夹杂的文件方法 1:使用 VS Code 插件(推荐)步骤 1:安装必要插件步骤 2:安装 `nbconvert`步骤 3:间接导出(HTML → PDF)本文遇见了系列错误:解决方案:问题原因步骤 1:降级 Jinja2 至兼容版本步骤 2:确保 nbconvert 版本兼容替代…...

精益数据分析(58/126):移情阶段的深度实践与客户访谈方法论

精益数据分析&#xff08;58/126&#xff09;&#xff1a;移情阶段的深度实践与客户访谈方法论 在创业的漫长旅途中&#xff0c;正确识别和验证问题是成功的第一步。今天&#xff0c;我们继续围绕《精益数据分析》中创业阶段的核心内容&#xff0c;深入探讨移情阶段的关键实践…...

Vue3学习(组合式API——Watch侦听器、watchEffect()详解)

目录 一、Watch侦听器。 &#xff08;1&#xff09;侦听单个数据。 &#xff08;2&#xff09;侦听多个数据。&#xff08;数组写法&#xff1f;&#xff01;&#xff09; &#xff08;3&#xff09;immediate参数。(立即执行回调) &#xff08;3&#xff09;deep参数。(深层监…...

【node.js】安装与配置

个人主页&#xff1a;Guiat 归属专栏&#xff1a;node.js 文章目录 1. Node.js简介1.1 Node.js的特点1.2 Node.js架构 2. Node.js安装2.1 下载和安装方法2.1.1 Windows安装2.1.2 macOS安装2.1.3 Linux安装 2.2 使用NVM安装和管理Node.js版本2.2.1 安装NVM2.2.2 使用NVM管理Node…...

《AI大模型应知应会100篇》第62篇:TypeChat——类型安全的大模型编程框架

第62篇&#xff1a;TypeChat——类型安全的大模型编程框架 摘要 在构建 AI 应用时&#xff0c;一个常见的痛点是大语言模型&#xff08;LLM&#xff09;输出的不确定性与格式不一致问题。开发者往往需要手动解析、校验和处理模型返回的内容&#xff0c;这不仅增加了开发成本&a…...

HttpMessageConverter 的作用是什么? 它是如何实现请求体到对象、对象到响应体的自动转换的(特别是 JSON/XML)?

HttpMessageConverter (HTTP 消息转换器) 是 Spring MVC 框架中一个非常核心的组件&#xff0c;它的主要作用是在 HTTP 请求和响应体与 Java 对象之间进行双向转换。 核心作用&#xff1a; 读取请求体 (Request Body) 到 Java 对象&#xff1a; 当 Controller 方法的参数使用 …...

EdgeShard:通过协作边缘计算实现高效的 LLM 推理

(2024-05-23) EdgeShard: Efficient LLM Inference via Collaborative Edge Computing (EdgeShard:通过协作边缘计算实现高效的 LLM 推理) 作者: Mingjin Zhang; Jiannong Cao; Xiaoming Shen; Zeyang Cui;期刊: (发表日期: 2024-05-23)期刊分区:本地链接: Zhang 等 - 2024 …...

火山 RTC 引擎9 ----集成 appkey

一、集成 appkey 1、网易RTC 初始化过程 1&#xff09;、添加头文件 实现互动直播 - 互动直播 2.0网易云信互动直播产品的基本功能包括音视频通话和连麦直播&#xff0c;当您成功初始化 SDK 之后&#xff0c;您可以简单体验本产品的基本业务流程&#xff0c;例如主播加入房间…...

ArcGIS Pro 3.4 二次开发 - 框架

环境&#xff1a;ArcGIS Pro SDK 3.4 .NET 8 文章目录 框架1 框架1.1 如何在 DockPane 可见或隐藏时订阅和取消订阅事件1.2 执行命令1.3 设置当前工具1.4 激活选项卡1.5 激活/停用状态 - 修改条件1.6 判断应用程序是否繁忙1.7 获取应用程序主窗口1.8 关闭 ArcGIS Pro1.9 获取 …...

Adminer:一个基于Web的轻量级数据库管理工具

Adminer 是一个由单个 PHP 文件实现的免费数据库管理工具&#xff0c;支持 MySQL、MariaDB、PostgreSQL、CockroachDB、SQLite、SQL Server、Oracle、Elasticsearch、SimpleDB、MongoDB、Firebird、Clickhouse 等数据库。 Adminer 支持的主要功能如下&#xff1a; 连接数据库服…...

RK3568下QT实现按钮切换tabWidget

运行效果: 在 Qt 应用程序开发过程中,TabWidget 是一种非常实用的 UI 组件,它能够以选项卡的形式展示多个页面内容,帮助我们有效组织和管理复杂的界面布局。而在实际使用时,常常会有通过按钮点击来切换 TabWidget 页面的需求,本文将通过一个完整的示例,详细介绍如何在 Q…...

2025 OceanBase 开发者大会全议程指南

5 月 17 日&#xff0c;第三届 OceanBase 开发者大会将在广州举办。 我们邀请数据库领军者与AI实践先锋&#xff0c;与开发者一起探讨数据库与 AI 协同创新的技术趋势&#xff0c;面对面交流 OceanBase 在 TP、AP、KV 及 AI 能力上的最新进展&#xff0c;深度体验“打破技术栈…...

GitHub 趋势日报 (2025年05月15日)

本日报由 TrendForge 系统生成 https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日整体趋势 Top 10 排名项目名称项目描述今日获星总星数语言1TapXWorld/ChinaTextbookPDF教材。⭐ 6685⭐ 15287Roff2xming521/WeClone&…...

day017-磁盘管理-实战

文章目录 1. 硬盘命名规则2. 添加硬盘2.1 查看硬盘名称 3. 硬盘分区3.1 分区命名规则&#xff1a;mbr分区表格式3.2 创建分区&#xff1a;fdisk3.2.1 fdisk -l&#xff1a;查看硬盘及分区信息3.2.2 fdisk /dev/sdc :为该硬盘分区3.2.3 创建扩展分区和逻辑分区3.2.4 保存设置并退…...

【成品设计】STM32和UCOS-II的项目

项目1&#xff1a;《基于STM32和UCOS-II的水质监测系统》 Ps&#xff1a;分为带系统版本和不带系统版本&#xff0c;功能都一样。 功能说明&#xff1a; 1. 单片机主控&#xff1a;STM32F103C8T6单片机作为核心控制。 2. 酸碱度传感器&#xff1a;实时采集当前PH值。 3. 水质…...

当通过PHP在线修改文件数组遇到不能及时生效问题

当你通过PHP在线修改文件中的数组(比如配置文件、缓存文件等)后,发现修改不能及时生效,常见原因和解决办法如下: 1. 缓存未刷新 问题描述:PHP应用通常会对配置、数据等做缓存(如Redis、Memcached、OPcache、文件缓存等),导致你修改了文件但实际运行时还是旧内容。解决…...

Ngrok 配置:实现 Uniapp 前后端项目内网穿透

文章目录 一、下载并安装 ngrok二、配置 ngrok Authtoken三、启动本地 uniapp 项目四、使用 ngrok 暴露本地服务五、通过公网 URL 访问项目六、后端API项目的穿透问题排查 (uni-app 后端 API 示例)交互流程图示 七、ngrok Web 界面 (本地监控)八、停止 ngrok总结 ngrok 是一款…...

鸿蒙ArkUI体验:Hexo博客客户端开发心得

最近部门也在跟进鸿蒙平台的业务开发&#xff0c;自己主要是做 Android 开发&#xff0c;主要使用 Kotlin/Java 语言。&#xff0c;需要对新的开发平台和开发模式进行学习&#xff0c;在业余时间开了个项目练手&#xff0c;做了个基于 Hexo 博客内容开发的App。鸿蒙主要使用Ark…...

鸿蒙NEXT开发动画案例10

1.创建空白项目 2.Page文件夹下面新建Spin.ets文件&#xff0c;代码如下&#xff1a; interface TranslateOffset {x?:numbery?:number } /*** SpinKit动画组件 - SpinTen* author: CSDN-鸿蒙布道师* since: 2025/05/16*/ ComponentV2 export struct SpinTen {Require Para…...

Python 的 os 库常见使用方法(操作目录及文件)

前言&#xff1a; os 模块是 Python 标准库中用于与操作系统交互的核心模块&#xff0c;提供了许多操作文件和目录的功能。以下是常见的使用方法&#xff1a; 1. 目录操作 方法功能说明示例os.getcwd()获取当前工作目录print(os.getcwd())os.chdir(path)切换当前工作目录os.ch…...

【Linux】Linux安装并配置Redis

目录 1.安装 2.启动服务 3.配置 3.1.绑定地址 3.2.保护模式 3.3.持久化选项 3.3.1.RDB 持久化 3.3.2.AOF 持久化 3.3.3.如何选择 1.安装 Redis 可以从默认的 CentOS 软件仓库中安装。运行以下命令来安装 Redis sudo dnf install redis -y 响应如下 2.启动服务 安装完成后&…...

【11408学习记录】考研英语辞职信写作三步法:真题精讲+妙句活用+范文模板

应聘信 英语写作2005年考研英语真题小作文写作思路第一段第二段妙句7 9妙句11补充3补充4 第三段 妙句成文 每日一句词汇第一步&#xff1a;找谓语第二步&#xff1a;断句第三步&#xff1a;简化主句原因状语从句 英语 写作 2005年考研英语真题小作文 Directions:​​ Two m…...

数据库(一):分布式数据库

定义 分布式数据库&#xff08;Distributed Database&#xff09; 是指&#xff1a; 数据分布在多个物理位置&#xff0c;但对用户透明&#xff0c;表现为一个统一逻辑数据库的系统。 结构模式&#xff08;三层模式扩展&#xff09; 层次作用对应实体用户层提供统一视图&…...

Java并发编程-线程池(三)

文章目录 线程池实现原理addWorker(Runnable firstTask, boolean core)1. 状态检查&#xff1a;校验线程池是否允许添加线程2. 工作线程数调整&#xff1a;CAS保证并发安全3. 初始化变量4. 创建 Worker 对象并获取线程5. 加锁保证线程安全6. 启动工作线程7. 异常处理核心作用 线…...

《黑马前端ajax+node.js+webpack+git教程》(笔记)——node.js教程+webpack教程(nodejs教程)

黑马程序员前端AJAX入门到实战全套教程&#xff0c;包含学前端框架必会的&#xff08;ajaxnode.jswebpackgit&#xff09;&#xff0c;一套全覆盖 文章目录 Node.js与Webpack-01.Node.js入门定义和作用什么是前端工程化&#xff1f;&#xff08;离不开node.js&#xff09;Node.…...

Flink 快速入门

本文涉及到大量的底层原理知识&#xff0c;包括运行机制图解都非常详细&#xff0c;还有一些实战案例&#xff0c;所以导致本篇文章会比较长&#xff0c;内容比较多&#xff0c;由于内容太多&#xff0c;很多目录可能展示不出来&#xff0c;需要去细心的查看&#xff0c;非常适…...

高效管理多后端服务:Nginx 配置与实践指南

在现代的 Web 开发和运维中&#xff0c;一个系统往往由多个后端服务组成&#xff0c;每个服务负责不同的功能模块。例如&#xff0c;一个电商网站可能包括用户服务、订单服务和支付服务&#xff0c;每个服务都运行在独立的服务器或容器中。为了高效地管理这些服务并提供统一的访…...

阻塞队列:线程安全与生产者消费者模型解析

一、阻塞队列 阻塞队列就是基于普通队列做出扩展 1.线程安全的 如果针对一个已经满了的队列进行入队列&#xff0c;此时入队列操作就会阻塞&#xff0c;一直阻塞到队列不满&#xff08;其他线程出队列元素&#xff09;之后 如果针对一个已经空了的队列进行出队列&#xff0c…...