网站建设负责人证明,wordpress站点地址,大连响应式网站建设,品牌网站建设策划方案本文将基于 Quasar 框架#xff0c;针对表格#xff08;QTable#xff09;、选项卡#xff08;QTabs#xff09;、步进器#xff08;QStepper#xff09; 三个高频组件#xff0c;模拟真实业务场景开发简易 Demo#xff0c;涵盖「数据表格筛选 分页联动」「表单分步提…本文将基于 Quasar 框架针对表格QTable、选项卡QTabs、步进器QStepper三个高频组件模拟真实业务场景开发简易 Demo涵盖「数据表格筛选 分页联动」「表单分步提交」核心功能帮助你掌握组件的实战用法。template q-card q-tab-panels v-modeltab animated q-tab-panel namemails styleheight: 600px classbg-blue-2 div classq-pa-md !-- 使用 q-table 组件创建一个数据表格 titleTreats 设置表格标题 :rowsrows 绑定表格数据 :columnscolumns 绑定列配置 row-keyname 设置行的唯一标识 selectionmultiple 启用多选功能 v-model:selectedselected 双向绑定选中的行 getSelectedString 用于显示选中行的数量信息-- q-table title表格标题 :rowsrows :columnscolumns row-keyname :selected-rows-labelgetSelectedString selectionmultiple v-model:selectedselected classbg-red-2 / !--JSON.stringify() 是JavaScript原生方法将JavaScript对象转换为JSON字符串-- q-card classq-mt-md q-pa-md text-h5 rounded-lg 已选择: {{ selected.map((item) item.name).join(, ) }}/q-card /div /q-tab-panel q-tab-panel namealarms styleheight: 600px classbg-blue-2 div classq-pa-md q-stepper v-modelstep refstepper animated done-colordeep-orange active-colorpurple inactive-colorsecondary styleheight: 550px classtext-h6 q-px-lg q-pt-md q-step :name1 title请假信息 iconevent :donestep 1 div classq-pa-md q-form refstep1Form classq-gutter-md q-input filled v-modelleaveForm.type label请假类型 :options[事假, 病假, 年假, 婚假, 产假] emit-value map-options / q-input filled v-modelleaveForm.reason typetextarea label请假原因 rows4 / /q-form /div /q-step q-step :name2 title请假时间 caption选择起止时间 icondate_range :donestep 2 div classq-pa-md q-pa-xl q-form refstep2Form classq-gutter-md q-input filled v-modelleaveForm.startDate label开始日期 template v-slot:append q-icon nameevent classcursor-pointer q-popup-proxy cover transition-showscale transition-hidescale q-date v-modelleaveForm.startDate maskYYYY-MM-DD div classrow items-center justify-end q-btn v-close-popup label确定 colorprimary flat / /div /q-date /q-popup-proxy /q-icon /template /q-input q-input filled v-modelleaveForm.endDate label结束日期 template v-slot:append q-icon nameevent classcursor-pointer q-popup-proxy cover transition-showscale transition-hidescale q-date v-modelleaveForm.endDate maskYYYY-MM-DD div classrow items-center justify-end q-btn v-close-popup label确定 colorprimary flat / /div /q-date /q-popup-proxy /q-icon /template /q-input q-input filled v-modelleaveForm.days label请假天数 typenumber min1 / /q-form /div /q-step q-step :name3 title确认提交 iconfact_check div classq-pa-md q-card flat bordered classq-pa-md q-card-section div classtext-h6请假信息确认/div /q-card-section q-card-section div classq-gutter-md div请假类型{{ leaveForm.type }}/div div请假原因{{ leaveForm.reason }}/div div开始日期{{ leaveForm.startDate }}/div div结束日期{{ leaveForm.endDate }}/div div请假天数{{ leaveForm.days }}天/div /div /q-card-section /q-card /div /q-step template v-slot:navigation q-stepper-navigation classflex q-space/ q-btn classtext-h6 clickhandleNext colordeep-orange :labelstep 3 ? 提交 : 下一步 / q-btn v-ifstep 1 flat colordeep-orange click$refs.stepper.previous() label上一步 classq-ml-sm text-h6 /q-space/ /q-stepper-navigation /template /q-stepper /div /q-tab-panel q-tab-panel namemovies styleheight: 600px classbg-blue-2 div classtext-h6选项卡选项三/div 选项卡选项三选项卡选项三选项卡选项三选项卡选项三选项卡选项三选项卡选项三选项卡选项三选项卡选项三选项卡选项三选项卡选项三选项卡选项三选项卡选项三选项卡选项三选项卡选项三选项卡选项三选项卡选项三选项卡选项三选项卡选项三选项卡选项三选项卡选项三选项卡选项三 /q-tab-panel /q-tab-panels q-separator / q-tabs v-modeltab dense classbg-grey-3 alignjustify narrow-indicator q-tab namemails label零食含量表格分页阅览 classq-pa-sm text-h4 / q-tab namealarms label步进器请假 classq-pa-sm text-h4 / q-tab namemovies label选项卡选项三 classq-pa-sm text-h4 / /q-tabs /q-card /template script setup import { ref } from vue const stepper ref(null) const step1Form ref(null) const step2Form ref(null) const step ref(1) const tab ref(mails) const leaveForm ref({ type: , reason: , startDate: , endDate: , days: , }) const handleNext async () { if (step.value 1) { const isValid await step1Form.value.validate() if (!isValid) return } else if (step.value 2) { const isValid await step2Form.value.validate() if (!isValid) return } else if (step.value 3) { // 提交表单 submitLeaveForm() return } stepper.value.next() } const submitLeaveForm () { // 这里添加提交逻辑 console.log(提交请假表单:, leaveForm.value) // 提交成功后可以重置表单或跳转页面 } /*定义了 columns 数组配置表格的各个列 name: 列的唯一标识 required: 是否必填 label: 列标题 align: 对齐方式 field: 数据字段 format: 格式化函数 sortable: 是否可排序 sort: 自定义排序函数*/ const columns [ { name: desc, required: true, label: 甜点100克, align: left, field: (row) row.name, format: (val) ${val}, sortable: true, }, { name: calories, align: center, label: 卡路里, field: calories, sortable: true, }, { name: fat, label: 脂肪克, field: fat, sortable: true, }, { name: carbs, label: 碳水化合物克, field: carbs, }, { name: protein, label: 蛋白质克, field: protein, }, { name: sodium, label: 钠毫克, field: sodium, }, { name: calcium, label: 钙%, field: calcium, sortable: true, sort: (a, b) parseInt(a, 10) - parseInt(b, 10), }, { name: iron, label: 铁%, field: iron, sortable: true, sort: (a, b) parseInt(a, 10) - parseInt(b, 10), }, ] const rows [ { name: 冻酸奶, calories: 159, fat: 6.0, carbs: 24, protein: 4.0, sodium: 87, calcium: 14%, iron: 1%, }, { name: 冰淇淋三明治, calories: 237, fat: 9.0, carbs: 37, protein: 4.3, sodium: 129, calcium: 8%, iron: 1%, }, { name: 闪电泡芙, calories: 262, fat: 16.0, carbs: 23, protein: 6.0, sodium: 337, calcium: 6%, iron: 7%, }, { name: 纸杯蛋糕, calories: 305, fat: 3.7, carbs: 67, protein: 4.3, sodium: 413, calcium: 3%, iron: 8%, }, { name: 姜饼, calories: 356, fat: 16.0, carbs: 49, protein: 3.9, sodium: 327, calcium: 7%, iron: 16%, }, { name: 软糖豆, calories: 375, fat: 0.0, carbs: 94, protein: 0.0, sodium: 50, calcium: 0%, iron: 0%, }, { name: 棒棒糖, calories: 392, fat: 0.2, carbs: 98, protein: 0, sodium: 38, calcium: 0%, iron: 2%, }, { name: 蜂窝糖, calories: 408, fat: 3.2, carbs: 87, protein: 6.5, sodium: 562, calcium: 0%, iron: 45%, }, { name: 甜甜圈, calories: 452, fat: 25.0, carbs: 51, protein: 4.9, sodium: 326, calcium: 2%, iron: 22%, }, { name: 奇巧巧克力, calories: 518, fat: 26.0, carbs: 65, protein: 7, sodium: 54, calcium: 12%, iron: 6%, }, ] const selected ref([]) const getSelectedString () { return selected.value.length 0 ? : ${selected.value.length} record${selected.value.length 1 ? s : } selected of ${rows.length} } /script style .w-600 { width: 600px; } .h-600 { height: 600px; } /style前置准备确保已搭建 Quasar 项目参考 Quasar 官方文档核心依赖Quasar v2 Vue 3组合式 API模拟数据使用faker-js生成测试数据可选也可手动造数。安装测试数据依赖可选npm install faker-js/faker --save-dev场景一QTable 数据表格筛选 分页联动业务场景实现「商品列表」功能支持按商品名称 / 分类筛选、分页切换、每页条数调整筛选条件变化时自动重置分页到第一页。步骤 1基础结构与数据准备在src/pages/TableDemo.vue中编写基础代码生成模拟商品数据template q-page classq-pa-md !-- 筛选区域 -- div classq-mb-md row items-center gap-md !-- 商品名称筛选 -- q-input v-modelsearchName label商品名称 placeholder输入名称筛选 clearable clearhandleFilter inputhandleFilter / !-- 商品分类筛选 -- q-select v-modelsearchCategory label商品分类 :optionscategoryOptions clearable placeholder全部分类 inputhandleFilter / /div !-- 数据表格 -- q-table :rowsfilteredRows !-- 筛选后的数据源 -- :columnscolumns !-- 列配置 -- :paginationpagination !-- 分页配置 -- paginationonPagination !-- 分页变化回调 -- row-keyid !-- 行唯一标识 -- dense !-- 紧凑模式 -- bordered !-- 带边框 -- !-- 自定义操作列 -- template #body-cell-actionsprops q-td :propsprops q-btn sizexs label编辑 colorprimary classq-mr-xs / q-btn sizexs label删除 colornegative / /q-td /template /q-table /q-page /template script setup import { ref, computed, onMounted } from vue import { faker } from faker-js/faker // 若无faker可手动造数 // 1. 模拟原始数据100条商品数据 const rawData ref([]) // 商品分类选项 const categoryOptions ref([ { label: 电子产品, value: electronics }, { label: 生活用品, value: daily }, { label: 食品, value: food }, { label: 服饰, value: clothes } ]) // 2. 筛选条件 const searchName ref() // 名称筛选 const searchCategory ref() // 分类筛选 // 3. 分页配置核心与筛选联动 const pagination ref({ page: 1, // 当前页 rowsPerPage: 10, // 每页条数 rowsNumber: 0 // 总条数筛选后 }) // 4. 表格列配置 const columns ref([ { name: id, label: ID, align: center, width: 80px }, { name: name, label: 商品名称, align: left }, { name: category, label: 分类, align: center, width: 120px }, { name: price, label: 价格(元), align: center, width: 100px }, { name: stock, label: 库存, align: center, width: 100px }, { name: actions, label: 操作, align: center, width: 180px } ]) // 5. 生成模拟数据 onMounted(() { rawData.value Array.from({ length: 100 }, (_, index) { const category categoryOptions.value[Math.floor(Math.random() * 4)] return { id: index 1, name: faker.commerce.productName(), // 随机商品名 category: category.label, // 分类名称 categoryValue: category.value, // 分类值用于筛选 price: faker.commerce.price({ min: 10, max: 1000, dec: 2 }), stock: Math.floor(Math.random() * 1000) } }) // 初始化筛选 handleFilter() })步骤 2实现筛选 分页联动逻辑在上述代码的script中补充核心逻辑// 6. 筛选数据计算属性根据名称/分类过滤 const filteredRows computed(() { let result rawData.value // 名称筛选模糊匹配 if (searchName.value) { result result.filter(item item.name.toLowerCase().includes(searchName.value.toLowerCase()) ) } // 分类筛选精确匹配 if (searchCategory.value) { result result.filter(item item.categoryValue searchCategory.value) } // 更新总条数 pagination.value.rowsNumber result.length // 分页截取数据 const start (pagination.value.page - 1) * pagination.value.rowsPerPage const end start pagination.value.rowsPerPage return result.slice(start, end) }) // 7. 筛选条件变化时重置分页到第1页 const handleFilter () { pagination.value.page 1 // 筛选后默认回到第一页 } // 8. 分页变化回调页码/每页条数改变时触发 const onMounted (newPagination) { pagination.value { ...pagination.value, ...newPagination } }核心要点说明筛选逻辑通过computed计算属性实时过滤原始数据避免重复遍历分页联动筛选条件变化时重置page为 1防止筛选后数据不足导致分页异常row-key必须设置唯一标识如id否则表格渲染会出现复用异常自定义列通过#body-cell-xxx插槽自定义操作列适配业务按钮需求。效果验证输入商品名称关键词表格实时筛选并重置到第一页选择分类筛选仅显示对应分类商品切换页码 / 调整每页条数数据正确分页展示。场景二QTabs QStepper 表单分步提交业务场景实现「用户注册 信息完善」分步表单选项卡QTabs区分「基础信息」「联系方式」「确认提交」三个步骤步进器QStepper可视化展示步骤进度支持下一步 / 上一步 / 提交操作表单校验每一步必填项校验通过后才能进入下一步最终提交所有数据。步骤 1基础结构搭建在src/pages/StepperTabDemo.vue中编写基础代码template q-page classq-pa-md div classmax-w-2xl mx-auto !-- 步进器可视化进度 -- q-stepper v-modelcurrentStep typehorizontal :active-iconcurrentStep :done-icon[1, 2, 3] classq-mb-lg q-step name1 label基础信息 iconperson / q-step name2 label联系方式 iconphone / q-step name3 label确认提交 iconcheck_circle / /q-stepper !-- 选项卡分步表单容器 -- q-tabs v-modelcurrentStep classq-mb-md alignjustify no-caps q-tab name1 label基础信息 / q-tab name2 label联系方式 / q-tab name3 label确认提交 / /q-tabs !-- 选项卡面板表单内容 -- q-tab-panels v-modelcurrentStep animated classq-mb-md !-- 步骤1基础信息 -- q-tab-panel name1 q-form refform1 submit.preventnextStep q-input v-modelformData.username label用户名 placeholder请输入用户名 :rules[val !!val || 用户名不能为空] classq-mb-md / q-input v-modelformData.realName label真实姓名 placeholder请输入真实姓名 :rules[val !!val || 真实姓名不能为空] classq-mb-md / q-input v-modelformData.idCard label身份证号 placeholder请输入18位身份证号 :rules[ val !!val || 身份证号不能为空, val val.length 18 || 身份证号必须为18位 ] classq-mb-md / /q-form /q-tab-panel !-- 步骤2联系方式 -- q-tab-panel name2 q-form refform2 submit.preventnextStep q-input v-modelformData.phone label手机号 placeholder请输入11位手机号 :rules[ val !!val || 手机号不能为空, val /^1[3-9]\\d{9}$/.test(val) || 手机号格式错误 ] classq-mb-md / q-input v-modelformData.email label邮箱 placeholder请输入邮箱 :rules[ val !!val || 邮箱不能为空, val /^\\w([.-]?\\w)*\\w([.-]?\\w)*(.\\w{2,3})$/.test(val) || 邮箱格式错误 ] classq-mb-md / q-input v-modelformData.address label详细地址 placeholder请输入详细地址 :rules[val !!val || 详细地址不能为空] classq-mb-md / /q-form /q-tab-panel !-- 步骤3确认提交 -- q-tab-panel name3 div classq-pa-md bg-grey-5 rounded-lg h4 classq-mb-md提交信息确认/h4 div classrow q-mb-sm div classcol-4 text-grey-6用户名/div div classcol-8{{ formData.username }}/div /div div classrow q-mb-sm div classcol-4 text-grey-6真实姓名/div div classcol-8{{ formData.realName }}/div /div div classrow q-mb-sm div classcol-4 text-grey-6手机号/div div classcol-8{{ formData.phone }}/div /div div classrow q-mb-sm div classcol-4 text-grey-6邮箱/div div classcol-8{{ formData.email }}/div /div /div /q-tab-panel /q-tab-panels !-- 操作按钮 -- div classrow justify-between q-btn label上一步 iconarrow_back clickprevStep :disabledcurrentStep 1 / q-btn v-ifcurrentStep ! 3 label下一步 iconarrow_forward colorprimary clicknextStep / q-btn v-else label提交 iconsend colorpositive clicksubmitForm / /div /div /q-page /template script setup import { ref, reactive } from vue import { useQuasar } from quasar // 1. 初始化Quasar通知用于提交成功提示 const $q useQuasar() // 2. 步骤控制 const currentStep ref(1) // 绑定选项卡和步进器的当前步骤 // 3. 表单数据 const formData reactive({ username: , realName: , idCard: , phone: , email: , address: }) // 4. 表单引用用于校验 const form1 ref(null) const form2 ref(null)步骤 2实现分步校验与提交逻辑在script中补充核心方法// 5. 下一步含表单校验 const nextStep async () { let isValid false // 步骤1校验 if (currentStep.value 1) { isValid await form1.value.validate() } // 步骤2校验 else if (currentStep.value 2) { isValid await form2.value.validate() } // 校验通过则切换步骤 if (isValid) { if (currentStep.value 1) { currentStep.value 2 } else if (currentStep.value 2) { currentStep.value 3 } } } // 6. 上一步无需校验直接切换 const prevStep () { if (currentStep.value 2) { currentStep.value 1 } else if (currentStep.value 3) { currentStep.value 2 } } // 7. 最终提交 const submitForm () { // 模拟接口提交 setTimeout(() { $q.notify({ type: positive, message: 表单提交成功, caption: 您的信息已保存 }) // 重置表单 form1.value.resetValidation() form2.value.resetValidation() Object.assign(formData, { username: , realName: , idCard: , phone: , email: , address: }) currentStep.value 1 // 回到第一步 }, 1000) }核心要点说明组件联动currentStep同时绑定QStepper和QTabs实现步骤与选项卡的同步切换表单校验每一步使用QForm的validate()方法做异步校验校验通过才允许下一步步进器配置v-model绑定当前步骤active-icon标记当前激活步骤done-icon标记已完成步骤用户体验上一步按钮在第一步禁用避免无效操作提交后重置表单和步骤方便再次填写使用 Quasar 通知组件反馈提交结果。效果验证第一步未填必填项点击「下一步」触发表单校验提示校验通过后切换到第二步步进器和选项卡同步更新第二步同理校验通过后进入第三步预览所有信息点击「提交」模拟接口请求后提示成功并重置表单。扩展优化建议表格组件扩展远程数据适配若表格数据来自接口将filteredRows改为异步请求筛选 / 分页时调用接口传递searchNamepagerowsPerPage参数多条件筛选增加日期范围、价格区间等筛选条件通过URLSearchParams拼接参数表格排序开启 QTable 的sort配置支持点击列头排序const columns ref([ { name: price, label: 价格(元), align: center, sortable: true } ])步进器 / 选项卡扩展步骤禁用若某一步需要前置条件如第二步需第一步审核通过可通过QStep的disable属性控制q-step name2 label联系方式 iconphone :disable!formData.username /表单缓存使用localStorage缓存表单数据避免页面刷新后数据丢失自定义校验规则抽离通用校验规则如手机号、邮箱到工具函数提升复用性// src/utils/validate.js export const phoneRule [ val !!val || 手机号不能为空, val /^1[3-9]\d{9}$/.test(val) || 手机号格式错误 ]总结本教程通过两个核心业务场景覆盖了 Quasar 高频组件的核心用法QTable筛选、分页、自定义列的联动逻辑适配大数据列表展示QTabs QStepper分步表单的联动、校验、提交适配多步骤业务流程所有 Demo 均基于 Vue 3 组合式 API 编写贴近实际项目开发模式你可根据业务需求进一步扩展功能如表格导出、表单回显、步骤进度保存等。