使用MMVVC模式和JSAppSugar將iOS原生應用UI層業務邏輯轉爲JavaScript

JSAUIKitCocoa是爲使用JavaScript混合Objective-C開發iOS應用提供的MVC框架,以及爲部分原生UI組件(如UIView)提供JavaScript快速初始化支持。使用JSAUIKitCocoa,你能夠方便的使用JavaScript來編寫iOS應用的顯示層業務邏輯,以及實現顯示層業務邏輯的動態下發。javascript

核心概念

使用MMVVC模式構建混合編程應用程序

咱們將用JavaScript和MMVVC模式建立這樣一個應用界面java

用戶進入登陸頁面時,顯示最後一次登陸的用戶信息,用戶修改用戶名後,頭像中的名稱顯示當前用戶名(真實場景應該會改變頭像圖片)git

Model:用戶管理

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

lastloginUser方法返回最後一次登陸的用戶信息,即Domain-value Object。github

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以顯示用戶名文本。app

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對象。post

onLogin方法處理loginView視圖中的登陸事件。

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

相關文章
相關標籤/搜索