自定义tabs(支持横向/竖向排列)

效果展示:

组件代码:

CustomTabs.vue组件代码如下:

<template> <div class="custom-tabs" :class="[`tabs-${type}`, { 'tabs-vertical': type === 'vertical' }]"> <!-- 横向布局 --> <template v-if="type === 'horizontal'"> <!-- 左侧翻页按钮 --> <div class="scroll-btn left-btn" :class="{ disabled: !canScrollLeft }" @click="scrollLeft" v-show="showScrollButtons"> <span>&lt;</span> </div> <!-- 标签页容器 --> <div class="tabs-container" ref="containerRef"> <div class="tabs-wrap" ref="wrapRef" :style="{ transform: `translateX(${translateX}px)` }"> <!-- 标签页 --> <div v-for="(tab, index) in tabs" :key="index" class="tab-item" :class="{ active: modelValue === tab.value }" @click="handleTabClick(tab.value)" ref="tabRefs" > {{ tab.label }} </div> <!-- 底部滑动条 --> <div class="active-bar" :style="activeBarStyle"></div> </div> </div> <!-- 右侧翻页按钮 --> <div class="scroll-btn right-btn" :class="{ disabled: !canScrollRight }" @click="scrollRight" v-show="showScrollButtons"> <span>&gt;</span> </div> </template> <!-- 竖向布局 --> <template v-else> <!-- 上侧翻页按钮 --> <div class="scroll-btn top-btn" :class="{ disabled: !canScrollTop }" @click="scrollTop" v-show="showScrollButtons"> <span>↑</span> </div> <!-- 标签页容器 --> <div class="tabs-container" ref="containerRef"> <div class="tabs-wrap" ref="wrapRef" :style="{ transform: `translateY(${translateY}px)` }"> <!-- 标签页 --> <div v-for="(tab, index) in tabs" :key="index" class="tab-item" :class="{ active: modelValue === tab.value }" @click="handleTabClick(tab.value)" ref="tabRefs" > {{ tab.label }} </div> <!-- 右侧滑动条 --> <div class="active-bar" :style="activeBarStyle"></div> </div> </div> <!-- 下侧翻页按钮 --> <div class="scroll-btn bottom-btn" :class="{ disabled: !canScrollBottom }" @click="scrollBottom" v-show="showScrollButtons"> <span>↓</span> </div> </template> </div> </template> <script setup> import { ref, computed, watch, onMounted, nextTick, onUnmounted } from "vue"; const props = defineProps({ modelValue: { type: [String, Number], required: true }, tabs: { type: Array, required: true, default: () => [] }, type: { type: String, default: "horizontal", validator: value => ["horizontal", "vertical"].includes(value) }, height: { type: String, default: "300px" } }); const emit = defineEmits(["update:modelValue", "tab-click"]); // Refs const containerRef = ref(null); const wrapRef = ref(null); const tabRefs = ref([]); // 状态 const translateX = ref(0); const translateY = ref(0); const containerWidth = ref(0); const containerHeight = ref(0); const wrapWidth = ref(0); const wrapHeight = ref(0); const activeTabIndex = ref(0); // 计算属性 const showScrollButtons = computed(() => { if (props.type === "horizontal") { return wrapWidth.value > containerWidth.value; } else { return wrapHeight.value > containerHeight.value; } }); const canScrollLeft = computed(() => translateX.value < 0); const canScrollRight = computed(() => { const remainingWidth = wrapWidth.value + translateX.value; return remainingWidth > containerWidth.value; }); const canScrollTop = computed(() => translateY.value < 0); const canScrollBottom = computed(() => { const remainingHeight = wrapHeight.value + translateY.value; return remainingHeight > containerHeight.value; }); // 激活标签的滑动条样式 const activeBarStyle = computed(() => { if (!tabRefs.value.length || activeTabIndex.value >= tabRefs.value.length) { return props.type === "horizontal" ? { width: "0px", transform: "translateX(0px)" } : { height: "0px", transform: "translateY(0px)" }; } const activeTab = tabRefs.value[activeTabIndex.value]; if (!activeTab) { return props.type === "horizontal" ? { width: "0px", transform: "translateX(0px)" } : { height: "0px", transform: "translateY(0px)" }; } if (props.type === "horizontal") { return { width: `${activeTab.offsetWidth}px`, transform: `translateX(${activeTab.offsetLeft}px)` }; } else { return { height: `${activeTab.offsetHeight}px`, transform: `translateY(${activeTab.offsetTop}px)` }; } }); // 更新容器和包裹层尺寸 const updateDimensions = () => { if (!containerRef.value || !wrapRef.value) return; containerWidth.value = containerRef.value.offsetWidth; containerHeight.value = containerRef.value.offsetHeight; wrapWidth.value = wrapRef.value.scrollWidth; wrapHeight.value = wrapRef.value.scrollHeight; // 重置偏移值为0,确保靠左/上对齐 if (props.type === "horizontal") { if (wrapWidth.value <= containerWidth.value) { translateX.value = 0; } } else { if (wrapHeight.value <= containerHeight.value) { translateY.value = 0; } } // 确保当前激活标签可见 ensureActiveTabVisible(); }; // 左右/上下翻页 const scrollLeft = () => { if (!canScrollLeft.value) return; const scrollAmount = Math.min(containerWidth.value * 0.8, -translateX.value); translateX.value += scrollAmount; }; const scrollRight = () => { if (!canScrollRight.value) return; const remainingWidth = wrapWidth.value + translateX.value - containerWidth.value; const scrollAmount = Math.min(containerWidth.value * 0.8, remainingWidth); translateX.value -= scrollAmount; }; const scrollTop = () => { if (!canScrollTop.value) return; const scrollAmount = Math.min(containerHeight.value * 0.8, -translateY.value); translateY.value += scrollAmount; }; const scrollBottom = () => { if (!canScrollBottom.value) return; const remainingHeight = wrapHeight.value + translateY.value - containerHeight.value; const scrollAmount = Math.min(containerHeight.value * 0.8, remainingHeight); translateY.value -= scrollAmount; }; // 确保激活标签可见 const ensureActiveTabVisible = () => { // 如果没有溢出,直接返回 if (props.type === "horizontal") { if (wrapWidth.value <= containerWidth.value) { translateX.value = 0; return; } } else { if (wrapHeight.value <= containerHeight.value) { translateY.value = 0; return; } } nextTick(() => { if (!tabRefs.value.length || activeTabIndex.value >= tabRefs.value.length) return; const activeTab = tabRefs.value[activeTabIndex.value]; if (!activeTab) return; if (props.type === "horizontal") { const tabLeft = activeTab.offsetLeft; const tabRight = tabLeft + activeTab.offsetWidth; // 如果标签在可视区域左侧 if (tabLeft < -translateX.value) { translateX.value = -tabLeft; } // 如果标签在可视区域右侧 else if (tabRight > -translateX.value + containerWidth.value) { translateX.value = -(tabRight - containerWidth.value); } // 限制边界 clampTranslateX(); } else { const tabTop = activeTab.offsetTop; const tabBottom = tabTop + activeTab.offsetHeight; // 如果标签在可视区域上方 if (tabTop < -translateY.value) { translateY.value = -tabTop; } // 如果标签在可视区域下方 else if (tabBottom > -translateY.value + containerHeight.value) { translateY.value = -(tabBottom - containerHeight.value); } // 限制边界 clampTranslateY(); } }); }; // 限制平移范围 const clampTranslateX = () => { const maxTranslate = Math.min(0, containerWidth.value - wrapWidth.value); translateX.value = Math.max(maxTranslate, Math.min(0, translateX.value)); }; const clampTranslateY = () => { const maxTranslate = Math.min(0, containerHeight.value - wrapHeight.value); translateY.value = Math.max(maxTranslate, Math.min(0, translateY.value)); }; // 标签点击处理 const handleTabClick = value => { emit("update:modelValue", value); emit("tab-click", value); // 查找激活的索引 const index = props.tabs.findIndex(tab => tab.value === value); if (index !== -1) { activeTabIndex.value = index; ensureActiveTabVisible(); } }; // 监听值变化 watch( () => props.modelValue, newVal => { const index = props.tabs.findIndex(tab => tab.value === newVal); if (index !== -1) { activeTabIndex.value = index; ensureActiveTabVisible(); } } ); // 监听tabs变化 watch( () => props.tabs, () => { nextTick(() => { updateDimensions(); }); }, { deep: true } ); // 监听type变化 watch( () => props.type, () => { translateX.value = 0; translateY.value = 0; nextTick(() => { updateDimensions(); }); } ); // 生命周期 onMounted(() => { nextTick(() => { updateDimensions(); }); // 监听窗口大小变化 window.addEventListener("resize", updateDimensions); // 使用ResizeObserver监听容器大小变化 const resizeObserver = new ResizeObserver(updateDimensions); if (containerRef.value) { resizeObserver.observe(containerRef.value); } // 清理 onUnmounted(() => { window.removeEventListener("resize", updateDimensions); resizeObserver.disconnect(); }); }); // 初始查找激活标签索引 const initActiveIndex = () => { const index = props.tabs.findIndex(tab => tab.value === props.modelValue); activeTabIndex.value = index !== -1 ? index : 0; }; initActiveIndex(); </script> <style scoped> .custom-tabs { display: inline-flex; position: relative; /* width: 100%; */ } /* 横向布局 */ .tabs-horizontal { flex-direction: row; align-items: center; height: 40px; border-bottom: 1px solid #e4e7ed; } .tabs-horizontal .tabs-container { flex: 1; overflow: hidden; position: relative; height: 100%; } .tabs-horizontal .tabs-wrap { display: inline-flex; position: relative; height: 100%; white-space: nowrap; transition: transform 0.3s ease; min-width: 100%; } .tabs-horizontal .tab-item { position: relative; display: inline-flex; align-items: center; justify-content: center; padding: 0 20px; height: 100%; font-size: 14px; color: #606266; cursor: pointer; user-select: none; transition: all 0.3s ease; flex-shrink: 0; } .tabs-horizontal .tab-item:hover { color: #409eff; } .tabs-horizontal .tab-item.active { color: #409eff; font-weight: 500; } .tabs-horizontal .active-bar { position: absolute; bottom: 0; left: 0; height: 2px; background-color: #409eff; transition: all 0.3s ease; z-index: 1; } .tabs-horizontal .scroll-btn { display: flex; align-items: center; justify-content: center; width: 32px; height: 100%; color: #606266; cursor: pointer; user-select: none; transition: color 0.3s; background: #fff; border-bottom: 1px solid #e4e7ed; z-index: 2; flex-shrink: 0; } .tabs-horizontal .scroll-btn:hover { color: #409eff; } .tabs-horizontal .scroll-btn.disabled { color: #c0c4cc; cursor: not-allowed; } .tabs-horizontal .scroll-btn.left-btn { border-right: 1px solid #e4e7ed; } .tabs-horizontal .scroll-btn.right-btn { border-left: 1px solid #e4e7ed; } .tabs-horizontal .scroll-btn span { font-size: 14px; } /* 竖向布局 */ .tabs-vertical { flex-direction: column; height: v-bind(height); border-right: 1px solid #e4e7ed; } .tabs-vertical .tabs-container { flex: 1; overflow: hidden; position: relative; width: 100%; } .tabs-vertical .tabs-wrap { display: inline-flex; flex-direction: column; position: relative; /* width: 100%; */ transition: transform 0.3s ease; min-height: 100%; } .tabs-vertical .tab-item { position: relative; display: flex; align-items: center; padding: 12px 20px; font-size: 14px; color: #606266; cursor: pointer; user-select: none; transition: all 0.3s ease; flex-shrink: 0; white-space: nowrap; } .tabs-vertical .tab-item:hover { color: #409eff; background-color: #f5f7fa; } .tabs-vertical .tab-item.active { color: #409eff; font-weight: 500; background-color: #ecf5ff; } .tabs-vertical .active-bar { position: absolute; top: 0; right: 0; width: 2px; background-color: #409eff; transition: all 0.3s ease; z-index: 1; } .tabs-vertical .scroll-btn { display: flex; align-items: center; justify-content: center; width: 100%; height: 32px; color: #606266; cursor: pointer; user-select: none; transition: color 0.3s; background: #fff; flex-shrink: 0; z-index: 2; } .tabs-vertical .scroll-btn:hover { color: #409eff; background-color: #f5f7fa; } .tabs-vertical .scroll-btn.disabled { color: #c0c4cc; cursor: not-allowed; background-color: #fff; } .tabs-vertical .scroll-btn.top-btn { border-bottom: 1px solid #e4e7ed; } .tabs-vertical .scroll-btn.bottom-btn { border-top: 1px solid #e4e7ed; } .tabs-vertical .scroll-btn span { font-size: 14px; } </style>

