Vue Composition API如何向Razor Page传递事件与值?
技术场景与问题
在基于ASP.NET Razor构建的页面中嵌入Vue组件(因现有系统架构复杂度,选择组件形式集成Vue)。Vue组件内包含带顶部筛选面板的DataGrid,支持按周期维度加载数据;Razor页面上的现有ReportViewer报表组件需要获取Vue面板的选择值(如目标周期ID、目标值等)来重新加载报表,同时需根据Vue面板中复选框的状态切换报表与DataGrid的显示状态。
现有困惑
- 如何在Vue Composition API中通过emit向Razor Page传递事件与选中参数值?
- 在Razor Page接收到这些参数后,需要执行哪些操作来重新加载ReportViewer组件?
相关代码片段
Vue组件代码
<template> <DxForm :col-count="1" :show-colon-after-label="true" :show-validation-summary="true" :columnWidth="100" @field-data-changed="onHandleFieldDataChanged"> <DxGroupItem :col-count="3"> <DxItem data-field="ViewType" editor-type="dxLookup" :label="{ text: formatMessage('lblSelectView') }" :editor-options="{ items: viewTypes, valueexpr: 'value', displayexpr: 'text' }"> </DxItem> <DxItem data-field="equityGoalLookup" editor-type="dxLookup" :label="{ text: formatMessage('lblSelectGoal') }" :editor-options="{ dataSource: goalPeriodDataStore, valueExpr: 'value', displayExpr: 'text' }" :visible="goalSelectVisible"> <DxLabel text="Select Goal" /> </DxItem> <DxItem data-field="targetLookup" editor-type="dxLookup" :label="{ text: formatMessage('lblSelectTarget') }" :editor-options="{ dataSource: targetPeriodDataStore, valueExpr: 'value', displayExpr: 'text' }" :visible="targetSelectVisible"> <DxLabel text="Select Target" /> </DxItem> <DxItem data-field="compareToActuals" editor-type="dxCheckBox" :label="{ text: formatMessage('lblCompareActuals') }" :visible="compareToActualsVisible"> </DxItem> </DxGroupItem> </DxForm> </template> <script setup> const area = "Company.EmploymentEquityValue"; initLocale(area); function onHandleFieldDataChanged(e) { employmentEquityService.HandleFieldDataChanged(e); emit("goalPeriodId", e.value); emit("targetPeriodId", e.value); console.log(props.filterPanel); if (props.filterPanel) { props.filterPanel.goalPeriodId = e.value; } } const panelHandleChange = (event) => { emit("customChange", event.target.value) } return { panelHandleChange, onHandleFieldDataChanged } </script>
Razor Page代码
@section scripts { <script> DevExpress.Analytics.Utils.ajaxSetup.ajaxSettings.headers = DevExpress.Analytics.Utils.ajaxSetup.ajaxSettings.headers || {}; DevExpress.Analytics.Utils.ajaxSetup.ajaxSettings.headers["X-Parameters"] = "@Model.Parameters"; </script> } <script type="module" src="~/pages/company-employment-equity-plan.js"></script> <page-content> <div class="panel-box"> <div class="panel-box__content"> <div class="panel-box__body"> <company-employment-equity-plan allow-edit=@Model.AllowEdit api-endpoint="@Url.Action("Get", "EquityValueApi")" api-equity-plan-goal-endpoint="@Url.Action("GetEquityPlanGoals", "EquityValueApi")" api-equity-plan-target-endpoint="@Url.Action("GetEquityPlanTargets", "EquityValueApi")" :filter-panel=@Model /> </div> </div> </div> <div style="height:700px;"> @await Component.InvokeAsync("ReportViewer", new { Name = "EmploymentEquityPlanGoalVsActual/EmploymentEquityPlanGoalVsActual.repx", Parameters = $"CompanyId={6464}&EffectiveDate=2023-02-01&UserId={Model.UserId}&pkEquityPlanPeriodIDGoal={Model.GoalPeriodId}", ShowParameters = false }) </div> <script type="text/html" id="equity-report"></script> <script> </script> </page-content>
解决方案
1. Vue Composition API中通过emit传递参数给Razor Page
修正Vue组件的emit逻辑,统一事件名称并传递完整筛选参数集合,避免直接修改props(props为单向数据流):
<script setup> const props = defineProps({ filterPanel: Object }); const area = "Company.EmploymentEquityValue"; initLocale(area); // 统一传递筛选更新事件 const emitFilterUpdate = (filterData) => { emit('filter-updated', filterData); }; function onHandleFieldDataChanged(e) { employmentEquityService.HandleFieldDataChanged(e); // 收集所有筛选字段的最新值,根据实际表单结构调整 const filterData = { goalPeriodId: e.dataField === 'equityGoalLookup' ? e.value : props.filterPanel?.goalPeriodId, targetPeriodId: e.dataField === 'targetLookup' ? e.value : props.filterPanel?.targetPeriodId, compareToActuals: e.dataField === 'compareToActuals' ? e.value : props.filterPanel?.compareToActuals, viewType: e.dataField === 'ViewType' ? e.value : props.filterPanel?.ViewType }; emitFilterUpdate(filterData); } return { onHandleFieldDataChanged } </script>
在Razor页面的Vue组件标签上添加事件监听:
<company-employment-equity-plan allow-edit=@Model.AllowEdit api-endpoint="@Url.Action("Get", "EquityValueApi")" api-equity-plan-goal-endpoint="@Url.Action("GetEquityPlanGoals", "EquityValueApi")" api-equity-plan-target-endpoint="@Url.Action("GetEquityPlanTargets", "EquityValueApi")" :filter-panel=@Model @filter-updated="handleFilterUpdated" />
2. Razor Page接收参数后重新加载ReportViewer
在Razor页面的脚本中实现事件处理函数,通过DevExpress ReportViewer API刷新报表,并切换显示状态:
<script> let reportViewerInstance; // 初始化时获取ReportViewer实例 document.addEventListener('DOMContentLoaded', () => { reportViewerInstance = DevExpress.Reporting.Viewer.ReportViewer.getInstance('#reportViewerContainer'); }); // 处理Vue传递的筛选参数 function handleFilterUpdated(filterData) { // 组装新的报表参数 const newParams = `CompanyId=${@Model.CompanyId}&EffectiveDate=2023-02-01&UserId=${@Model.UserId}&pkEquityPlanPeriodIDGoal=${filterData.goalPeriodId}&pkEquityPlanPeriodIDTarget=${filterData.targetPeriodId}`; // 刷新报表 if(reportViewerInstance) { reportViewerInstance.openReport('EmploymentEquityPlanGoalVsActual/EmploymentEquityPlanGoalVsActual.repx', { parameters: newParams }); } // 根据复选框状态切换报表与DataGrid的显示 const reportContainer = document.querySelector('#reportViewerContainer'); const dataGridContainer = document.querySelector('.panel-box__body'); if(filterData.compareToActuals) { reportContainer.style.display = 'block'; dataGridContainer.style.display = 'none'; } else { reportContainer.style.display = 'none'; dataGridContainer.style.display = 'block'; } } </script>
同时给ReportViewer容器添加ID:
<div id="reportViewerContainer" style="height:700px;"> @await Component.InvokeAsync("ReportViewer", new { Name = "EmploymentEquityPlanGoalVsActual/EmploymentEquityPlanGoalVsActual.repx", Parameters = $"CompanyId={@Model.CompanyId}&EffectiveDate=2023-02-01&UserId={@Model.UserId}&pkEquityPlanPeriodIDGoal={@Model.GoalPeriodId}", ShowParameters = false }) </div>
内容的提问来源于stack exchange,提问作者Donald N. Mafa
相关产品推荐
相关产品推荐

