这次讲的是把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,props);
- return { controlsDescendantBindings: true };
- },update: function ( el,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