您的位置:首页 > Web前端 > React

React

2019-06-06 11:38 1406 查看
  • 虚拟DOM 浏览器中的概念,用JS对象来表示页面上的元素,并提供了操作DOM对象的API
  • 是框架的概念,是程序员用JS对象来模拟页面上的DOM元素和DOM嵌套
  • 为了实现页面的高效更新
  • diff算法
      tree
    • 组件
    • 元素
  • 生成虚拟dom
  • function createElement(tag, props, children) {
    return {
    tag,
    props: {...props},
    children: [...children]
    }
    }
    let p = createElement("p", {
    class: "p"
    }, ["自信"])
    let createEle = createElement("div", {
    id: "wrap",
    class: "wrap",
    style: {
    width: "100",
    height: "100",
    background: "cornflowerblue"
    }
    }, ["1701B",p])
    • 把虚拟的dom转成真实的dom,并且把它渲染到页面
    render(createEle, document.getElementById("root")) //必须是id
    function render(vTree, root) {
    //渲染到页面
    let dom = createDom(vTree)
    root.appendChild(dom)
    //把虚拟的dom转成真实的dom
    function createDom(vTree) {
    let {
    tag,
    props,
    children
    } = vTree;
    let dom = document.createElement(tag)
    Object.entries(props).forEach(item => {
    let [key, val] = item;
    //如果属性值是css样式
    if (typeof val == "object") {
    Object.entries(val).map(i => i[0] + ":" + i[1]).join(";")
    }
    dom.setAttribute(key, val)
    })
    //添加子节点
    if (children) {
    children.forEach(item => {
    //递归调用
    let text = typeof item == "string" ? document.createTextNode(item) : createDom(item)
    dom.appendChild(text)
    })
    }
    return dom
    }
    }
    • Object.entries 打印结果是
    • React 创建react元素
    React.createElement(string/function/reactClass,props,children)
    • ReactDOM 虚拟dom变为真实的dom节点
    ReactDOM.render(vnode,rootdom)
    • JSX 是JavaScript对象
      符合xml规范的JS语法
    • 并不是直接把jsx渲染到页面,而是内部通过babel转换成createElement形式,在渲染
    • 注释
    {/**/}
    • 用className添加class类名
    • htmlFor替换label中的for属性
    • 标签必须成对出现,单标签必须闭合
    • jsx运行更快,在编译js代码后进行了优化,更加简单快捷,安全
    • 规则: 一个react元素必须要有一个根节点
    • 遇见<>解析html模板,遇见</>解析结束
    • 遇见{开始解析js,遇见}js解析结束
  • {[1,2,3,“小美”]} 123小美
  • 组件
      可复用的html结构
    • 组件名首字母必须大写
    • 无状态组件(没有生命周期)
      相当于使用构造函数,来创建组件,必须要向外return一个合法的JSX创建的虚拟DOM
    • 特点是解析速度快,
  • 有状态组件(有生命周期)
  • class 组件名称 extends React.Component{
    constructor(props){ //可写可不写,写了必须调用super
    super(props)
    //定义组件内部的状态
    this.state = {
    count:8
    }
    },
    render(){
    let {grade} = this.props
    let {count} = this.state
    return <div>
    //创建的组件
    <h3>{grade}</h3>
    <div>{count}</div>
    <button onClick={() => {
    //修改组件内部的状态,必须通过setState()来修改,是个异步的方法
    this.setState({
    count:this.state.count+1
    },() => {
    console.log(this.state.count)
    })
    }}>点击</ button>
    </div>
    }
    }
    • setState 是一个异步方法,第一个参数是要合并的状态对象,第二个是回调函数
    • state是组件内部的状态,props是外界传进来的状态
    • 区别 class 有私有数据(this.state) 和 生命周期
    • function 只有props,没有私有数据和生命周期
  • 脚手架
      npm i -g create-react-app
    • create-react-app name
    • cd name
    • npm start
    • npm run eject
  • 父传子
  • render(){
    let {header,center} = this.state
    return (
    <div className="App">
    <Head header={header}/>
    <Section center={center}/>
    </div>
    );
    }
    • 子接收
    let {title,img,content} = props.header
    let {center} = this.props
    • 点击事件,切换class样式,tab切换
    <p>
    {
    center.map((item,index) => <span onClick={()=>{
    this.setState({
    ind:index
    })
    }} className={index == ind ? 'active' : ''}>{item.title}</span>)
    }
    </p>
    <p>
    <img src={center[ind].img} />
    <h6>{center[ind].content}</h6>
    {
    center[ind].link.map(item => <span>{item}</span>)
    }
    
    </p>
    • 子传父
    <p onClick={()=>{
    this.props.add()
    }}>123</p>
    • 父接收
    <Chil add={() => {
    console.log("add")
    }}/>
    • 点击++
    //父组件
    class App extends React.Component{
    constructor(){
    super()
    this.state = {
    count:0
    }
    }
    render(){
    let {count}= this.state
    return <div className="App">
    <Chil count={count} add={() => {
    this.setState({
    count:count+1
    })
    }}/>
    </div>
    }
    }
    //子组件
    class  Chil extends React.Component{
    constructor(props){
    super(props)
    }
    render(){
    let {count} = this.props
    return <div>
    <p>{count}</p>
    <button onClick={() => {
    this.props.add()
    }}>+</button>
    </div>
    }
    }
    • 弹框
    //父组件
    class App extends React.Component {
    constructor(){
    super()
    this.state = {
    list:[
    {
    name:"打开alert提示框",
    title:"提示",
    mess:"确定执行此操作?",
    type:"alert"
    },{
    name:"打开confirm提示框",
    title:"提示",
    mess:"操作成功",
    type:"confirm"
    },{
    name:"打开prompt提示框",
    title:"请输入姓名",
    type:"prompt"
    }
    ],
    obj:{},
    isShow:false
    }
    }
    render(){
    let {list} = this.state
    let {obj,isShow} = this.state
    return (
    <div className="App">
    <ul>
    {
    list.map((item,key) => <li
    onClick={() => {
    this.setState({
    //点击谁把谁的数据传过去
    obj:item,
    isShow:true
    })
    }}
    >{item.name}</li>)
    }
    </ul>
    //弹框,父接收
    {isShow ? <Dialog obj={obj} sure={() => {
    this.setState({
    isShow:false
    })
    }}/> : null}
    </div>
    );
    }
    }
    //子组件
    class Dialog extends React.Component{
    constructor(props){
    super(props)
    }
    render(){
    let {obj} = this.props;
    return <div className="dialog">
    <h5>{obj.title}</h5>
    <p>{obj.mess ? obj.mess : <input/>}</p>
    <div>
    {obj.type !== 'prompt' ? <button>取消</button> : ""}
    //子传父
    <button onClick={() => {
    this.props.sure()
    }}>确定</button>
    </div>
    </div>
    }
    }
    • 旧生命周期,描述组件一系列的生长过程,分3个周期(出生,成长,死亡) 创建阶段(出生) constructor(){} 初始化函数,接收props,设置组件的默认状态(state),执行一次
    • componentWillMount(){} 组件将要被渲染,执行一次,可以修改state
    • render (){} 组件正在被渲染,进行diff算法,产生最小化差异
    • componentDidMount(){} 组件渲染结束,执行一次,请求数据,第一次获取到真实dom,想要在组件内操作dom
    //响应拦截器
    import axios from "axios"
    let request = axios.create()
    request.interceptors.response.use(function (response) {
    // 对响应数据做点什么
    return response.data;
    }, function (error) {
    // 对响应错误做点什么
    return Promise.reject(error);
    });
    export default request
    //处理数据
    import request from "./request"
    componentDidMount(){
    request.get(path).then((res) => {
    let {data} = res
    this.setState({data})
    })
    }
    • 变化阶段(成长)------- 存在期包含的方法 props发生变化 componentWillReceiveProps(nextProps,nextState){} props发生变化,监听props,存在期包含
  • state发生变化,
      shouldComponentUpdate(nextProps,nextState){return true} 组件是否更新?返回true或false,性能优化,存在其包含
    • componentWillUpdate(nextProps,nextState){} 组件将要被更新,存在期包含
    • 调render
    • componentDidUpdate(prevProps,prevState){} 组件更新完成,存在期包含
  • 卸载阶段(死亡)
      componentWillUnmount 组件将卸载,清理组件垃圾
  • 新旧生命周期不能一起使用
  • 新生命周期
      出生 constructor
    • static getDerivedStateFromProps(nextProps,prevState){
      return {}
      }
      用static关键字,静态方法里没有this,必须return 一个对象或是 null,如果返回null,不会更新,如果返回一个对象,会通过serState更新组件。 监听props变化,更新state状态
    • render
    • componentDidMount
  • 成长
      shouldComponentUpdate() {return true}
    • render
    • getSnapshotBeforeUpdate(prevProps,prevState){
      return {aa:666}
      }
      Snapshot快照,返回一个null或一个对象,返回值作为componentDidUpdate的第三个参数存在,需要配合DidUpdata一起使用
    • componentDidUpdate(prevProps,prevState,value){}
  • 卸载
      componentWillUnmount(){}
  • 更改期不属于react的周期
  • 怎么写页面上中下数据
  • 获得数据
  • tab 切换
  • //父组件
    this.state = {
    obj:{
    leftList:[{
    type:"紧凑型车",
    rightLift:[
    {
    img:"1.jpg",
    name:"紧凑型车",
    price:"82.80-249万"
    },
    {
    img:"2.jpg",
    name:"奔驰S级",
    price:"87.68-200万"
    }
    ]
    },{
    type:"小型车",
    rightLift:[
    {
    img:"1.jpg",
    name:"小型车",
    price:"82.80-249万"
    },
    {
    img:"2.jpg",
    name:"奔驰S级",
    price:"87.68-200万"
    }
    ]
    }
    list:{},
    flag:false
    }
    render(){
    let {leftList} = this.state.obj
    let {list,flag} = this.state
    return (
    <div className="App">
    <ul className="list">
    {
    leftList.map((item,index) =>
    <li key={index} onClick={() =>
    this.setState({
    flag:true,
    list:item
    })
    }>{item.type}</li>
    )
    }
    </ul>
    {flag ? <RightList list={list.rightLift}/> : ""}
    </div>
    );
    }
    //子组件
    render(){
    let {list} = this.props
    return <div className="right">
    {
    list.map((item,index) =>
    <div>
    <p key={index}>{item.name}</p>
    <p key={index}>{item.price}</p>
    </div>
    )
    }
    </div>
    }
    • DOM ref – findDOMNode 获取dom
    //普通元素
    ref = "string"    this.refs.string  this.refs获取的是一个对象
    ref = {(name) => {
    if(name){}
    }}
    render就会调用,函数里的参数就是要获取的dom节点,更改状态时,回调函数会触发俩次,第一次dom是null,第二次才是真实的dom
    //组件
    ref = "string"   this.refs.string  获取的是组件实例
    findDOMNode(this.refs.string) 获取的是组件的整个dom
    • unmountComponentAtNode(根节点root) 清空所有的dom
    • Event

      事件三要素:事件源,事件类型,事件处理函数(事件对象e)

    • DOM0 onclick 只能添加一次,没有兼容

    • DOM2 addEventListener(事件类型,处理函数,false) 多次添加,有兼容 IE ,

      默认false冒泡,true捕获
    • 捕获和冒泡只影响触发顺序,不影响谁被触发,触发的元素从当前点击的元素往外触发
    • 同时有捕获和冒泡,先执行捕获,再执行冒泡
  • stopPropagation 阻止默认事件

  • 事件对象 是事件处理函数参数里最后一个

  • 合成事件

      react 事件默认是冒泡,所有合成事件都是加在document上,没有兼容,合成事件的捕获–onClickCapture
  • 原生事件

  • 原生事件和合成事件同时出现先执行原生事件

  • 原生事件里阻止事件冒泡,有可能合成事件就都不执行了

  • 组件卸载的时候,清空事件,定时器……

  • This
  • 用箭头函数,可以获取this
    <h1 onClick={this.thisClick}>打印this</h1>
    thisClick () {
    console.log(this) //undefined
    }
    
    <h1 onClick={this.thisClick}>打印this</h1>
    thisClick = () => {
    console.log(this)   //This {props: {…}, context: {…}, refs: {…}, updater: {…}, thisClick: ƒ, …}
    }
    
    bind改变this指向
    <h1 onClick={this.thisClick.bind(this)}>打印this</h1>
    thisClick () {
    console.log(this)  //This {props: {…}, context: {…}, refs: {…}, updater: {…}, _reactInternalFiber: FiberNode, …}
    }
    
    constructor周期方法只执行一次,可以优化性能
    constructor(){
    super()
    this.thisClick = this.thisClick.bind(this)
    }
    render(){
    return <div>
    <h1 onClick={this.thisClick}>打印this</h1>
    </div>
    }
    thisClick () {
    console.log(this)
    }
    • this指向
    //改变this指向后,不会立马触发函数
    bind
    //改变this指向后,会立马触发函数
    call 参数是一个一个的
    apply 参数是数组
    • 定义默认的props
    static defaultProps = {}
    Name.defaultProps = {}
    • 拖拽
      原理:盒子的距离 = 最后手指到页面距离 - (开始手指到页面距离 - 盒子到页面距离)
    • 侧边栏
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: