iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 18
4
Modern Web

大內魔術 Blazor - 誰說前端一定要寫JS系列 第 18

魔術技巧 - 取得元件參考

  • 分享至 

  • xImage
  •  

Blazor WebAssembly 的核心就是元件,所以今天也是介紹元件的觀念。


當我們建立元件後,外部除了使用 UI 外,其實是可以存取公開成員的,只需要透過 @ref 指示詞,將 @ref 屬性新增至子元件,並且使用與子元件相同的類型來定義欄位,就可以輕鬆取得元件的公開成員了,如:

<Child @ref="Child"></Child>

@code {
  private Child Child;
}

要注意元件渲染完成後才會填入子元件的實體!也就是 OnAfterRender/OnAfterRenderAsync 方法後才能夠存取其成員。

在使用子元件的方法時,如果直接這樣寫:

<button type="button" @onclick="Child.PublicFunction">Child Funtion</button>

執行時期就會直接噴錯,因為 Child 實體還沒有被填充,這時候就可以透過表達式來確保在指派事件處理常式之前,會先指派參考變數:

<button type="button" @onclick="@(()=> Child.PublicFunction())">Child Funtion</button>

倘若是透過迴圈來產生子元件,要取得所有實體可以參考此技巧:

@for (int i = 0; i < 10; i++)
{
    <Child @ref="component" />
}

@code {
  Child component { set => components.Add(value); }
  List<Child> components = new List<Child>();
}

這樣在被填入實體時,設定的方法會轉為新增在列表中,但如果你是懶人,不想要使用這方式,這邊推薦你一個黑魔法:

@for (int i = 0; i < 10; i++)
{
    <Day18SampleChild @ref="components.Add((Day18SampleChild)__value);//" />
}

@code {
  List<Child> components = new List<Child>();
}

這邊的 __value 與後面的 // 我還沒搞清楚,如果之後弄懂了會再發一篇來講解,或者有路過大神再請大神幫忙講解,感謝。

以上就是存取元件實體的方法,是不是很簡單啊?


但存取元件實體這種事情,有時候是為了實現 Focus, Click 等等事件時的目標,但這個好像並不能解決耶?

那是因為 Blazor WebAssembly 在渲染時,並不會像 Angular(或者其他前端框架) 多包一層 component 的標籤,也就是 Blazor WebAssembly 的 Component 並不會存在於 UI 上

那麼如果我們需要在特定事件發生時,Focus 在指定元素時,我們應該怎麼處理?

這時候一樣是透過 @ref 來取得元素實體參考,但對象不能是元件,而是 input, button 等等原生標籤,並且以 ElementReference 型別來做為參數類型:

<input @ref="inputRef" />

@code{
  private ElementReference inputRef;
}

但是 ElementReference 型別只有一個 Id 成員,並不能實現上面的需求,因為這時候是需要將資訊交給 JavaScript,由 JavaScript 來幫我們處理。

雖然開場說大話表示不用寫 JavaScript 也能寫網頁,但那種情況真的滿狹隘的,除非之後的更新處理好了這塊。

因為本篇的重點不想放太多在 JavaScript 的使用上,會在後續文章將針對JS interop詳細介紹,所以這邊將快速帶過用法。

建立 exampleJsInterop.js 檔案其內容為:

window.exampleJsFunctions = {
    focusElement: function (element) {
        element.focus();
    }
}

記得在 index.html 中引用:

<script src="../js/exampleJsInterop.js"></script>

然後回到我們的元件來,只需要注入 IJSRuntime 並使用其 InvokeVoidAsync 方法就可以使用剛剛撰寫的 JS 方法了。

@inject IJSRuntime JSRuntime

@code {
public async Task SetFocus()
  {
    await JSRuntime.InvokeVoidAsync(
           "exampleJsFunctions.focusElement", InputRef);
  }
}

只要呼叫 SetFocus 方法,就能夠正確 focus 在 input 上了,這樣了解了嗎?


以上就是元件參考的取得方法了,是不是很簡單呀?一樣有我寫的範例程式碼 - day18

感謝大家的閱讀,我們明天見。

參考資料
捕獲元件的參考
Capture references to multiple similar child-components #13358


上一篇
魔術技巧 - 樣板化元件
下一篇
魔術技巧 - 版型配置
系列文
大內魔術 Blazor - 誰說前端一定要寫JS30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言