我已阅读 Microsoft 的有关从 Blazor 调用 JavaScript 的文档。我访问过 Telerik 网站并搜索了他们的文档和论坛。我已经做了很多搜索引擎查询。我搜索过,发现类似的问题并不能完全回答我的问题。
具体来说,我希望作为传递给
kendo.Class.extend
的对象属性的 JavaScript 代码能够调用 Blazor 组件实例方法。
我不想做的是调用静态方法 - 我可以让它工作,但这不是我想要的。我不想在脚本标记中调用任意方法,因为我有使用具有特定语法的 Telerik Chat 控件的特定场景。
再次强调,如果您向我推荐另一个问题或向我显示链接,请确保它针对我的情况。
此方法的背景是 Telerik 没有 Blazor 聊天控件。因此,根据 Telerik 的建议,我需要在 Blazor 组件和 Kendo jQuery Chat 小部件之间进行通信。
这里的代码与如何编写 jQuery 部分的 Telerik 示例类似:
// MyChatComponent.razor.js
var chat = $("#chat").kendoChat({
post: function (args) {
agent.postMessage(args);
}
}).data("kendoChat");
window.ChatAgent = kendo.Class.extend({
init: function (chat, dotnet) {
this.chat = chat;
this.dotnet = dotnet;
console.log('dotneti', dotnet);
},
postMessage: function (args) {
var chat = this.chat;
this.dotnet.invokeMethodAsync('MyChatComponent', 'AskAsync', args.text)
.then(data => {
chat.renderMessage({
type: "text",
text: data,
timestamp: new Date()
}, {
name: "Generellem"
});
});
}
});
var agent = new ChatAgent(chat);
agent.chat.renderMessage({
type: "text",
text: "Hi, How can I help today?",
timestamp: new Date()
}, {
name: "Generellem"
});
我所做的修改是将
dotnet
参数添加到 init
对象中的 kendo.Class.extend
函数中。再往下,在 postMessage
函数中,我使用 dotnet
实例变量来调用 invokeMethodAsync
。这不起作用 - console.log
函数中的 init
打印出 dotnet
是 undefined
。
问题之一是我不知道将
dotnet
放在哪里才能拥有正确的实例引用。这将我带到了组件,这是我希望上面的代码接收的实例:
// MyChatComponent.razor
@page "/chat"
@rendermode InteractiveServer
@inject IJSRuntime JS
<h3>Chat</h3>
<div id="chat"></div>
@code {
CancellationTokenSource cancelTokenSource = new();
DotNetObjectReference<Chat>? objRef;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
objRef = DotNetObjectReference.Create(this);
await JS.InvokeAsync<IJSObjectReference>(
"import", "./Components/Pages/Chat.razor.js", objRef);
}
}
[JSInvokable]
public async Task<string> AskAsync(string message)
{
return await Task.FromResult(message);
}
}
这里有一些有趣的项目。第一个是在
OnAfterRenderAsync
中,我调用 DotNetObjectReference.Create(this)
来获取当前对象的实例,如 objRef
。我想将 objRef
传递给 JavaScript 代码,以便我可以调用 AskAsync
实例方法。
在
AskAsync
内部,我添加了 objRef
作为 InvokeAsync
的第三个参数。我不知道这样做是否正确,但我尝试过。
总而言之,我想将
objRef
从 C# 代码传递到 JavaScript 代码,以便 JavaScript 代码在调用 AskAsync
时拥有对组件实例的引用。
这是我正在使用的解决方法,尽管感觉它缺乏优雅。本质上,我调用了 JS 函数来显式设置对象引用,而不是试图弄清楚如何在导入过程中传递参数。这是更新后的 JS 代码:
// MyChatComponent.razor.js
var chat = $("#chat").kendoChat({
post: function (args) {
agent.postMessage(args);
}
}).data("kendoChat");
window.ChatAgent = kendo.Class.extend({
init: function (chat) {
this.chat = chat;
},
postMessage: function (args) {
var chat = this.chat;
this.dotnet.invokeMethodAsync('MyChatComponent', 'AskAsync', args.text)
.then(data => {
chat.renderMessage({
type: "text",
text: data,
timestamp: new Date()
}, {
name: "Generellem"
});
});
}
});
var agent = new ChatAgent(chat);
agent.chat.renderMessage({
type: "text",
text: "Hi, How can I help today?",
timestamp: new Date()
}, {
name: "Generellem"
});
var dotnet = {};
export function setDotnetInstance(objRef) {
dotnet = objRef;
};
我从
dotnet
中删除了 kendo.Class.extend.init
参数。然后,我在文件末尾创建了一个对象变量 dotnet
。我还添加了 setDotnetInstance
函数导出,以引用 Blazor 组件来设置 dotnet
变量。
在 Blazor 组件中,我在
setDotnetInstance
中省略了 OnAfterRenderAsync
,如下所示:
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
objRef = DotNetObjectReference.Create(this);
IJSObjectReference module = await JS.InvokeAsync<IJSObjectReference>(
"import", "./Components/Pages/Chat.razor.js");
await module.InvokeVoidAsync("setDotnetInstance", objRef);
}
}
改变是乘坐
IJSObjectReference
,module
,从JS.InvokeAsync
返回来用setDotnetInstance
打电话给InvokeVoidAsync
。
如果我找到更好的方法来做到这一点,我会更新这个答案。