使用方式:

<template> <div class="demo-container"> <h2>支持横向和竖向的Tabs组件</h2> <div class="demo-section"> <h3>横向布局(默认)</h3> <div style="margin-bottom: 20px"> <label> <input type="radio" v-model="direction" value="horizontal" /> 横向 </label> <label style="margin-left: 20px"> <input type="radio" v-model="direction" value="vertical" /> 竖向 </label> </div> <CustomTabs v-model="activeTab" :tabs="tabs" :type="direction" :height="'400px'" @tab-click="handleTabClick" /> <div class="tab-content"> <div v-if="activeTab === 'home'"> <h4>首页</h4> <p>这是首页的内容...</p> </div> <div v-if="activeTab === 'products'"> <h4>产品中心</h4> <p>展示我们的产品和服务...</p> </div> <div v-if="activeTab === 'cases'"> <h4>客户案例</h4> <p>成功案例展示...</p> </div> <div v-if="activeTab === 'about'"> <h4>关于我们</h4> <p>公司介绍和团队信息...</p> </div> <div v-if="activeTab === 'contact'"> <h4>联系我们</h4> <p>联系方式和地址...</p> </div> </div> </div> <div class="demo-section"> <h3>动态切换演示</h3> <div class="demo-grid"> <div class="demo-box"> <h4>横向窄容器(显示滚动按钮)</h4> <CustomTabs v-model="activeTab2" :tabs="longTabs" type="horizontal" style="width: 400px" /> </div> <div class="demo-box"> <h4>横向宽容器(不显示滚动按钮)</h4> <CustomTabs v-model="activeTab2" :tabs="longTabs" type="horizontal" style="width: 800px" /> </div> <div class="demo-box"> <h4>竖向矮容器(显示滚动按钮)</h4> <CustomTabs v-model="activeTab2" :tabs="longTabs" type="vertical" height="200px" /> </div> <div class="demo-box"> <h4>竖向高容器(不显示滚动按钮)</h4> <CustomTabs v-model="activeTab2" :tabs="longTabs" type="vertical" height="400px" /> </div> </div> </div> </div> </template> <script setup> import { ref, watch } from "vue"; import CustomTabs from "@/components/customTabs/index.vue"; const direction = ref("horizontal"); const activeTab = ref("home"); const activeTab2 = ref("tab1"); const tabs = ref([ { label: "首页", value: "home" }, { label: "产品中心", value: "products" }, { label: "客户案例", value: "cases" }, { label: "关于我们", value: "about" }, { label: "联系我们", value: "contact" } ]); const longTabs = ref([ { label: "标签页 1", value: "tab1" }, { label: "标签页 2", value: "tab2" }, { label: "标签页 3", value: "tab3" }, { label: "标签页 4", value: "tab4" }, { label: "标签页 5", value: "tab5" }, { label: "标签页 6", value: "tab6" }, { label: "标签页 7", value: "tab7" }, { label: "标签页 8", value: "tab8" } ]); const handleTabClick = value => { console.log("标签被点击:", value); }; // 监听方向变化时重置激活标签 watch(direction, () => { activeTab.value = "home"; }); </script> <style scoped> .demo-container { padding: 20px; margin: 0 auto; } .demo-section { margin: 40px 0; padding: 20px; border: 1px solid #e4e7ed; border-radius: 8px; } .demo-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; margin-top: 20px; } .demo-box { padding: 15px; border: 1px solid #dcdfe6; border-radius: 4px; background: #f8f9fa; } .demo-box h4 { margin: 0 0 10px 0; font-size: 14px; color: #606266; } .tab-content { padding: 20px; background: #f5f7fa; margin-top: 20px; border-radius: 4px; min-height: 150px; } label { display: inline-flex; align-items: center; cursor: pointer; } input[type="radio"] { margin-right: 5px; } h2 { color: #303133; border-bottom: 1px solid #e4e7ed; padding-bottom: 10px; } h3 { color: #606266; margin-bottom: 15px; } h4 { color: #303133; margin-bottom: 10px; } </style>

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小文件自动化处理流程

