我正在使用app.net core 3.1
和blazor
构建一个网站。在我的一个组件中,我有:
<input @bind="Message" type="text" id="input-message"/>
Message
只是一个字符串属性。
我有javascript:
document.getElementById('input-message').value = 'some text';
问题是在运行上面的js之后,<input>
的值会改变,但Message
的值不会改变,当然,如果我在<input>
中键入或粘贴一些东西,Message
的值也会改变。
显然,通过javascript更改<input>
值或DOM中的任何其他更改都不会更改State,因此blazor不会重新渲染组件。即使在剃须刀页面中手动调用StateHasChanged();
也不起作用。
要做到这一点,您只需要触发与用户正常修改<input>
时相同的DOM事件,如下所示:
var myElement = document.getElementById('input-message');
myElement.value = 'some text';
var event = new Event('change');
myElement.dispatchEvent(event);
您不应该直接在javascript中更改输入值,您应该调用一个c函数来更新值,然后它会更新javascript。
而不是做
document.getElementById('input-message').value = 'some text';
你应该做一些类似的事情
DotNet.invokeMethodAsync('UpdateMessageValue', 'some text');
在哪里
public void UpdateMessageValue(string value){
Message = value;
}
因为您在输入中使用bind
,所以document.getElementById('input-message').value
的值将更改,c#中的值也将更改。
这个答案还不完整,我向您传递的是如何做到这一点的想法,而不是解决您的问题的正确代码,但如果您想了解更多关于如何做到的信息,您可以查看ASP.NET Core Blazor中JavaScript函数的Call.NET方法。
如果您无法控制正在修改输入字段的第三方lib脚本,则可以始终使用以下解决方案
概念如下:
渲染组件后,我们调用JS开始拦截所有输入字段的值设置器,然后我们从JS中获得Blazor中的回调。Blazor随后派遣到适当的场地。
字段示例:
<div class="input-group input-daterange" data-date-format="dd.mm.yyyy">
<input type="text"
id="InputDateFrom"
@bind="InputDateFrom"
class="form-control text-center" placeholder="От">
<span class="input-group-addon"><i class="fa fa-angle-right"></i></span>
<input type="text"
id="InputDateTo"
@bind="InputDateTo"
class="form-control text-center" placeholder="До">
</div>
JS:
function WatchInputFields(callbackChangedName, dotnetRef) {
var descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value");
var originalSet = descriptor.set;
// define our own setter
descriptor.set = function (val) {
console.log("Value set", this, val);
originalSet.apply(this, arguments);
dotnetRef.invokeMethodAsync(callbackChangedName, this.id, this.value);
}
Object.defineProperty(HTMLInputElement.prototype, "value", descriptor); }
BLAZOR:
在OnAfterRenderAsync
内部,在第一次渲染时调用InitInputFieldsToTrackOnce
(如果服务器有预渲染,则调用第二次(:
private async Task InitInputFieldsToTrackOnce()
{
_objRef = DotNetObjectReference.Create(this);
await JS.InvokeVoidAsync(
"WatchInputFields",
"OnInputFieldChanged",
_objRef);
WatchInputField("InputDateFrom", (value) => { _InputDateFrom = value; Console.WriteLine($"Setting FROM to {value}"); });
WatchInputField("InputDateTo", (value) => { _InputDateTo = value; ; Console.WriteLine($"Setting TO to {value}"); });
}
void WatchInputField(string id, Action<string> onChanged)
{
InputFieldChanges.TryAdd(id, onChanged);
}
private ConcurrentDictionary<string, Action<string>> InputFieldChanges { get; } = new ConcurrentDictionary<string, Action<string>>();
private DotNetObjectReference<ShopDesk> _objRef;
[JSInvokable]
public async Task OnInputFieldChanged(string id, string value)
{
var ok = InputFieldChanges.TryGetValue(id, out Action<string> action);
if (ok)
action(value);
}
并在处理组件时处理_objRef
。