开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第5天,点击查看活动详情
Header
只有1个Header组件 通过控制样式来决定不同页面的Header
写css in js 可以样式嵌套 在index中用HeaderWrapper包裹组件
export const HeaderWrapper = styled.div`
display: flex;
align-items: center;
height: 80px;
border-bottom: 1px solid #eee;
`;
模版字符串就相当于调用函数
让中间的居中:大的盒子 display: flex; 左右两边盒子为flex:1
svg可以让图片所占用的内存变小
svg引入的方式 => 封装成组件,即把svg放在独立jsx组件中,在另一个文件中引入组件即可
svg中currentColor就是离它最近的父级的颜色
styleStrToObject可以将style中字符串转成对象(在谷歌中用英语搜索style to Object)
svg图片使用到了styleStrToObject 将网页复制下来的svg中字符串样式转为对象
<svg
viewBox="0 0 32 32"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
role="presentation"
focusable="false"
style={styleStrToObject(
"display: block; height: 25px; width: 25px; fill: currentcolor;"
)}
>
<path></path>
</svg>
项目的主题配置
在index.js中使用
<ThemeProvider theme={theme}>
<HashRouter>
<App/>
</HashRouter>
</ThemeProvider>
用styled-component来管理样式主题 用props读取主题颜色
import styled from "styled-components";
.desc {
margin: 10px 0 5px;
font-size: 12px;
font-weight: 700;
color: ${(props) => props.verifyColor};
}
将阴影动画抽取用Mixins
在theme中
mixin: {
boxShadow: `
transition: box-shadow 200ms ease;
&:hover {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.18); //x y 扩展 透明度
}
`,
},
需要加阴影的元素的css中:
${(props) => props.theme.mixin.boxShadow}
点击出现panel栏
一定是绝对定位 高度由内部元素撑起,不设置固定值
切换显示、隐藏:showPanel值 再写事件处理函数
隐藏:监听点击 是在useEffect 监听window的点击,这样在页面其他地方仍然可以交互;在捕获阶段
useEffect(() => {
function windowHandleClick() {
setShowPanel(false);
}
// 最后1个参数true 是为了做事件捕获 防止事件冒泡而将showPanel设置为false
window.addEventListener("click", windowHandleClick, true);
return () => {
window.removeEventListener("click", windowHandleClick, true);
};
}, []);
主页
banner
在react中引入图片的方法:
- import
- 通过require传入src或url 因为webpack打包后图片的路径不再是原来
background:url(${require("图片路径")})
高性价比模块
直接子元素 > 避免类名重复导致样式被错误应用
export const HomeWrapper = styled.div`
> .content {
width: 1032px;
margin: 0 auto;
}
`;
网络请求获取数据的过程
代码在:
airbnb\src\store\modules\home.js
airbnb\src\store\index.js
修改state要通过reducer
reducers: {
changeGoodPriceInfoAction(state, { payload }) {
state.goodPriceInfo = payload;
},
redux中(store文件夹)通过createAsyncThunk调用网络请求方法得到数据
export const fetchHomeDataAction = createAsyncThunk(
"fetchdata",
(payload, { dispatch }) => {
getHomeGoodPriceData().then((res) => {
dispatch(changeGoodPriceInfoAction(res));
});}
在组件中的useEffect通过dispatch派发异步事件 通过useSelector获取数据
const { goodPriceInfo } = useSelector(
(state) => ({
goodPriceInfo: state.home.goodPriceInfo,
}),
shallowEqual
);
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchHomeDataAction("xxxx"));
}, [dispatch]);
数据展示
小的组件放到components
rmcp会增加propTypes对传入的参数做类型验证
footer部分
直接看代码
room-item组件
代码:airbnb\src\components\room-item\style.js
总的是弹性布局,可以换行
第一次没有数据 就给map之前的数据后面加上?
只展示前8条数据:用slice
**间距:**一行排4个 每个width是25% border-box 然后间距用padding撑开 最右和最左的左边距和右边距在最外层的盒子用margin:0 -数值 对齐
除了padding之外做一个inner div
先搭html结构展示数据
服务器给的图片的比例不一样 宽度100% 高度就会不一致
使用padding让高度是宽度的2/3 图片绝对定位
.cover {
position: relative;
box-sizing: border-box;
padding: 66.6% 8px 0;
border-radius: 3px;
overflow: hidden;
img {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
}
文本的颜色由服务器决定 服务器会返回颜色:
给ItemWrapper传入服务器返回的数据
Antd和MUI的集成
MUI的集成
css是用css in js 要用styled-component\emotion编译
如果用styled-component需要在webpack中配置别名 要同时安装emotion,因为底层MUI的依赖了emotion(卸载emotion的时候,nodemodule里面还有这个包)
npm install @mui/material @mui/styled-engine-sc styled-components
npm install @mui/material @emotion/react @emotion/styled
引入组件才能用
Antd的集成
- 安装antd
如果要写less就要在craco.config中配置插件选项
plugins: [
{
plugin: CracoLessPlugin,
options: {
lessLoaderOptions: {
lessOptions: {
modifyVars: {},
javascriptEnabled: true,
},
},
},
},
],
- 在index中引入
import "antd/dist/antd.less";
做五星好评:
自定义大小和颜色、间距
高评分模块
在service的home模块里封装网络请求
在store的home里发生请求,在AsyncThunk里发送网络请求,有2种方法
- 如果用await 就会等到一个请求完成后再请求另一个
- 用Promise,然后将store解构出dispatch,然后派发action
可以用第二种方法Promise.then的方法拿到数据后dispatch
export const fetchHomeDataAction = createAsyncThunk(
"fetchdata",
(payload, { dispatch }) => {
getHomeGoodPriceData().then((res) => {
dispatch(changeGoodPriceInfoAction(res));
});
getHomeHighScoreData().then((res) => {
dispatch(changeHighScoreInfoAction(res));
});
}
在view的home里拿到数据并展示
选项卡切换
点击每个选项卡就显示对应的页面
整理数据 过滤出有对应id的数据
在service的home模块里封装网络请求
在store的home里的AsyncThunk里发送网络请求,
因为sectionRoom封装成组件,宽度由外界决定,所以2个地方不能写固定值 动态传入宽度:
在index中传入 然后通过props拿到 在sectionRoom拿到width再传递给RoomItem,RoomItem通过props接收,再传递给ItemWrapper(样式组件) 在ItemWrapper中通过props拿到itemWidth
tabs的封装和切换
封装SectionTabs组件
数据转换 :在home的index中拿到每个item的name
展示数据 html和css flex-basis
内部切换:监听点击 currentIndex记录哪个被点击
const SectionTabs = memo((props) => {
const { tabNames = [], tabClick } = props;
const [currentIndex, setCurrentIndex] = useState(0);
function itemClickHandle(index, item) {
setCurrentIndex(index);
tabClick(index, item);
}
return (
<TabsWrapper>
<ScrollView>
{tabNames.map((item, index) => {
return (
<div
key={index}
//安装classnames 样式里有active就添加背景色
className={classNames("item", { active: index === currentIndex })}
onClick={(e) => itemClickHandle(index, item)}
>
{item}
</div>
);
})}
</ScrollView>
</TabsWrapper>
将内部切换的事件传递给外部 子传父:
父给子传递函数 在Home的index中给SectionTabs传函数 用useCallback包裹
将name定义为变量