运行browserify打包JS后调用collectQuestions方法提示未定义如何解决
问题根因
- Browserify打包后的代码默认运行在独立闭包中,你导出的
QuestionnaireView实例没有挂载到全局window对象上,Blazor JSInterop 仅能调用挂载在window下的全局方法/对象,自然找不到collectQuestions方法。 collectQuestions是类的实例成员方法,不能直接作为全局方法调用,必须先获取类实例,再通过实例调用该方法。- 现有代码存在隐藏bug:
$j(this.options.questionId).each(function () {})使用普通函数作为回调,内部this指向已经改变,运行时会取不到this.options配置,哪怕方法能正常调用也会抛出异常。 - 原有代码中
answersAndWeightingsDict、weightingDict定义在循环外部,会导致所有问题共用同一个答案数组、所有返回结果共用同一个权重数组,返回数据会出现逻辑错误。
解决方案
第一步:修改JS代码,暴露实例到全局、修复逻辑问题
import $j from "jquery"; import BaseComponent from './Components/base-component'; class QuestionnaireView extends BaseComponent { constructor() { super(); this.defaultOptions = { questionId : '#questionId', responseId : '#responseId', answerId : '#answerId', questionTextId : '#questionTextId' }; this.state = {}; } initChildren() {} addListeners() {} collectQuestions() { const questionAndAnswersDict = []; // 改用箭头函数修复this指向问题 $j(this.options.questionId).each((index, questionEl) => { const questionText = $j(questionEl).find("input")[0].value; // 将答案数组移到循环内部,避免不同问题共用同一份答案 const answersAndWeightingsDict = []; $j(this.options.answerId).each((index, answerEl) => { const answerText = $j(answerEl).find("input")[0].value; const weighting = $j(answerEl).find("input")[1].value; answersAndWeightingsDict.push({ key: answerText, value: weighting }); }); questionAndAnswersDict.push({ key: questionText, value: answersAndWeightingsDict }); }); // 增加返回值,供Blazor接收处理结果 return questionAndAnswersDict; } collectResponses() { const responsesDict = []; $j(this.options.responseId).each((index, responseEl) => { // 将权重数组移到循环内部,避免不同返回结果共用同一份权重 const weightingDict = []; const minWeighting = $j(responseEl).find("input")[0].value; const maxWeighting = $j(responseEl).find("input")[1].value; const responseText = $j(responseEl).find("input")[2].value; weightingDict.push({ key: minWeighting, value: maxWeighting }); responsesDict.push({ key: responseText, value: weightingDict }); }); return responsesDict; } } // 实例化类并挂载到全局window对象,供Blazor JSInterop调用 window.QuestionnaireView = new QuestionnaireView();
第二步:安装依赖(若未安装)
确保本地已安装打包需要的所有依赖:
npm install --save-dev @babel/core @babel/preset-env @babel/preset-react @babel/plugin-transform-modules-commonjs babelify browserify
第三步:执行打包命令
原有带babelify的打包命令无需修改,直接执行即可:
browserify Scripts/questionnaire-view.js -o wwwroot/js/questionnaire-view.js -t [ babelify --presets [ @babel/preset-env @babel/preset-react ] --plugins [ @babel/plugin-transform-modules-commonjs ] ]
第四步:修改Blazor端调用方式
将原来直接调用方法名的逻辑,改为调用挂载到window上的实例方法:
// 错误的原有调用方式 // await JSRuntime.InvokeAsync<object>("collectQuestions"); // 修正后的调用方式 var questionList = await JSRuntime.InvokeAsync<object>("QuestionnaireView.collectQuestions"); var responseList = await JSRuntime.InvokeAsync<object>("QuestionnaireView.collectResponses");
验证步骤
- 打开打包后的
wwwroot/js/questionnaire-view.js文件,搜索window.QuestionnaireView确认挂载逻辑存在 - 打开浏览器控制台,输入
window.QuestionnaireView.collectQuestions,可以正常输出函数定义即说明挂载成功 - 触发Blazor端的调用逻辑,即可正常获取返回结果
内容的提问来源于stack exchange,提问作者James Blackburn
相关产品推荐
相关产品推荐

