鸿蒙OSUniApp制作自定义的下拉菜单组件(鸿蒙系统适配版)#三方框架 #Uniapp
UniApp制作自定义的下拉菜单组件(鸿蒙系统适配版)
前言
在移动应用开发中,下拉菜单是一个常见且实用的交互组件,它能在有限的屏幕空间内展示更多的选项。虽然各种UI框架都提供了下拉菜单组件,但在一些特定场景下,我们往往需要根据产品需求定制自己的下拉菜单。尤其是在鸿蒙系统逐渐普及的今天,如何让我们的组件在华为设备上有更好的表现,是值得思考的问题。
本文将分享我在实际项目中使用UniApp开发自定义下拉菜单组件的经验,包括基础实现、动画效果以及在鸿蒙系统上的特殊适配。希望能给同样面临这类需求的开发者提供一些参考。
需求分析
在开始编码前,我们先明确一下自定义下拉菜单需要满足的基本需求:
- 支持单选/多选模式
- 可自定义菜单项的样式和内容
- 支持搜索筛选功能
- 展开/收起的流畅动画
- 支持级联选择
- 良好的交互反馈
- 在鸿蒙系统上的适配优化
技术选型
基于上述需求,我选择的技术栈如下:
- UniApp作为跨端开发框架
- Vue3 + TypeScript提供响应式编程体验
- SCSS处理样式
- 使用CSS3实现过渡动画
- 鸿蒙系统特有API支持
组件设计
首先,我们来设计组件的基本结构:
<template><view class="custom-dropdown" :class="{'harmony-dropdown': isHarmonyOS}"><!-- 触发器部分 --><view class="dropdown-trigger" @click="toggleDropdown"><text class="trigger-text">{{ triggerText }}</text><view class="trigger-icon" :class="{'is-active': isOpen}"><text class="iconfont icon-down"></text></view></view><!-- 下拉内容部分 --><view class="dropdown-content" :class="{'is-open': isOpen}":style="contentStyle"><!-- 搜索框 --><view class="search-box" v-if="showSearch"><input type="text" v-model="searchText" placeholder="搜索..." class="search-input"confirm-type="search"@input="handleSearch"/><text class="clear-icon" v-if="searchText" @click.stop="clearSearch">×</text></view><!-- 选项列表 --><scroll-view scroll-y class="options-list":enhanced="isHarmonyOS":bounces="false"><view v-for="(item, index) in filteredOptions" :key="index"class="option-item":class="{'is-selected': isSelected(item),'harmony-item': isHarmonyOS}"@click="selectOption(item)"><text class="option-text">{{ item[labelKey] }}</text><text v-if="isSelected(item)" class="selected-icon iconfont icon-check"></text></view><!-- 空状态 --><view class="empty-tip" v-if="filteredOptions.length === 0"><text>无匹配结果</text></view></scroll-view><!-- 操作按钮 --><view class="action-btns" v-if="mode === 'multiple'"><view class="btn btn-clear" @click="clearSelection">清空</view><view class="btn btn-confirm" @click="confirmSelection">确定</view></view></view><!-- 遮罩层 --><view class="dropdown-mask" :class="{'is-visible': isOpen}" @click="closeDropdown"></view></view>
</template><script lang="ts">
import { defineComponent, ref, computed, watch, onMounted, onBeforeUnmount } from 'vue';
import { isHarmonyOS } from '@/utils/system';export default defineComponent({name: 'CustomDropdown',props: {// 选项列表options: {type: Array,default: () => []},// 显示的键名labelKey: {type: String,default: 'label'},// 值的键名valueKey: {type: String,default: 'value'},// 选择模式:single/multiplemode: {type: String,default: 'single'},// 是否显示搜索框showSearch: {type: Boolean,default: false},// 最大高度maxHeight: {type: [String, Number],default: 300},// 触发器文本placeholder: {type: String,default: '请选择'},// 默认选中值modelValue: {type: [String, Number, Array],default: ''}},emits: ['update:modelValue', 'change', 'open', 'close'],setup(props, { emit }) {// 状态变量const isOpen = ref(false);const searchText = ref('');const selectedOptions = ref<any[]>([]);const isHarmonyOS = ref(false);// 计算下拉内容样式const contentStyle = computed(() => {const style: any = {};if (typeof props.maxHeight === 'number') {style.maxHeight = `${props.maxHeight}px`;} else {style.maxHeight = props.maxHeight;}return style;});// 计算过滤后的选项const filteredOptions = computed(() => {if (!searchText.value) return props.options;return props.options.filter((item: any) => {const label = item[props.labelKey]?.toString() || '';return label.toLowerCase().includes(searchText.value.toLowerCase());});});// 计算触发器显示文本const triggerText = computed(() => {if (selectedOptions.value.length === 0) {return props.placeholder;}if (props.mode === 'single') {return selectedOptions.value[0][props.labelKey];}if (selectedOptions.value.length === 1) {return selectedOptions.value[0][props.labelKey];}return `已选择${selectedOptions.value.length}项`;});// 初始化选中项const initSelection = () => {if (!props.modelValue) {selectedOptions.value = [];return;}if (props.mode === 'single') {const value = props.modelValue;const option = props.options.find((item: any) => item[props.valueKey] === value);selectedOptions.value = option ? [option] : [];} else {const values = Array.isArray(props.modelValue) ? props.modelValue : [props.modelValue];selectedOptions.value = props.options.filter((item: any) => values.includes(item[props.valueKey]));}};// 检查选项是否被选中const isSelected = (option: any) => {return selectedOptions.value.some((item: any) => item[props.valueKey] === option[props.valueKey]);};// 选择选项const selectOption = (option: any) => {if (props.mode === 'single') {selectedOptions.value = [option];emitChange();closeDropdown();} else {const index = selectedOptions.value.findIndex((item: any) => item[props.valueKey] === option[props.valueKey]);if (index > -1) {selectedOptions.value.splice(index, 1);} else {selectedOptions.value.push(option);}}// 鸿蒙系统震动反馈if (isHarmonyOS.value) {vibrateForHarmony();}};// 确认多选结果const confirmSelection = () => {emitChange();closeDropdown();};// 清空选择const clearSelection = () => {selectedOptions.value = [];if (props.mode === 'single') {emitChange();}};// 处理搜索const handleSearch = () => {// 可以添加防抖逻辑};// 清空搜索const clearSearch = () => {searchText.value = '';};// 切换下拉菜单状态const toggleDropdown = () => {isOpen.value = !isOpen.value;if (isOpen.value) {emit('open');} else {emit('close');}};// 关闭下拉菜单const closeDropdown = () => {if (!isOpen.value) return;isOpen.value = false;searchText.value = '';emit('close');};// 提交变更const emitChange = () => {let value;if (props.mode === 'single') {value = selectedOptions.value.length ? selectedOptions.value[0][props.valueKey] : '';} else {value = selectedOptions.value.map((item: any) => item[props.valueKey]);}emit('update:modelValue', value);emit('change', {value,options: [...selectedOptions.value]});};// 鸿蒙系统震动反馈const vibrateForHarmony = () => {// #ifdef APP-PLUStry {if (plus.os.name === 'Android' && plus.device.vendor === 'HUAWEI') {plus.device.vibrate(10);}} catch (e) {console.error('震动反馈失败', e);}// #endif};// 点击外部关闭const handleOutsideClick = (e: Event) => {const target = e.target as HTMLElement;const dropdown = document.querySelector('.custom-dropdown');if (dropdown && !dropdown.contains(target)) {closeDropdown();}};// 监听modelValue变化watch(() => props.modelValue, () => {initSelection();}, { immediate: true });// 监听options变化watch(() => props.options, () => {initSelection();});// 组件挂载onMounted(() => {isHarmonyOS.value = isHarmonyOS();initSelection();// 添加点击外部关闭事件document.addEventListener('click', handleOutsideClick);});// 组件卸载onBeforeUnmount(() => {document.removeEventListener('click', handleOutsideClick);});return {isOpen,searchText,selectedOptions,isHarmonyOS,contentStyle,filteredOptions,triggerText,isSelected,selectOption,confirmSelection,clearSelection,handleSearch,clearSearch,toggleDropdown,closeDropdown};}
});
</script><style lang="scss">
.custom-dropdown {position: relative;width: 100%;.dropdown-trigger {display: flex;align-items: center;justify-content: space-between;height: 80rpx;padding: 0 20rpx;background-color: #fff;border: 1rpx solid #ddd;border-radius: 8rpx;.trigger-text {flex: 1;font-size: 28rpx;color: #333;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}.trigger-icon {width: 40rpx;text-align: center;transition: transform 0.3s;&.is-active {transform: rotate(180deg);}.iconfont {font-size: 24rpx;color: #666;}}}.dropdown-content {position: absolute;top: 90rpx;left: 0;width: 100%;background-color: #fff;border: 1rpx solid #eee;border-radius: 8rpx;box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);z-index: 100;overflow: hidden;max-height: 0;opacity: 0;transform: translateY(-10rpx);transition: all 0.3s ease-out;&.is-open {max-height: var(--dropdown-max-height, 600rpx);opacity: 1;transform: translateY(0);}.search-box {position: relative;padding: 16rpx;border-bottom: 1rpx solid #eee;.search-input {width: 100%;height: 64rpx;padding: 0 60rpx 0 20rpx;background-color: #f5f5f5;border: none;border-radius: 32rpx;font-size: 26rpx;}.clear-icon {position: absolute;right: 36rpx;top: 50%;transform: translateY(-50%);width: 40rpx;height: 40rpx;line-height: 40rpx;text-align: center;font-size: 32rpx;color: #999;}}.options-list {max-height: 400rpx;.option-item {display: flex;align-items: center;justify-content: space-between;padding: 20rpx;border-bottom: 1rpx solid #f5f5f5;&:active {background-color: #f9f9f9;}&.is-selected {background-color: #f0f9ff;.option-text {color: #0078ff;font-weight: bold;}.selected-icon {color: #0078ff;}}.option-text {flex: 1;font-size: 28rpx;color: #333;}.selected-icon {font-size: 32rpx;margin-left: 10rpx;}}.empty-tip {padding: 40rpx 0;text-align: center;color: #999;font-size: 26rpx;}}.action-btns {display: flex;padding: 16rpx;border-top: 1rpx solid #eee;.btn {flex: 1;height: 70rpx;line-height: 70rpx;text-align: center;font-size: 28rpx;border-radius: 35rpx;&.btn-clear {color: #666;background-color: #f5f5f5;margin-right: 10rpx;}&.btn-confirm {color: #fff;background-color: #0078ff;margin-left: 10rpx;}}}}.dropdown-mask {position: fixed;top: 0;left: 0;right: 0;bottom: 0;background-color: rgba(0, 0, 0, 0);z-index: 99;pointer-events: none;transition: background-color 0.3s;&.is-visible {background-color: rgba(0, 0, 0, 0.4);pointer-events: auto;}}
}/* 鸿蒙系统特有样式 */
.harmony-dropdown {.dropdown-trigger {border-radius: 16rpx;border: none;background-color: #f5f7fa;box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);.trigger-text {font-family: 'HarmonyOS Sans', sans-serif;}}.dropdown-content {border-radius: 20rpx;border: none;box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.12);.search-box {padding: 24rpx 20rpx 16rpx;.search-input {background-color: #f5f7fa;border-radius: 20rpx;height: 72rpx;}}.options-list {.option-item {&.harmony-item {padding: 24rpx 20rpx;&.is-selected {background: linear-gradient(to right, #f0f7ff, #f5faff);.option-text {background: linear-gradient(to right, #0078ff, #0092ff);-webkit-background-clip: text;color: transparent;}}&:active {background-color: #f7f9fc;}}}}.action-btns {padding: 20rpx;.btn {border-radius: 20rpx;height: 80rpx;line-height: 80rpx;font-family: 'HarmonyOS Sans', sans-serif;&.btn-clear {background-color: #f5f7fa;}&.btn-confirm {background: linear-gradient(to right, #0078ff, #0092ff);box-shadow: 0 4rpx 16rpx rgba(0, 120, 255, 0.3);}}}}
}
</style>
鸿蒙系统适配关键点
在为鸿蒙系统适配我们的下拉菜单组件时,需要特别注意以下几点:
1. 检测鸿蒙系统
首先,我们需要一个工具函数来检测当前设备是否运行鸿蒙系统:
// utils/system.ts/*** 检测当前设备是否为鸿蒙系统*/
export function isHarmonyOS(): boolean {// #ifdef APP-PLUSconst systemInfo = uni.getSystemInfoSync();const systemName = systemInfo.osName || '';const systemVersion = systemInfo.osVersion || '';// 鸿蒙系统识别return systemName.toLowerCase().includes('harmony') || (systemName === 'android' && systemVersion.includes('harmony'));// #endifreturn false;
}
2. UI风格适配
鸿蒙系统的设计语言强调简洁、轻盈、自然,需要适配以下UI细节:
- 圆角设计:鸿蒙系统偏好较大的圆角,我们在组件中使用了20rpx的圆角值
- 渐变色:按钮和激活态使用渐变色提升视觉效果
- 阴影效果:适当的阴影增强层次感,但要保持轻盈质感
- 字体适配:使用鸿蒙系统的HarmonyOS Sans字体
- 间距调整:鸿蒙UI通常有更宽松的内边距
3. 交互体验优化
鸿蒙系统注重流畅的交互体验:
- 震动反馈:选择选项时添加轻微震动
- 滚动优化:使用enhanced模式增强滚动性能
- 过渡动画:确保展开/收起有流畅的过渡效果
// 鸿蒙系统震动反馈
const vibrateForHarmony = () => {// #ifdef APP-PLUStry {if (plus.os.name === 'Android' && plus.device.vendor === 'HUAWEI') {plus.device.vibrate(10); // 非常轻微的震动,提供触觉反馈}} catch (e) {console.error('震动反馈失败', e);}// #endif
};
实际应用案例
案例一:筛选条件下拉菜单
在一个电商App的商品列表页中,我们使用了自定义下拉菜单组件来实现筛选功能。用户可以通过下拉菜单选择价格区间、品牌、尺寸等筛选条件。
<template><view class="filter-bar"><custom-dropdownv-model="selectedPrice":options="priceOptions"placeholder="价格"label-key="label"value-key="value"mode="single"@change="applyFilter"></custom-dropdown><custom-dropdownv-model="selectedBrands":options="brandOptions"placeholder="品牌"label-key="name"value-key="id"mode="multiple"show-search@change="applyFilter"></custom-dropdown><custom-dropdownv-model="selectedSort":options="sortOptions"placeholder="排序"@change="applyFilter"></custom-dropdown></view>
</template><script>
import CustomDropdown from '@/components/CustomDropdown.vue';export default {components: {CustomDropdown},data() {return {selectedPrice: '',selectedBrands: [],selectedSort: 'default',priceOptions: [{ label: '全部', value: '' },{ label: '0-100元', value: '0-100' },{ label: '100-300元', value: '100-300' },{ label: '300-500元', value: '300-500' },{ label: '500元以上', value: '500-' }],brandOptions: [{ name: '华为', id: 'huawei' },{ name: '小米', id: 'xiaomi' },{ name: '苹果', id: 'apple' },{ name: '三星', id: 'samsung' },{ name: 'OPPO', id: 'oppo' },{ name: 'vivo', id: 'vivo' }],sortOptions: [{ label: '默认排序', value: 'default' },{ label: '价格从低到高', value: 'price-asc' },{ label: '价格从高到低', value: 'price-desc' },{ label: '销量优先', value: 'sales-desc' },{ label: '评分优先', value: 'rating-desc' }]};},methods: {applyFilter() {// 应用筛选条件this.$emit('filter-change', {price: this.selectedPrice,brands: this.selectedBrands,sort: this.selectedSort});}}
};
</script>
案例二:级联选择器
我们还使用自定义下拉菜单组件实现了地址选择的级联选择器,用户可以依次选择省、市、区。
<template><view class="address-selector"><custom-dropdownv-model="selectedProvince":options="provinces"placeholder="选择省份"@change="onProvinceChange"></custom-dropdown><custom-dropdownv-model="selectedCity":options="cities"placeholder="选择城市":disabled="!selectedProvince"@change="onCityChange"></custom-dropdown><custom-dropdownv-model="selectedDistrict":options="districts"placeholder="选择区县":disabled="!selectedCity"@change="onDistrictChange"></custom-dropdown></view>
</template><script>
import { defineComponent, ref, watch } from 'vue';
import CustomDropdown from '@/components/CustomDropdown.vue';
import { fetchProvinces, fetchCities, fetchDistricts } from '@/api/address';export default defineComponent({components: {CustomDropdown},emits: ['change'],setup(props, { emit }) {const selectedProvince = ref('');const selectedCity = ref('');const selectedDistrict = ref('');const provinces = ref([]);const cities = ref([]);const districts = ref([]);// 加载省份数据const loadProvinces = async () => {try {provinces.value = await fetchProvinces();} catch (error) {console.error('加载省份失败', error);}};// 加载城市数据const loadCities = async (provinceId) => {if (!provinceId) {cities.value = [];return;}try {cities.value = await fetchCities(provinceId);} catch (error) {console.error('加载城市失败', error);}};// 加载区县数据const loadDistricts = async (cityId) => {if (!cityId) {districts.value = [];return;}try {districts.value = await fetchDistricts(cityId);} catch (error) {console.error('加载区县失败', error);}};// 省份变化const onProvinceChange = () => {selectedCity.value = '';selectedDistrict.value = '';loadCities(selectedProvince.value);emitChange();};// 城市变化const onCityChange = () => {selectedDistrict.value = '';loadDistricts(selectedCity.value);emitChange();};// 区县变化const onDistrictChange = () => {emitChange();};// 发送变化事件const emitChange = () => {emit('change', {province: selectedProvince.value,city: selectedCity.value,district: selectedDistrict.value});};// 初始化onMounted(() => {loadProvinces();});return {selectedProvince,selectedCity,selectedDistrict,provinces,cities,districts,onProvinceChange,onCityChange,onDistrictChange};}
});
</script>
常见问题与解决方案
在开发和使用这个组件的过程中,我遇到了一些常见问题,分享解决方案:
1. 下拉菜单被裁剪问题
问题:当下拉菜单位于页面底部时,展开的内容可能会被裁剪。
解决方案:计算剩余空间,动态调整下拉方向:
const adjustDropdownPosition = () => {const triggerEl = triggerRef.value;const contentEl = contentRef.value;if (!triggerEl || !contentEl) return;// 获取触发器位置信息const rect = triggerEl.getBoundingClientRect();// 视窗高度const viewHeight = window.innerHeight;// 触发器底部到视窗底部的距离const spaceBelow = viewHeight - rect.bottom;// 内容高度const contentHeight = contentEl.offsetHeight;// 如果下方空间不足,向上展开if (spaceBelow < contentHeight && rect.top > contentHeight) {dropdownDirection.value = 'up';} else {dropdownDirection.value = 'down';}
};
2. 多个下拉菜单同时打开问题
问题:当页面中有多个下拉菜单时,打开一个菜单,其他已打开的菜单应该自动关闭。
解决方案:使用全局事件总线管理下拉菜单的打开状态:
// 全局事件总线
const emitter = mitt();// 打开下拉菜单
const openDropdown = () => {// 通知其他下拉菜单关闭emitter.emit('dropdown-open', dropdownId.value);isOpen.value = true;emit('open');
};onMounted(() => {// 监听其他下拉菜单打开事件emitter.on('dropdown-open', (id) => {if (id !== dropdownId.value && isOpen.value) {isOpen.value = false;emit('close');}});
});onBeforeUnmount(() => {emitter.off('dropdown-open');
});
3. 在鸿蒙系统上的滚动卡顿问题
问题:在某些华为设备上,下拉菜单内容滚动不够流畅。
解决方案:开启硬件加速和使用Native View:
<scroll-view scroll-y class="options-list":enhanced="isHarmonyOS":show-scrollbar="false":fast-deceleration="isHarmonyOS":bounces="false"
>
同时,对滚动容器添加硬件加速样式:
.options-list {transform: translateZ(0);-webkit-overflow-scrolling: touch;will-change: scroll-position;
}
总结
通过本文,我们详细介绍了如何使用UniApp开发一个自定义下拉菜单组件,并特别关注了在鸿蒙系统上的适配优化。从组件的基本结构设计,到交互细节的处理,再到在实际应用中的案例展示,希望能给大家提供一些思路。
随着鸿蒙系统的普及,做好相关适配工作将越来越重要。在下拉菜单这样的基础交互组件上,通过一些细节的优化,可以大大提升用户体验,尤其是在华为设备上。
最后,欢迎大家基于这个组件进行二次开发,添加更多功能或者根据自己的业务需求进行定制。如有任何问题或改进建议,也欢迎交流讨论。
参考资源
- UniApp官方文档
- HarmonyOS设计指南
- Vue3官方文档
- CSS Animation完整指南
相关文章:
鸿蒙OSUniApp制作自定义的下拉菜单组件(鸿蒙系统适配版)#三方框架 #Uniapp
UniApp制作自定义的下拉菜单组件(鸿蒙系统适配版) 前言 在移动应用开发中,下拉菜单是一个常见且实用的交互组件,它能在有限的屏幕空间内展示更多的选项。虽然各种UI框架都提供了下拉菜单组件,但在一些特定场景下&…...
C++面试2——C与C++的关系
C与C++的关系及核心区别的解析 一、哲学与编程范式:代码组织的革命 过程式 vs 多范式混合 C语言是过程式编程的典范,以算法流程为中心,强调“怎么做”(How)。例如,实现链表操作需手动管理节点指针和内存。 C++则是多范式语言,支持面向对象(OOP)、泛型编程(模板)、函…...

常用的Java工具库
1. Collections 首先是 java.util 包下的 Collections 类。这个类主要用于操作集合,我个人非常喜欢使用它。以下是一些常用功能: 1.1 排序 在工作中,经常需要对集合进行排序。让我们看看如何使用 Collections 工具实现升序和降序排列&…...
基于LabVIEW的双音多频系统设计
目录 1 系统设计概述 双音多频(Dual-Tone Multi-Frequency, DTMF)信号是一种广泛应用于电话系统中的音频信号,通过不同的频率组合表示不同的按键。每个按键对应两个频率,一个低频和一个高频,共同组成独特的信号。在虚拟仪器技术快速发展的背景下,利用LabVIEW等图形化编程…...

R S的EMI接收机面板
图片摘自R & S官网。 根据您提供的第一张图(设备前面板带屏幕的图像),这是 Rohde & Schwarz ESRP7 EMI Test Receiver 的正面显示界面,我将对屏幕上显示的参数逐项进行解读: 🖥️ 屏幕参数解读 左…...

[ctfshow web入门] web122
信息收集 这一题把HOME开放了,把#和PWD给过滤了 <?php error_reporting(0); highlight_file(__FILE__); if(isset($_POST[code])){$code$_POST[code];if(!preg_match(/\x09|\x0a|[a-z]|[0-9]|FLAG|PATH|BASH|PWD|HISTIGNORE|HISTFILESIZE|HISTFILE|HISTCMD|US…...
Nginx+Lua 实战避坑:从模块加载失败到版本冲突的深度剖析
Nginx 集成 Lua (通常通过 ngx_http_lua_module 或 OpenResty) 为我们提供了在 Web 服务器层面实现动态逻辑的强大能力。然而,在享受其高性能和灵活性的同时,配置和使用过程中也常常会遇到各种令人头疼的问题。本文将结合实际案例,深入分析在 Nginx+Lua 环境中常见的技术问题…...
LangChain框架-Chain 链详解
摘要 本文基于源码分析与官方文档梳理,系统解析 LangChain 框架中的核心组件 Chain 链,旨在帮助开发者深入理解其设计原理、功能分类及实践应用场景。 作为 LangChain 的核心机制,Chain 链采用管道-过滤器(Pipe-Filter)…...

Java虚拟机 - JVM与Java体系结构
Java虚拟机 JVM与Java体系结构为什么要学习JVMJava与JVM简介Java 语言的核心特性JVM:Java 生态的基石JVM的架构模型基于栈的指令集架构(Stack-Based)基于寄存器的指令集架构(Register-Based)JVM生命周期 总结 JVM与Jav…...
elementUI调整滚动条高度后与固定列冲突问题解决
/* 1. 首先确保基础样式生效 */ .el-table.el-table–scrollable-x .el-table__body-wrapper { overflow-x: auto !important; } /* 2. 设置滚动条高度(对所有表格生效) */ .el-table__body-wrapper::-webkit-scrollbar { height: 10px !important; } …...
基于 nvitop+Prometheus+Grafana 的物理资源与 VLLM 引擎服务监控方案
一、方案背景与目标 在人工智能与高性能计算场景中,对物理资源(尤其是 GPU)的实时监控以及对 VLLM 引擎服务的性能追踪至关重要。本方案通过整合 nvitop、Prometheus 和 Grafana 三大组件,构建一套完整的监控体系,实现…...
互联网大厂Java求职面试:Spring AI与大模型交互在短视频平台中的应用
互联网大厂Java求职面试:Spring AI与大模型交互在短视频平台中的应用 面试场景设定 郑薪苦,一名有着丰富项目经验但总是能用奇葩比喻解释复杂技术的程序员,正在接受某知名互联网大厂技术总监的面试。 第一轮提问 面试官:假设我…...
【Lua】java 调用redis执行 lua脚本
【Lua】java 调用redis执行 lua脚本 public Object executeLuaScript(String script, List<String> keys, Object... args) {// 注意: 这里 Long.class 是返回值类型, 一定要指定清楚 不然会报错return this.redisTemplate.execute(RedisScript.of(j脚本, Long.class), k…...
【工奥阀门科技有限公司】签约智橙PLM
近日,工奥阀门科技有限公司正式签约了智橙泵阀行业版PLM。 忠于质量,臻于服务,精于研发 工奥阀门科技有限公司(以下简称工奥阀门)坐落于浙江永嘉,是一家集设计、开发、生产、销售、安装、服务为一体的阀门…...

灌区量测水自动化监测解决方案
一、方案背景 随着社会发展和人口增长,水资源需求不断增大。我国水资源总量虽然丰富,但时空分布不均,加之农业用水占比大且效率偏低,使得水资源短缺问题日益凸显。农业用水一直是我国的耗水大户,占全部耗水总量的60%以…...
SpringBoot整合MQTT实战:基于EMQX构建高可靠物联网通信,从零到一实现设备云端双向对话
一、引言 随着物联网(IoT)技术的快速发展,MQTT(Message Queuing Telemetry Transport)协议因其轻量级、低功耗和高效的特点,已成为物联网设备通信的事实标准。本文将详细介绍如何使用SpringBoot框架整合MQTT协议,基于开源MQTT代理EMQX实现设…...
AI与机器学习深度集成:从设备端能力爆发到开发工具智能化
简介 AI与机器学习技术正以惊人的速度在移动开发领域深入集成,设备端AI能力爆发与AI辅助开发工具的崛起,为开发者带来了前所未有的高效开发体验和应用创新机遇。本文将全面解析Google最新AI技术栈(包括ML Kit 2.0和Gemini Nano模型)的特性与应用场景,探索Android Studio …...

界面控件DevExpress WinForms v24.2 - 数据处理功能增强
DevExpress WinForms拥有180组件和UI库,能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForms能完美构建流畅、美观且易于使用的应用程序,无论是Office风格的界面,还是分析处理大批量的业务数据,它都能轻松胜…...

Linux的MySQL头文件和找不到头文件问题解决
头文件 #include <iostream> #include <mysql_driver.h> #include <mysql_connection.h> #include <cppconn/statement.h> #include <cppconn/resultset.h> #include <cppconn/prepared_statement.h> #include <cppconn/exception.h&g…...

wps excel将表格输出pdf时所有列在一张纸上
记录:wps excel将表格输出pdf时所有列在一张纸上 1,调整缩放比例,或选择将所有列打印在一页 2,将表格的所有铺满到这套虚线...

zabbix7.2最新版本 nginx自定义监控(三) 设置触发器
安装zabbix-get服务 在zabbix-server端口安装zabbix-get服务 [rootlocalhost ~]# dnf install -y zabbix-get Last metadata expiration check: 1:55:49 ago on Wed 14 May 2025 09:24:49 AM CST. Dependencies resolved. Package Architectur…...
CDN加速对云手机延迟的影响
一、CDN加速对云手机延迟的核心作用 缩短物理距离,降低网络延迟 CDN通过全球分布的节点,将云手机的服务内容(如应用数据、画面流)缓存至离用户最近的服务器,减少数据传输的物理距离。例如,用户在中国访问美…...
为什么 Docker 建议关闭 Swap
在使用 Docker 时,关闭系统 Swap(交换分区) 是一个常见的推荐做法,尤其是在生产环境中。虽然 Docker 不强制要求禁用 Swap,但出于性能、稳定性、可控性和资源管理的目的,通常建议这样做。 为什么 Docker 建…...

缓存的相关内容
缓存是一种介于数据永久存储介质与数据应用之间数据临时的存储介质 实用化保存可以有效地减少低俗数据读取的次数 (例如磁盘IO), 提高系统性能 缓存不仅可以用于提高永久性存储介质的数据读取效率,还可以提供临时的数据存储空间 spring boot中提供了缓存技术, 方便…...

[ctfshow web入门] web77
信息收集 上一题的读取flag方式不能用了,使用后的回显是:could not find driver 解题 同样的查目录方法 cvar_export(scandir("glob:///*"));die();cforeach(new DirectoryIterator("glob:///*") as $a){echo($a->__toString…...

C++学习-入门到精通-【7】类的深入剖析
C学习-入门到精通-【7】类的深入剖析 类的深入剖析 C学习-入门到精通-【7】类的深入剖析一、Time类的实例研究二、组成和继承三、类的作用域和类成员的访问类作用域和块作用域圆点成员选择运算符(.)和箭头成员选择运算符(->)访问函数和工具函数 四、具有默认实参的构造函数重…...
API 加速方案:如何使用 Redis 与 Memcached 进行高效缓存优化
API 加速方案:如何使用 Redis 与 Memcached 进行高效缓存优化 1. 引言 在现代 Web 开发中,API 响应速度至关重要。用户期望实时访问数据,而后端服务可能受到数据库查询、计算开销或网络传输的限制。这时候,缓存技术可以有效减少 API 延迟,提升系统性能。 本篇文章将深入…...

主成分分析的应用之sklearn.decomposition模块的PCA函数
主成分分析的应用之sklearn.decomposition模块的PCA函数 一、模型建立整体步骤 二、数据 2297.86 589.62 474.74 164.19 290.91 626.21 295.20 199.03 2262.19 571.69 461.25 185.90 337.83 604.78 354.66 198.96 2303.29 589.99 516.21 236.55 403.92 730.05 438.41 225.80 …...

1. Go 语言环境安装
👑 博主简介:高级开发工程师 👣 出没地点:北京 💊 人生目标:自由 ——————————————————————————————————————————— 版权声明:本文为原创文章…...

IP协议深度解析:互联网世界的核心基石
作为互联网通信的基础协议,IP(Internet Protocol)承载着全球99%的网络数据流量。本文将深入剖析IP协议的核心特性、工作原理及演进历程,通过技术原理、协议对比和实战案例分析,为您揭示这个数字世界"隐形交通规则…...