React-Knockout无缝粘合,JavaScript项目MVVM框架下的控件化

这次讲的是把React和Knockout结合使用的示例,两个框架各有所长,也有不同的特点和特色,这次把他们结合起来,似乎有些胆大妄为,然而有时候就是容易遇到一些奇怪的需求。使得我们不得不去出一些奇招。然而这样真的很奇怪吗?实际上并不是这样子,使用react创建控件,再使用knockout构建MVVM框架,开发流程可以变得有条不絮,易于扩展维护,同时可实现代码重用,减少开发的工作量。

1.要构建React-Knockout MVVM框架我们首先需要下载React和knockout的JS库

React:http://facebook.github.io/react/

Knockout:http://knockoutjs.com/

2.下载完成后将react和knockout库文件导入到工程里,我在工程量建了framework文件夹来放置这些框架文件。

3. 要使React和knockout融合,需要做一个特别的处理,在framework文件夹里新建一个knockoutReact.js文件,并向其添加如下代码。

var KnockoutMixin = {

    updateKnockout:function() {
        this.__koTrigger(!this.__koTrigger());
    },

    componentDidMount:function() {
        this.__koTrigger = ko.observable(true);
        this.__koModel = ko.computed(function () {
            this.__koTrigger(); // subscribe to changes of this...

            return {
                props: this.props,
                state: this.state
            };
        }, this);

        ko.applyBindings(this.__koModel, this.getDOMNode());
    },

    componentWillUnmount:function() {
        ko.cleanNode(this.getDOMNode());
    },

    componentDidUpdate:function() {
        this.updateKnockout();
    }
};

var reactHandler = ko.bindingHandlers.react = {
    render: function ( el, Component, props ) {
        React.render(
            React.createElement(Component,props),
            el
        );
    },

    init: function ( el, valueAccessor, allBindingsAccessor, viewModel, bindingContext ) {
        var options = valueAccessor();
        var Component = ko.unwrap(options.component || options.$);
        var props = ko.toJS(options.props || viewModel);

        reactHandler.render(el, Component, props);

        return { controlsDescendantBindings: true };
    },

    update: function ( el, valueAccessor, allBindingsAccessor, viewModel, bindingContext ) {
        var options = valueAccessor();
        var Component = ko.unwrap(options.component || options.$);
        var props = ko.toJS(options.props || viewModel);

        reactHandler.render(el, Component, props);

        return { controlsDescendantBindings: true };
    }
};

这片代码中第一段的作用是在react文件里添加knockout绑定机制,第二段代码作用则是实现在UI中直接绑定UI元素来创建一个控件,例如使用<div data-bind="react: { $: CustomTextBox, props: $data }><div>就可以直接在html里创建一个CustomTextBox控件了

4. 下面我们来创建一个控件login,并将其放置在文件夹controls中,文件名称为login.jsx

/**
 * data bind datas
 *      1. username 用户名
 *      2. password 密码
 *      3. loginCommand 登录事件
 */

var UserLogin = React.createClass({
    mixins: [ KnockoutMixin ],

    getDefaultProps:function(){
        return {
            labelUsername:  "Username",
            labelPassword:  "Password",
        };
    },

    render: function(){
        return <div style={{marginTop: 20, marginLeft: 20}}>
                    <div>
                        <label>{this.props.labelUsername}</label>
                        <input type="text" style={{marginLeft: 20}}
                               data-bind="value: props.username"/>
                    </div>
                    <div style={{marginTop: 10}}>
                        <label>{this.props.labelPassword}</label>
                        <input type="text" style={{marginLeft: 20}}
                               data-bind="value: props.password"/>
                    </div>
                    <div style={{marginTop: 20, marginLeft: 150}}>
                        <button data-bind="click: props.loginCommand"
                                style={{width:100}}>Login</button>
                    </div>
               </div>;
    },
});

控件里用户名username,密码password,登录操作loginCommand是适应knockout data-bind绑定的,这个控件会被引用在某个view中然后绑定到viewmodel中,viewmodel的数据改变后,控件UI也会跟随改变,具体会是什么样子,请继续跟随下面的步骤。

5.在view文件夹里创建一个登录界面login.html。在这个页面里,使用了data-bind react:来创建我们上一个步骤的登录控件,并在后面的js代码中新建了一个viewmodel并将其绑定至UI中。

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title id="title">Login</title>

	<script type="text/javascript" src="../framework/react.js"></script>
	<script type="text/javascript" src="../framework/knockout-v3.3.0.js"></script>
	<script type="text/javascript" src="../framework/JSXTransformer.js"></script>
	<script type="text/javascript" src="../framework/knockoutReact.js"></script>

	<script type="text/jsx" src="../controls/login.jsx"></script>

	<script type="text/javascript" src="../viewmodel/loginViewModel.js"></script>
</head>
<body style="background:lightblue">
	<div style="margin-left:30px">
		<button data-bind="click: viewModel.fillInfo">Fill username and password</button>
		<button data-bind="click: viewModel.clear">Clear</button>
	</div>

	<div data-bind="react: { $: UserLogin,
					 	  	 props: {
					 	  	 			 username : username,
					 	  	 			 password : password,
					 	  	 			 loginCommand : viewModel.startLogin.bind($data)
					 	  	 	    }
					 	    }">
	<div>
</body>

<script type="text/jsx">
	var viewModel = new loginViewModel();

    ko.applyBindings(loginViewModel);
</script>

</html>

绑定的元素有

username : username, 控件的username绑定了View Model的username

password : password, 控件的password绑定了View Model的password

loginCommand : viewModel.startLogin.bind($data) 控件的loginCommand绑定了View Model的startLogin方法

