React.js的确很好用,可是我相信,除非是整个团队,彻底使用React.js重写全部UI组件,React.js才可能用得比较顺手。多数情况下,仍是半React.js组件,半传统JS技术架构的模式。
而React.js的组件,本身是一个比较封闭的状态,除了通过setState的方式从外部和组件进行交互,并不推荐使用传统OOP的方式,对组件属性进行强行修改(真的不建议,这么做你就是找死),当然,你可以把setState方法写n个接口,这样仍然属于setState范畴。
那么问题来了,传统前端JS技术架构下,如何和React.js进行交互呢?这篇文章就针对这个问题,进行一些简单的介绍,解决思路其实都是很简单的土办法。
中间代理对象
假定,我做了一个React.js的组件,这个组件用于选定公司的ID。在组件显示上,我们需要显示一个按钮,按钮的文字是选中的公司的名称,点击按钮,可以显示挑选公司的弹出层。而按钮的后面有一个隐藏域,放的是实际的公司ID。
那么因为种种原因,这个弹出层,没有用React.js封装,而是传统的html,采用ajax的方式加载,且这个弹出层要加载的页面内容、交互都已经完成了,不想再额外用React.js重新做一个组件了。
所以这时候的需求是,点击按钮,ajax加载公司列表,然后选中公司,将数据反馈回给React.js组件。问题的难点就在最后,何如将数据反馈回React.js组件。
这时候,可以考虑使用中间代理对象的模式,将React.js的组件实例,传递给中间代理对象,然后在ajax的页面,判定中间代理对象是否具有这个React.js实例,如果存在,则执行组件实例的setState方法。
下面举个实际的例子。
初始的界面如下:
这里有一个【选择供应商】的按钮,当点击供应商按钮后,会弹出如下的界面:
这个界面是用传统的html做的,采用ajax的方式进行加载。当用户点击【选中】按钮,则会关闭这个弹出层,且将用户选定的供应商名称和ID传回给刚才的React.js的组件。
代码部分如下:
React.js的组件叫做ClientSearchInput.jsx
import * as _ from 'lodash'; import * as React from 'react'; import * as ReactDOM from 'react-dom'; import Erp from 'page/erp/Erp'; import UI from 'module/UI'; let erp = Erp.getInstance(); let copy = false; class ClientSearchInput extends React.Component { index = 0; constructor(props) { super(props); this.index += 1; this.state = { value: this.props.value || '',name: '',}; } getColumn() { return this.props.column } getType() { let column = this.getColumn(); if (column.type !== 'client' && column.type !== 'supplier') return 'client'; return column.type; } getTypeName() { if (this.state.name) return this.state.name; return '选择' + (this.getType() === 'client' ? '客户' : '供应商'); } getPlaceholder() { return '输入' + (this.getType() === 'client' ? '客户' : '供应商') + '名称或者简称'; } openLayer() { let uri = erp.uri('ui_search_client').setData({ type: this.getType() }) + ''; let ajax = $.ajax(uri); ajax.done((html) => { UI.modal('ui_search_client',{ header: '搜索' + this.getTypeName(),content: html,component: this,}).show(html); }); } clean() { this.setState({ value: '',}); } copy() { copy = { name: this.state.name,value: this.state.value,} } paste() { if (copy) { this.setState(copy); console.log(copy); } } render() { let editable = !!this.props.editable; return ( <div> <div className="ui tiny buttons"> <button type="button" disabled={!editable} className="ui button tiny blue" onClick={e => this.openLayer()}>{this.getTypeName()}</button> <button type="button" disabled={!this.state.value} className="ui button tiny green" onClick={e => this.copy()}>复制</button> <button type="button" disabled={!this.state.value} className="ui button tiny red" onClick={e => this.paste()}>粘贴</button> <button type="button" disabled={!this.state.value} className="ui button tiny black" onClick={e => this.clean()}>清除</button> </div> <input type="hidden" name={this.props.name} value={this.state.value}/> </div> ); } } module.exports = ClientSearchInput;
openLayer函数部分,是触发打开弹出层的位置。UI这个类的源代码在这篇文章里面《Semantic UI带你飞——Modal》,当时因为还没开始接触React.js,所以这个Modal没有做成是React.js的组件。这里UI.modal('ui_search_client')实际上就充当了中间代理对象,当然,实际上我们也没有需要额外做什么,只是把组件实例传过去而已。
而在ajax的页面js中,重新加载回这个组件:
requirejs(['module/UI'],function(UI) { // 前面省略 var modal = UI.modal('ui_search_client'),opts = modal.options; if (opts && opts.component) { parent.find('button.select-client-button').click(function() { var button = $(this); var id = button.data('id'),name = button.data('name'); opts.component.setState({ value: id,name: name },function() { modal.hide(); }) }); } });
哦,其实一切都很简单,是不是?
对象快捷链接
现在前端开发,大多是遵循amd规范,或者npm那样的模式(这是什么md来着,忘记了),即不直接写入全局对象的环境,而采用exports的方法,将需要的元素对外暴露,所以每个js脚本等于实际上都是一个密闭的scope。我们通过暴露接口的方法,提供一个读取、写入的接口,数据存放在密闭的scope中,不直接被外部访问。
这样做,的确保证了一定的安全性,但频繁的使用接口,有时候也加大了代码调试过程中繁琐。那么现在提供一种很直接的方式。
假定读取、写入的接口,明确写入的是一个对象接口,这时候我们可以利用JS对象的特性,做直接的链接操作。
即假定有,这样一个set/get的接口:
var storage = {} any.set = function(key,object) { storage[key] = object || {}; } any.get = function(key) { return storage[key] || false; }
我们在另外一个scope中,确保了某个key的对象必然存在。
var localObject = any.get('local'); if (localObject === false) { localObject = {} any.set('local',localObject); }
这样,localObject实际上已经直接指向了storage['local'],之后,我们可以对localObject,进行直接的对象访问或操作,而在别的scope中,取回local,已经是实时更新的状态,这样是不是顿时明朗了很多呢?
这实际上是JS的好处,也是JS的弊端,可以适用于如jQuery的 $(id).prop 的方法中。
原文链接:https://www.f2er.com/react/305219.html