【问题标题】:Reset <input> text after @onchange在@onchange 之后重置 <input> 文本
【发布时间】:2020-04-27 08:30:20
【问题描述】:

我正在构建一个 blazor 组件,如果输入的文本无效,它将恢复为原始输入。 由于ValueText 不会更改渲染过程,因此不会更新/替换用户输入。

<input type="text"
       value="@ValueText"
       @onchange="TextChanged" />

调用StateHasChanged() 不会改变结果。

在我的情况下,ValueText 总是空的。 解决方法是在 null"" 之间交替,这将导致输入被重置。

有没有办法将元素属性标记为“脏”,这样即使虚拟 DOM 没有改变,blazor 渲染也会刷新 DOM?

【问题讨论】:

标签: blazor


【解决方案1】:
ValueText  = "";
await Task.Delay(1); //Magic!  
StateHasChanged();
ValueText  = value;
StateHasChanged();

感谢 https://github.com/dotnet/aspnetcore/issues/17281#issuecomment-620541274

【讨论】:

  • 是的,这是我在那个问题上的评论 :) 关键字是“魔术”,解决方案需要解释它为什么起作用。像这样的奇怪案例今天可能有效,但明天不行,它可能在一种浏览器中有效,但在另一种浏览器中无效。我并不是说这最终不是一个好的解决方案,但我们需要知道为什么。
【解决方案2】:

将设置的值替换为ValueText
这将导致虚拟 DOM 发生变化并导致 DOM 被更新。
通过使用特殊的不可打印的 unicode 字符,它不会影响视觉或交互行为。
由于在执行 diff 算法之前可以多次触发事件,我们不能依赖两个值之间的单个交换,这里我选择了任意 10 个替代值。

最终#17281 将不再需要它。

请务必在解析输入时删除workaroundChar

代替

ValueText = "";

使用

    int workaroundIndex = 0;
    const string workaroundChar = "\u00AD";

    void SetValueText(string? text)
    {
            //Special case for empty values, otherwise the unicode character will hide the placeholder.
            if (string.IsNullOrWhiteSpace(text))
            {
                if (text == null)
                    ValueText = "";
                else
                    ValueText = null;
                return;
            }

            string w = "";
            for (int n = 0; n < workaroundIndex; n++)
                w += workaroundChar;

            ValueText = text + w;

            workaroundIndex = (workaroundIndex + 1) % 10;
    }
}

【讨论】:

    【解决方案3】:

    当您在 Blazor(或 Razor)中设置属性值并且该值为 null 时,该属性将被删除。因此value=@ValueText 不会更新该值。

    将值设置为空字符串可以解决此问题:

    <input type="text" value=@ValueText @onchange="TextChanged" />
    @if (isValid)
    {
        <span class="text-success">✔</span>
    }
    <p>
        Current value is: @ValueText
    </p>
    
    @code
    {
        string ValueText = null;
        bool isValid = false;
    
        void TextChanged(ChangeEventArgs e)
        {
            // only accept values starting with 'a'
            string newValue = (string)e.Value;
            if (!string.IsNullOrEmpty(newValue) && newValue.StartsWith('a'))
            {
                // accept
                ValueText = newValue;
                isValid = true;
            }
            else
            {
                ValueText = "";
                isValid = false;
            }
        }
    }
    

    此示例仅允许以“a”开头的值:

    【讨论】:

    • 对不起,你的例子和我的尝试有同样的问题。在第一次错误输入时,输入文本设置为空,但是在第二次尝试输入无效输入时,输入的文本仍然存在。我的解释是,你的代码和我的一样,都没有修改虚拟 dom,它仍然是 "",所以内容不会被发送到 DOM。
    • 嗯,确实如此。不知道该推荐什么 - 我确实在文档中看到了一个可能指向正确方向的代码示例:docs.microsoft.com/en-us/aspnet/core/blazor/…
    【解决方案4】:

    KISS - 保持简单...

    HTML:

    <input type="file" value="@_fileValue"@onchange="async () => await OpenFileAsync()" />
    

    代码:

    fileValue = _fileValue == null ? "" : null;
    

    【讨论】:

      【解决方案5】:

      你必须创建一个输入值属性,自定义它的setter,并添加一个字段来存储值

      在您的 HTML 部分

      <input @bind=@inputBindValue /> 
      

      然后在 @code 部分

        private string _privateValue = string.Empty;
      
      private string inputBindValue
      {
          get => _privateValue;
      
          set
          {
              if( InputIsValid(value) ) return; // check if valid - if yes, then do nothing
      
              // do stuff if input value is not valid
      
              _privateValue = string.Empty; // empty Your input field value
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2016-12-18
        • 1970-01-01
        • 2021-02-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-09
        • 2012-02-03
        • 1970-01-01
        相关资源
        最近更新 更多