6.新建一个viewmodel的文件夹并向其添加loginViewModel.js,这是login view的viewmodel文件了,处理了login view里所需要的逻辑。

var loginViewModel = (function () {
    function loginViewModel() {
        this.username = ko.observable();
        this.password = ko.observable();
    }

    /**
     * 登录操作
     */
    loginViewModel.prototype.startLogin = function () {
    	var name = this.username();
    	var secure = this.password();

        alert("Username: " + name + "\nPassword: " + secure);
    }

    /**
     * 填充用户名和密码
     */
    loginViewModel.prototype.fillInfo = function () {
        this.username("YLD");
        this.password("123");
    }

    /**
     * 清空用户名和密码
     */
    loginViewModel.prototype.clear = function () {
        this.username("");
        this.password("");
    }

    return loginViewModel;
})();

7.工程创建实现完成,现在运行下吧。我这里使用的是google chrome浏览器,然后要此工程在浏览器里运作成功,还必须做一个特别的处理。右击chrome浏览器快捷方式,打开属性。在目标后面添加 --disable-web-security

工程运行效果如下

源代码下载地址:http://download.csdn.net/detail/leyyang/9022673

版权声明:本文为博主原创文章,转载时须注明本文的详细链接,否则作者将保留追究其法律责任。

时间: 2024-10-03 15:01:28

React-Knockout无缝粘合,JavaScript项目MVVM框架下的控件化的相关文章

Silverlight项目笔记1:UI控件与布局、MVVM、数据绑定、await/async、Linq查询、WCF RIA Services、序列化、委托与事件

最近从技术支持转到开发岗,做Silverlight部分的开发,用的Prism+MVVM,框架由同事搭好,目前做的主要是功能实现,用到了一些东西,侧重于如何使用,总结如下:   1.UI控件与布局     2.MVVM     3.数据绑定     4.await/async     5.Linq查询     6.WCF RIA Services     7.序列化     8.委托与事件 1.UI控件与布局 常用的主要是Grid.StackPanel.Border,其中最常用的的是Grid,是一

我的开源框架之Accordion控件

需求: (1)实现手风琴面板控件,支持静态HTML与JSON方式创建控件 (2)支持远程加载数据 (3)支持面板激活.远程加载事件注册 (4)支持动态添加.删除项目 实现图例 客户代码 <div> <div style="padding-left:100px; padding-bottom:12px; float:left"> <div id="accordionContainer" style="width:300px;he

我的开源框架之TAB控件

需求 (1)支持iframe.html.json格式的tab内容远程请求 (2)支持动态添加tab (3)支持远程加载完成监听,支持tab激活事件监听 (4)支持reload tab内容[如果是远程加载] (5)支持邮件菜单[未实现] 实现图例 客户代码 1 <body> 2 <div id="text"> 3 <h3>无题</h3> 4 <p>月落湖面两清影,</p> 5 <p>岸柳丝丝弄轻盈.<

我的开源框架之树控件

需求: 1.根据无限级的树形结构的json生成树菜单 2.树样式可以是图标类型和简单类型 3.可以自定义节点的图标 4.支持复选框 5.支持懒加载方式请求数据 6.支持节点点击事件 7.只有右键菜单[未实现] 8.支持拖拽调整节点[未实现] 实现图例 客户代码 1 <body> 2 <div id="Container" style="padding:10px; margin:0 auto;width:800px;height:300px;padding-t

我的开源框架之面板控件

需求: (1)可伸缩.扩大.缩小 (2)可自定义工具栏(依赖工具栏控件),工具栏可定义位置 (3)可加装远程数据 实现图例 客户代码 function addMoreTools() { var toolbar = panel.panel("getToolbar"); toolbar.toolbar('addButtons', [ { id: 'btn_5', text: '按钮5', iconCls: 'icon-edit', handler: function () { alert(

在MVVM中使用PasswordBox控件

在MVVM中使用PasswordBox控件,碰到一个问题.由于**PasswordBox.Password**属性并不是一个依赖属性,所以无法将其作为Binding的目标. # 使用附加属性的解决方案 ![Password Demo.gif](http://upload-images.jianshu.io/upload_images/140233-dbd415eb4cf9aeb2.gif) **思路:**定义两个依赖属性**Attach**和**AttachPassoword** Attatch

如何通过JavaScript构建Asp.net服务端控件

摘要 虽然ASP.NET的服务器控件一直被大家所诟病,但是用户控件(ACSX)在某些场景下还是非常有用的. 在一些极特珠的情况下,我们会使用JavaScript动态的构建页面中的控件,但假设遇到了我要用JavaScript构建一个服务端控件.用户控件时,该怎么办? 我们常常说,服务端控件运行在服端器上,那么这话是什么意思呢? 服务端控件,其本质是一构建HTML语句的封装,以事先编排好的方式,生成一套HTML并通过Http协议返回给客户端.因此,我们所写的服务端控件,在响应HTTP请求时,早已不存

MVVM模式下 DataTemplate 中控件的绑定

原文:MVVM模式下 DataTemplate 中控件的绑定 今天给ListBox中通过DataTemplate生成的Button绑定命令时,一开始Button始终找不到绑定的命令.现找到了正确的绑定方式,特来记录一下. 先上个正确的示例: <ListBox Grid.Column="0" ItemsSource="{Binding CallBussiness}"> <ListBox.ItemsPanel> <ItemsPanelTem

zui框架配置日期控件只显示年月

zui框架配置日期控件datetimepicker只显示年月 <!DOCTYPE html> <head> <script src="~/Scripts/jquery-1.11.3.min.js"></script> <script src="~/res/zui-1.9.1-dist/dist/js/zui.min.js"></script> <script src="~/res