[英]Dynamically applying CSS to JSX objects
我很高興在多年引用此網站后終於發表了第一篇文章。 非常感謝您在這里的每個人,我期待着成為一個積極的成員並為社區做出積極的貢獻。
我試圖為以下問題尋找更多的react-js(ish)解決方案:我們有一個使用React構建的小型應用程序,其中包含一個簡單的事件列表。 要求之一是客戶端能夠為特定事件提供自定義樣式。 因此,當我們獲取事件的數據時,該特定事件可能具有某些特定的樣式。 這些是通過API調用檢索的,該API調用將它們作為文本返回。
為了使客戶端盡可能簡單而不繁瑣,這些樣式由簡單的選擇器組成,例如'.event-container','。event-date'等。
在我具有這些樣式的原始JS工作代碼中,我將事件ID解析為它們,然后將事件ID附加到這些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);
}
};
這是我們的事件容器組件,也是實現香草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;
我不確定這是否是您的最佳選擇,但是將樣式存儲到這樣的對象中可能會更好:
const styleOptions={
eventStatus:{
color:"white",
/* other stuff in camelCase */
},
/* other options */
}
然后應用您的樣式,如下所示:
render(){
const style = styleOptions.eventStatus;
return(
<div style={style}>
...
</div>
)
}
看來這是一種更為React的樣式化組件樣式,您無需創建節點,也不必解析CSS文件。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.