# 1. 查看表的存储目录&#xff08;先执行show create table your_table;找到LOCATION&#xff09; hdfs dfs -ls /user/hive/warehouse/your_db.db/your_table/pt2026-01-06# 2. 【新增】备份原目录小文件&#xff08;防止误删&#xff0c;关键&#xff01;&#xff09; hdfs …

2026大模型风口已至!产品经理学习路线+免费资料,助你月薪30K+,建议收藏!

本文详细介绍了大模型产品经理的五阶段学习路线&#xff1a;基础知识、大模型技术、产品管理、实战经验和持续提升。行业数据显示大模型领域存在47万岗位缺口&#xff0c;初级工程师平均薪资达28K。文章提供四阶段实战学习计划&#xff08;初阶应用、高阶应用、模型训练、商业闭…

金属导电涂层双极板垂直比电阻仪

金属导电涂层双极板垂直比电阻仪 电导率与电阻的关系Rρll/σ定义或解释 电阻率的倒数为电导率。σ1/ρ (2)单位: 在国际单位制中,电导率的单位是西门子/米。 (3)说明 电导率的物理意义是表示物质导电的性能。电导率越大则导电性能越强,反之越小。金属导电涂层双极板垂直比电…

C++中的指针与内存管理

引言 在C++编程中,指针和内存管理一直是让许多程序员头疼的问题。今天,我们通过一个实际的例子来探讨C++中指针的使用,特别是关于**悬空指针(Dangling Pointer)和数组越界(Out of Bounds Access)**的问题。 实例分析 假设我们有一个音频播放程序,需要根据不同类别的…

