- A+
所属分类:.NET技术
想到动画,你可能会去安装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>
2. 为左侧菜单组件NavMenu.razor添加一个js文件:NavMenu.razor.js
内容如下:
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是当前展示的菜单编码 } } ...省略此处的代码 }
效果图
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"; } } } }