使用MMVVC模式和JSAppSugar将iOS原生应用UI层业务逻辑转为JavaScript

JSAUIKitCocoa是为使用JavaScript混合Objective-C开发iOS应用提供的MVC框架,以及为部分原生UI组件(如UIView)提供JavaScript快速初始化支持。使用JSAUIKitCocoa,你可以方便的使用JavaScript来编写iOS应用的显示层业务逻辑,以及实现显示层业务逻辑的动态下发。

核心概念

使用MMVVC模式构建混合编程应用程序

我们将用JavaScript和MMVVC模式创建这样一个应用界面

用户进入登录页面时,显示最后一次登录的用户信息,用户修改用户名后,头像中的名称显示当前用户名(真实场景应该会改变头像图片)

Model:用户管理

$class("app.UserManagerModel",{
	$static:{
		lastloginUser:function(){
			return {
				username:"UserA",
				password:"password"
			}
		}
	}
});

lastloginUser方法返回最后一次登录的用户信息,即Domain-value Object。

ModelView:用户头像

$class("app.AvatarView",{
	$init : function(param){
		this.textView = $new("UILabel","initWithJSAParam:",{
			fontSize:12,
			textColor:"#FFFFFF",
			textAlignment:"center"
		});
		var avatarView = $new("MyRelativeLayout","initWithJSAParam:",Object.assign(param,{
			backgroundColor:"#03A9F4",
			subviews:[
			{
				view:this.textView,
				leftPos:5,
				topPos:5,
				rightPos:5,
				bottomPos:5,
			}
			]
		}));
		//这里是一个小技巧,将一个非OC代理对象转换为OC代理对象,以便该对象传递到OC系统时转换为OC对象
		this.$this = avatarView.$this;
	},
	setName:function(name){
		name = name.trim();
		if(name == ""){
			name = "Unknown";
		}
		this.textView.invoke("setText:",name);
	}
});

用户头像是一个ModelView,即和业务逻辑相关的View,这个View将显示用户头像,并可以重新设置用户名(setName方法),setName方法在此DEMO实现中只是将头像中的文本设置为新的名字,真实业务场景可以调用Model层方法获取用户名对应的图片,然后修改头像图片。相比ViewMode的Data-Bind,ModelView可以包含更加复杂的显示转换逻辑。同时这个ModelView可以复用到任何需要展示用户头像的地方。

使用OC编写ModelView

如果这个ModelView的显示逻辑更为复杂,如处理复杂动画显示,则这个ModelView可直接使用OC编写,即编写一个UIView的继承类,在这个例子中,AvatarView实际是一个MyRelativeLayout(MyLayout框架中的相对布局UIView)对象,AvatarView使用JS脚本编写显示业务逻辑,在MyRelativeLayout中放入了一个UILabel以显示用户名文本。

ModelView中使用的OC原生类,如MyRelativeLayout、UILabel,因为其与业务逻辑无关,则可视为View层组件。

ModelView:登录界面

$class("app.LoginView",{
	$init : function(lastloginUser){
		this.avatarView = new app.AvatarView({
			width:80,height:80
		});
		this.avatarView.setName(lastloginUser.username);
		this.userNameInput = $new("UITextField","initWithJSAParam:",{
			width:200,height:30,borderStyle:"RoundedRect",
			placeholder:"用户名",
			text:lastloginUser.username,
			onEditingDidEnd:function(view){
				jsa.cocoa.UIResponder.fromNative(view).dispatch("onEditingDidEnd",null,null);
			}
		});
		this.passwordInput = $new("UITextField","initWithJSAParam:",{
			width:200,height:30,borderStyle:"RoundedRect",secureTextEntry : true,
			placeholder:"密码",
			text:lastloginUser.password,
		});
		var loginView = $new("MyRelativeLayout","initWithJSAParam:",{
			subviews:[
			{
				id : "avatar",
				view:this.avatarView,
				topPos :{value : "safeAreaMargin",offset : 20},
				centerXPos : 0,
			},
			{
				id:"username",
				view:this.userNameInput,
				topPos :{id : "avatar",pos : "bottomPos",offset : 10,},
				centerXPos : 0,
			},
			{
				id:"password",
				view:this.passwordInput,
				topPos :{id : "username",pos : "bottomPos",offset : 10,},
				centerXPos : 0,
			},{
				view:jsa.cocoa.UIButton.button({
					type:"System",
					width:50,
					height:30,
					title:"登录",
					onClick:function(view){
						jsa.cocoa.UIResponder.fromNative(view).dispatch("onLoginClicked",null,null);
					}
				}),
				topPos :{id : "password",pos : "bottomPos",offset : 10,},
				centerXPos : 0,
			}
			]
		});
		jsa.cocoa.UIResponder.fromNative(loginView.$this).setObserver(this);
		this.$this = loginView.$this;
	},
	onEditingDidEnd:function(){
		//在用户名输入结束后,将新的用户名更新到avatarView
		var username = this.userNameInput.invoke("text");
		this.avatarView.setName(username);
	},
	onLoginClicked:function(){
		//当点击登录按钮时,发出登录事件,并在事件对象中加入登录表单对象的值(类似于form的post)
		var username = this.userNameInput.invoke("text");
		var password = this.passwordInput.invoke("text");
		//抛出事件,Controller可监听该事件以处理登录事件
		jsa.cocoa.UIResponder.fromNative(this.$this).dispatch("onLogin",null,{
			username:username,
			password:password
		});
	}
});

LoginView即登录页面,在LoginView中使用app.AvatarView来展示用户头像,并监听UITextField组件的onEditingDidEnd事件,以动态改变登录用户名对应的用户头像。通过引入ModelView,可有效的将显示业务中的临时交互逻辑放在ModelView中,而避免将显示逻辑代码写在Controller中。

Controller:登录页面

$class("app.Main",{
	$extends : "jsa.cocoa.JSAUIViewController",
	getView : function(viewController){
		var lastloginUser = app.UserManagerModel.lastloginUser();
		this.loginView = new app.LoginView(lastloginUser);
		return this.loginView;
	},
	onLogin:function(object,userInfo){
		console.log("User:"+userInfo.username+" Password:"+userInfo.password);
	}
});

在将显示逻辑分离到ModelView后,Controller的职责就更加清晰了,getView方法中获得页面所需的Model数据,并用Model数据初始化页面对应的ModelView对象。

onLogin方法处理loginView视图中的登录事件。

该DEMO的可运行版本已包含在JSAUIKitCocoaDemo,JS脚本地址:https://github.com/JSAppSugar/JSAUIKitCocoa/tree/master/JSAUIKitCocoaDemo/JSApp/app

转载于:https://my.oschina.net/u/4018755/blog/2962455

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值