四、View(视图层)
4.1 View的职责
View是用户实际交互的界面,它通过声明式数据绑定关联ViewModel的状态与命令。View不包含业务逻辑,仅负责UI的展示和用户交互的传递。
核心职责:
展示UI界面
绑定ViewModel的状态和命令
响应用户交互并传递给ViewModel
4.2 数据绑定
数据绑定是MVVM的核心机制,它将View中的UI元素与ViewModel中的属性连接起来。当ViewModel状态变化时,View自动更新;当用户在View中输入时,ViewModel状态也自动同步。
在Web框架中(KnockoutJS):
<!-- View:声明式绑定 -->
<p>联系人姓名:<strong data-bind="text: contactName"></strong></p>
<input data-bind="value: contactName, valueUpdate: 'keyup'" />
<!-- 当用户在输入框中输入时,contactName自动更新 -->
<!-- 当contactName变化时,p标签的内容自动更新 -->
在移动端框架中(Flutter):
dart
class UserView extends StatelessWidget {
final UserViewModel viewModel;
const UserView({required this.viewModel});
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('姓名:${viewModel.userInfo.name}'),
Text('年龄:${viewModel.userInfo.age}(${viewModel.ageDesc})'),
ElevatedButton(
onPressed: () => viewModel.loadUser('123'),
child: Text('加载用户'),
),
],
);
}
}
4.3 View与ViewModel的关系
在MVVM中,View持有ViewModel的引用,但ViewModel不知道View的存在。这种单向依赖确保了ViewModel的独立性和可测试性。
关键原则:
View只了解一个ViewModel,不了解其他层
ViewModel不知道View是否存在
通信通过数据绑定和命令完成
4.4 被动视图
MVVM中的View通常是“被动”的——它只负责展示和事件传递,不主动处理状态。这种设计使View更加简单,更容易测试。
五、双向数据绑定
5.1 什么是双向数据绑定
双向数据绑定是MVVM的核心特性,它实现了ViewModel状态与View之间的自动同步:
ViewModel状态变化 → View自动更新
View用户输入 → 自动更新ViewModel状态
5.2 数据绑定的底层机制
MVVM的数据绑定通过编译期依赖分析和运行时状态追踪实现自动同步:
5.2.1 编译期:建立依赖关系图
编译器解析View的UI结构,识别所有与ViewModel绑定的状态,生成“状态→UI组件”的依赖关系图。
5.2.2 运行时:INotifyPropertyChanged接口
在.NET环境中,ViewModel通过实现INotifyPropertyChanged接口来实现变更通知:
csharp
public class UserViewModel : INotifyPropertyChanged
{
private string _name;
public string Name
{
get => _name;
set
{
if (_name != value)
{
_name = value;
OnPropertyChanged(nameof(Name));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
5.3 数据绑定类型
六、通信与依赖注入
6.1 层间通信规则
MVVM各层之间的通信需要遵循明确的规则:
6.2 依赖注入
依赖注入是实现MVVM层间通信的关键技术。它确保:
依赖关系在构造函数中明确声明
各层之间解耦,便于测试
typescript
// ViewModel通过构造函数接收依赖
class UserViewModel {
private readonly userRepository: UserRepository;
private readonly logger: LoggerService;
constructor(
userRepository: UserRepository,
logger: LoggerService
) {
this.userRepository = userRepository;
this.logger = logger;
}
}
// 依赖注入容器配置
const container = {
userViewModel: new UserViewModel(
new UserRepository(),
new LoggerService()
)
};
6.3 跨组件状态共享
在现代MVVM框架中,通常通过@Provider/@Consumer或类似机制实现跨组件状态共享,避免“props逐层传递”的问题。
来源:
https://dnuhf.cn/