为什么说使用React就是提高生产力呢?
我也不想多做解释了,大概类如以下这样的界面,用React实现,连HTML、JS、交互,250行不到,额外使用了jQuery和lodash。
完成效果大致如下:
以下是源代码:
var React = require('react');
var ReactDOM = require('react-dom');
const PropTypes = React.PropTypes;
var $ = jQuery;
class GoodsSearchInput extends React.Component {
static defaultProps = {
min: 2,
max: 20,
name: '',
url: location.href,
delay: 1000,
debug: false,
selectId: 0,
selectName: '',
tip: '请输入关键字'
};
static propTypes = {
min: PropTypes.number,
max: PropTypes.number,
url: PropTypes.string,
delay: PropTypes.number
};
constructor(props) {
super(props);
this.state = {
value: this.props.value,
category: '',
results: {},
searching: {},
isHide: false,
isSearch: true,
selected: {
id: this.props.selectId,
name: this.props.selectName
}
};
}
tick = null;
clearTick() {
if (this.tick != null)
clearTimeout(this.tick);
return this;
}
resetTick() {
this.clearTick();
let delay = this.props.delay < 300 ? 300 : this.props.delay;
this.tick = setTimeout(() => {
this.search().then((result) => {
}).catch((result) => {
});
}, this.props.delay);
return this;
}
changeInput(value) {
if (this.state.isSearch) {
if (value.length >= this.props.min) {
this.resetTick();
}
else {
this.clearTick();
}
}
this.setState({
value: value,
isHide: false,
isSearch: true
});
}
getValue() {
return this.state.value;
}
search() {
let me = this
, state = this.state
, value = this.getValue()
, results = state.results
, searching = state.searching;
return new Promise((resolve, reject) => {
if (typeof results[value] !== 'undefined') {
if (results[value] === false)
resolve(results[value]);
else
reject(results[value]);
}
else if (!searching[value]) {
searching[value] = 1;
me.setState({searching: searching});
$.ajax({
url: this.props.url,
data: {
search: value
// category: value
},
dataType: 'json'
}).done(function (data) {
if (!data.count || data.count <= 0) {
results[value] = false;
searching[value] = 3;
me.setState({
results: results,
searching: searching,
isHide: false
});
reject(false);
}
else {
results[value] = data;
searching[value] = 2;
me.setState({
results: results,
searching: searching
});
resolve(results[value]);
}
}).fail(function () {
results[value] = false;
searching[value] = 3;
me.setState({
results: results,
searching: searching
});
reject(false);
});
}
});
}
hideResult() {
this.setState({isHide: true});
}
showResult() {
this.setState({isHide: false});
}
selectItem(row) {
this.setState({
value: row.name,
selected: row,
isHide: true,
isSearch: false
});
}
isSelected() {
return this.state.selected.id > 0;
}
cleanSelected() {
this.setState({
value: '',
selected: {
id: 0,
name: ''
}
});
}
renderState() {
let value = this.getValue(), searching = this.state.searching;
switch (searching[value]) {
case 1 :
return <span className="searching">{`搜索“${this.state.value}”中`}</span>;
break;
case 2 :
let result = this.state.results[value];
if (this.state.isHide)
return <span className="success">
{`搜索“${this.state.value}”共${result.count}条结果`}
<a onClick={() => this.showResult()} className="show">显示结果</a>
</span>;
else
return <span className="success">
{`搜索“${this.state.value}”共${result.count}条结果`}
</span>;
break;
case 3 :
return <span className="failure">{`搜索“${this.state.value}”无结果`}</span>;
break;
default :
return this.props.tip;
}
}
renderResult() {
let result = this.state.results[this.getValue()];
if (!result || result.count <= 0) {
return '';
}
else if (!this.state.isHide) {
return <div className="search-result abs">
<div>
{result.data.map((row) => {
return <div key={'search_result_' + row.id}
className="search-item"
onClick={() => this.selectItem(row)}>
<div className="search-icon"><img src={row.img}/></div>
<div className="search-info">
<div><strong>{row.name}</strong></div>
<span className="goods-price">{row.price}</span>
</div>
</div>;
})}
</div>
<div className="search-hide" onClick={() => this.hideResult()}>隐藏</div>
</div>;
}
}
renderHidden() {
if (this.props.name) {
return <input type="hidden"
name={this.props.name}
value={this.state.selected.id}/>
}
}
render() {
return <div className="">
<div className="search-input-box">
<div className="uk-form-icon input">
<i className="uk-icon-search"/>
<input type="text"
value={this.state.value}
min={this.props.min}
maxLength={this.props.max}
placeholder={`输入最少${this.props.min}个字符`}
onChange={(event) => this.changeInput(event.target.value)}
className="af-input"
/>
</div>
<button type="button"
className="uk-button uk-button-primary"
title="清除选中结果"
disabled={!this.isSelected()}
onClick={() => this.cleanSelected()}>
<i className="uk-icon-remove"/>
</button>
</div>
{this.renderHidden()}
<div className="rel">
{this.renderResult()}
</div>
<div className="af-tip">
{this.renderState()}
</div>
</div>;
}
}
$.fn.goodsSearchInput = function (props) {
if (!this.get(0))
throw new ReferenceError('Invalid DOM Element!');
else if (!this.prop('goods-search-input')) {
props = props || {};
props = _.merge(props, this.data());
let input = ReactDOM.render(<GoodsSearchInput {...props}/>, this.get(0));
this.prop('goods-search-input', input);
}
return this.prop('goods-search-input');
};
module.exports = GoodsSearchInput;
其实严格来说,还可以再优化一下,做成一个通用版本,代码也可以再少些,不过因为做的时候,是赶着项目的需求做的,所以暂时就不折腾了。
做的时候是命名为GoodsSearchInput,其实事后基本上所有自动检索部分的输入框都用了他。
忘记收了,如何调用呢?巨简单,这是js方法:
<div id="test"></div>
<script type="text/javascript">
(function($) {
$('#test').goodsSearchInput({
name: 'test',
url: 'http://localhost/test/search_goods.php',
value: '商业包装设计',
});
})(jQuery)
</script>
下面是标签方法:
<?php
$goods = Goods::getCacheOne($value);
?>
<div id="<?php echo $attr['id']; ?>"
goods-search-input
class="af-min-height"
data-url="<?php echo linkUri('ajax/search_goods', ['supplier_id' => $this->supplier->id]); ?>"
data-name="<?php echo $attr['name']; ?>"
data-value="<?php echo $goods->isExists() ? $goods->name : '' ?>"
data-select-id="<?php echo $goods->isExists() ? $goods->id : 0 ?>"
data-select-name="<?php echo $goods->isExists() ? $goods->name : '' ?>"></div>
写完调试完上述代码,用了1个小时左右的时间,增加样式调试0.5小时。剩下来的时间,可以去b站补两集番。
用React就是这样简单,如果你还没用,你out了。