Blazor - 组件包装和数据绑定
Posted
技术标签:
【中文标题】Blazor - 组件包装和数据绑定【英文标题】:Blazor - Component wrapping and data binding 【发布时间】:2020-12-19 14:47:01 【问题描述】:我在 blazor 组件中进行了范围输入。 现在我正在尝试进行对数范围输入。
为此,我想使用我的第一个范围输入,并简单地在范围输入中的假值和真实值之间进行包装。
但是我觉得我对组件绑定的理解还不够,索引页面没有被通知修改。
这是范围输入组件:
<div id="rc-@ID">
@(new MarkupString($@"<style>
#rc-ID
position: relative;
width: 100%;
#rc-ID > input[type='range']
padding: 0;
margin: 0;
display: inline-block;
vertical-align: top;
width: 100%;
--range-color: hsl(211deg 100% 50%);
background: var(--track-background);
#rc-ID > input[type='range']::-moz-range-track
border-color: transparent; /* needed to switch FF to 'styleable' control */
#rc-ID > input[name='low-range']
position: absolute;
#rc-ID > input[name='low-range']::-webkit-slider-thumb
position: relative;
z-index: 2;
#rc-ID > input[name='low-range']::-moz-range-thumb
transform: scale(1); /* FF doesn't apply position it seems */
z-index: 1;
#rc-ID > input[name='high-range']
position: relative;
--track-background: linear-gradient(to right, transparent (int)(100 * (LowerValue - MinBound) / (MaxBound - MinBound) + 1 + 0.5f)%, var(--range-color) 0, var(--range-color) (int)(100 * (HigherValue - MinBound) / (MaxBound - MinBound) - 1 + 0.5f)%, transparent 0 ) no-repeat 0 50% / 100% 100%;
background: linear-gradient(to right, gray (int)(100 * (LowerValue - MinBound) / (MaxBound - MinBound) + 1+ 0.5f)%, transparent 0, transparent (int)(100 * (HigherValue - MinBound) / (MaxBound - MinBound) - 1 + 0.5f)%, gray 0 ) no-repeat 0 50% / 100% 30%
#rc-ID > input[type='range']::-webkit-slider-runnable-track
background: var(--track-background);
#rc-ID > input[type='range']::-moz-range-track
background: var(--track-background);
</style>"))
<input class="custom-range" name="low-range" type="range" min="@MinBound" max="@MaxBound" step="@Step" @bind="@LowerValue" @bind:event="oninput" />
<input class="custom-range" name="high-range" type="range" min="@MinBound" max="@MaxBound" step="@Step" @bind="@HigherValue" @bind:event="oninput" />
</div>
@code
[Parameter] public float MinBound get; set; = 0;
[Parameter] public float MaxBound get; set; = 1;
[Parameter] public float Step get; set; = 0.01f;
[Parameter]
public float? ValueLow
get
var res = Math.Min(_valueLow, _valueHigh);
if (res == MinBound)
return null;
return res;
set
if (!value.HasValue)
if (_valueLow.Equals(MinBound))
return;
_valueLow = MinBound;
else
if (_valueLow.Equals(value.Value))
return;
_valueLow = value.Value;
if (_valueLow > _valueHigh)
_valueLow = _valueHigh;
_valueHigh = value.Value;
ValueHighChanged.InvokeAsync(_valueHigh);
if (_valueLow == MinBound)
ValueLowChanged.InvokeAsync(null);
else
ValueLowChanged.InvokeAsync(_valueLow);
[Parameter]
public float? ValueHigh
get
var res = Math.Max(_valueLow, _valueHigh);
if (res == MaxBound)
return null;
return res;
set
if (!value.HasValue)
if (_valueHigh.Equals(MaxBound))
return;
_valueHigh = MaxBound;
else
if (_valueHigh.Equals(value.Value))
return;
_valueHigh = value.Value;
if (_valueLow > _valueHigh)
_valueHigh = _valueLow;
_valueLow = value.Value;
ValueLowChanged.InvokeAsync(_valueLow);
if (_valueHigh == MaxBound)
ValueHighChanged.InvokeAsync(null);
else
ValueHighChanged.InvokeAsync(_valueHigh);
[Parameter] public EventCallback<float?> ValueLowChanged get; set;
[Parameter] public EventCallback<float?> ValueHighChanged get; set;
float _valueLow = 0;
float _valueHigh = 1;
private float LowerValue
get => Math.Min(_valueLow, _valueHigh);
set => ValueLow = value;
private float HigherValue
get => Math.Max(_valueLow, _valueHigh);
set => ValueHigh = value;
string ID = Guid.NewGuid().ToString().Replace("-", "").Substring(15);
这是我的 Range 输入日志组件:
<RangeControl @bind-ValueLow="Low"
@bind-ValueHigh="High"
MaxBound="max"
MinBound="min"
Step="1" />
<div class="d-flex">
<strong>Log values : </strong>
<span>@Low</span>
<span class="ml-2">@High</span>
</div>
@code
private float min = 1.0f;
private float max = 100.0f;
[Parameter] public float MinBound get; set; = 10;
[Parameter] public float MaxBound get; set; = 10000;
[Parameter] public float Step get; set; = 1;
private float r => MinBound == 0 ? MaxBound : (MaxBound / MinBound);
private float? _valueLow;
[Parameter]
public float? ValueLow
get => _valueLow;
set
if (value == _valueLow) return;
_valueLow = value;
ValueLowChanged.InvokeAsync(ValueLow);
private float? _valueHigh;
[Parameter]
public float? ValueHigh
get => _valueHigh;
set
if (value == _valueHigh) return;
_valueHigh = value;
ValueHighChanged.InvokeAsync(ValueHigh);
private float? Low
get
if (ValueLow.HasValue)
return (float)((min = max) * Math.Log(ValueLow.Value) / Math.Log(r));
return null;
set
if (value.HasValue)
ValueLow = (float)Math.Exp(value.Value * Math.Log(r) / (max - min));
else
ValueLow = null;
private float? High
get
if (ValueHigh.HasValue)
return (float)((min = max) * Math.Log(ValueHigh.Value) / Math.Log(r));
return null;
set
if (value.HasValue)
ValueHigh = (float)Math.Exp(value.Value * Math.Log(r) / (max - min));
else
ValueHigh = null;
[Parameter] public EventCallback<float?> ValueLowChanged get; set;
[Parameter] public EventCallback<float?> ValueHighChanged get; set;
还有索引页:
@page "/"
<h1>Hello, world!</h1>
<RangeControl @bind-ValueHigh="ValueHigh" @bind-ValueLow="ValueLow" MinBound="10" MaxBound="10000" Step="1"></RangeControl>
<br />
<RangeControlLog @bind-ValueHigh="ValueHigh" @bind-ValueLow="ValueLow" MinBound="10" MaxBound="10000" Step="1"></RangeControlLog>
<div class="d-flex">
<strong>Real values : </strong>
<span>@ValueLow</span>
<span class="ml-2">@ValueHigh</span>
</div>
@code
float? ValueHigh = null;
float? ValueLow = null;
【问题讨论】:
【参考方案1】:您不能嵌套@bind-
,即拥有一个使用被包装组件的@bind-
的包装器,并且还公开一个与@bind-
一起使用的属性。
您需要将Foo
和FooChanged
传递给被包装的组件。
这意味着在您的RangeControlLog
中,您需要传递给RangeControl
ValueLow
和ValueLowChanged
而不是使用@bind-ValueLow
<RangeControl ValueLow="Low"
ValueHigh="High"
ValueLowChanged="ValueLowChanged"
ValueHighChanged="ValueHighChanged"
MaxBound="max"
MinBound="min"
Step="1" />
要了解更多信息,您可以查看有关 chained binding 的文档,也可以查看我制作的 this question,以更好地了解 ValueChanged
及其工作原理。
但简而言之,当您使用@bind-Foo="Bar"
时,它会将其转换为Foo="Bar"
、FooChanged="@(foo => Bar = foo;)"
,它们是用于更新属性的一种默认值。但是当你有多个@bind-
时它不起作用,所以你需要直接传递它。
对我来说,@bind-
看起来像是绑定属性的语法糖,当你有参数Foo
和FooChanged
时,你可以使用@bind-Foo
。
【讨论】:
以上是关于Blazor - 组件包装和数据绑定的主要内容,如果未能解决你的问题,请参考以下文章