原理图:
使用的技术点:
- 服务端:
- express 创建服务器应用
- ws插件提供websocket服务
- chokidar插件提供监听文件夹改动服务
- fs插件提供文件读写功能
- path插件提供路径操作
- pm2插件 提供dyna服务脱离终端长久运行的功能
客户端:
SocketRocket三方库提供websocket连接功能
对于.out文件仿照官方,使用base64传递给客户端
- 客户端的UI刷新:
因为是开发阶段的工具,建议刷新规则以整体为准,因为VirtualView的局部刷新方法并不靠谱,可以去看VVViewContainer的updateData方法,它只会刷新带有表达式的属性,普通属性并不会刷新
/// VVViewContainer的刷新源码
- (void)updateData:(id)data
{
if (data != self.lastData) {
self.lastData = data;
for (VVBaseNode *node in _variableNodes) {
[node reset];
for (VVPropertyExpressionSetter *setter in node.expressionSetters.allValues) {
if ([setter isKindOfClass:[VVPropertyExpressionSetter class]]) {
[setter applyToNode:node withObject:data];
}
}
if ([data isKindOfClass:[NSDictionary class]]) {
NSDictionary *dict = (NSDictionary *)data;
node.actionValue = [dict objectForKey:node.action];
}
[node didUpdated];
}
}
}
作者通过给VVViewContainer加分类,调用以下代码实现了vv模板视图的全属性刷新,这只作为debug模式下热重载使用,不建议release下使用
/// 作者实现的模板全属性刷新
#import "VVViewContainer+ZPNDRefreshSupport.h"
@implementation VVViewContainer (ZPNDRefreshSupport)
+ (void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method originalMethod = class_getInstanceMethod(self, @selector(updateData:));
Method myMethod = class_getInstanceMethod(self,@selector(hook_updateData:));
method_exchangeImplementations(originalMethod, myMethod);
});
}
- (void)hook_updateData:(id)data
{
if (data != [self valueForKey:@"lastData"]) {
VVNodeCreater *creater = [[[VVTemplateManager sharedManager] valueForKey:@"creaters"] valueForKey:self.rootNode.templateType];
[self _refreshPropertyOfNode:self.rootNode creater:creater data:data];
}
[self hook_updateData:data];
}
- (void)_refreshPropertyOfNode:(VVBaseNode *)node creater:(VVNodeCreater *)creater data:(id)data
{
for (VVPropertySetter *setter in creater.propertySetters) {
if (![setter isKindOfClass:[VVPropertyExpressionSetter class]]) {
[setter applyToNode:node withObject:data];
}
}
if (node.subNodes) {
for (NSInteger i = 0; i < node.subNodes.count; ++i) {
VVBaseNode *subNode = node.subNodes[i];
VVNodeCreater *subCreater = creater.subCreaters[i];
[self _refreshPropertyOfNode:subNode creater:subCreater data:data];
}
}
}
@end
如果是一个列表中某个cell或item的模板有改动,建议刷新整个列表,以保证整体高度分配正确