FireFox 和 selected="selected"

FireFox and selected="selected"

注意:我在本文末尾添加了工作示例 post。在我的 FireFox 中,他们演示了这个问题。任何人都可以在您的 FIREFOX 中使用我的示例和重现。我不知道这是不是工作问题。

我想要的只是让我的 Blazor 解决方案在 Edge 和 FireFox 中工作,但后者在 select 列表中没有按预期工作。

我的问题已经被反复讨论4, 10 and 15 years ago yet the solutions discussed are not solving the problem nor are some other 。您可以看到一些修复尝试的残余仍在我的 html 中,例如 selectedIndex = "-1" 并且所有内容都有一个唯一的名称。

下图是select在渲染显示和浏览器开发工具中的初始状态

当我选择第三个或第四个选项时出现问题 - FireFox 将其翻转回第二个选项。在 Edge 中,它坚持我选择的选项。

Blazor 使用基本循环技术生成 select。 (我也试过使用 JSRuntime 设置 selectedIndex)。

<select name="@QuestionItem.Id" style="width: 218px; height:34px;" TValue="Answer" @onchange="SelectChanged">
    <option disabled="" selected="">Select Answer</option>
    @foreach (var a in QuestionItem.Answers)
    {
        // maybe 
        @if (a.IsDisqualified)
        {
            <option disabled="disabled" value="@a.Id">@a.Name</option>
        }
        else
        {
            @if (a.IsSelected)
            {
                <option name="@a.Id" value="@a.Id" selected="selected">@a.Name</option>
            }
            else
            {
                <option name="@a.Id" value="@a.Id">@a.Name</option>
            }
        }
    }
</select>

驱动循环的对象有一个 IsSelected 属性,它让 Blazor 写出一个 <option selected="selected"> 元素。 @onchange 事件将新选择的选项提交给数据库并运行一系列业务规则。

现在,我将演示这个问题。

使用 Edge,我选择了“完全安装”选项并且它表现良好 - select 正确呈现“完全安装”和 html在同一个选项上有 selected="selected"

现在我用 FireFox 重复这些步骤。这里又是默认状态。

我再次选择“完全安装”,但现在出现了不一致的状态 - select 变为“否”,但 html 显示“完整安装”已 selected.

无论如何,正确的值会写入数据库,因此在刷新 FireFox 时会显示正确的 selected 选项。似乎不可思议的是 Web 开发人员已经忍受了这个或者 Mozilla 一直没有解决这个问题。那我做错了什么?

我的 FireFox 版本是 78.11.0esr(64 位)。

这是一个重现问题的简单示例。

@page "/Select"
<h3>Select</h3>

@if (SelectData != null)
{
<div class="form-group col-md-6">
    <label for="dur">Duration</label>
    <select class="custom-select" @onchange="this.SelectChanged">
        <option disabled value="-1" selected>Select an Option</option>
        @foreach (var duration in SelectData)
        {
            @if (duration.IsSelected)
            {
            <option value="@duration.Name" selected>@duration.Name</option>
            }
            else
            {
            <option value="@duration.Name">@duration.Name</option>
            }
        }
    </select>
</div>
}
else
{
    <label>Loading</label>
}

<div class="p-2 m-2">
    Current Value : @_Duration.Name
</div>
<div class="p-2 m-2">
    IsSelected : @_Duration.IsSelected
</div>


@code {
    private class Duration
    {
        public string Name { get; set; }
        public bool IsSelected { get; set; }
    }

    private Duration _Duration = new Duration();


    private void SelectChanged(ChangeEventArgs e)
    {
        var selected = SelectData.SingleOrDefault(t => t.Name == (string)e.Value);

        if (selected != null)
        {
            _Duration = selected;
            _Duration.IsSelected = true;
        }
    }

    private List<Duration> SelectData = new List<Duration>
{
        new Duration{ Name = "Hello1", IsSelected = false},
        new Duration{ Name = "Hello2", IsSelected = false},
        new Duration{ Name = "Hello3", IsSelected = false},
    };
}

这是一个略有不同的示例,但具有相同的 FF 问题

@page "/Select"
<h3>Select</h3>

@if (SelectData != null)
{
<div class="form-group col-md-6">
    <label for="dur">Duration</label>
    <select class="custom-select" @onchange="this.SelectChanged">
        <option disabled selected>Select an Option</option>
        @foreach (var duration in SelectData)
        {
            @if (_Duration == duration)
            {
            <option value="@duration.Name" selected>@duration.Name</option>
            }
            else
            {
            <option value="@duration.Name">@duration.Name</option>
            }
        }
    </select>
</div>
}
else
{
    <label>Loading</label>
}