零基础转行AI大模型产品经理,我的完整学习路线与资源分享

文章讲述了作者从风景园林专业成功转型为AI大模型产品经理的经历。通过自学产品知识、参与项目实践&#xff0c;最终获得AI领域龙头企业offer。作者指出AI产品经理入门成本不高&#xff0c;无需深入算法细节&#xff0c;而应关注用户和业务视角。文章提供了AI大模型学习的七个阶…

NestJS 中动态 Swagger 参数文档的实现

在 NestJS 项目中,常常需要对 API 的参数进行验证和文档化。特别是在使用 UUID 作为参数时,确保参数格式的正确性以及在 Swagger 中正确展示这些参数是非常重要的。今天我们来探讨如何在 NestJS 中创建一个自定义装饰器来验证 UUID 格式,并动态生成 Swagger 文档。 背景介绍…

双极板材料四探针低阻电阻测试仪

双极板材料四探针低阻电阻测试仪 四端测试法是目前较先进之测试方法&#xff0c;主要针对高精度要求之产品测试&#xff1b;本仪器广泛用于生产企业、高等院校、科研部门&#xff0c;是检验和分析导体材料和半导体材料质量的一种重要的工具。双极板材料四探针低阻电阻测试仪 …

Java 程序员如何快速上手浏览器插件开发?一篇文章讲透 Chrome Extension

