第 5 節練習:學習加上 Styles。
1. Setting Styles Dynamically
App.js
修改
const style = {
backgroundColor: 'green',
color: 'white',
font: 'inherit',
border: '1px solid blue',
padding: '8px',
cursor: 'pointer'
};
以及增加 77 行的
style.backgroundColor = 'red';
// import logo from './logo.svg';
import './App.css';
// import { render } from 'react-dom';
import { Component } from 'react';
import Person from './Person/Person';
import person from './Person/Person';
//function App() {
class App extends Component{
state = {
persons: [
{ id:'asfa1', name:'Max', age: 28 },
{ id:'vasfa1', name:'Manu', age: 29 },
{ id:'asdf1', name:'Stephanie', age: 26 }
],
otherState: 'Some other value',
showPersons: false
}
nameChangedHandler = (event, id) => {
const personIndex =this.state.persons.findIndex(p => {
return p.id === id;
});
const person = {
...this.state.persons[personIndex]
};
//const person = Object.assign({}, this.state.persons[personIndex])
person.name = event.target.value;
const persons = [...this.state.persons];
persons[personIndex] = person;
this.setState({persons: persons});
}
deletePersonHandler = (personIndex) => {
//const persons = this.state.persons.splice();
const persons = [...this.state.persons];
persons.splice(personIndex, 1);
this.setState({persons: persons})
}
togglePersonHandler = () => {
const doesShow = this.state.showPersons;
this.setState({showPersons: !doesShow});
}
render() {
const style = {
backgroundColor: 'green',
color: 'white',
font: 'inherit',
border: '1px solid blue',
padding: '8px',
cursor: 'pointer'
};
let persons = null;
if (this.state.showPersons === true) {
persons = (
<div>
{this.state.persons.map((person, index) => {
return <Person
click={() => this.deletePersonHandler(index)}
name={person.name}
age={person.age}
key={person.id}
changed={(event) => this.nameChangedHandler(event, person.id)} />
})}
</div>
);
style.backgroundColor = 'red';
}
return (
<div className="App">
<h1>Hi, I'm a React App, Wendy</h1>
<p>This is really working!</p>
<button style={style} onClick={this.togglePersonHandler}>Taggle Persons</button>
{persons}
</div>
);
//return React.createElement('div', {classname: 'App'}, React.createElement('h1', null, 'Does this work now?'));
}
}
export default App;
呈現結果:按鈕未點選時是綠色,點選後變成紅色。
2. Setting Class Names Dynamically
App.js
// import logo from './logo.svg';
import './App.css';
// import { render } from 'react-dom';
import { Component } from 'react';
import Person from './Person/Person';
//import person from './Person/Person';
//import classes from '*.module.css';
//function App() {
class App extends Component{
state = {
persons: [
{ id:'asfa1', name:'Max', age: 28 },
{ id:'vasfa1', name:'Manu', age: 29 },
{ id:'asdf1', name:'Stephanie', age: 26 }
],
otherState: 'Some other value',
showPersons: false
}
nameChangedHandler = (event, id) => {
const personIndex =this.state.persons.findIndex(p => {
return p.id === id;
});
const person = {
...this.state.persons[personIndex]
};
//const person = Object.assign({}, this.state.persons[personIndex])
person.name = event.target.value;
const persons = [...this.state.persons];
persons[personIndex] = person;
this.setState({persons: persons});
}
deletePersonHandler = (personIndex) => {
//const persons = this.state.persons.splice();
const persons = [...this.state.persons];
persons.splice(personIndex, 1);
this.setState({persons: persons})
}
togglePersonHandler = () => {
const doesShow = this.state.showPersons;
this.setState({showPersons: !doesShow});
}
render() {
const style = {
backgroundColor: 'green',
color: 'white',
font: 'inherit',
border: '1px solid blue',
padding: '8px',
cursor: 'pointer'
};
let persons = null;
if (this.state.showPersons === true) {
persons = (
<div>
{this.state.persons.map((person, index) => {
return <Person
click={() => this.deletePersonHandler(index)}
name={person.name}
age={person.age}
key={person.id}
changed={(event) => this.nameChangedHandler(event, person.id)} />
})}
</div>
);
style.backgroundColor = 'red';
}
//let classes = ['red', 'bold'].join(' ');
const classes = [];
if (this.state.persons.length <= 2) {
classes.push('red'); //classes = ['red']
}
if (this.state.persons.length <= 1) {
classes.push('bold'); //classes = ['red', 'bold']
}
return (
<div className="App">
<h1>Hi, I'm a React App, Wendy</h1>
<p className={classes.join(' ')}>This is really working!</p>
<button style={style} onClick={this.togglePersonHandler}>Taggle Persons</button>
{persons}
</div>
);
//return React.createElement('div', {classname: 'App'}, React.createElement('h1', null, 'Does this work now?'));
}
}
export default App;
App.css
.App {
text-align: center;
}
.red {
color: red;
}
.bold {
font-weight: bold;
}
button{
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
呈現結果:當卡片長度>=2時,This is really working!會變成紅色,當卡片長度>=1時,This is really working!會變成紅色+粗體。
3. Adding and Using Radium
安裝 radium:npm install --save radium
過程中遇到無法執行程式...
有可能一開始有東西沒有裝好/版本問題:
先移除一些東西:rm -rf node_modules package-lock.json
再重新安裝:npm install
執行後恢復正常。
App.js
// import logo from './logo.svg';
import React, { Component } from 'react';
import './App.css';
import Radium from 'radium';
// import { render } from 'react-dom';
import Person from './Person/Person';
//import person from './Person/Person';
//import classes from '*.module.css';
//function App() {
class App extends Component{
state = {
persons: [
{ id:'asfa1', name:'Max', age: 28 },
{ id:'vasfa1', name:'Manu', age: 29 },
{ id:'asdf1', name:'Stephanie', age: 26 }
],
otherState: 'Some other value',
showPersons: false
}
nameChangedHandler = (event, id) => {
const personIndex =this.state.persons.findIndex(p => {
return p.id === id;
});
const person = {
...this.state.persons[personIndex]
};
//const person = Object.assign({}, this.state.persons[personIndex])
person.name = event.target.value;
const persons = [...this.state.persons];
persons[personIndex] = person;
this.setState({persons: persons});
}
deletePersonHandler = (personIndex) => {
//const persons = this.state.persons.splice();
const persons = [...this.state.persons];
persons.splice(personIndex, 1);
this.setState({persons: persons})
}
togglePersonHandler = () => {
const doesShow = this.state.showPersons;
this.setState({showPersons: !doesShow});
}
render() {
const style = {
backgroundColor: 'green',
color: 'white',
font: 'inherit',
border: '1px solid blue',
padding: '8px',
cursor: 'pointer',
':hover': {
backgroundColor: 'lightgreen',
color: 'black'
}
};
let persons = null;
if (this.state.showPersons === true) {
persons = (
<div>
{this.state.persons.map((person, index) => {
return <Person
click={() => this.deletePersonHandler(index)}
name={person.name}
age={person.age}
key={person.id}
changed={(event) => this.nameChangedHandler(event, person.id)} />
})}
</div>
);
style.backgroundColor = 'red';
style[':hover'] = {
backgroundColor: 'salmon',
color: 'black'
}
}
//let classes = ['red', 'bold'].join(' ');
const classes = [];
if (this.state.persons.length <= 2) {
classes.push('red'); //classes = ['red']
}
if (this.state.persons.length <= 1) {
classes.push('bold'); //classes = ['red', 'bold']
}
return (
<div className="App">
<h1>Hi, I'm a React App, Wendy</h1>
<p className={classes.join(' ')}>This is really working!</p>
<button style={style} onClick={this.togglePersonHandler}>Taggle Persons</button>
{persons}
</div>
);
//return React.createElement('div', {classname: 'App'}, React.createElement('h1', null, 'Does this work now?'));
}
}
export default Radium(App);
Person.js
import React from 'react';
import Radium from 'radium';
import './Person.css';
const person = (props) => {
return (
<div className="Person">
<p onClick={props.click}>I'm {props.name} and I am {props.age} years old.</p>
<p>{props.children}</p>
<input type="text" onChange={props.changed} value={props.name}/>
</div>
)
}
export default Radium(person);
呈現結果:滑鼠移到按鈕上可以改變顏色(截圖是移到按鈕上時所截取的)。
4. Using Radium for Media Queries
App.js
// import logo from './logo.svg';
import React, { Component } from 'react';
import './App.css';
import Radium, { StyleRoot } from 'radium';
// import { render } from 'react-dom';
import Person from './Person/Person';
//import person from './Person/Person';
//import classes from '*.module.css';
//function App() {
class App extends Component{
state = {
persons: [
{ id:'asfa1', name:'Max', age: 28 },
{ id:'vasfa1', name:'Manu', age: 29 },
{ id:'asdf1', name:'Stephanie', age: 26 }
],
otherState: 'Some other value',
showPersons: false
}
nameChangedHandler = (event, id) => {
const personIndex =this.state.persons.findIndex(p => {
return p.id === id;
});
const person = {
...this.state.persons[personIndex]
};
//const person = Object.assign({}, this.state.persons[personIndex])
person.name = event.target.value;
const persons = [...this.state.persons];
persons[personIndex] = person;
this.setState({persons: persons});
}
deletePersonHandler = (personIndex) => {
//const persons = this.state.persons.splice();
const persons = [...this.state.persons];
persons.splice(personIndex, 1);
this.setState({persons: persons})
}
togglePersonHandler = () => {
const doesShow = this.state.showPersons;
this.setState({showPersons: !doesShow});
}
render() {
const style = {
backgroundColor: 'green',
color: 'white',
font: 'inherit',
border: '1px solid blue',
padding: '8px',
cursor: 'pointer',
':hover': {
backgroundColor: 'lightgreen',
color: 'black'
}
};
let persons = null;
if (this.state.showPersons === true) {
persons = (
<div>
{this.state.persons.map((person, index) => {
return <Person
click={() => this.deletePersonHandler(index)}
name={person.name}
age={person.age}
key={person.id}
changed={(event) => this.nameChangedHandler(event, person.id)} />
})}
</div>
);
style.backgroundColor = 'red';
style[':hover'] = {
backgroundColor: 'salmon',
color: 'black'
}
}
//let classes = ['red', 'bold'].join(' ');
const classes = [];
if (this.state.persons.length <= 2) {
classes.push('red'); //classes = ['red']
}
if (this.state.persons.length <= 1) {
classes.push('bold'); //classes = ['red', 'bold']
}
return (
<StyleRoot>
<div className="App">
<h1>Hi, I'm a React App, Wendy</h1>
<p className={classes.join(' ')}>This is really working!</p>
<button style={style} onClick={this.togglePersonHandler}>Taggle Persons</button>
{persons}
</div>
</StyleRoot>
);
//return React.createElement('div', {classname: 'App'}, React.createElement('h1', null, 'Does this work now?'));
}
}
export default Radium(App);
Person.js
import React from 'react';
import Radium from 'radium';
import './Person.css';
const person = (props) => {
const style = {
'@media (min-width: 500px)': {
width: '450px'
}
};
return (
<div className="Person" style={style}>
<p onClick={props.click}>I'm {props.name} and I am {props.age} years old.</p>
<p>{props.children}</p>
<input type="text" onChange={props.changed} value={props.name}/>
</div>
)
};
export default Radium(person);
呈現結果:可以有響應式頁面的效果。
問題:但將頁面縮到最小的時候,text輸入框無法呈現效果。
5. Introducing Styled Components & Dynamic Styles
安裝 styled-components:npm install --save styled-components
過程中遇到無法執行程式...
跟著出現的提示照做之後再重新安裝可以正常。
App.js
注意:要用;
const StyledButton = styled.button`
background-color: ${props => props.alt ? 'red' : 'green'};
color: white;
font: inherit;
border: 1px solid blue;
padding: 8px;
cursor: pointer;
&:hover {
background-color: ${props => props.alt ? 'salmon' : 'lightgreen'};
color: black;
}
`;
// import logo from './logo.svg';
import React, { Component } from 'react';
import styled from 'styled-components';
import './App.css';
//import Radium, { StyleRoot } from 'radium';
// import { render } from 'react-dom';
import Person from './Person/Person';
//import person from './Person/Person';
//import classes from '*.module.css';
const StyledButton = styled.button`
background-color: ${props => props.alt ? 'red' : 'green'};
color: white;
font: inherit;
border: 1px solid blue;
padding: 8px;
cursor: pointer;
&:hover {
background-color: ${props => props.alt ? 'salmon' : 'lightgreen'};
color: black;
}
`;
//function App() {
class App extends Component{
state = {
persons: [
{ id:'asfa1', name:'Max', age: 28 },
{ id:'vasfa1', name:'Manu', age: 29 },
{ id:'asdf1', name:'Stephanie', age: 26 }
],
otherState: 'Some other value',
showPersons: false
}
nameChangedHandler = (event, id) => {
const personIndex =this.state.persons.findIndex(p => {
return p.id === id;
});
const person = {
...this.state.persons[personIndex]
};
//const person = Object.assign({}, this.state.persons[personIndex])
person.name = event.target.value;
const persons = [...this.state.persons];
persons[personIndex] = person;
this.setState({persons: persons});
}
deletePersonHandler = (personIndex) => {
//const persons = this.state.persons.splice();
const persons = [...this.state.persons];
persons.splice(personIndex, 1);
this.setState({persons: persons})
}
togglePersonHandler = () => {
const doesShow = this.state.showPersons;
this.setState({showPersons: !doesShow});
}
render() {
const style = {
backgroundColor: 'green',
color: 'white',
font: 'inherit',
border: '1px solid blue',
padding: '8px',
cursor: 'pointer',
':hover': {
backgroundColor: 'lightgreen',
color: 'black'
}
};
let persons = null;
if (this.state.showPersons === true) {
persons = (
<div>
{this.state.persons.map((person, index) => {
return <Person
click={() => this.deletePersonHandler(index)}
name={person.name}
age={person.age}
key={person.id}
changed={(event) => this.nameChangedHandler(event, person.id)} />
})}
</div>
);
/*style.backgroundColor = 'red';
style[':hover'] = {
backgroundColor: 'salmon',
color: 'black'
}*/
}
//let classes = ['red', 'bold'].join(' ');
const classes = [];
if (this.state.persons.length <= 2) {
classes.push('red'); //classes = ['red']
}
if (this.state.persons.length <= 1) {
classes.push('bold'); //classes = ['red', 'bold']
}
return (
//<StyleRoot>
<div className="App">
<h1>Hi, I'm a React App, Wendy</h1>
<p className={classes.join(' ')}>This is really working!</p>
<StyledButton alt={this.state.showPersons} onClick={this.togglePersonHandler}>Taggle Persons</StyledButton>
{persons}
</div>
//</StyleRoot>
);
//return React.createElement('div', {classname: 'App'}, React.createElement('h1', null, 'Does this work now?'));
}
}
//export default Radium(App);
export default App;
Person.js
import React from 'react';
//import Radium from 'radium';
import styled from 'styled-components';
//import './Person.css';
const StyledDiv = styled.div`
width: 60%;
margin: 16px auto;
border: 1px solid #eee;
box-shadow: 0 2px 3px #ccc;
padding: 16px;
text-align: center;
@media (min-width: 500px) {
width: 450px;
}
`;
const person = (props) => {
/*const style = {
'@media (min-width: 500px)': {
width: '450px'
}
};*/
return (
//<div className="Person" style={style}>
<StyledDiv>
<p onClick={props.click}>I'm {props.name} and I am {props.age} years old.</p>
<p>{props.children}</p>
<input type="text" onChange={props.changed} value={props.name}/>
</StyledDiv>
)
};
//export default Radium(person);
export default person;
Person.css
/*.Person{
width: 60%;
margin: 16px auto;
border: 1px solid #eee;
box-shadow: 0 2px 3px #ccc;
padding: 16px;
text-align: center;
}
@media (min-width: 500px) {
.Person {
width: 450px;
}
}*/
呈現結果:跟前面的結果一樣,只是將原本 CSS 程式部分整理成單一 component 的 CSS。
6. Workong with CSS Modules & Media Queries
npm run eject
git add .
git commit -m "removed styled components from app.js"
npm run eject
App.js
// import logo from './logo.svg';
import React, { Component } from 'react';
import styled from 'styled-components';
import './App.css';
//import Radium, { StyleRoot } from 'radium';
// import { render } from 'react-dom';
import Person from './Person/Person';
//import person from './Person/Person';
//import classes from '*.module.css';
/*const StyledButton = styled.button`
background-color: ${props => props.alt ? 'red' : 'green'};
color: white;
font: inherit;
border: 1px solid blue;
padding: 8px;
cursor: pointer;
&:hover {
background-color: ${props => props.alt ? 'salmon' : 'lightgreen'};
color: black;
}
`;*/
//function App() {
class App extends Component{
state = {
persons: [
{ id:'asfa1', name:'Max', age: 28 },
{ id:'vasfa1', name:'Manu', age: 29 },
{ id:'asdf1', name:'Stephanie', age: 26 }
],
otherState: 'Some other value',
showPersons: false
}
nameChangedHandler = (event, id) => {
const personIndex =this.state.persons.findIndex(p => {
return p.id === id;
});
const person = {
...this.state.persons[personIndex]
};
//const person = Object.assign({}, this.state.persons[personIndex])
person.name = event.target.value;
const persons = [...this.state.persons];
persons[personIndex] = person;
this.setState({persons: persons});
}
deletePersonHandler = (personIndex) => {
//const persons = this.state.persons.splice();
const persons = [...this.state.persons];
persons.splice(personIndex, 1);
this.setState({persons: persons})
}
togglePersonHandler = () => {
const doesShow = this.state.showPersons;
this.setState({showPersons: !doesShow});
}
render() {
const style = {
backgroundColor: 'green',
color: 'white',
font: 'inherit',
border: '1px solid blue',
padding: '8px',
cursor: 'pointer',
':hover': {
backgroundColor: 'lightgreen',
color: 'black'
}
};
let persons = null;
if (this.state.showPersons === true) {
persons = (
<div>
{this.state.persons.map((person, index) => {
return <Person
click={() => this.deletePersonHandler(index)}
name={person.name}
age={person.age}
key={person.id}
changed={(event) => this.nameChangedHandler(event, person.id)} />
})}
</div>
);
/*style.backgroundColor = 'red';
style[':hover'] = {
backgroundColor: 'salmon',
color: 'black'
}*/
}
//let classes = ['red', 'bold'].join(' ');
const classes = [];
if (this.state.persons.length <= 2) {
classes.push('red'); //classes = ['red']
}
if (this.state.persons.length <= 1) {
classes.push('bold'); //classes = ['red', 'bold']
}
return (
//<StyleRoot>
<div className="App">
<h1>Hi, I'm a React App, Wendy</h1>
<p className={classes.join(' ')}>This is really working!</p>
<button className="button" onClick={this.togglePersonHandler}>Taggle Persons</button>
{persons}
</div>
//</StyleRoot>
);
//return React.createElement('div', {classname: 'App'}, React.createElement('h1', null, 'Does this work now?'));
}
}
//export default Radium(App);
export default App;
App.css
.App {
text-align: center;
}
.red {
color: red;
}
.bold {
font-weight: bold;
}
.button{
background-color: green;
color: white;
font: inherit;
border: 1px solid blue;
padding: 8px;
cursor: pointer;
}
.button:hover{
background-color: lightgreen;
color: black;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
呈現結果:跟前面的結果一樣,只是將 styled-components 的 CSS 程式部分整理成 .css,但是紅色暫時沒有出現,另外執行 npm run eject 後的程式碼跟教學相比看似有些不同了(第 73. 的 6 分鐘左右),後面 73, 74 先大概看過,待處理。