怎么建设商品网站,企业注册信息,一个软件开发需要什么技术,wordpress是公益1.React介绍
React由Meta公司开发#xff0c;是一个用于构建Web和原生交互界面的库 1.1 React优势
相较于传统基于DOM开发的优势
1.组件化的开发方式
2.不错的性能
相较于其他前端框架的优势
1.丰富的生态
2.跨平台支持
1.2React的时长情况 全球最流行#xff0c;大厂…1.React介绍
React由Meta公司开发是一个用于构建Web和原生交互界面的库 1.1 React优势
相较于传统基于DOM开发的优势
1.组件化的开发方式
2.不错的性能
相较于其他前端框架的优势
1.丰富的生态
2.跨平台支持
1.2React的时长情况 全球最流行大厂必备 2.开发环境创建
create-react-app是一个快速创建React开发环境的工具底层由Webpack构件封装了配置细节开箱即用执行命令
npx create-react-app react-basiccd react-basic
npm start创建项目更多方式
https://zh-hans.react.dev/learn/start-a-new-react-project
3.JSX基础
3.1什么是JSX JSX是JavaScript和XML(HTML)的缩写表示在JS代码中编写HTML模板结构是React构建UI的方式 const message this is messagefunction App() {return (div classNameApph1My First React App/h1{message}/div);
}export default App;
3.2 JSX的本质 JSX并不是标准的JS语法它是 JS的语法扩展浏览器本身不能识别需要通过解析工具做解析之后才能在浏览器中使用 3.3JSX高频场景-JS表达式 在JSX中可以通过 font stylecolor:rgb(119, 119, 119);background-color:rgb(248, 248, 248);大括号语法{}/font 识别JavaScript中的表达式比如常见的变量、函数调用、方法调用等等 使用引号传递字符串、JS变量、函数调用和方法调用、对象
注意不能使用条件语句
const message this is messagefunction getAge(){return 18
}function App() {return (div classNameApph1My First React App/h1{message}{/*函数调用*/}{getAge()}/div);
}export default App;
3.4JS高频场景-列表场景 const list [{id:1001, name:Vue},{id:1002, name: React},{id:1003, name: Angular}
]function App(){return (ul{list.map(item li key{item.id}{item.name}/li)}/ul);
}export default App;
3.5JS高频场景-条件渲染 在React中可以通过逻辑与运算、三元表达式(?:)实现基础的条件渲染 const flag true;
const loading true;function App() {return ({flag spanthis is span/span}{loading ? spanloading.../span:spanthis is span/span}/)
}export default App;3.6JSX高频场景-复杂条件渲染
需求列表中需要根据文章的状态适配
const type 0; // 0 1 3function getArticleJSX() {if (type 0) {return div无图模式/div} else if (type 1) {return div单图模式/div} else if(type 3){return div多图模式/div}
}function App() {return ({getArticleJSX()}/)
}export default App;4.React的事件绑定
4.1基础实现 React中的事件绑定通过语法on 事件名称 {事件处理程序}。整体上遵循驼峰命名 function App() {const clickHandle () {console.log(button按钮点击了);}return (button onClick{clickHandle}click me/button)
}export default App;4.2使用事件参数 在事件回调函数中设置形参e即可 function App() {const clickHandle (e) {console.log(button按钮点击了, e);}return (button onClick{clickHandle}click me/button)
}export default App;4.3传递自定义参数 语法事件绑定的位置改造成箭头函数的写法再执行clickHandler实际处理业务函数的时候传递实参 function App() {const clickHandle (name) {console.log(button按钮点击了, name);}return (button onClick{()clickHandle(jack)}click me/button)
}export default App;注意不能直接写函数调用这里事件绑定需要一个函数引用 4.4同时传递事件对象的自定义参数 语法在事件绑定位置传递事件实参e的自定义参数clickHandle中声明形参注意顺序对应 function App() {const clickHandle (name, e) {console.log(button按钮点击了, name, e);}return (button onClick{(e)clickHandle(jack, e)}click me/button)
}export default App;5.React组件基础使用
5.1 组件是什么
概念一个组件就是一个用户界面的一部分它可以有自己的逻辑和外观组件之间可以互相嵌套也可以服用多次 5.2组件基础使用 在React中一个组件就是首字母大写的函数内部存放了组件的逻辑和视图UI渲染增加只需要把组件当作标签书写即可 function Button() {return buttonclick me/button
}
function App() {return (divButton/Button/Button/div)
}export default App;6.组件状态管理-useStatue
6.1基础使用 useState是一个React Hook函数它允许我们向组件添加一个状态变量从而控制影响组件的渲染结果和普通的JS变量不同的是状态变量一旦发生变化组件的视图UI也会跟着发生变化数据驱动试图 import React from react;function App() {const [count, setCount] React.useState(0)return (divbutton onClick{()setCount(count 1)}{count}/button/div)
}export default App;6.2状态的修改规则 在React中状态被认为是只读的我们应该始终替换它而不是修改它直接修改状态不能引发视图更新 6.3修改对象状态 对于对象类型的状态变量应该始终给set方法一个全新的对象来进行修改 import React from react;function App() {const [form, setForm] React.useState({name : jack})const handleChageName() {setForm({...form,name : john})}return (divbutton onClick{()handleChageName()}{form.name}/button/div)
}export default App;
7.组建的基础样式处理 React组件基础的样式控制有两种方式行内样式和class类名控制 import React from react;function App() {return (divdiv style{{color:red}} this is div/div/div)
}export default App;
index.css
.foo{color: red;
}App.js
import ./index.css;function App() {return (divdiv classNamefoo this is div/div/div)
}export default App;
8.B站评论案例 渲染评论列表删除评论实现渲染导航Tab和高亮实现评论列表排序功能实现
8.1基础项目
App.js
import ./App.scss
import avatar from ./images/bozai.png/*** 评论列表的渲染和操作** 1. 根据状态渲染评论列表* 2. 删除评论*/// 评论列表数据
const defaultList [{// 评论idrpid: 3,// 用户信息user: {uid: 13258165,avatar: ,uname: 周杰伦,},// 评论内容content: 哎哟不错哦,// 评论时间ctime: 10-18 08:15,like: 88,},{rpid: 2,user: {uid: 36080105,avatar: ,uname: 许嵩,},content: 我寻你千百度 日出到迟暮,ctime: 11-13 11:29,like: 88,},{rpid: 1,user: {uid: 30009257,avatar,uname: 黑马前端,},content: 学前端就来黑马,ctime: 10-19 09:00,like: 66,},
]
// 当前登录用户信息
const user {// 用户iduid: 30009257,// 用户头像avatar,// 用户昵称uname: 黑马前端,
}/*** 导航 Tab 的渲染和操作** 1. 渲染导航 Tab 和高亮* 2. 评论列表排序* 最热 喜欢数量降序* 最新 创建时间降序*/// 导航 Tab 数组
const tabs [{ type: hot, text: 最热 },{ type: time, text: 最新 },
]const App () {return (div classNameapp{/* 导航 Tab */}div classNamereply-navigationul classNamenav-barli classNamenav-titlespan classNamenav-title-text评论/span{/* 评论数量 */}span classNametotal-reply{10}/span/lili classNamenav-sort{/* 高亮类名 active */}span classNamenav-item最新/spanspan classNamenav-item最热/span/li/ul/divdiv classNamereply-wrap{/* 发表评论 */}div classNamebox-normal{/* 当前用户头像 */}div classNamereply-box-avatardiv classNamebili-avatarimg classNamebili-avatar-img src{avatar} alt用户头像 //div/divdiv classNamereply-box-wrap{/* 评论框 */}textareaclassNamereply-box-textareaplaceholder发一条友善的评论/{/* 发布按钮 */}div classNamereply-box-senddiv classNamesend-text发布/div/div/div/div{/* 评论列表 */}div classNamereply-list{/* 评论项 */}div classNamereply-item{/* 头像 */}div classNameroot-reply-avatardiv classNamebili-avatarimgclassNamebili-avatar-imgalt//div/divdiv classNamecontent-wrap{/* 用户名 */}div classNameuser-infodiv classNameuser-namejack/div/div{/* 评论内容 */}div classNameroot-replyspan classNamereply-content这是一条评论回复/spandiv classNamereply-info{/* 评论时间 */}span classNamereply-time{2023-11-11}/span{/* 评论数量 */}span classNamereply-time点赞数:{100}/spanspan classNamedelete-btn删除/span/div/div/div/div/div/div/div)
}export default AppApp.scss
.app {width: 80%;margin: 50px auto;
}.reply-navigation {margin-bottom: 22px;.nav-bar {display: flex;align-items: center;margin: 0;padding: 0;list-style: none;.nav-title {display: flex;align-items: center;width: 114px;font-size: 20px;.nav-title-text {color: #18191c;font-weight: 500;}.total-reply {margin: 0 36px 0 6px;color: #9499a0;font-weight: normal;font-size: 13px;}}.nav-sort {display: flex;align-items: center;color: #9499a0;font-size: 13px;.nav-item {cursor: pointer;:hover {color: #00aeec;}:last-child::after {display: none;}::after {content: ;display: inline-block;height: 10px;width: 1px;margin: -1px 12px;background-color: #9499a0;}}.nav-item.active {color: #18191c;}}}
}.reply-wrap {position: relative;
}
.box-normal {display: flex;transition: 0.2s;.reply-box-avatar {display: flex;align-items: center;justify-content: center;width: 80px;height: 50px;}.reply-box-wrap {display: flex;position: relative;flex: 1;.reply-box-textarea {width: 100%;height: 50px;padding: 5px 10px;box-sizing: border-box;color: #181931;font-family: inherit;line-height: 38px;background-color: #f1f2f3;border: 1px solid #f1f2f3;border-radius: 6px;outline: none;resize: none;transition: 0.2s;::placeholder {color: #9499a0;font-size: 12px;}:focus {height: 60px;background-color: #fff;border-color: #c9ccd0;}}}.reply-box-send {position: relative;display: flex;flex-basis: 86px;align-items: center;justify-content: center;margin-left: 10px;border-radius: 4px;cursor: pointer;transition: 0.2s; .send-text {position: absolute;z-index: 1;color: #fff;font-size: 16px;}::after {position: absolute;width: 100%;height: 100%;background-color: #00aeec;border-radius: 4px;opacity: 0.5;content: ;}:hover::after {opacity: 1;}}
}
.bili-avatar {position: relative;display: block;width: 48px;height: 48px;margin: 0;padding: 0;border-radius: 50%;
}
.bili-avatar-img {position: absolute;top: 50%;left: 50%;display: block;width: 48px;height: 48px;object-fit: cover;border: none;border-radius: 50%;image-rendering: -webkit-optimize-contrast;transform: translate(-50%, -50%);
}// 评论列表
.reply-list {margin-top: 14px;
}
.reply-item {padding: 22px 0 0 80px;.root-reply-avatar {position: absolute;left: 0;display: flex;justify-content: center;width: 80px;cursor: pointer;}.content-wrap {position: relative;flex: 1;::after {content: ;display: block;height: 1px;width: 100%;margin-top: 14px;background-color: #e3e5e7;}.user-info {display: flex;align-items: center;margin-bottom: 4px;.user-name {height: 30px;margin-right: 5px;color: #61666d;font-size: 13px;line-height: 30px;cursor: pointer;}}.root-reply {position: relative;padding: 2px 0;color: #181931;font-size: 15px;line-height: 24px;.reply-info {position: relative;display: flex;align-items: center;margin-top: 2px;color: #9499a0;font-size: 13px;.reply-time {width: 86px;margin-right: 20px;}.reply-like {display: flex;align-items: center;margin-right: 19px;.like-icon {width: 14px;height: 14px;margin-right: 5px;color: #9499a0;background-position: -153px -25px;:hover {background-position: -218px -25px;}}.like-icon.liked {background-position: -154px -89px;}}.reply-dislike {display: flex;align-items: center;margin-right: 19px;.dislike-icon {width: 16px;height: 16px;background-position: -153px -153px;:hover {background-position: -217px -153px;}}.dislike-icon.disliked {background-position: -154px -217px;}}.delete-btn {cursor: pointer;:hover {color: #00aeec;}}}}}
}.reply-none {height: 64px;margin-bottom: 80px;color: #99a2aa;font-size: 13px;line-height: 64px;text-align: center;
}
8.2完成版本
8.2.1列表渲染
{/* 评论项 */}{list.map((item) (div key{item.user.uid} classNamereply-item{/* 头像 */}div classNameroot-reply-avatardiv classNamebili-avatarimgclassNamebili-avatar-imgalt//div/divdiv classNamecontent-wrap{/* 用户名 */}div classNameuser-infodiv classNameuser-name{item.user.uname}/div/div{/* 评论内容 */}div classNameroot-replyspan classNamereply-content{item.content}/spandiv classNamereply-info{/* 评论时间 */}span classNamereply-time{item.ctime}/span{/* 评论数量 */}span classNamereply-time点赞数:{item.like}/spanspan classNamedelete-btn onClick{()deleteItem(item.rpid)}
删除
/span/div/div/div/div))8.2.2 删除评论 const [list, setList] useState(defaultList)const deleteItem (rpid) {setList(list.filter(item item.rpid ! rpid));}8.3.2渲染导航Tab和高亮显示 li classNamenav-sort{/* 高亮类名 active */}{tabs.map((tab) (spankey{tab.type}className{nav-item ${tab.type activeTabType ? active : }}onClick{() tabChange(tab.type)}{tab.text}/span))}{/*span classNamenav-item onClick{()tabChange(time)}最热/span*/}/liconst [activeTabType, setActiveTabType] useState(tabs[0].type); // 初始激活第一个 tabconst tabChange (type) {setActiveTabType(type);};8.3.4评论列表排序
安装lodash库
npm install lodashconst [list, setList] useState(defaultList)
useEffect(() {// 根据点赞数量排序热度排序const sortedComments _.orderBy(list, like, desc)setList(sortedComments);
}, []); // 空依赖数组表示这个 effect 只在组件挂载和卸载时运行一次
const deleteItem (rpid) {setList(list.filter(item item.rpid ! rpid));
}
const [activeTabType, setActiveTabType] useState(tabs[0].type); // 初始激活第一个 tabconst tabChange (type) {setActiveTabType(type);if (type hot) {setList(_.orderBy(list, like, desc));} else if (type time) {setList(_.orderBy(list, ctime, asc));}
};8.3.5 样式书写优化
npm install classnames className{classNames(nav-item, {active: tab.type activeTabType})}9.React表单控制
9.1受控绑定 概念使用React组件的状态useState控制表单状态 import {useState} from react;function App() {const [value, setValue] useState();return (input typetextvalue{value}onChange{(e) setValue(e.target.value)}/input);
}export default App;9.2非受控绑定 概念通过DOM的方式获取表单的输入数据 import {useRef} from react;function App() {var inputRef useRef(null);const onChange () {console.log(inputRef.current.value)}return (input typetextref{inputRef}onChange{onChange}/input);
}export default App;
10.案例-B站评论案例 1.输入评论内容并发布评论
1进行表单受控绑定 div classNamereply-box-wrap{/* 评论框 */}textareaclassNamereply-box-textareaplaceholder发一条友善的评论value {textValue}onChange{(e)setTextValue(e.target.value)}/{/* 发布按钮 */}div classNamereply-box-senddiv classNamesend-text onClick{()sendComment(textValue)}发布/div/div
/div2点击“发布”触发发布评论 const [textValue, setTextValue] useState();
const sendComment () {setList([...list,{// 评论idrpid: 3,// 用户信息user: user,// 评论内容content: textValue,// 评论时间ctime: new Date().toLocaleString(),like: 88,}])setTextValue();}3非受控绑定输入框 div classNamereply-box-wrap{/* 评论框 */}textareaclassNamereply-box-textareaplaceholder发一条友善的评论value {textValue}ref{inputRef}onChange{(e)setTextValue(e.target.value)}/{/* 发布按钮 */}div classNamereply-box-senddiv classNamesend-text onClick{()sendComment(textValue)}发布/div/div
/div4光标聚焦 const sendComment () {setList([...list,{// 评论idrpid: 3,// 用户信息user: user,// 评论内容content: textValue,// 评论时间ctime: new Date().toLocaleString(),like: 88,}])setTextValue();inputRef.current.focus();}2.id处理和时间处理uuid和day.js
npm install dayjs --save
npm install uuid --save具体代码实现
const sendComment () {setList([...list,{// 评论idrpid: uuidV4(),// 用户信息user: user,// 评论内容content: textValue,// 评论时间ctime: dayjs(new Date()).format(MM-DD hh:mm),like: 88,}])setTextValue();inputRef.current.focus();}11.React组件通信 概念组件通信就是组件之间的数据传递根据组件嵌套关系的不同有不同的通信手段和方法 A-B 父子通信B-C 兄弟通信A-E 跨层通信
11.1 父子通信-父传子 11.1.1 基础实现
实现步骤
1.父组件传递数据-在子组件标签上绑定属性
2.子组件接收数据-子组件通过props参数接受数据
function Son(props) {return (div{props.name}/div)
}function App() {const name reactreturn (divSon name{name} //div);
}export default App;
11.1.2props说明
props可以传递任意的合法数据比如数字、字符串、布尔值、数组、对象、函数、JSX props是只读对象
子组件只能读取props中的数据不能直接进行修改父组件的数据只能由父组件修改
11.1.3特殊的prop-chilren 场景当我们把内容嵌套在组件的标签内部时组件会自动在名为children的prop属性中接受该内容 function Son(props) {return div{props.children}/div
}
function App() {const name reactreturn (Sonspanthis is span/span/Son);
}export default App;
11.2 父子通信-子传父 核心思想子组件中调用父组件中的参数并传递函数 function Son({ onGetMsg}) {const msg this is son msg;return (divbutton onClick{() onGetMsg(msg)}send/button/div)
}
function App() {const getMsg (msg) {console.log(msg)}return (divSon onGetMsg{getMsg}/Son/div);
}export default App;
11.3兄弟组件通信 实现思路
借助状态提升机制通过共同的父组件进行相抵之间的数据传递
import {useState} from react;function A({onGetAName}) {const mag this is A name;return (divthis is A,button onClick{() onGetAName(mag)}send/button/div);
}function B({name}) {return divthis is B,{name}/div
}function App() {const [name, setName] useState();const getAName (name) {setName(name);}return (divA onGetAName{getAName}/AB name{name}/B/div);
}export default App;
11.4 跨层组件通信 实现步骤
1.使用createContext方法创建一个上下文对象Ctx
2.在顶层组件{App}中通过Ctx.Provider组件提供数据
3.在底层组件{B}中通过useContext钩子函数获取消费消息
import {createContext, useContext} from react;var MsgContext createContext();function A() {const msg this is A Component;return (div{msg}.B//div);
}function B() {const msg useContext(MsgContext);return divthis is B,{msg}/div
}function App() {const msg this is App Component;return (divMsgContext.Provider value{msg}A//MsgContext.Provider/div);
}export default App;
12.React副作用管理-useEffect
12.1概念理解
useEffect是一个React Hook函数用于在React组件中创建不是由时间引起而是由渲染本身引起的操作副作用比如发送AJAX请求更改DOM等等 说明上面的组件中没有发生任何的用户事件组件渲染完毕之后就需要跟服务器要数据整个过程属于“只渲染引起的操作”
12.2基础使用 需求在组建渲染完毕之后立刻从服务器端获取数据并展示在页面中 useEffect(() { }, [])说明
参数1是一个函数可以把它叫做副作用函数在函数内部可以放置要执行的操作 参数2是一个数组可选参在数组里放置依赖项不同依赖项会影响第一个参数函数的执行当是一个空数组的时候副作用函数只会在组件渲染完毕之后执行一次
接口地址http://geek.itheima.net/v1_0/channels
1安装axios
npm install axios 2发送请求
const [list, setList] useState([]);
useEffect(() {const getData async () {const res await axios.get(http://geek.itheima.net/v1_0/channels);console.log(res.data.data.channels)setList(res.data.data.channels)}getData();}, []);3展示数据
import axios from axios;
import {useEffect, useState} from react;function App() {const [list, setList] useState([]);useEffect(() {const getData async () {const res await axios.get(http://geek.itheima.net/v1_0/channels);console.log(res.data.data.channels)setList(res.data.data.channels)}getData();}, []);return (divul{list.map(item li key{item.id}{item.name}/li)}/ul/div);
}export default App;
12.3useEffect依赖说明
useEffect副作用函数执行时机存在多种情况根据传入依赖项的不同会有不同的执行表现
依赖项副作用功函数的执行时机没有依赖项组件初始渲染 组件更新时执行空数组依赖只在初始渲染时执行一次添加特定依赖项组件初始渲染 依赖项变化时执行
12.4清除副作用 概念在useEffect中编写的由渲染本身引起的对接组件外部的操作社区也经常把它叫做副作用函数比如在useEffect中开启一个定时器在组件卸载时把这个定时器清除掉这个过程就是清楚副作用。 useEffect((){return (){// 清除副作用}
},[])说明清除副作用函数最常见的执行时机是在组件卸载时自动执行
import {useEffect, useState} from react;function Son() {useEffect(() {const timer setInterval(() {console.log(我是子组件的定时器)}, 1000)return () {clearInterval(timer)console.log(子组件的定时器被销毁了)}}, []);return (div我是子组件/div)
}function App() {const [show, setShow] useState(true)return (div{show Son/}button onClick{() setShow(false)}卸载组件/button/div);
}export default App;
13.自定义Hook
13.1自定义Hook实现 概念自定义Hook是以use大头的函数通过自定义Hook函数可以用来实现逻辑的封装和复用 封装自定义hook通用思路
1.声明一个以use打头的函数
2.在函数体内封装可复用的逻辑只要是可复用的逻辑
3.把组件中用到的状态或者回调return出去以对象或者数组
4.在哪个组件中要用这个逻辑就执行这个函数结构出来状态和回调进行使用
import {useState} from react;function useToggle() {const [value, setValue] useState(true);const toggle () setValue(!value);return {value, toggle};
}function App() {const {value, toggle} useToggle();return (div{value divthis is div/div}button onClick{toggle}toggle/button/div);
}export default App;
13.2React Hooks使用规则
1.只能在组件或者其他自定义Hook函数中调用
2.只能在组件的顶层调用不能嵌套在if、for、其它函数中 14.案例-优化B站评论案例 14.1使用接口的方式获取评论列表并渲染
1使用json-server工具模拟接口服务通过axios发送请求
下载json-server到当前项目
npm i json-server -D在项目文件夹下创建db.json文件
{list: [{rpid: 3,user: {uid: 13258165,avatar: http://toutiao.itheima.net/resources/images/98.jpg,uname: 周杰伦},content: 哎哟不错哦,ctime: 10-18 08: 15,like: 126},{rpid: 2,user: {uid: 36080105,avatar: http://toutiao.itheima.net/resources/images/98.jpg,uname: 许嵩},content: 我寻你千百度 日出到迟暮,ctime: 11-13 11: 29,like: 88},{rpid: 1,user: {uid: 30009257,avatar: http://toutiao.itheima.net/resources/images/98.jpg,uname: 黑马前端},content: 学前端就来黑马,ctime: 10-19 09: 00,like: 66}]
}在package.json下添加启动命令 serve: json-server db.json --port 30042使用useEffect调用接口获取数据
封装Hook调用接口函数
function useGetList() {const [list, setList] useState([]);useEffect(() {async function getList() {const res await axios.get(http://localhost:3004/list);setList(res.data);}getList()}, []);return {list,setList}}调用Hook函数 const {list, setList} useGetList();14.2把评论中的每一项抽象成一个独立的组件实现渲染
1封装组件
function Item({item, onDel}) {return (div key{item.rpid} classNamereply-item{/* 头像 */}div classNameroot-reply-avatardiv classNamebili-avatarimgclassNamebili-avatar-imgalt//div/divdiv classNamecontent-wrap{/* 用户名 */}div classNameuser-infodiv classNameuser-name{item.user.uname}/div/div{/* 评论内容 */}div classNameroot-replyspan classNamereply-content{item.content}/spandiv classNamereply-info{/* 评论时间 */}span classNamereply-time{item.ctime}/span{/* 评论数量 */}span classNamereply-time点赞数:{item.like}/spanspan classNamedelete-btn onClick{() onDel(item.rpid)}删除/span/div/div/div/div);
}2调用组件
div classNamereply-list{/* 评论项 */}{list.map((item) (Item key{item.id} item{item} onDel{deleteItem}/))}
/div