<div class="p-2 m-2">
    Current Value : @_Duration.Name
</div>
<div class="p-2 m-2">
    IsSelected : @_Duration.IsSelected
</div>


@code {
    private class Duration
    {
        public string Name { get; set; }
        public bool IsSelected { get; set; }
    }

    private Duration _Duration = new Duration();


    private void SelectChanged(ChangeEventArgs e)
    {
        var selected = SelectData.SingleOrDefault(t => t.Name == (string)e.Value);

        if (selected != null)
        {
            _Duration = selected;
            _Duration.IsSelected = true;
        }
    }

    private List<Duration> SelectData = new List<Duration>
    {
        new Duration{ Name = "Hello1", IsSelected = false},
        new Duration{ Name = "Hello2", IsSelected = false},
        new Duration{ Name = "Hello3", IsSelected = false},
    };

    protected override async Task OnInitializedAsync()
    {
        var a = SelectData.FirstOrDefault(t => t.IsSelected);
        if (a != null)
            _Duration = a;
    }
}

由于您没有提供代码,但此处的屏幕截图是一个独立的 Blazor 页面,我相信它概括了您的问题。我错过了您的一些代码位。我还没有测试它是否会在你的屏幕截图上显示所有额外的位,这是有原因的,据我所知它是有效的(引用“正如它在罐头上所说的那样”)。

@page "/Select"
<h3>Select</h3>
<div class="form-group col-md-6">
    <label for="dur">Duration</label>
    <select @bind="Duration" class="custom-select">
        <option disabled value="-1" selected>Select an Option</option>
        @foreach (var kvp in SelectData)
        {
            <option value="@kvp.Key">@kvp.Value</option>
        }
    </select>
</div>
<div class="p-2 m-2">
    Current Value : @_Duration
</div>


@code {
    private string _Duration;

    private string Duration
    {
        get => _Duration;
        set
        {
            if (value != _Duration)
            {
                _Duration = value;
            }
        }
    }

    private Dictionary<int, string> SelectData = new Dictionary<int, string>()
    {
        { 11746, "No"},
        { 11747, "Provision Only"},
        { 11748, "Full Installation"}
    };
}

我的 Firefox 是“88.0.1”。 64 位。 Windows10.

请告诉我您在此演示中的问题出在哪里?

这是 onchanged 版本:

@page "/Select"
<h3>Select</h3>

<div class="form-group col-md-6">
    <label for="dur">Duration</label>
    <select class="custom-select" @onchange="this.SelectChanged">
        <option disabled value="-1" selected>Select an Option</option>
        @foreach (var kvp in SelectData)
        {
            <option value="@kvp.Key">@kvp.Value</option>
        }
    </select>
</div>
<div class="p-2 m-2">
    Current Key : @_Duration
</div>
<div class="p-2 m-2">
    Current Value : @_DurationValue
</div>


@code {
    private string _Duration;

    private string _DurationValue;

    private string Duration
    {
        get => _Duration;
        set
        {
            if (value != _Duration)
            {
                _Duration = value;
            }
        }
    }

    private void SelectChanged(ChangeEventArgs e)
    {
        _Duration = e.Value.ToString();
        if (int.TryParse(e.Value.ToString(), out int value))
            _DurationValue = SelectData[value];

    }

    private Dictionary<int, string> SelectData = new Dictionary<int, string>()
{
        { 11746, "No"},
        { 11747, "Provision Only"},
        { 11748, "Full Installation"}
    };
}

如果您使用完全相同的代码生成了 Edge 和 FF 标记,那么当您尝试为他们。

我记得曾几何时不得不使用 disabled="disabled" 之类的东西,但据我所知,现在的标准只是包含没有值的标志名称。 我的猜测是您的代码行 <option disabled="" selected="">Select Answer</option> 由 Edge 处理得更好,而由 FF 处理得更差,但原因是您提供的标记不明确。

你能从 3 处改变开始,让我知道它是否适合你吗?

  • 删除“SelectedIndex=-1”行,因为它没有任何作用。您将在 @onchange 和您的标题选项中发送您的价值 无法选择,因为它已被禁用。
  • 将标题行修改为<option disabled selected>Select Answer</option>
  • 将所有 selected = "selected" 项更改为仅 selected 并执行 disabled 也一样。

以下在 FF 中对我来说效果很好。注意:

-您不必为标题选项设置 -1 值

-由于您是直接初始化 SelectData ,因此它不会为空。

@page "/Select"
<h3>Select</h3>

