React【Day1】

    <img src={item.img[1]} alt={item.img[1]} />
  </div>
);

} else if (item.img.length === 2) {
return (


{item.img[0]}
{item.img[1]}
{item.img[2]}

);
}
};
function App() {
return data.map((item) =>
{getImgTemplate(item)}
);
}

export default App;


## 五、React的事件绑定


### 基础实现



> 
> React中的事件绑定,通过语法 `on + 事件名称 = { 事件处理程序 }`,整体上遵循驼峰命名法
> 
> 
> 



function App(){
const clickHandler = ()=>{
console.log(‘button按钮点击了’)
}
return (
click me
)
}


### 使用事件参数



> 
> 在事件回调函数中设置形参e即可
> 
> 
> 



function App(){
const clickHandler = (e)=>{
console.log(‘button按钮点击了’, e)
}
return (
click me
)
}


### 传递自定义参数



> 
> 语法:事件绑定的位置改造成箭头函数的写法,在执行clickHandler实际处理业务函数的时候传递实参
> 
> 
> 



function App(){
const clickHandler = (name)=>{
console.log(‘button按钮点击了’, name)
}
return (
<button onClick={()=>clickHandler(‘jack’)}>click me
)
}


注意:必须写成箭头函数,如果直接在 JSX 中使用 `{clickHandler('jack')}`,那么这个函数会在每次渲染时被调用,而不是在点击按钮时触发!!!!!!  
 :::warning  
 注意:不能直接写函数调用,这里事件绑定需要一个函数引用  
 :::


### 同时传递事件对象和自定义参数



> 
> 语法:在事件绑定的位置传递事件实参e和自定义参数,clickHandler中声明形参,注意顺序对应
> 
> 
> 


注意箭头函数里面也要加参数e



function App(){
const clickHandler = (name,e)=>{
console.log(‘button按钮点击了’, name,e)
}
return (
<button onClick={(e)=>clickHandler(‘jack’,e)}>click me
)
}


## 六、React组件基础使用


### 组件是什么


概念:一个组件就是一个用户界面的一部分,它可以有自己的逻辑和外观,组件之间可以互相嵌套,也可以服用多次  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/5cc4a56768184e1494bd6621f282698b.png)


### 组件基础使用



> 
> 在React中,一个组件就是**首字母大写的函数**,内部存放了组件的逻辑和视图UI, 渲染组件只需要把组件当成标签书写即可
> 
> 
> 



// 1. 定义组件
// 写成箭头函数也可以
function Button(){
return click me
}

// 2. 使用组件
function App(){
return (


{/* 自闭和 */}

{/* 成对标签 */}


)
}


## 七、组件状态管理-useState


### 基础使用



> 
> useState 是一个 React Hook(函数),它允许我们向组件添加一个`状态变量`, 从而控制影响组件的渲染结果  
>  和普通JS变量不同的是,状态变量一旦发生变化组件的视图UI也会跟着变化(数据驱动视图)
> 
> 
> 


![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/b8111fde425e479992917c675efba915.png)![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/52550c5e6b1346a0af809b72118c3c25.png)



// useState实现计数器按钮
import { useState } from “react”;
function App() {
// 1.调用useState添加一个状态变量
const [count, setCount] = useState(0); // 解构

// 2. 点击事件回调
const handleClick = () => {
// 使用setCount的作用:
// (1)修改count值
// (2)触发组件重新渲染的作用,从而实现了视图的更新
setCount(count + 1);
};
return (


{count}

);
}

export default App;


### 状态的修改规则



> 
> 在React中状态被认为是只读的,我们应该始终`替换它而不是修改它`, 直接修改状态不能引发视图更新
> 
> 
> 


![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/57763e0b967a4b7788d5dd78252e3385.png)


### 修改对象状态



> 
> 对于对象类型的状态变量,应该始终给set方法一个`全新的对象` 来进行修改
> 
> 
> 


![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/dcbe384358574bb7b7a6d2f37fedaaaf.png)



// useState实现计数器按钮
import { useState } from “react”;
function App() {
const [obj, setObj] = useState({ name: “slx”, age: 12, sex: “s” });
const [newName, setNewName] = useState(“”);
const handleNewName = (e) => {
setNewName(e.target.value);
};
const handleObjName = () => {
setObj({ …obj, name: newName });
};
return (


<input type=“text” value={newName} onChange={(e) => handleNewName(e)} />
click

newName:{newName}


{/*

{obj}

*/}
{/* 不可以这样写,在React中,不能直接将对象 直接渲染到组件中 */}

obj.name:{obj.name}


obj.age:{obj.age}


obj.sex:{obj.sex}



);
}

export default App;


![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/f3c220b1829644c6be8ed9bafad38f2b.png)


## 八、组件的基础样式处理



> 
> React组件基础的样式控制有俩种方式,行内样式和class类名控制
> 
> 
> 


### 1. 行内样式


注意有短横线的要写成驼峰 font-size fontSize



function App() {
return <div style={{ color: “red”, backgroundColor: “pink” }}>ddddddd;
}


或者抽出来写



const style = {
color: “red”,
backgroundColor: “pink”,
};

function App() {
return

ddddddd
;
}


### 2. class类名控制


注意是className,并且不用加花括号,直接引号



.foo{
color: red;
}