作者背景&#xff1a;8 年 Java 开发 阅读建议&#xff1a;收藏 实操 适合人群&#xff1a;Java / 后端 / 想做自动化工具的程序员一、写在前面&#xff1a;我为什么要学浏览器插件&#xff1f; 作为一个 Java 程序员&#xff0c;我以前一直有个刻板印象&#xff1a;浏览器插件…

制码指南:轻松生成文本二维码和文件二维码

对于想要生成二维码的用户来说&#xff0c;了解基本步骤至关重要。生成二维码的过程并不复杂&#xff0c;您只需&#xff1a; 选择工具&#xff1a;通常可以在网络上找到多种免费的二维码生成工具。输入内容&#xff1a;无论是上传文件还是输入文本&#xff0c;确保信息准确无…

MATLAB实现稀疏编码中的基学习:使用拉格朗日对偶方法带L2范数约束

在稀疏编码(Sparse Coding)和字典学习领域,一个核心任务是从数据中学习一组过完备基(dictionary或basis),使得数据样本可以用这些基的稀疏线性组合来表示。传统的字典学习通常交替优化稀疏系数和字典,但计算开销较大。 今天我们要探讨一种高效的字典学习方法:针对固定…

速卖通关键词搜索接口深度实战:智能优化与跨境搜索精准化全方案

