封装一个可以左右滑动的Blazor组件
阅读原文时间:2023年07月23日阅读:1

为什么要封装组件

最近写MAUI Blazor的时候,总是苦于对移动端没有什么好的支持,没有一个能左右滑动的tab切换组件。

既然没有,那就自己封装一个。

简单了解轮播图、tab切换的库之后,决定使用根据Swiper来封装。

Swiper是js的插件,所以需要js与.NET互操作,有以下两点

  • 当js中的索引变化时,调用.NET方法改变Blazor中的索引;
  • 当Blazor中的索引变化时,调用js方法改变js中的索引。

准备工作

下载Swiper,一个js文件和一个css文件,swiper-bundle.min.jsswiper-bundle.min.css

最好用7的版本,8的版本会有一些兼容问题。

将文件引入index.html

Blazor部分

如官网所示,swiper的结构如下

<div class="swiper">
  <div class="swiper-wrapper">
    <div class="swiper-slide">slider1</div>
    <div class="swiper-slide">slider2</div>
    <div class="swiper-slide">slider3</div>
  </div>
</div>

所以我们的组件分为两部分,一个外壳,一个是可重复的内容。

分别命名为SwiperTabItems.razorSwiperTabItem.razor

SwiperTabItems.razor
@inject IJSRuntime JSRuntime

<div class="@("swiper " + Id)">
    <div class="swiper-wrapper">
        @ChildContent
    </div>
</div>
@code{
[Parameter]
        public int Value
        {
            get => _value;
            set
            {
                if (_value != value)
                {
                    _value = value;
                    if(AfterFirstRender)
                    {
                        UpdateSwiper(value);
                    }
                }
            }
        }
        [Parameter]
        public EventCallback<int> ValueChanged { get; set; }
        [Parameter]
        public RenderFragment? ChildContent { get; set; }

        private int _value = 0;
        private bool AfterFirstRender;
        private string Id = "swiper" + Guid.NewGuid().ToString();

        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            if (firstRender && ChildContent is not null)
            {
                var dotNetCallbackRef = DotNetObjectReference.Create(this);
                await JSRuntime!.InvokeVoidAsync("swiperInit", new object[4] { dotNetCallbackRef, "UpdateValue", Id, Value });
                AfterFirstRender = true;
            }
        }
        private async void UpdateSwiper(int value)
        {
            await JSRuntime!.InvokeVoidAsync($"{Id}.slideTo", new object[1] { value });
        }
        [JSInvokable]
        public async Task UpdateValue(int value)
        {
            _value = value;
            if (ValueChanged.HasDelegate)
            {
                await ValueChanged.InvokeAsync(value);
            }
            StateHasChanged();
        }

        public async void Dispose()
        {
            await JSRuntime!.InvokeVoidAsync($"{Id}.destroy", new object[2] { true, true });
        }
}
SwiperTabItem.razor
<div class="swiper-slide">
    @ChildContent
</div>

@code {
    [Parameter]
    public RenderFragment? ChildContent { get; set; }
}

注:

1.id使用guid是为了如果存在多个组件,js的实例化不会重复

2.OnAfterRenderAsync是blazor的一个生命周期,位于渲染之后,将swiper的初始化实例放在这个位置才能正确初始化。firstRender 代表第一次渲染。

js部分

如swiper官网所示,需要初始化实例

<script>
var mySwiper = new Swiper('.swiper', {
    autoplay: true,//可选选项,自动滑动
})
</script>

所以我们需要写一个init-swiper.js文件,包含初始化实例的函数,以供Blazor的调用

init-swiper.js
function swiperInit(dotNetCallbackRef, callbackMethod,id,index) {
    console.log('Entered initSwiper!');
    let className = "." + id;
    window[id] = new Swiper(className, {
        observer: true,
        observeParents: true,
        observeSlideChildren: true,
        autoHeight: true,
        initialSlide: index,
        on: {
            slideChangeTransitionStart: function () {
                dotNetCallbackRef.invokeMethodAsync(callbackMethod, this.activeIndex);
                //alert(this.activeIndex);//切换结束时,告诉我现在是第几个slide
            },
        }
    });
}

init-swiper.js引入index.html

使用

<SwiperTabItems @bind-Value="tabs">
    <SwiperTabItem>
        你的内容1
    </SwiperTabItem>
    <SwiperTabItem>
        你的内容2
    </SwiperTabItem>
    <SwiperTabItem>
        你的内容3
    </SwiperTabItem>
</SwiperTabItems>

演示

这个封装的比较简单,如果需要更多的属性,可以看看swiper的文档

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器