WPF中在MVVM模式下实现导航功能
WPF中在MVVM模式下实现导航功能
一、利用TabControl
使用场景:项目小,不用考虑内存开销的问题。
实现方式1-手动指定ViewModel
- 分别定义3个
UserControl
作为View用于演示
<UserControl...><Grid><StackPanel Orientation="Vertical"><TextBlockHorizontalAlignment="Center"VerticalAlignment="Top"Text="Page 1" /><TextBlockd:Text="Page 1"FontSize="50"Text="{Binding PageMessage}" /></StackPanel></Grid></UserControl>
- 分别定义ViewModel
public abstract class PageViewModelBase {public string? Header { get; set; }}public class MainViewModel {public List<PageViewModelBase> ViewModels { get; }public MainViewModel(Page1ViewModel p1, Page2ViewModel p2, Page3ViewModel p3){ViewModels = new List<PageViewModelBase> { p1, p2, p3 };}}public class Page1ViewModel : PageViewModelBase{public Page1ViewModel() => Header = "Page 1";public string PageMessage { get; set; } = "Hello, Page 1";}public class Page2ViewModel : PageViewModelBase{public Page2ViewModel() => Header = "Page 2";public string PageMessage { get; set; } = "Hello, Page 2";}public class Page3ViewModel : PageViewModelBase{public Page3ViewModel() => Header = "Page 3";public string PageMessage { get; set; } = "Hello, Page 3";}
- 在MainWindow上定义Tabcontrol
<Window...><Grid><TabControl ItemsSource="{Binding ViewModels}"><TabItem Header="Pag1"><view:Page1><view:Page1.DataContext><local:Page1ViewModel /></view:Page1.DataContext></view:Page1></TabItem><TabItem Header="Pag2"><view:Page1><view:Page1.DataContext><local:Page2ViewModel /></view:Page1.DataContext></view:Page1></TabItem><TabItem Header="Pag3"><view:Page1><view:Page1.DataContext><local:Page3ViewModel /></view:Page1.DataContext></view:Page1></TabItem></TabControl></Grid></Window>
这种方式需要手动指定每个View的ViewModel
实现方式2-利用ItemTemplate
- 在MainViewModel中声明一个ViewModel列表
public class MainViewModel
{public List<PageViewModelBase> ViewModels { get; }public MainViewModel(Page1ViewModel p1, Page2ViewModel p2, Page3ViewModel p3){ViewModels = new List<PageViewModelBase> { p1, p2, p3 };}
}
- 在MainWindow中为TabControl指定ItemTemplate,上一步声明的ViewModel列表作为 TabControl 的 ItemsSource;为 TabControl.Resources 添 加多个 DataTemplate,指定 VM 对应什么样的 Page
<Window d:DataContext="{d:DesignInstance Type=local:MainViewModel}"....><Grid><TabControl ItemsSource="{Binding ViewModels}"><TabControl.ItemTemplate><DataTemplate><TextBlock Text="{Binding Header}"/></DataTemplate></TabControl.ItemTemplate><TabControl.Resources><DataTemplate DataType="{x:Type local:Page1ViewModel}"><view:Page1/></DataTemplate><DataTemplate DataType="{x:Type local:Page2ViewModel}"><view:Page2/></DataTemplate><DataTemplate DataType="{x:Type local:Page3ViewModel}"><view:Page3/></DataTemplate></TabControl.Resources> </TabControl></Grid>
</Window>
这样的好处是自动会为不同的View绑定了相应的ViewModel。
小技巧:在xaml中加上了d:DataContext="{d:DesignInstance Type=local:MainViewModel}
,这样在写Binding的时候就有了智能提示。
以上两种方式均可结合依赖注入的方式来实现
二、自定义NavigationService服务
- 实现一个NavigationService服务,并作为单例
class NavigationService{//设置一个单例服务public static NavigationService Instance { get; private set; } = new NavigationService();//声明一个事件,当更改CurrentViewModel时触发public event Action? CurrentViewModelChanged;//设置一个当前VM的属性,并在属性改变时触发CurrentViewModelChangedprivate ViewModelBase? currentViewModel;public ViewModelBase? CurrentViewModel{get => currentViewModel;set{currentViewModel = value;CurrentViewModelChanged?.Invoke();}}//页面导航方法,给CurrentViewModel赋值,触发CurrentViewModelChanged事件public void NavigateTo(ViewModelBase viewModel)=>CurrentViewModel = viewModel;}
- 设置MainViewModel中的CurrentViewModel属性
public class ViewModelBase : ObservableObject{}public partial class MainViewModel : ViewModelBase{[ObservableProperty]private ViewModelBase? currentViewModel;//当前的VMpublic MainViewModel(){//为事件绑定委托方法,设置CurrentVM和NavigationService中的CurrentVM保持一致NavigationService.Instance.CurrentViewModelChanged += () =>{CurrentViewModel = NavigationService.Instance.CurrentViewModel;};//调用导航方法NavigationService.Instance.NavigateTo(new LoginViewModel());}}
其他两个ViewModel分别为
public partial class LoginViewModel : ViewModelBase{[ObservableProperty]string? userName = "Sean";[RelayCommand]void Login(){NavigationService.Instance.NavigateTo(new HomeViewModel());}}public partial class HomeViewModel : ViewModelBase{[ObservableProperty]string? userName;[RelayCommand]void Logout(){NavigationService.Instance.NavigateTo(new LoginViewModel());}}
- 使用ContentControl作为MainWindow上不同页面载体显示内容,并借助DataTemplate来实现View和ViewModel的映射
<Window ...><ContentControl Content="{Binding CurrentViewModel}"><ContentControl.Resources><DataTemplate DataType="{x:Type vm:LoginViewModel}"><view:Login /></DataTemplate><DataTemplate DataType="{x:Type vm:HomeViewModel}"><view:Home /></DataTemplate></ContentControl.Resources></ContentControl></Window>
在ContentControl.Resources中设置DataTemplate,根据DataType自动选择相应的VM,这样做的好处是会自动将View和VM进行了绑定。
改进
- 单例方式可以采用依赖注入的方式来实现
- 在NavigationService服务中,可以改进页面导航的方法
public void NavigateTo<T>() where T : ViewModelBase=> CurrentViewModel = App.Current.Services.GetService<T>();//在调用导航方法时可以使用
navigationService.NavigateTo<HomeViewModel>();
三、借助ValueConverter
实现上一章节的功能,这种方法本质上是通过View来自动绑定VM。
- 定义Page的枚举
public enum ApplicationPage{Empty,Login,Home}
- 定义各ViewModel
public class ViewModelBase : ObservableObject{}public partial class MainViewModel : ViewModelBase{//MainViewModel中的CurrentPage是一个枚举类型[ObservableProperty]ApplicationPage currentPage;public MainViewModel(){CurrentPage = ApplicationPage.Login;}}public partial class LoginViewModel : ViewModelBase{public string UserName { get; set; } = "AngelSix";[RelayCommand]void Login(){var mainVM= App.Current.MainWindow.DataContext as MainViewModel;mainVM!.CurrentPage = ApplicationPage.Home;}}public partial class HomeViewModel : ViewModelBase{[RelayCommand]void Logout(){var mainVM = App.Current.MainWindow.DataContext as MainViewModel;mainVM!.CurrentPage = ApplicationPage.Login;}}
-
定义Page基类和各个Page
这种方法本质上是通过View来自动绑定VM,所以在此处使用泛型
public abstract class BasePage<VM> : UserControl where VM : ViewModelBase, new(){public BasePage(){DataContext = new VM();}}
- 实现Home页面
将Home.xaml.cs中的继承删掉,以为它和Home.xaml相互为分部类,只在一个分部类上实现继承就可以。
<local:BasePage x:TypeArguments="vm:HomeViewModel"...><!--x:TypeArguments指定泛型--><Grid><TextBlock HorizontalAlignment="Center"VerticalAlignment="Center"Text="Home"FontSize="32" /><Button Margin="10" Grid.Row="1"HorizontalAlignment="Right"VerticalAlignment="Bottom"Content="Logout"Command="{Binding LogoutCommand}" /></Grid></local:BasePage>
- 实现Login页面
方法和实现Home页面方法相同
<local:BasePagex:TypeArguments="vm:LoginViewModel" ...><Grid><BorderPadding="10"HorizontalAlignment="Center"VerticalAlignment="Center"BorderBrush="LightGray"BorderThickness="1"CornerRadius="10"><StackPanel Width="300"><TextBlock HorizontalAlignment="Center" FontSize="28">Login</TextBlock><Separator Margin="0,10" /><TextBlock>User name:</TextBlock><TextBoxMargin="0,10"InputMethod.IsInputMethodEnabled="False"Text="{Binding UserName}" /><TextBlock>Password:</TextBlock><PasswordBox Margin="0,10" Password="123456" /><Button Command="{Binding LoginCommand}" Content="Login" /></StackPanel></Border></Grid></local:BasePage>
-
定义PageViewConverter
public class PageViewConverter : IValueConverter {public object Convert(object value, Type targetType, object parameter, CultureInfo culture){switch ((ApplicationPage)value){case ApplicationPage.Empty:return new TextBlock { Text = "404 Not Found" };case ApplicationPage.Login:return new Login();case ApplicationPage.Home:return new Home();default:throw new ArgumentException("Invalid value passed to ApplicationPageViewConverter");}}public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture){throw new NotImplementedException();} }
-
完成MainWindow
<Window ...><Window.DataContext><local:MainViewModel/></Window.DataContext><Window.Resources><share:PageViewConverter x:Key="pageConv"/></Window.Resources><ContentControl Content="{Binding CurrentPage,Converter={StaticResource pageConv}}"/></Window>
改进
-
可以结合依赖注入的方式来实现
-
导航方法可以封装为一个NavigationService服务
//封装服务class NavigationService{public static NavigationService Instance { get; } = new NavigationService();private MainViewModel mainVM;public void Navigate(ApplicationPage page){if (mainVM == null){mainVM = (MainViewModel)App.Current.MainWindow.DataContext;}mainVM.CurrentPage = page;}}//原来的方式void Logout(){var mainVM = App.Current.MainWindow.DataContext as MainViewModel;mainVM!.CurrentPage = ApplicationPage.Login;}//使用封装好的服务void Login(){NavigationService.Instance.Navigate(ApplicationPage.Login);}
四、使用Frame和NavigationService
实现上一章节功能,本质上是使用依赖注入的方式将View和ViewModel进行绑定,并利用Frame的自带的Navigate方法进行导航
- 定义ViewModel
public class ViewModelBase : ObservableObject{}public partial class MainWindowViewModel : ViewModelBase{private readonly NavigationService navigationService;//依赖注入public MainWindowViewModel(NavigationService navigationService){this.navigationService = navigationService;}[RelayCommand]void Loaded(){ //navigationService实现的导航方法navigationService.Navigate<LoginViewModel>();}}public partial class HomeViewModel : ViewModelBase{[ObservableProperty]string? userName;}public partial class LoginViewModel : ViewModelBase{private readonly NavigationService navigationService;//依赖注入public string UserName { get; set; } = "Sergio";public LoginViewModel(NavigationService navigationService){this.navigationService = navigationService;}[RelayCommand]void Login(){ //navigationService实现的导航方法,此处进行了传参navigationService.Navigate<HomeViewModel>(new Dictionary<string, object?>{[nameof(HomeViewModel.UserName)] = UserName});}}
- 定义View
主窗口,使用Behaviors实现mvvm模式
<Windowxmlns:b="http://schemas.microsoft.com/xaml/behaviors"><b:Interaction.Triggers><b:EventTrigger><b:InvokeCommandAction Command="{Binding LoadedCommand}" /></b:EventTrigger></b:Interaction.Triggers>
</Window>
主窗口后台类
public partial class MainWindow : Window
{public MainWindow(MainWindowViewModel viewModel,Frame frame){InitializeComponent();DataContext = viewModel;AddChild(frame);}
}
其他View
<!--使用Page来承载内容-->
<Page ...><Grid><TextBlock HorizontalAlignment="Center"VerticalAlignment="Center"d:Text="Hello, world!"Text="{Binding UserName, StringFormat='Hello, {0}!'}"FontSize="32" /></Grid>
</Page><Page ...><Grid><Border Padding="10"HorizontalAlignment="Center"VerticalAlignment="Center"BorderThickness="1"CornerRadius="10"BorderBrush="LightGray"><StackPanel Width="300"><TextBlock HorizontalAlignment="Center" FontSize="28">Login</TextBlock><Separator Margin="0,10" /><TextBlock>User name:</TextBlock><TextBox Margin="0,10" Text="{Binding UserName}" InputMethod.IsInputMethodEnabled="False" /><TextBlock>Password:</TextBlock><PasswordBox Margin="0,10" Password="123456" /><Button Content="Login" Command="{Binding LoginCommand}" /></StackPanel></Border></Grid>
</Page>
在后台类中使用依赖注入的方式定义DataContext
public Home(HomeViewModel viewModel)
{InitializeComponent();DataContext = viewModel;
}public Login(LoginViewModel viewModel)
{InitializeComponent();DataContext = viewModel;
}
- 实现NavigationService
public class NavigationService{//注册了单例的Frameprivate readonly Frame? mainFrame;public NavigationService(Frame? frame){mainFrame = frame;//要使用LoadCompleted事件mainFrame.LoadCompleted += MainFrame_LoadCompleted;}private void MainFrame_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e){if (e.ExtraData is not Dictionary<string,object?> extraData){return;}if ((mainFrame?.Content as FrameworkElement)?.DataContext is not ViewModelBase vm){return;}foreach (var item in extraData){//为每个属性赋值vm.GetType().GetProperty(item.Key)?.SetValue(vm, item.Value);}}//根据VM类型查找View,要注意VM和View的命名规范private Type? FindView<T>(){return Assembly.GetAssembly(typeof(T))?.GetTypes().FirstOrDefault(x => x.Name == typeof(T).Name.Replace("ViewModel", ""));}public void Navigate<T>(Dictionary<string,object?>? extraData=null) where T:ViewModelBase{var viewType = FindView<T>();if (viewType is null)return;var page = App.Current.Services.GetService(viewType) as Page;//利用Frame的Navigate方法进行导航和传参mainFrame?.Navigate(page,extraData);} }
- 注册需要的类,此案例在App.cs中进行注册
public partial class App : Application{public IServiceProvider Services { get; }public static new App Current => (App)Application.Current;public App(){var container = new ServiceCollection();container.AddSingleton(_ => new Frame { NavigationUIVisibility = NavigationUIVisibility.Hidden });container.AddSingleton<MainWindow>();container.AddSingleton<MainWindowViewModel>();container.AddTransient<Login>();container.AddTransient<Home>();container.AddTransient<LoginViewModel>();container.AddTransient<HomeViewModel>();container.AddSingleton<NavigationService>();Services = container.BuildServiceProvider();}protected override void OnStartup(StartupEventArgs e){base.OnStartup(e);MainWindow = Services.GetRequiredService<MainWindow>();MainWindow.Show();}}
相关文章:

WPF中在MVVM模式下实现导航功能
WPF中在MVVM模式下实现导航功能 一、利用TabControl 使用场景:项目小,不用考虑内存开销的问题。 实现方式1-手动指定ViewModel 分别定义3个UserControl作为View用于演示 <UserControl...><Grid><StackPanel Orientation"Vertic…...

SpringBoot面试题2:SpringBoot与SpringCloud 区别?SpringBoot和Spring、SpringMVC的区别
该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:SpringBoot与SpringCloud 区别? Spring Boot 和 Spring Cloud 是 Spring 生态系统中的两个关键组件,它们有以下区别: 定位:Spring Boot 用于简…...

Practical Deep Raw Image Denoisingon Mobile Devices
Abstract 近年来,基于深度学习的图像去噪方法得到了广泛的研究,并在许多公共基准数据集中盛行。然而,最先进的网络计算成本太高,无法直接应用于移动设备。在这项工作中,我们提出了一种轻量级、高效的基于神经网络的原…...
如何在Android项目中制作和使用三方包(jar文件)
文章目录 1 概念介绍2 制作方法2.1 制作步骤2.2 制作结果3 使用方法3.1 具体步骤3.2 示例代码4 内容总结在项目中为了跨部门协作需要把相关的内容打成包文件,基于这个需求,我们将介绍如何把 代码制作成三方包,这里的三方包是指jar文件。同时也会介绍如何在Android项目中使用…...
消息队列Beanstalkd介绍
摘要: Beanstalkd是一个高性能、轻量级的、分布式的、内存型的消息队列系统。最初设计的目的是想通过后台异步执行耗时的任务来降低高容量Web应用系统的页面访问延迟。其实Beanstalkd是典型的类Memcached设计,协议和使用方式都是同样的风格。其基本设计思…...

【C++】继承 ⑥ ( 继承中的构造函数和析构函数 | 类型兼容性原则 | 父类指针 指向 子类对象 | 使用 子类对象 为 父类对象 进行初始化 )
文章目录 一、public 公有继承 - 示例分析1、类型兼容性原则2、类型兼容性原则应用场景 二、类型兼容性原则 - 示例分析1、父类指针 指向 子类对象2、使用 子类对象 为 父类对象 进行初始化3、完整代码示例 一、public 公有继承 - 示例分析 1、类型兼容性原则 类型兼容性原则 :…...

15 | JPA 对 Web MVC 开发者做了哪些支持
我们使用 Spring Data JPA 的时候,一般都会用到 Spring MVC,Spring Data 对 Spring MVC 做了很好的支持,体现在以下几个方面: 支持在 Controller 层直接返回实体,而不使用其显式的调用方法;对 MVC 层支持标…...

链表的概念+MySingleList的实现
文章目录 链表一、 链表的概念1.概念2. 结构 二、MySingleList的实现1 .定义内部类2 .创建链表3. 遍历链表并打印4.查找单链表中是否包含关键字key5.得到链表的长度6.头插法7. 尾插法8.任意位置插入8.删除结点清空 链表 顺序存储:顺序表/ArrayList 优点࿱…...

小黑子—Maven基础
Maven基础 一 小黑子的Maven学习1. Mavn的介绍2. Maven基础概念2.1 仓库2.2 坐标2.3 仓库配置 3. 手动写一个maven项目3.1 Maven项目构建命令3.2 插件创建工程 4. IDEA下的maven项目5. 依赖管理5.1 依赖配置5.2 依赖传递5.3 可选依赖(不透明)5.4 排除依赖…...

【Netty专题】【网络编程】从OSI、TCP/IP网络模型开始到BIO、NIO(Netty前置知识)
目录 前言前置知识一、计算机网络体系结构二、TCP/IP协议族2.1 简介*2.2 TCP/IP网络传输中的数据2.3 地址和端口号2.4 小总结 三、TCP/UDP特性3.1 TCP特性TCP 3次握手TCP 4次挥手TCP头部结构体 3.2 UDP特性 四、总结 课程内容一、网络通信编程基础知识1.1 什么是Socket1.2 长连…...

扬帆起航:许战海方法论日文版正式发布
近日,中国头部战略咨询机构‘许战海咨询’最新研究成果《中国汽车行业新能源转型战略》行业白皮书日文版,即将在日本发布。同时发布的日文版核心方法论白皮书还有《主品牌进化战略》、《第二招牌增长战略》、《链主品牌:制造业的竞争之王》等…...

Docker 安装zookeeper
一、安装单机版 1、拉取镜像 docker pull zookeeper2、创建挂载目录 mkdir -p /mydata/zookeeper/{conf,data,logs}3、新建配置文件 cd /mydata/zookeeper/conf vi zoo.cfgdataDir/data dataLogDir/logs tickTime2000 initLimit10 syncLimit5 clientPort21814、单机主机启…...

项目管理与SSM框架(二)| Spring
Spring简介 Spring是一个开源框架,为简化企业级开发而生。它以IOC(控制反转)和AOP(面向切面)为思想内核,提供了控制层 SpringMVC、数据层SpringData、服务层事务管理等众多技术,并可以整合众多…...

Ubuntu系统忘记Root用户密码-无法登录系统-更改Root密码-Ubuntu系统维护
一、背景 很多时候,我们总会设计复杂的密码,但是大多数时候,我们反而会先忘记我们的密码,导致密码不仅仅阻挡其他用户进入系统,同时也阻碍我们进入系统。 本文将介绍在忘记密码的情况下,如何进入系统并更改…...
webSocket 有哪些安全问题?
WebSocket在实现实时通信和双向数据传输方面非常有用,但也存在一些安全问题需要注意。以下是一些与WebSocket相关的安全问题: 1:跨站脚本攻击(XSS): WebSocket在消息传递过程中可能传输恶意脚本ÿ…...

ArcGis打开影像显示全黑解决方法
我们加载图像,显示如下: 解决方法: 问题分析:Gamma值高于1影像亮化,低于1影像暗化。栅格影像导入进来呈现黑色,可能是因为影像的“Gamma校正”设置出现问题,影响了影像的拉伸度、亮度、对比度等…...

雷达基础导论及MATLAB仿真
文章目录 前言一、雷达基础导论二、Matlab 仿真1、SNR 相对检测距离的仿真①、Matlab 源码②、仿真1)、不同 RCS,SNR 相对检测距离仿真2)、不同雷达峰值功率,SNR 相对检测距离仿真 2、脉冲宽度相对所要求的 SNR 仿真①、Matlab 源…...

设计模式再探——适配器模式
目录 一、背景介绍二、思路&方案三、过程1.适配器模式简介2.适配器模式的类图3.适配器模式代码4.适配器模式,类适配器模式和对象的对比5.适配器模式终极奥秘 四、总结五、升华 一、背景介绍 最近公司在对业务模型做构建的时候,涉及到和三方系统的对…...

【无标题】光伏逆变器的IEC62109测试,逆变器IEC62109测试项目
光伏逆变器的IEC62109测试,逆变器IEC62109测试项目 逆变器又称电源调整器,根据逆变器在光伏发电系统中的用途可分为独立型电源用和并网用二种。根据波形调制方式又可分为方波逆变器、阶梯波逆变器、正弦波逆变器和组合式三相逆变器。对于用于并网系统的…...

Windows用VM虚拟机安装MacOS Ventura 13.6系统全流程教程(附资源)
安装成果: 所需容量:至少40GB的硬盘空间,推荐80GB以上。 所需资源 VMware虚拟机激活密钥:VMware Workstation Pro 17.0.2MacOS Ventura 13.6的ISO镜像MacOS的解锁工具卡顿优化工具:beamoff 有人反馈说需要能用的ISO镜…...

linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)
2025年能源电力系统与流体力学国际会议(EPSFD 2025)将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会,EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...