Blazor实现菜单动画

  • Blazor实现菜单动画已关闭评论
  • 155 次浏览
  • A+
所属分类:.NET技术
摘要

想到动画,你可能会去安装Blazor的动画组件BlazorAnimate,然后使用它。本人初学,暂时我也不知道原理,先不用组件,自己实现吧。虽然项目中我用了AntDesignBlazor,但是我忘了使用它的菜单组件,我用的菜单组件还是VS2022自动生成的,后来我把这个菜单改造了一下,支持多级菜单,加了展示收缩箭头,那就在这基础上做吧。

想到动画,你可能会去安装Blazor的动画组件BlazorAnimate,然后使用它。本人初学,暂时我也不知道原理,先不用组件,自己实现吧。虽然项目中我用了AntDesignBlazor,但是我忘了使用它的菜单组件,我用的菜单组件还是VS2022自动生成的,后来我把这个菜单改造了一下,支持多级菜单,加了展示收缩箭头,那就在这基础上做吧。

1. 引用jQuery

这里使用jquery的animate方法实现动画
在wwwroot/js目录放一个jquery-1.9.1.js文件,然后在html(或_Layout.cshtml文件)中引入该js

<script src="js/jquery-1.9.1.js"></script> 

Blazor实现菜单动画

2. 为左侧菜单组件NavMenu.razor添加一个js文件:NavMenu.razor.js

Blazor实现菜单动画
内容如下:

