用 Quasar 框架高效构建跨平台前端应用实战经验分享
项目初期的技术选型
去年年底接手一个内部管理系统,需求是做一套同时支持桌面和移动端的后台界面。团队人少,工期紧,老板还要求“看起来专业点”。我一开始想用纯 Vue + Element Plus,但测试发现移动端体验太差,滚动卡顿、按钮太小,用户反馈一堆问题。后来翻了下 Quasar 的文档,发现它主打“一次开发,多端部署”,而且组件库对移动端做了深度优化,就决定试试。
其实之前没用过 Quasar,心里有点打鼓,但看它基于 Vue 3,生态也成熟,社区活跃度还行,就硬着头皮上了。事实证明,这个选择在基础体验上确实省了不少事——比如表单、表格、弹窗这些,开箱即用,适配手机和平板基本不用额外调样式。
最大的坑:性能问题
项目做到一半,突然发现列表页在低端安卓机上滚动特别卡,甚至偶尔白屏。一开始以为是数据量太大(一页 100 条),但用 Chrome DevTools 看,FPS 掉到 10 以下,明显是渲染问题。折腾了半天才发现,Quasar 的 QTable 在默认模式下会把所有行都渲染出来,哪怕你只看到 10 行。
查了官方文档,发现它支持虚拟滚动(virtual scroll),但配置有点绕。我一开始直接套用示例代码,结果滚动时内容错乱,行高不对。后来才意识到,虚拟滚动要求每一行的高度必须固定,而我们的表格里有动态内容(比如备注字段可能换行),导致实际高度不一致。
没办法,只能妥协:限制备注字段最多显示两行,超出部分用 text-overflow: ellipsis 截断。这样虽然牺牲了一点信息完整性,但性能立马稳了。附上最终配置:
<q-table
virtual-scroll
:virtual-scroll-item-size="60"
:rows="tableData"
:columns="columns"
row-key="id"
/>
注意这里 virtual-scroll-item-size 必须和 CSS 中设定的行高一致,否则会出现空白或重叠。我踩过好几次坑,每次改完样式忘了同步这个值,上线后又被测试提 bug。
又踩坑了,touchmove 滚动失效
另一个头疼的问题是在 iOS 上,某些页面内嵌的滚动区域(比如弹窗里的长表单)无法正常滑动。手指一划,整个页面跟着动,而不是弹窗内容滚动。查了好久,发现是 Quasar 的全局事件监听和我们自定义的 touch 逻辑冲突了。
具体来说,我们在某个组件里加了 @touchmove.prevent 来阻止默认行为,结果把 Quasar 内部用于识别滚动容器的逻辑也干掉了。解决方法是在需要滚动的容器上显式加上 scroll-target 属性,并且确保没有其他地方拦截了 touch 事件。
后来调整了方案,把所有自定义手势逻辑都移到了 passive: true 的监听器里,避免调用 preventDefault()。关键代码如下:
// 错误做法
el.addEventListener('touchmove', (e) => {
e.preventDefault(); // 别这么干!
});
// 正确做法
el.addEventListener('touchmove', handler, { passive: true });
这个改动不大,但影响范围广,改完后所有弹窗内的滚动都恢复正常了。不过现在想想,其实更稳妥的做法是完全依赖 Quasar 提供的滚动组件(比如 QScrollArea),而不是自己处理 touch 事件——但当时时间紧,只能局部修复。
核心代码就这几行
项目里最让我满意的部分是主题切换功能。Quasar 支持动态主题,但文档写得比较散。我最后用 Vuex 管理主题状态,配合 Quasar 的 setBrand API 实现一键切换。核心逻辑其实就几行:
// store/modules/theme.js
import { setBrand } from 'quasar';
const state = {
darkMode: false
};
const mutations = {
TOGGLE_DARK_MODE(state) {
state.darkMode = !state.darkMode;
const mode = state.darkMode ? 'dark' : 'light';
// 动态切换主色和背景
setBrand('primary', mode === 'dark' ? '#88c7ff' : '#1976d2');
setBrand('background', mode === 'dark' ? '#121212' : '#ffffff');
}
};
然后在 App.vue 里监听状态变化:
watch: {
'$store.state.theme.darkMode'(newVal) {
this.$q.dark.set(newVal);
}
}
亲测有效,切换流畅,连动画过渡都自带。不过有个小问题一直没解决:首次加载时如果系统是深色模式,页面会先闪一下白色再变黑。理论上可以通过 SSR 或 localStorage 预判,但项目没上 SSR,最后就加了个 loading 遮罩糊弄过去了——反正只闪 100ms,用户基本无感。
回顾与反思
整体来看,Quasar 在这个项目里表现不错。开发效率高,组件一致性好,移动端适配省心。特别是它的 CLI 工具,打包 PWA、生成 Cordova 项目都很方便,虽然我们最后只用了 Web 版。
但也有几个地方可以优化:
- Bundle 体积偏大:即使按需引入,基础包还是比纯 Vue 大不少。下次如果只是简单后台,可能还是选轻量级方案。
- 文档示例不够实战:很多高级用法(比如虚拟滚动 + 动态高度)得自己摸索,社区问答质量参差不齐。
- TypeScript 支持一般:类型定义有些滞后,经常要自己加
@ts-ignore。
不过话说回来,在人手不足、多端需求明确的场景下,Quasar 依然是个靠谱的选择。至少比自己从零搭一套响应式系统强多了。
以上是我踩坑后的总结,希望对你有帮助。如果你也在用 Quasar,遇到类似问题或者有更好的解法,欢迎评论区交流——尤其是那个深色模式闪白的问题,至今耿耿于怀。

暂无评论