<div class="form-group col-md-6">
    <label for="dur">Duration</label>
    <select class="custom-select" @onchange="this.SelectChanged">
        <option disabled selected>Select an Option</option>
        @foreach (var duration in SelectData)
        {
            if (duration == _Duration)
            {
                <option value="@duration.Name" selected>@duration.Name</option>
            }
            else
            {
                <option value="@duration.Name">@duration.Name</option>
            }
        }
    </select>
</div>


<div class="p-2 m-2">
    Current Value : @_Duration.Name
</div>
<div class="p-2 m-2">
    Duration : @_Duration.Value.ToString()
</div>


@code {
    private class Duration
    {
        public string Name { get; set; }
        public TimeSpan Value { get; set; }
    }

    private Duration _Duration = new Duration();


    private void SelectChanged(ChangeEventArgs e)
    {
        _Duration = SelectData.SingleOrDefault(t => t.Name == (string)e.Value);
    }

    private List<Duration> SelectData = new List<Duration>
{
        new Duration{ Name = "Hello1", Value= new TimeSpan(1, 30, 0)},
        new Duration{ Name = "Hello2", Value= new TimeSpan(3, 0, 0)},
        new Duration{ Name = "Hello3", Value= new TimeSpan(10, 0, 0)},
    };

    protected override async Task OnInitializedAsync()
    {
        _Duration = SelectData[2]; // Do your awaitable DB stuff here.
    }
}

这是一个完整的解决方案...复制并粘贴,运行 并测试。

@page "/"


@if (SelectData != null)
{
    <div class="form-group col-md-6">
        <label for="dur">Duration</label>
        <select class="custom-select" @onchange="this.SelectChanged">
            <option disabled selected>Select an Option</option>
            @foreach (var duration in SelectData)
            {
                  <option value="@duration.Name" selected="@duration.IsSelected">@duration.Name</option>
               
            }
        </select>
    </div>

   
}
else
{
    <label>Loading</label>
}

<span class="p-2 m-2">
    Current Value : @_Duration.Name
</span>
<span class="p-2 m-2">
    IsSelected : @_Duration.IsSelected
</span>
<br />
<div>
@foreach (var duration in SelectData)
 {
     <div>@duration.Name: @duration.IsSelected</div>
 }
</div>


@code {
    private class Duration
    {
        public string Name { get; set; }
        public bool IsSelected { get; set; }
    }

    private Duration _Duration = new Duration();


    private void SelectChanged(ChangeEventArgs e)
    {
        var selected = SelectData.SingleOrDefault(t => t.Name == (string)e.Value);

           
        if (selected != null)
        {
            _Duration = selected;
            _Duration.IsSelected = true;
        }
    }

    private List<Duration> SelectData = new List<Duration>
{
        new Duration{ Name = "Hello1", IsSelected = false},
        new Duration{ Name = "Hello2", IsSelected = false},
        new Duration{ Name = "Hello3", IsSelected = false},
        new Duration{ Name = "Hello4", IsSelected = false}
    };
} 

编辑

John Mc,selected="@duration.IsSelected" 不是 Html。这是呈现为空 Html selected 属性或 selected="" 的 Razor 标记,具体取决于所使用的浏览器。这就是在 Blazor 中执行此操作的方法(尽管在当前情况下,您可以仅应用没有值的 selected 属性。也就是说,您可以编写:

@if (_Duration == duration)
{ 
  <option value="@duration.Name" selected>@duration.Name</option>
}

),意思是selected属性的值是Blazor团队处理的,如果求值为true,则selectedHtml属性添加,如果它被评估为“false”,它会被完全省略,然后在浏览器中呈现为 Html。

您提供的答案 link 处理 Html,这里不是这种情况。上面的@if语句不是Html。它是 Razor 标记。 Html 是浏览器呈现的标记。无论如何,答案至少可以说是有问题的,我认为回答者不了解Html、编码等基础知识。并不是说我是那个专家……我什至不是一个开发者。我已经部分阅读了他的回答,这是我的输入,没有通过代码验证。如果您愿意,可以自己做:

selectedHtml属性为空属性;也就是说,它的存在指示浏览器 select 给定的 option.If 不存在,则不会产生 selection。如果您使用 selected="false",给定的选项将被 selected。如果您使用 selected="Not false",给定的选项将被 selected。如果您使用 selected="Whosebug",给定的选项将被 selected。你明白这个想法吗?验证我是否正确...如果正确,请对答案投反对票。

总而言之,根据您真正想做的事情,有很多更好的方法可以实现。最重要的是,您应该使用两种方式的数据绑定,以及 @bind 属性。您知道您使用的是单向数据绑定吗?