export function animate(index) { //index是菜单编码 2位数是一级菜单,4位数是二级菜单,以此类推     let time = 200;     let content = $(".content" + index);     let h = content.height() + "px";     content.css("overflow", "hidden");      if (index <= 99 || content.hasClass("collapse")) { //index<=99表示一级菜单,一级菜单只有展开动画,没有收缩动画;content.hasClass("collapse")表示当前是收缩状态。         content.css("height", "0");         //展开动画         content.animate({             height: h         }, time, "linear", () => {             content.css("height", "auto");         });     } else { //不是一级菜单并且当前是展开状态,将执行收缩动画         content.css("height", "auto");         //收缩动画         content.animate({             height: 0         }, time, "linear", () => {             setTimeout(function () { //延迟执行,否则会导致闪烁                 content.css("height", "auto");             }, 100);         });         return [time]; //收缩时,需要等待收缩动画展示完成,再隐藏菜单容器div     }     return [0]; } 

3. 在Blazor组件NavMenu.razor文件中引入该js

@inject IJSRuntime _js;  @code {     IJSObjectReference _module;      protected override async void OnAfterRender(bool firstRender)     {         if (firstRender)         {             _module = await _js.InvokeAsync<IJSObjectReference>("import", "./Shared/NavMenu.razor.js");         }     } } 

4. 调用js方法实现菜单动画

@code{     ...省略此处的代码          private async Task ToggleMenuClick(int index)     {         object[] args = new object[] { index };         object[] objs = await _module.InvokeAsync<object[]>("animate", args);         int time = ((JsonElement)objs[0]).GetInt32();         if (time > 0) { await Task.Delay(time); } //time大于0,表示需要等待收缩动画展示完成,再隐藏菜单容器div          if (index > 99)         {             if (_dict.ContainsKey(index))             {                 _dict[index] = !_dict[index]; //记录非一级菜单的展开状态             }             else             {                 _dict[index] = false; //记录非一级菜单的展开状态             }         }         else         {             _index = index; //_index是当前展示的菜单编码         }     }      ...省略此处的代码 } 

效果图

Blazor实现菜单动画

NavMenu.razor页面完整代码如下

@using System.Text.Json; @inject IJSRuntime _js;  <!-- 菜单组 --> <div class="top-row ps-3 navbar navbar-dark" @onclick="@(async ()=>await ToggleMenuClick(01))">     <div class="container-fluid">         <a class="navbar-brand" href="javascript:void(0);">任务管理</a>         <button title="Navigation menu" class="navbar-toggler">             <span class="navbar-toggler-icon"></span>         </button>         <div class="@ArrowClass(01)"></div>     </div> </div>  <!-- 菜单组内容 --> <div class="@MenuGroupContentClass(01)">     <nav class="flex-column">         <div class="nav-item px-3">             <NavLink class="nav-link" href="kpTask/taskList">                 <span class="oi oi-list" aria-hidden="true"></span> 任务列表             </NavLink>         </div>         <div class="nav-item px-3">             <NavLink class="nav-link" href="kpTask/taskRunList">                 <span class="oi oi-list" aria-hidden="true"></span> 任务执行记录             </NavLink>              <!-- 二级菜单组 -->             <NavLink class="nav-link" href="javascript:void(0);" @onclick="@(()=> ToggleMenuClick(0101))" style="display:;">                 <span class="oi oi-list" aria-hidden="true"></span> 测试二级菜单组                 <div class="@ArrowClass(0101)"></div>             </NavLink>              <!-- 二级菜单组内容 -->             <div class="@MenuGroupContentClass(0101)" style="display:;">                 <nav class="flex-column">                     <div class="nav-item px-3">                         <NavLink class="nav-link" href="counter">                             <span class="oi oi-list" aria-hidden="true"></span> 测试二级菜单                         </NavLink>                          <!-- 三级菜单组 -->                         <NavLink class="nav-link" href="javascript:void(0);" @onclick="@(()=> ToggleMenuClick(010101))" style="display:;">                             <span class="oi oi-list" aria-hidden="true"></span> 测试三级菜单组                             <div class="@ArrowClass(010101)"></div>                         </NavLink>                          <!-- 三级菜单组内容 -->                         <div class="@MenuGroupContentClass(010101)" style="display:;">                             <nav class="flex-column">                                 <div class="nav-item px-3">                                     <NavLink class="nav-link" href="counter">                                         <span class="oi oi-list" aria-hidden="true"></span> 测试三级菜单                                     </NavLink>                                 </div>                             </nav>                         </div>                     </div>                     <div class="nav-item px-3">                         <NavLink class="nav-link" href="counter">                             <span class="oi oi-list" aria-hidden="true"></span> 测试二级菜单2                         </NavLink>                     </div>                 </nav>             </div>         </div>     </nav> </div>  <!-- 菜单组 --> <div class="top-row ps-3 navbar navbar-dark" @onclick="@(async ()=>await ToggleMenuClick(02))">     <div class="container-fluid">         <a class="navbar-brand" href="javascript:void(0);">任务管理</a>         <button title="Navigation menu" class="navbar-toggler">             <span class="navbar-toggler-icon"></span>         </button>         <div class="@ArrowClass(01)"></div>     </div> </div>  <!-- 菜单组内容 --> <div class="@MenuGroupContentClass(02)">     <nav class="flex-column">         <div class="nav-item px-3">             <NavLink class="nav-link" href="kpTask/taskList">                 <span class="oi oi-list" aria-hidden="true"></span> 任务列表             </NavLink>         </div>         <div class="nav-item px-3">             <NavLink class="nav-link" href="kpTask/taskRunList">                 <span class="oi oi-list" aria-hidden="true"></span> 任务执行记录             </NavLink>              <!-- 二级菜单组 -->             <NavLink class="nav-link" href="javascript:void(0);" @onclick="@(()=> ToggleMenuClick(0201))" style="display:none;">                 <span class="oi oi-list" aria-hidden="true"></span> 测试二级菜单组                 <div class="@ArrowClass(0201)"></div>             </NavLink>              <!-- 二级菜单组内容 -->             <div class="@MenuGroupContentClass(0201)" style="display:none;">                 <nav class="flex-column">                     <div class="nav-item px-3">                         <NavLink class="nav-link" href="counter">                             <span class="oi oi-list" aria-hidden="true"></span> 测试二级菜单                         </NavLink>                     </div>                 </nav>             </div>         </div>     </nav> </div>  <!-- 菜单组 --> <div class="top-row ps-3 navbar navbar-dark" @onclick="@(async ()=>await ToggleMenuClick(03))">     <div class="container-fluid">         <a class="navbar-brand" href="javascript:void(0);">任务管理</a>         <button title="Navigation menu" class="navbar-toggler">             <span class="navbar-toggler-icon"></span>         </button>         <div class="@ArrowClass(01)"></div>     </div> </div>  <!-- 菜单组内容 --> <div class="@MenuGroupContentClass(03)">     <nav class="flex-column">         <div class="nav-item px-3">             <NavLink class="nav-link" href="kpTask/taskList">                 <span class="oi oi-list" aria-hidden="true"></span> 任务列表             </NavLink>         </div>         <div class="nav-item px-3">             <NavLink class="nav-link" href="kpTask/taskRunList">                 <span class="oi oi-list" aria-hidden="true"></span> 任务执行记录             </NavLink>              <!-- 二级菜单组 -->             <NavLink class="nav-link" href="javascript:void(0);" @onclick="@(()=> ToggleMenuClick(0301))" style="display:none;">                 <span class="oi oi-list" aria-hidden="true"></span> 测试二级菜单组                 <div class="@ArrowClass(0301)"></div>             </NavLink>              <!-- 二级菜单组内容 -->             <div class="@MenuGroupContentClass(0301)" style="display:none;">                 <nav class="flex-column">                     <div class="nav-item px-3">                         <NavLink class="nav-link" href="counter">                             <span class="oi oi-list" aria-hidden="true"></span> 测试二级菜单                         </NavLink>                     </div>                 </nav>             </div>         </div>     </nav> </div>  @code {     int _index = 01;     Dictionary<int, bool> _dict = new Dictionary<int, bool>();     IJSObjectReference _module;      protected override async void OnAfterRender(bool firstRender)     {         if (firstRender)         {             _module = await _js.InvokeAsync<IJSObjectReference>("import", "./Shared/NavMenu.razor.js");         }     }      private async Task ToggleMenuClick(int index)     {         object[] args = new object[] { index };         object[] objs = await _module.InvokeAsync<object[]>("animate", args);         int time = ((JsonElement)objs[0]).GetInt32();         if (time > 0) { await Task.Delay(time); }          if (index > 99)         {             if (_dict.ContainsKey(index))             {                 _dict[index] = !_dict[index];             }             else             {                 _dict[index] = false;             }         }         else         {             _index = index;         }     }      private string MenuGroupContentClass(int index)     {         if (index > 99)         {             if (!_dict.ContainsKey(index) || _dict[index])             {                 return $"collapse content{index}";             }             else             {                 return $"content{index}";             }         }         else         {             if (index == _index)             {                 return $"content{index}";             }             else             {                 return $"collapse content{index}";             }         }     }      private string ArrowClass(int index)     {         if (index > 99)         {             if (!_dict.ContainsKey(index) || _dict[index])             {                 return "arrow-collapse arrow-float";             }             else             {                 return "arrow arrow-float";             }         }         else         {             if (index == _index)             {                 return "arrow";             }             else             {                 return "arrow-collapse";             }         }     }  }