受控组件:表单
- 非受控组件表单元素值不受所在组件状态的控制, 我们将这样的表单元素称作: 非受控组件.
- 受控组件受控组件 : 值受到 React 组件状态控制的表单元素一般是通过 defaultValue 属性, onChange 事件配合将非受控组件变为受控组件.
- 多表单元素操作 :4,5,6
- 给表单元素添加 name 属性,名称与 state 相同
- 根据表单元素类型获取对应值
- 在 change 事件处理程序中通过 [name] 来修改对应的 state
通过value和onChange事件,让表单元素变成 受控组件
复选框,是否勾选 checked={ }, 配合onChange事件
获取最新input值
操作value使其变成受控组件(文本框、富文本框、下拉框)
name判断点的哪个
[ ]:可以对其中的表达式进行取值预算:取值结束,[ ] 就没有了
e.target 获取目标对象
e.target.type 获取元素类型
e.target.name 获取元素的name
e.target.type="checkbox" 获取元素的复选状态
e.target.value 获取元素的值
value获取表单元素的值
升级:name 判断,考虑表单提交的很多元素比较麻烦
升级:[ ] 对其中表达式取值预算,取值结束 [ ] 就没了
复选框
代码如下:::
import React, { Component } from 'react';
import './App.scss'
// react应用的组件有两种创建方式:函数式组件,类组件
// rcc 创建calss组件
// rsf创建函数式组件
class App extends Component {
constructor(props){
super(props)
// 定义组件状态
this.state={
loginname:'',
password:'',
isread:false
}
}
handleChange(e){
console.log(e.target);
// if (e.target.name == 'loginname') {
// this.setState({loginname:e.target.value})
// }else if(e.target.name == 'password'){
// this.setState({password:e.target.value})
// }
//[] 可以对其中的表达式进行取值运算,取值结束,[] 就没有了
// e.target //获取目标对象
// e.target.type //获取元素类型
// e.target.name //获取元素的name
// e.target.type='checkbox' //元素的复选状态
// e.target.value //元素的值
// name名和state中名一样,那就可以这样简写了,一次修改所有表单元素的值
this.setState({[e.target.name]:e.target.type == "checkbox" ? e.target.checked : e.target.value})
}
login(){
console.log(this.state);
}
render() {
return (
<div className='login'>
<div className='block'>
{/* 通过 value属性 和 onChange事件 让表单元素变成 受控元素 */}
<input name='loginname' type="text" placeholder='输入账号' value={this.state.loginname} onChange={(e)=>{this.handleChange(e)}} />
</div>
<div className='block'>
{/* 通过value属性 和 onChange事件 让表单元素变成 受控元素 */}
<input name='password' type="password" placeholder='输入密码' value={this.state.password} onChange={(e)=>{this.handleChange(e)}} />
</div>
<div className='block'>
{/* 通过value属性 和 onChange事件 让表单元素变成受控元素 */}
<input name='isread' type="checkbox" checked={this.state.isread} onChange={(e)=>{this.handleChange(e)}} />勾选用户协议
</div>
<div className='block'>
{/* input type=buttom 相当于提交表单 */}
<input type="button" value='登录' onClick={()=>{this.login()}}/>
</div>
</div>
);
}
}
export default App;
组件通信:
自定义属性:父向子传值
方法:子向父传值:本质就是一个回调函数
和vue都是写在父中导入的子组件上
//父组件向子组件传值: 父组件通过自定义属性传值给子组件, 子组件内部通过props获取值
//子组件向父组件传值: 父组件通过自定义属性传一个函数给子组件, 子组件内部通过props获取该函数并在合适的时机回调该函数完成传值.
//兄弟组件传值: 借助events库 先实例化一个公共的通信对象, 其中一个组件提前监听事件, 另一个兄弟组件在合适的时机触发事件并传值.
//跨组件传值: 借助createContext方法 先实例化一个公共的上下文通信对象, 外层组件通过Provider组件的value属性传值, 内层组件和上下文通信对象建立连接, 然后再通过this.context获取值.
父向子,子向父
兄弟组件通信:自带 events 不用装(尝试自己封装eventBus库)
使用之前要先建立eventBus文件,导入eventBus:::emit 触发事件传值,on监听,off 取消监听
emit触发传值
、
on监听,off 写在取消监听,性能优化
性能优化:取消监听。不是同一个函数名不能取消监听js中有体验:绑定函数名可以取消监听成功
跨组件通信:需要借助createContext方法,先实例化一个 utils文件夹下
React.createContext 实例化一个功能的通信上下文对象
创建上下文
MyContext.Provider 的value属性传值
app主文件。我的上下文
中间隔层文件
Class.contextType 和组件通信建立连接
类 构造函数
非嵌套组件间通信
1.利用二者共同父组件进行通信
2.使用自定义事件的方式
创建新项目typescript项目:::安装ts。
已有项目添加typescript则需要加配置项
npx create-react-app my-app --template typescript
tabbar底部导航:另类写法:主要用来子向父传递了索引,父判断
父
import './App.scss';
// React应用的组件有两种创建方式: 函数式组件, 类组件
// rcc 创建class组件
// rsf 创建函数式组件
import React, { Component } from 'react';
import TopNav from '@/components/TopNav';
import Swiper from '@/components/Swiper';
import CateList from '@/components/CateList';
import Tabbar from '@/components/Tabbar';
import Cate from '@/components/Cate/Cate';
class App extends Component {
constructor(props){
super(props);
this.state = { index:0 }
}
getIndex = (i)=>{
this.setState({ index: i })
}
render() {
return (
<div>
{/* 顶部导航 */}
{/* 轮播图 */}
{/* 分类导航 */}
{
this.state.index == 0 &&
<>
<TopNav />
<Swiper />
<CateList />
</>
}
{
this.state.index == 1 && <Cate />
}
{/* 底部导航 */}
<Tabbar getIndex={this.getIndex} />
</div>
);
}
}
export default App;
子
import React, { Component } from 'react';
import './index.scss'
class Tabbar extends Component {
constructor(props) {
// props和state的区别
// 分别介绍两个技术的概念,先回答相同点,再回到不同点,最后总结一下(个人感悟,注意事项)
// props是个对象,用来接收父组件传来的值,props默认是只读的(如果某个属性是引用类型,则引用数据的属性是可以修改)
// state是个对象,用来定义组件自身的状态,可以通过setState来修改
super(props)
// 定义组件状态
this.state = {
tabs: [
{ text: '首页', img: '' },
{ text: '分类', img: '' },
{ text: '首页', img: '' },
{ text: '首页', img: '' },
],
currentIndex: 0,
}
}
handleClick(index) {
// 回调父组件的方法
this.props.getIndex(index)
// this.state.currentIndex = index //这个写法可以保存数据到组件状态中,但是无法触发组件更新
// setState会保存数据到组件状态中,同时会触发组件更新
this.setState({ currentIndex: index }, () => {
// 想要获取setState保存的最新状态值,必须在第二个参数的回调函数中获取(setState本身是异步的)
// console.log('handleClick', this.state.currentIndex);
})
}
render() {
return (
<div className='tabbar'>
{
this.state.tabs.map((item, index) => {
return(
<div className={`btn ${this.state.currentIndex == index? 'active':''}`} key={index} onClick={()=>{this.handleClick(index)}}>
<img src={item.img} alt="" />
<div className='text'>{item.text}</div>
</div>
)
})
}
</div>
);
}
}
export default Tabbar;
.tabbar{
position: fixed;
bottom: 0;
width: 100%;
display: flex;
justify-content: space-around;
align-items: center;
margin: 15px;
border-top: 1px solid #ccc;
.btn.active{
color: red;
font-weight: bold;
}
}