【发布时间】:2018-11-04 08:16:36
【问题描述】:
很高兴在参考了这个网站多年之后,我终于发布了我的第一篇文章。非常感谢这里的每一个人,我期待成为一名积极的成员并为社区做出积极贡献。
我正在尝试为以下问题寻找更多 react-js(ish) 解决方案: 我们有一个用 React 构建的小应用程序,它由一个简单的事件列表组成。要求之一是客户端能够为特定事件提供自定义样式。因此,当我们获取某个事件的数据时,该特定事件可能会关联一些特定的样式。这些是通过以文本形式返回的 API 调用来检索的。
为了让客户端尽可能简单和不繁琐,这些样式由简单的选择器组成,例如'.event-container'、'.event-date' 等...
在 vanilla JS 工作代码中,我解析了这些样式,并将事件 ID 添加到这些样式之前,以便它们最终成为 '#event-1234 .event-container'、'#event-1234 .event-date ' 等等...然后我在文档的头部创建一个样式节点并用生成的 CSS 填充它...
这很好用,但它不是“反应”的做事方式,我被问到是否可以找到一个更符合 React 机制的不同解决方案......这基本上意味着,我认为,那些风格会有直接应用于 JSX 对象。为了做到这一点,我可能需要一种方法来在 react 事件组件中运行类似 querySelector 的东西,该组件返回该 JSX 节点,然后将样式应用于 JSX 节点......
到目前为止,我认为这有点麻烦......并且会增加代码复杂性并降低可能应用的 CSS 的灵活性,但也许有人比我有更好的想法,因为我没有丰富的经验还没反应过来……
非常感谢大家对此提出的意见。
这是来自特定事件的 API 调用的一些 CSS:
.event-card {
width: 100% !important;
background-color:black;
border-radius: 40px;
padding: 20px;
box-shadow: 2px 2px 2px 4px rgba(0, 0, 0, .4);
}
/* Title */
.event-name {
color:#79acd1;
}
/* Type */
.event-type {
color: white;
}
/* Progress: .event-status + .event-remaining */
.event-progress {
color:white;
}
/* Comments */
.event-comments {
color:white;
}
/* Description */
.event-description {
color:white;
}
/* Status 'open'|'closed' */
.event-status {
color:#57a5d0;
}
/* Remaining days */
.event-remaining {
color:#57a5d0;
}
/* Progress Bar Progress */
.mdc-linear-progress__bar-inner {
background-color:#57a5d0;
}
/* Progress Bar Buffer */
.mdc-linear-progress__buffer {
background-color:#44516C;
}
/* Date */
.event-date {
color:#89BBFE;
}
/* Load Button */
.mdc-button {
background-color:#79acd1;
}
这是一个普通的 JS 对象,它负责解析选择器并预先添加相关事件 ID 并将它们附加到文档:
export default {
applyStyle : function(css, id) {
let style = this.parseCSS(css, id);
if (css) {
this.createNode(style, id);
}
},
parseCSS: function (css, id) {
let _rules = css.trim().split('}');
_rules.pop();
let rules = [];
for (var rule of _rules) {
rule = rule.trim() + '}';
rules.push(`#${id} ${rule}`);
}
if (!rules.length) {
return;
}
return rules.join('\r\n');
},
createNode: function (css, id) {
let styleId = id + '-style';
if (document.getElementById(styleId)) {
return;
}
let node = document.createElement('style');
node.id = styleId;
node.innerHTML = css;
document.head.appendChild(node);
}
};
这是我们的事件容器组件,也是我实现 vanilla JS 解决方案的地方(参见“applyStyle”):
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import Loader from '../common/Loader.jsx';
import Error from '../common/Error.jsx';
import EventPanel from './EventPanel.jsx';
import {ERROR_FETCH_EVENT} from '../../constants/ErrorMessages';
import styles from '../../util/styles';
class Event extends Component {
constructor() {
super();
}
render() {
const {event} = this.props;
if (!event) {
return (<Loader/>);
}
if (event.errorMessage) {
return (
<Error messageHeader={ERROR_FETCH_EVENT} error={this.props.event.errorMessage}/>
);
}
this.htmlId = `event-${this.props.event.id}`;
let css = this.props.event.css.data || '';
styles.applyStyle(css, this.htmlId);
return (
<div id={this.htmlId} className="oc-kse-content">
<div className="oc-kse-events">
<EventPanel event={this.props.event} onEventClick={this.props.onEventClick}/>
</div>
</div>
);
}
}
Event.propTypes = {
event: PropTypes.object,
onEventClick: PropTypes.func
};
export default Event;
最后是包含大部分 JSX 的事件面板组件:
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {Button} from 'rmwc/Button';
import {Card} from 'rmwc/Card';
import {LinearProgress} from 'rmwc/LinearProgress';
import format from 'date-fns/format';
import differenceInDays from 'date-fns/difference_in_days';
import config from '../../config/AppConfig';
class EventPanel extends Component {
render() {
const {event} = this.props;
const daysRemaining = this.daysRemaining(event);
const percentagePassed = this.percentagePassed(event);
const isOpen = event.status && event.status === 'open';
const startDate = this.formattedDate(event.startEvent);
const endDate = this.formattedDate(event.endEvent);
const startTime = this.formattedTime(event.startEvent);
const endTime = this.formattedTime(event.endEvent);
if (event) {
return (
<React.Fragment>
<Card className="event-card">
{
event.imageFormats && <div className="media">
<img
src={`${config.IMAGE_HOST}${event.imageFormats.impexp.$ref}`}
alt={event.name}
className="media-image"/>
</div>
}
<div className="content">
<div className="detail">
<div className="event-type">{event.eventType}</div>
<div className="event-title">
<span className="event-name">{event.name}</span>
<span className="event-comments">
<i className="fa fa-comments fa-fw"></i>{
event.representationCount
? event.representationCount
: 0
}
</span>
</div>
<div className="event-description">
{event.description}
</div>
<div className="event-progress">
<span className="event-status">{event.status}</span>
<span className="event-remaining">{daysRemaining >= 0 && daysRemaining + ' days left'}</span>
</div>
<div>
{!isNaN(percentagePassed) && isOpen && <LinearProgress progress={percentagePassed}></LinearProgress>}
</div>
<div className="event-dates">
<div className="event-date">
<span className="span-block space-right-small">{startDate}</span>
<span>{startTime}</span>
</div>
<div className="event-date">
<span className="span-block space-right-small">{endDate}</span>
<span>{endTime}</span>
</div>
</div>
</div>
<div className="actions">
<Button
raised={true}
className="primary"
onClick={() => this.props.onEventClick(event.id)}>LOAD</Button>
</div>
</div>
</Card>
</React.Fragment>
);
}
}
}
EventPanel.propTypes = {
event: PropTypes.object,
onEventClick: PropTypes.func
};
export default EventPanel;
【问题讨论】:
-
如果你放一些代码来给你输入会更好......
-
大家好,在研究了一整天的 react 解决方案之后,我们认为 vanilla 方式是最有效和最简单的。谢谢
标签: javascript css reactjs jsx