import ‘./index.css’

function App(){
return (


this is span

)
}


## 九、【实战项目】B站评论案例


外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


1. 渲染评论列表  
 核心思路:  
 - 使用useState维护评论列表  
 - 使用map方法对列表进行遍历渲染  
 - 注意:图片动态路径写法 `<img src={item.user.avatar} />`
2. 删除评论实现


	* 只有自己的评论才显示删除按钮:条件渲染

{item.user.uid === user.uid && (
删除
)}


	* 点击删除按钮,删除当前按钮,列表中不在显示:filter过滤id

const handleDelect = (id) => {
// 注意filter返回的是满足条件的元素,所以这里要写成 !==
setList(list.filter((item) => item.rpid !== id));
};

 
 {item.user.uid === user.uid && (
   <span
    className="delete-btn"
  onClick={() => handleDelect(item.rpid)}
>
删除
 </span>
)}
3. 渲染导航Tab和高亮实现


	* 列表渲染

{tabs.map((item) => (
{item.text}

))}


	* 点击谁就把谁的type记录下来

// 记录type
const [type, setType] = useState(“hot”);
const handleClick = (type) => {
setType(type);
console.log(type);
};

{tabs.map((item) => (
<span
className=“nav-item”
key={item.type}
onClick={() => handleClick(item.type)}
>
{item.text}

))}


	* 通过记录的type和每一项遍历时的type做匹配 控制激活类名的显示

<span className={nav-item ${type===item.type && 'active'}}
key={item.type}
onClick={() => handleClick(item.type)}
>

4. 评论列表排序功能实现  
 需求:点击最新,评论列表倒序排列;点击最热,点赞数最多的在前  
 利用开发工具lodash:[lodash传送门]( )

 使用前安装:`npm i lodash`  
 引用:`import _ from 'lodash'` 下划线是使用各种方法的前缀  
 使用:

 
 const handleClick = (type) => {
setType(type);
console.log(type);
if (type === "hot") {
  setList(_.orderBy(list, "like", "desc"));
} else if (type === "time") {
  setList(_.orderBy(list, "ctime", "desc"));
}

};

 已进入页面就自动最热排序:

 

const [list, setList] = useState(_.orderBy(defaultList, “hot”, “desc”));



![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/b3ef22255d504061be7a0ae540eec06a.png)


### 基础模版



import { useState } from ‘react’
import ‘./App.scss’
import avatar from ‘./images/bozai.png’

/**

  • 评论列表的渲染和操作
    1. 根据状态渲染评论列表
    1. 删除评论
      */

// 评论列表数据
const defaultList = [
{
// 评论id
rpid: 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 = {
// 用户id
uid: ‘30009257’,
// 用户头像
avatar,
// 用户昵称
uname: ‘黑马前端’,
}

/**

  • 导航 Tab 的渲染和操作
    1. 渲染导航 Tab 和高亮
    1. 评论列表排序
  • 最热 => 喜欢数量降序
  • 最新 => 创建时间降序
    */

// 导航 Tab 数组
const tabs = [
{ type: ‘hot’, text: ‘最热’ },
{ type: ‘time’, text: ‘最新’ },
]

const App = () => {
return (


{/* 导航 Tab /}



  • 评论
    {/ 评论数量 /}
    {10}


  • {/ 高亮类名: active */}
    最新
    最热


  <div className="reply-wrap">
    {/* 发表评论 */}
    <div className="box-normal">
      {/* 当前用户头像 */}
      <div className="reply-box-avatar">
        <div className="bili-avatar">
          <img className="bili-avatar-img" src={avatar} alt="用户头像" />
        </div>
      </div>
      <div className="reply-box-wrap">
        {/* 评论框 */}
        <textarea
          className="reply-box-textarea"
          placeholder="发一条友善的评论"
        />
        {/* 发布按钮 */}
        <div className="reply-box-send">
          <div className="send-text">发布</div>
        </div>
      </div>
    </div>
    {/* 评论列表 */}
    <div className="reply-list">
      {/* 评论项 */}
      <div className="reply-item">
        {/* 头像 */}
        <div className="root-reply-avatar">
          <div className="bili-avatar">
            <img
              className="bili-avatar-img"
              alt=""
            />
          </div>
        </div>

        <div className="content-wrap">
          {/* 用户名 */}
          <div className="user-info">
            <div className="user-name">jack</div>
          </div>
          {/* 评论内容 */}
          <div className="root-reply">
            <span className="reply-content">这是一条评论回复</span>
            <div className="reply-info">
              {/* 评论时间 */}
              <span className="reply-time">{'2023-11-11'}</span>
              {/* 评论数量 */}
              <span className="reply-time">点赞数:{100}</span>
              <span className="delete-btn">
                删除
              </span>

            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

)
}

export default App



.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: 76px;
      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;
      }

总结

大厂面试问深度,小厂面试问广度,如果有同学想进大厂深造一定要有一个方向精通的惊艳到面试官,还要平时遇到问题后思考一下问题的本质,找方法解决是一个方面,看到问题本质是另一个方面。还有大家一定要有目标,我在很久之前就想着以后一定要去大厂,然后默默努力,每天看一些大佬们的文章,总是觉得只有再学深入一点才有机会,所以才有恒心一直学下去。

  • 25
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值