速卖通&#xff08;AliExpress&#xff09;关键词搜索接口是跨境选品、市场调研、竞品监控的核心入口。不同于国内电商搜索接口&#xff0c;速卖通搜索需适配 “多语言关键词、跨境筛选条件、区域化商品展示” 等特色场景&#xff0c;常规调用方案常面临关键词匹配度低、筛选条…

低代码破局零售电商数字化转型:从流量争夺到效率革命

年轻消费群体崛起&#xff0c;“线上种草、线下拔草”成常态&#xff0c;直播带货、社区团购等新场景涌现&#xff0c;零售电商行业竞争已从“流量争夺”升级为“效率比拼”。但多数企业数字化转型步履维艰&#xff1a;线上线下数据孤岛林立&#xff0c;用户信息不通&#xff1…

融云 回顾:「韧性」生长,「邪修」破局

2025 的进度条已经拉满&#xff0c;各个平台的年度词单也都如期而至了。从大洋彼岸权威词典的严肃定义&#xff0c;到中文互联网上脑洞大开的野生热梗&#xff1b;从传统媒体的时代注脚&#xff0c;到社交平台深夜刷屏的情绪共鸣。虽然语境不同、出处各异&#xff0c;但这些词一…

二维码工具是什么?主要有哪几种应用?

二维码工具的出现&#xff0c;极大地方便了信息的传递与管理。主要功能包括信息存储、链接活码和设备巡检二维码等。其中&#xff0c;信息存储让用户可以快速获取网址、文本和联系方式等信息&#xff1b;链接活码技术可实现内容实时更新&#xff0c;提升用户使用体验&#xff1…

Doris 开启 Partial Update:实现不存在就插入,存在就更新,NULL 不更新原值

这篇文章用一个测试表完整跑通 Doris 的 Partial Column Update&#xff08;部分列更新&#xff09;&#xff1a; 不存在就插入存在就只更新指定列值为 NULL 时不覆盖原值&#xff08;保持原值&#xff09; 1. 先搞懂&#xff1a;Partial Update 的前提条件 1.1 必须是 Uniqu…

docker快速部署docker私有仓库

前言 记录docker快速部署docker私有仓库命令 docker部署私有仓库 1. 创建认证密码文件 安装htpasswd工具 # CentOS/RHEL centos执行这个 yum install -y httpd-tools # Ubuntu/Debian apt-get install -y apache2-utils 2. 创建认证目录 mkdir -p /zero/registry/auth sudo…

【确认出席】卢勇 上海市数商协会秘书长丨上海·1月14日

第八届金猿论坛嘉宾“本次大会&#xff0c;现场将会举行十年先锋人物、十年标杆产品、CIO、数据要素价值释放、AI Infra领先企业、创新技术、Data Agent创新应用、国产化优秀代表厂商八项大奖的“第八届金猿季颁奖典礼”欢迎报名参与&#xff0c;观礼见证。大数据产业创新服务媒…

AI+敏捷时代,专项测试人员是否还有存在的必要?

一、PO 程序员 AI 能否覆盖全部测试需求&#xff1f;1. PO&#xff08;产品负责人&#xff09;的角色PO关注的是业务价值和用户需求&#xff0c;通过用户故事表达功能期望。虽然PO会参与验收&#xff08;UAT&#xff09;&#xff0c;但通常不具备系统性测试思维&#xff0c;也…

成为一名优秀的AI产品经理:2025年AI产品经理必备:大模型产品经理终极学习路线图,一篇就够了!

成为一名优秀的AI产品经理&#xff0c;需要具备深厚的技术背景、良好的产品直觉、敏锐的市场洞察力以及出色的沟通协调能力。以下是一份详尽的AI产品经理学习路线&#xff0c;旨在帮助有意进入该领域的学习者建立起坚实的基础&#xff0c;并逐步成长为行业内的专家。 一、基础知…

口碑好的无轨平车哪家好

口碑好的无轨平车哪家好在工业领域&#xff0c;无轨平车作为一种重要的物料运输设备&#xff0c;其质量和口碑备受关注。那么&#xff0c;口碑好的无轨平车哪家好呢&#xff1f;杭州龙立智能科技值得重点关注。卓越的技术实力杭州龙立智能科技在无轨平车的研发上投入了大量精力…