react项目创建以及运行
- 先安装
npm install create-react-app --save
- 创建项目
npx create-react-app my-app
- cd my-app
- npm start
组件里引入的css文件,其他组件是通用的,也就是说,不同组件引入的样式文件,有可能会产生冲突。这个时候需要我们引入第三方工具styled-components
- 安装
npm install styled-components --save
- 创建style.js文件,里边可以通过
createGlobalStyle
创建一些全局样式
import { createGlobalStyle } from 'styled-components';
// 比如reset.css可以写在这里
// 这里用的reset.css是 https://meyerweb.com/eric/tools/css/reset/
export const GlobalStyle = createGlobalStyle`
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
`;
- 然后在index.js里引入使用
import {GlobalStyle} from './style.js';
ReactDOM.render(
<React.StrictMode>
<GlobalStyle/>
<App />
</React.StrictMode>,
document.getElementById('root')
);
用styled-components创建局部样式,需要用styled-components的组件 styled
import styled from 'styled-components';
// 这里的意思是,创建HeaderWrapper这样一个组件
// HeaderWrapper本质是div这样一个标签,下边是标签的样式
// 注意,需要把组件导出
export const HeaderWrapper = styled.div`
height:56px;
background:red;
`
- 使用HeaderWrapper这个组件
import React ,{Component} from 'react';
import {HeaderWrapper} from './style';
class Header extends Component {
render(){
return (
<HeaderWrapper>header</HeaderWrapper>
)
}
}
export default Header;
可以在src目录下,创建statics文件夹,用来存放静态资源,比如图片。
- 存放的图片该怎么用呢?
// 先引入
import logoPic from '../../statics/logo.png';
// style.js
export const Logo = styled.a`
position:absolute;
top:0;
left:0;
display:block;
width:100px;
height:56px;
background:url(${logoPic});
`
- 如果这个图片可以跳转,该怎么写跳转地址呢?
// 方法1
<HeaderWrapper>
<Logo href='/'/>
</HeaderWrapper>
// 方法2 attrs方法,接收一个对象,对象里设置href
export const Logo = styled.a.attrs({
href:'/'
})`
position:absolute;
top:0;
left:0;
display:block;
width:100px;
height:56px;
background:url(${logoPic});
background-size:contain;
`
iconfont引入项目
-
iconfont创建项目,找图标后,下载至本地
image.png -
解压缩后,把iconfont命名的文件,复制到statics文件夹下,最好是statics里再创建一个文件夹,比如iconfont,然后把iconfont.css改为iconfont.js。
image.png - 因为图标是通用的,所以,可以用createGlobalStyle创建为全局样式。特别需要注意,url后边的路径要改为
./
开头。
import { createGlobalStyle } from 'styled-components';
export const IconStyle = createGlobalStyle`
@font-face {
font-family: "iconfont"; /* Project id 3282899 */
src:
url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAQgAAsAAAAACDQAAAPRAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHFQGYACDHAqDaINEATYCJAMQCwoABCAFhGcHPxtDBxEVnBHJfh7Y4DLlUlc4pBDD8IhG80ed0hKdLn2/g+fRjno/ycxmMwvwLFZgCaADvOiPrpbVqdLc/5y2bOypvqqg62TJswzeD/DPpeAGbtHzc3tVaigDcnJGbWJcvsSBVFoj0zuU3UpaAfr7PNfklaXItwOARSV1PR8e2NkK6EAXWYR7ez7nmW8Yu7iMcxDA0YwuqF59IhIAMYumN1QBMjBoVIGwXBbNL84FWNaKKSkXLIJfd6xBduGB2qx+gJ3u+6WWFmJB4Wm0RYbNCSwAlFR0KrvrjSHQn7ApCLC9AjxAA41mZpd55d4ZaD/RCI3L+46hDWCxKKigok2lbxhC+aq0VveBav3jiY9WGgVAK5jUUIFJQEFFGwIaKrvLT2AtA4AFIoCjHfgA5maxv0Iw0dndETY5mLjJ0pZ1fV9Vz02TjXmwdDeNaXTh2K4S9uzr+dBb396NXhw/v2nlm9z5NF1wiLJykWTtlZB4oDj4/Kgmt5yS19mW5LEW/5KYEuOuUcJjQrzFukUdu0xf2r7+FgvXx433gFg3JmqUWxiMn7DEQx1LS8m9QZfgxJW4LU+6m8Yee925OiVen7DxFpTlXXl8ss+ioSFgwhA5xgl/jmbx1NTRRrWeyeowZXCwMkx9hURIFIiihiv+ryfbZnE7ZucOZYgy2Fucksocjfpdh5WNyy9+i8IcgvV0Lb5/d8DLosymg/7+Gw9Wh0UMyQM9X/inSl8cU9ayXzOn/uClE1jRQ9K4cHGAD1O9ILg9taWktiql0tleYhendLB7jZ2SOX11il66wpjQnJvLukQlgXrMKPWyQP50Wdnw5tJUvO5NqpVJpdjJwcBubr9ZYxt+mMl/Moq/F+ewDICw7qG+QUij3gSgS/SrbkfDNXM/Wmyn3zY4zKov8+/nuoGQ6dSXviqZJH2xukk1SY0cBGPylKb8Z9F1j+SgAKc74E1mIIEvffgTIXQLlpVBKCLIhMZSwDCcBvAIaAEfS2c4GtJ7ckCikJQ+YiKBOjwBCHHcoIjhLjRxvDMMp4VHCn/wieMfjjESPV9AHbHmHA1CG8wreFYSM8NALt0NOkVo8KzoAXnuwTDIgpRMrzFG3sWA/OQoRAwYTyJY0c0wDBNIeeKjRYJLlM5EkeW9RLCSqDOHgxgQiA1gcgXwsEiIYTY5xT9vA+JQEGLAazIOCU6OB+kDMgJSDcZaG9eqOJNFck44KBAEA2BwkIoAVqwbCaVEApDmt/JBLAgBt0UsZYaok7G6WmF8fXR5mwCHdqQRJVqMePgr0eCWO16VxM7ViHvdjU4HAAAA') format('woff2'),
url('./iconfont.woff?t=1648626401195') format('woff'),
url('./iconfont.ttf?t=1648626401195') format('truetype'),
url('./iconfont.svg?t=1648626401195#iconfont') format('svg');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
`;
- 然后,就可以通过各种方式展示了,比如Unicode 、Fontclass、Symbol
<i className="iconfont"></i>
经过拆分后,Header组件就变得非常明晰了。
image.png- 首先style.js里放的是组件里所有的样式。
import styled from 'styled-components';
import logoPic from '../../statics/logo.png';
// 这里的意思是,创建HeaderWrapper这样一个组件
// HeaderWrapper本质是div这样一个标签,下边是标签的样式
export const HeaderWrapper = styled.div`
height:56px;
border-bottom:1px solid #f0f0f0;
position:relative;
`
export const Logo = styled.a.attrs({
href:'/'
})`
position:absolute;
top:0;
left:0;
display:block;
width:100px;
height:56px;
background:url(${logoPic});
background-size:contain;
`
export const Nav = styled.div`
width:960px;
height:100%;
padding-right:50px;
margin:0 auto;
box-sizing:border-box;
`
export const NavItem = styled.div`
line-height:56px;
padding:0 15px;
font-size:17px;
color:#333;
&.left{
float:left;
}
&.right{
float:right;
color:#969696;
}
&.active{
color:#ea6f5a;
}
`
export const NavSearch = styled.input.attrs({
placeholder:'搜索'
})`
width:160px;
height:38px;
padding:0 30px 0 20px;
margin-top:9px;
margin-left:20px;
box-sizing:border-box;
border:none;
outline:none;
border-radius:19px;
background:#eee;
font-size:14px;
color:#666;
&::placeholder{
color:#999;
}
&.focused{
width:240px;
}
&.slide-enter{
transition:all .2s ease-out;
}
&.slide-enter-active{
width:240px;
}
&.slide-exit{
transition:all .2s ease-out;
}
&.slide-exit-active{
width:160px;
}
`
export const Addition = styled.div`
position:absolute;
right:0;
top:0;
height:56px;
`
export const Button = styled.div`
float:right;
line-height:38px;
border-radius:19px;
margin-right:20px;
padding:0 20px;
margin-top:9px;
border:1px solid #ec6149;
font-size:14px;
&.reg{
color:#ec6149;
}
&.writting{
color:#fff;
background:#ec6149;
}
`
export const SearchWrapper = styled.div`
position:relative;
float:left;
.iconfont{
position:absolute;
right:5px;
bottom:5px;
width:30px;
line-height:30px;
border-radius:15px;
text-align:center;
&.focused{
background:#777;
color:#fff;
}
}
`
-
index.js是Header组件的整体的内容,里边包含了一个UI组件(负责渲染页面上的样式),和一个容器组件(负责处理页面上的数据和逻辑)。
image.png
image.png - 组件里要存放是内容(这里是focused),都是放在store下的reducer里
import * as constants from './constants';
const defaultState = {
focused:false
};
export default (state = defaultState,action) => {
if(action.type === constants.SEARCH_FOCUS){
const newState = JSON.parse(JSON.stringify(state));
newState.focused = true;
return newState;
}
if(action.type === constants.SEARCH_BLUR){
const newState = JSON.parse(JSON.stringify(state));
newState.focused =false;
return newState;
}
return state
}
- 所以,一个组件和它相关的页面展示的内容,包括数据的内容,都统一放在Header文件夹下,以后拆分和管理会更方便。出了什么BUG,定位问题也更便捷。
利用create-react-app
的特性,来创建模拟数据
-
在public文件夹下创建一个api文件夹,里边先创建一个headerList.json
-
我们通过
image.pnghttp://localhost:3000/api/headerList.json
可以访问到headerList.json里的内容。原理是利用create-react-app
的特性。
-
create-react-app的底层也是一个node的服务器,当我们去访问api下边的headerList.json的时候,它会先到工程目录下有没有对应的路由,如果找不到,它还会到public目录下去找这个路由,如果它发现public下有api这个目录,同时api这个目录下有headerList.json这个文件,它就会把api这个目录下headerList.json这个文件的内容输出出来。通过这个特性,我们可以在public这个目录下,写一些假的数据。
-
常见的做法就是,后端接口开发出来之前,可以先在public目录下创建一个API目录,里边放一些假数据,然后上线之前,再把API这个文件夹删除掉,然后当上线或者跟后端联调的时候,因为API这个文件夹已经不存在了,请求的时候,就会以接口的内容为主了。
注意,如果我们通过fromJS方法把一个JS对象转换为immutable对象后,那么这个immutable对象里的属性如果也是immutable对象,比如defaultState的list数组。当我们在改变list的时候,就要注意,不要用普通对象去赋值list了,同样要用immutable对象给它赋值。
const defaultState = fromJS({
focused:false,
list:[]
});
- changelist 接收data后,创建一个action,这个action的data属性的值也是一个immutable对象
const changelist = (data) => ({
type:constants.CHNAGE_LIST,
data:fromJS(data)
})
- dispatch把changelist创建的action,派发给store,store结合原来的数据和这个action传给reducer.
export const getList = () => {
return (dispatch) => {
axios.get('/api/headerList.json').then((res)=>{
const data = res.data;
dispatch(changelist(data.data));
}).catch(()=>{
console.log('error')
})
}
}
- reducer里state通过set方法修改list的时候,action.data也是一个immutable对象
export default (state = defaultState,action) => {
if(action.type === constants.SEARCH_FOCUS){
return state.set('focused',true);
}
if(action.type === constants.SEARCH_BLUR){
return state.set('focused',false);
}
if(action.type === constants.CHNAGE_LIST){
return state.set('list',action.data);
}
return state
}
如果我在组件上传一个url,然后想把这个url用到background的url里怎么办?这个时候需要借助styled-components的一个props语法
// 组件上定义imgUrl并赋值
<RecommendWrapper>
<RecommendItem imgUrl="https://test.png"/>
</RecommendWrapper>
// styled.js
export const RecommendItem = styled.div`
width:280px;
height:50px;
background:url(${(props)=>props.imgUrl});
background-size:contain;
`
网友评论