React核心原理与实际开发

news2024/11/19 5:50:19

学习目标

React是啥?

官方定义:将前端请求获取到的数据渲染为HTML视图JavaScript库

一、React入门

1、React项目创建

直接创建react,使用初始化会创建package.json

npm init -y

再安装

2、React基本使用

使用纯JS创建ReactDOM(元素)

<body>
<div id="root"></div>
<!--    1、引入js、react-dom文件-->
    <script src="./node_modules/react/umd/react.development.js"></script>
    <script src="./node_modules/react-dom/umd/react-dom.development.js"></script>
<script>
//     2、使用JS创建react元素----虚拟DOM
//     参数:元素名称、元素属性、元素子节点
    const title = React.createElement('h1',null,'Hello react 我是你大爷')
//      3、渲染react元素
//      参数:要渲染的react元素、挂载点
    ReactDOM.render(title,document.getElementById('root'))
</script>

</body>

React.createElement()方法使用不是很灵活,知道就好;

ReactDOM.render()方法渲染react元素很重要!!!使用起来友好。

3、React脚手架搭建完整项目框架

使用react脚手架初始化项目,避免了使用<script>标签嵌入到html页面中很繁琐!!!

        IDEA创建React项目

1、初始化项目:项目目录下输入命令 

(base) wangjia@wangbangjia reactTest %  npx create-react-app my-app

2、启动项目:项目根目录下输入命令

(base) wangjia@wangbangjia reactTest % cd my-app
(base) wangjia@wangbangjia my-app % npm start

在index.html文件中直接按照上述编写三小步骤运行就行了

总结:使用react创建react元素是基本,至于将元素渲染到什么平台(iOS,安卓,虚拟显示等)就需要再导入对应的包即可。

4、JSX语法

1、JSX基本使用

JSX就是JavaScript XML简写,表示在JavaScript代码中写XML(HTML)格式的代码。

在浏览器实际运行时,仍然是将JSX语句转化为JS语句执行。

 // 2、创建react元素
 const title2 = <h3>这是JSX语法写的</h3>
 // 3、渲染react元素
 ReactDOM.render(title2,document.getElementById('root'))

2、JSX中使用JavaScript表达式

为啥子这么干???数据存储在JS中,想要显示就要在JSX中嵌入JS表达式。

语法:{JavaScript表达式}

 const jsappend = '这是嵌入的JS的数据'
 const age = '18'
 const title2 =(
     <h3>这是JSX语法写的 {jsappend},显示的年龄为: {age}</h3>
 )
 ReactDOM.render(title2,document.getElementById('root'))

3、JSX的条件渲染

在创建react元素时引入的JS表达式是包含if-else、三元表达式、逻辑与运算符。

const isLoading = true
 // if-else
 // const loadData = () =>{
 //  if(isLoading){
 //   return <div>loading...</div>
 //  }
 //  return <div>数据加载完成,此处显示加载后的数据</div>
 // }

//三元表达式
//  const loadData = () =>{
//    return isLoading ?  <div>loading...</div> : <div>数据加载完成,此处显示加载后的数据</div>
//  }
//
//  逻辑与运算符
 const loadData=() =>{
 return isLoading && (<div>数据加载完成,此处显示加载后的数据</div>)
 }
 // 创建react元素  //函数调用作为表达式
const title=(
    <h1>
     条件渲染:
     {loadData()}
    </h1>
)
 // 渲染react元素
 ReactDOM.render(title,document.getElementById('root'))


4、JSX的列表渲染

创建react列表时应添加key属性,且唯一;map遍历谁就要给谁添加key属性

 使用map方法遍历列表所有元素

const  songs = [
 {id:1,name:'我是你大爷'},
 {id:2,name:'你是我好大儿'},
 {id:3,name:'你是我孙子'},
]

 const list = (
     <ul>
      {songs.map(item => <li key={item.id}> {item.name}</li>)}
     </ul>
 )

ReactDOM.render(list,document.getElementById('root'))

5、JSX的样式处理

使用类名:className

css类index.css

.title{
  text-align:center;
  color: crimson;
  size: A4;
  background-color: #61dafb;
  }

导入css类 所在文件 import './index.css' ;确定类名 className="title"

 import './index.css'

const test = (
    <h1 className="title">
     JSX的样式处理
    </h1>
)

 ReactDOM.render(test,document.getElementById('root'))

总结:JSX确定结构,JSX确定样式

二、React面向组件编程

学习目标:

1、组件创建俩方式

        1、函数式

    <div id="root"></div>
    <div id="demo"></div>
    
    <script type="text/babel">
        const title = <h1>react中的函数式组件</h1>
        // 1、创建普通函数式组件
        function MyComponent(){
            console.log(this);
            return <h2>我是用函数定义的组件(适用于简单组件的定义)</h2>;
        }
        // 2、创建箭头函数式组件
        const Button = () => {
            return <div>这是使用箭头函数创建的函数组件</div>
        }
        // 3、使用组件
        const content = (
            <div>
                {title};
                {<MyComponent/>}
                {<Button/>}
                </div>  
        )
        // 4、渲染组件到页面
        // ReactDOM.render(<MyComponent/>,document.getElementById('root'));
            ReactDOM.render(content,document.getElementById('root'));
/*
执行ReactDOM.render(<MyComponent/>怎么做的?
1、React解析组件标签,找到MyComponent组件
2、发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM作为真实DOM呈现在页面上

*/
        </script>

        2、类方式

        <div id="root"></div>
        <div id="demo"></div>
        
        <script type="text/babel">
           const title = (
            <h1>React中的类组件</h1>
           )
        // 1、创建类式组件 必须继承React.Component类
           class MyComponent extends React.Component{
            render(){
                 // render方法放在了哪里? -- MyComponent类的原型对象上,供实例使用
                // render中的this就是MyComponent组件实例对象
            
                return <div>类组件返回,适用于复杂组件</div>
            }
           }
            const content = (
                 <div>
                    {title}
                    {<MyComponent/>}
                    </div>
            
            )
        ReactDOM.render(content,document.getElementById('root'));
        
    /*
    执行ReactDOM.render(<MyComponent/>怎么做的?
    1、React解析组件标签,找到MyComponent组件
    2、发现组件是使用类定义的,随后new出该类的实例,并通过该实例调用到原型上的render方法 
    3、将render返回的虚拟DOM转为真实DOM呈现在页面上
    
    */
        
        </script> 

2、组件三大属性

1、state

理解

(1)state值是对象(可包含多个key-value)

(2)组件被称为”状态机“,通过更新组件来更新对应的页面

强烈注意

1、组件中render方法中的this指向为组件实例对象

2、组件自定义方法中this为undefined,咋解决?

a、强制绑定this:通过函数bind()

b、使用箭头函数

3、状态数据,不可直接更新,要使用setState

应用场景:state也就是状态变化,多用于触发事件等

标准版本及详解->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!-- 引入react-dom.用于支持react操作DOM -->
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <!-- 创建真实dom元素节点 -->
    <div id="root"></div>
    <div id="demo"></div>

    <script type="text/babel">
        const title = <h1>组件的属性--state</h1>
        //  1、创建组件
        class Weather extends React.Component{
            // 借助构造器初始化状态  -- 构造器中的this肯定是指向实例对象的
            constructor(props){
                super(props)
                // 初始化状态
                this.state = {isHot : false}
                /*使用原型上的方法changeWeather再调用bind传参实例创建一个新的函数,
                而且此新函数的this已变成类Weather的实例对象,然后将此新函数传给
                类Weather的实例自身,并起一个新的名字。
                那么直接调用此函数,就可以获取到

                简言之:拿原型上的方法生成一个新的方法挂在实例自身上
                ~原型上的方法 
                ~实例上的方法 -- 可使用指向实例的this直接调用
                */
            //    解决changeWeather中this指向问题
               this.test = this.changeWeather.bind(this);
            }
            render(){
                const {isHot} = this.state
                 // 读出实例对象的状态并使用  
                return <h1 onClick = {this.test}>今天天气很{this.state.isHot ? "炎热" : "凉爽"}</h1>
            }
            changeWeather(){
               //严重注意:状态(state)不可直接修改 this.state.isHot = !isHot 就是不行的
               const isHot = this.state.isHot;
               this.setState({isHot:!isHot})
            }
            /*
            changeWeather放在那里?  --- Weather的原型对象上,供实例使用
            由于changeWeather 是作为onClick的回调,不是直接通过实例调用的,是直接调用
            类中的方法默认开启了局部的严格模式,所以changeWeather中this为undefined
            */
        }
        /*
        整个组件运行机制:
        当按点击click时就开始调用函数this.test,
        并且执行将changeWeather函数添加到实例对象中修改当前状态,
        然后由改变后的状态进行页面修改

        1、构造器调用几次? 1次,用作实例化对象时
        2、render调用几次?1+n次,1是初始化那次,n是状态更新的次数
        3、changeWeather调用几次? 点击几次就调用几次
        
        */
      
        /*
        this指向总结:
        1、构造器里的this指向实例对象 常识了
        2、render中this指向实例对象,是React悄悄 const w1=new Weather() 然后执行w1.render()
        也就是说render是由实例对象调用的 肯定里面的this指向实例对象了啦
        3、然后changeWeather就只是咱们自定义的一个函数,并不是由实例对象调用,而是作为一个事件的回调在使用,
        当触发事件时直接拉出来调用函数changeWeather,并且由于类中的方法默认开启了严格模式,导致this丢了,
        按道理讲类中的this肯定指向实例对象但是丢了就指向undefined,
        this都没有指向实例对象,咋可能调用方法changeWeather呢
        */

        const content =  
        (
            <div>
                {title}
                {<Weather/>}
            </div>
        )
        // 3、渲染组件到页面
        ReactDOM.render(content,document.getElementById('root'))
    </script>
</body>

</html>

简化版本--企业开发

// 1、创建组件
         class Weather extends React.Component{
            // 初始化状态
            state = { isHot: false }
            // 触发事件
            render(){
                const {isHot} = this.state
                return <h2 onClick = {this.changeWeather}>今天天气很{this.state.isHot ? "炎热" : "凉爽"}</h2>
            }
            // 自定义方法--要用赋值语句+箭头函数
            changeWeather = () =>{
                const isHot = this.state.isHot;
                this.setState({isHot:!isHot})
            }
            
        }
!!!精华:此处的changeWeather就是组件Weather的一个变量,被赋值一个函数,那么在this.changeWeather拿到的就是一个函数传给onClick,而不是直接被调用返回数值给onClick

2、props

        官方定义为 --> 单向数据流值

        作用:接收外部数据(这是别人给的,只读!)

        传递数据: 通过给组件标签添加属性

        接收数据:函数组件通过 参数 props接收数据,类组件通过 this.props接收数据

        1、对标签限制 --类型、必要性

    // 对标签属性进行类型、必要性的限制
        Person.propTypes = {
            name:PropTypes.string.isRequired,//限制name必传,且为字符串
            sex:PropTypes.string,
            age:PropTypes.number,
            speak:PropTypes.func//限制speak必须是函数
        }
        //指定默认标签属性值
         Person.defaultProps = {
            sex:'不男不女',
            age:18
        }

        2、向组件传递数据 -- props批量传递

    // 批量传递props
    //注意: 冒号: 表示键值对 用于对象中 等于号= 用于给常量赋值
    const p = {name:"23",age:23,sex:"男"}
    ReactDOM.render(<Person {...p} />,document.getElementById('test3'))

        3、简写完整版

class Person extends React.Component{
             // 对标签属性进行类型、必要性的限制
            static propTypes = {
                name:PropTypes.string.isRequired,//限制name必传,且为字符串
                sex:PropTypes.string,
                age:PropTypes.number,
                speak:PropTypes.func//限制speak必须是函数
        }
        //指定默认标签属性值
            static defaultProps = {
                sex:'不男不女',
                age:18
        }
            state = {}
            render(){
                const{name,age,sex} = this.props
                // 获取到的props数据流是只读的
                // this.props.name = 'jack' 会报错
                return(
                    <ul>
                        <li>{name}</li>
                        <li>{sex}</li>
                        <li>{age}</li>
                    </ul>
                )
            }
            // 对组件标签进行限制
             

        }
        ReactDOM.render(<Person name= "{23}"  speak = {speak}/>, document.getElementById('test1'))
        ReactDOM.render(<Person name="小刘" age={12} sex="女"/>, document.getElementById('test2'))
        // 批量传递props
        //注意: 冒号: 表示键值对 用于对象中 等于号= 用于给常量赋值
        const p = {name:"23",age:23,sex:"男"}
         ReactDOM.render(<Person {...p} />, document.getElementById('test3'))

         function speak(){
            console.log(这是一段话);
         }
   </script>

实现组件通信方法    --  定义为父子组件

        将父组件的state作为子组件的props,当父组件的state改变,子组件的props也跟着改变,其实它仍旧遵循了这一定律:props是不可更改的。

子组件调用父组件的方法

(1)子组件要拿到父组件的属性,需要通过 this.props 方法。

(2)同样地,如果子组件想要调用父组件的方法,只需父组件把要被调用的方法以属性的方式放在子组件上, 子组件内部便可以通过“this.props.被调用的方法”这样的方式来获取父组件传过来的方法。

父组件传参数、函数,子组件接收实例

import React, { Component, Fragment } from "react";
//React的props传参
// 父组件
class App extends Component {
  render() {
    return (
      <Fragment>
        <Child name="卡卡罗特" jineng={this.bianshen}></Child>
      </Fragment>
    );
  }

  bianshen() {
    return "变身超级赛亚人";
  }
}
// 子组件
class Child extends Component {
  render() {
    return (
      <div>
        {this.props.name}
        {this.props.jineng()}
      </div>
    );
  }
}

export default App;

父组件调用子组件的方法 在 ReactJS 中有个叫 ref 的属性。这个属性就像给组件起个引用名字一样,子组件被设置为 ref 之后(比如 ref=“xxx”)。父组件便可以通过 this.refs.xxx 来获取到子组件了。

3、ref

组件内的标签定义ref标识自己

字符串形式 -- 简单好用但逐渐过时

<script type="text/babel">
        // 创建组件
        class Demo extends React.Component{
            // 展示左侧输入框的数据
            showData = ()=>{
                const {input1} = this.refs
                alert(input1.value)
            }
            // 展示右侧输入框的数据
            showData2 = ()=>{
                const {input2} = this.refs
                alert(input2.value)
            }
            render(){
                return(
                    <div>
                        <input ref="input1" type="text" placeholder="点击按钮提示数据"/>
                        <button onClick={this.showData}>点我提示左侧的数据</button>
                        <input ref="input2" onBlur={this.showData2}type="text" placeholder="失去焦点提示数据"/>
                    </div>
                )
            }
        }
        ReactDOM.render(<Demo/>,document.getElementById("test1"))
    </script>

回调形式 -- 麻烦

<script type="text/babel">
        // 创建组件
        class Demo extends React.Component{
            // 展示左侧输入框的数据
            showData = ()=>{
                const {input1} = this 
                alert(input1.value)
            }
            // 展示右侧输入框的数据
            showData2 = ()=>{
                const {input2} = this 
                alert(input2.value)
            }
            render(){
             //    使用回调函数,把input1挂载到组件实例对象this上 从而直接获取input1
                return(
                    <div>
                         <input ref={cur => this.input1 = cur} type="text" placeholder="点击按钮提示数据"/>
                        <button onClick={this.showData}>点我提示左侧的数据</button>
                        <input onBlur={this.showData2} ref={cur => this.input2 = cur}  type="text" placeholder="失去焦点提示数据"/>
                    </div>
                )
            }
        }
        ReactDOM.render(<Demo/>,document.getElementById("test1"))
    </script>

createRef -- 官方最新

<script type="text/babel">
        // 创建组件
        class Demo extends React.Component{
            // React.createRef调用后返回一个容器 可存储被ref标识的节点 但只能一个
            myRef = React.createRef()
            myRef2 = React.createRef()
            // 展示左侧输入框的数据
            showData = ()=>{
                alert(this.myRef.current.value)
            }
            // 展示右侧输入框的数据
            showData2 = ()=>{
                alert(this.myRef2.current.value)
            }
            render(){
                 return(
                    <div>
                        <input  ref={this.myRef} type="text" placeholder="点击按钮提示数据"/>
                        <button onClick={this.showData}>点我提示左侧的数据</button>
                        <input  onBlur={this.showData2} ref={this.myRef2} type="text" placeholder="点击按钮提示数据"/>
                     </div>
                )
            }
        }
        ReactDOM.render(<Demo/>,document.getElementById("test1"))
    </script>

3、事件处理

将发生的事件作为参数

        class Demo extends React.Component{
            // React.createRef调用后返回一个容器 可存储被ref标识的节点 但只能一个
            myRef = React.createRef()
            myRef2 = React.createRef()
            // 展示左侧输入框的数据
            showData = ()=>{
                alert(this.myRef.current.value)
            }

            // 展示右侧输入框的数据
            showData2 = (event)=>{
                alert(event.target.value)
            }
            render(){
                 return(
                    <div>
                        <input  ref={this.myRef} type="text" placeholder="点击按钮提示数据"/>
                        <button onClick={this.showData}>点我提示左侧的数据</button>
                        {/*发生事件的元素刚好是要操作的元素,就可省略ref*/}
                        <input  onBlur={this.showData2}  type="text" placeholder="点击按钮提示数据"/>
                     </div>
                )
            }
            // 事件处理中,点击第二个输入文本就是一个未指定的事件,在showData2函数中将点击事件作为参数获取值显示
        }
        ReactDOM.render(<Demo/>,document.getElementById("test1"))
    

4、React生命周期

旧版本

组件的钩子中只有三个钩子常用

1、初始化阶段:由ReactDOM.render()出发 -- 初次渲染

                        1、constructor()

                        2、componentWillMount()

                        3、render()

                        4、componentDidMount() ====》常用

             一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息

2、更新阶段:有组件内部this.setState()或父组件render触发

                        1、componentWillReceiveProps()

                        2、shouldComponentUpdate()

                        3、componentWillUpdate()

                        4、render() 必用

                        5、componentDidUpdate()

3、卸载阶段:由ReactDOM.unmountComponentAtNode()触发

                        1、componentWillUnmount() ===》常用

                                一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息

基本钩子实例

<script type="text/babel">
            class Count extends React.Component{
                //1、构造器
                constructor(props){
                    super(props)
                    console.log('1、Count --- Constructor')
                    // 初始化状态
                    this.state = {count:0}
                }
                //  各个事件的回调函数
                add = () => {
                    // 获取原状态
                    const{count} = this.state
                    // 更新状态
                    this.setState({count:count+1})
                }
                //卸载组件按钮的回调
                death = () => {
                    ReactDOM.unmountComponentAtNode(document.getElementById('test1'))
                }
                force = () => {
                    this.forceUpdate()
                }

                // 2、组件将要挂载的钩子 -- componentWillMount
                componentWillMount(){
                    console.log('2、Count --- componentWillMount')
                }
                // 4、组件挂载完毕的钩子 -- componentDidMount
                componentDidMount(){
                    console.log('4、Count --- componentDidMount')
                }
                // 4、2组件更新完毕的钩子
                componentDidUpdate(){
                    console.log('4.2、Count --- componentDidUpdate')
                }
                // 5、组件将要卸载的钩子 -- componentWillUnmount
                componentWillUnmount(){
                    console.log('5、Count --- componentWillUnmount')
                }
                // 3.1前置、判断组件是否可更新的钩子
                shouldComponentUpdate(){
                    console.log('3.1前置、Count --- shouldComponentUpdate')
                    return true
                }
                // 3.2前置、组件将要更新的钩子
                componentWillUpdate(){
                    console.log('3.2前置、Count --- ComponentWillUpdate')
                }
                // 3、render
                render(){
                    console.log('3、Count --- render')
                    const {count} = this.state
                    return(
                        <div>
                            <h2>当前求和为:{count}</h2>
                            <button onClick={this.add}>点我+1</button>
                            <button onClick={this.death}>卸载组件</button>
                            <button onClick={this.force}>不输入数据就是要强制更新一下</button>
                        
                        </div> 
                    )
                }
            }
            // 渲染组件
            ReactDOM.render(<Count/>,document.getElementById("test1"))

父组件与子组件

 class A extends React.Component{
                state = {carName:'宝马'}
                changeCar = () =>{
                    this.setState({carName:'奥迪'})
                }
                render(){
                    return(
                        <div>
                            <div>我是A组件</div>    
                            <button onClick={this.changeCar}>换车</button>
                            <B receiveCarName = {this.state.carName}/>
                        </div>
                    )
                }
            }

            class B extends React.Component{
                render(){
                    return(
                        <div>
                            我是B组件,接收到父组件A的车是:{this.props.receiveCarName}
                        </div>
                    )
                }
            }

            ReactDOM.render(<A/>,document.getElementById('test1'))

新版本

新版本与旧版本区别

1、新版本废弃了三个will钩子:

componentWillMount()、componentWillUpdate()、componentWillReceiveProps()

 2、增加了俩个钩子:

getDerivedStateProps()、getSnapshotBeforeUpdate()

其他的初始化组件、更新组件、卸载组件三大生命周期过程就原样。

// getDerivedStateFromProps作用:当前组件的state的值在任何时候都取决于外部传入的props  基本不用 
                static getDerivedStateFromProps(props,state){
                    console.log('执行getDerivedStateFromProps')
                    return props
                }

// 更新之前获取快照
                getSnapshotBeforeUpdate(){
                    console.log('执行getSnapshotBeforeUpdate')
                    return 'atguigu'
                }

1、初始化阶段:由ReactDOM.render()出发 -- 初次渲染

                        1、constructor()

                        2、getDerivedStateProps()

                        3、render()

                        4、componentDidMount() ====》常用

一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息

2、更新阶段:有组件内部this.setState()或父组件render触发

                        1、getDerivedStateProps()

                        2、shouldComponentUpdate()

                        3、render() 必用

                        4、getSnapshotBeforeUpdate()

                        5、componentDidUpdate()

3、卸载阶段:由ReactDOM.unmountComponentAtNode()触发

                        1、componentWillUnmount() ===》常用

                        一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息 -->

三、React应用(基于React脚手架)

create-react-app库提供脚手架,首先就要全局安装create-react-app库,

npm i -g create-react-app

接着就是使用库安装脚手架。

create-react-app  [脚手架名字]

详细讲解见我的另一篇React脚手架-详细解析目录与运行-CSDN博客

实例todoList    

        见代码:/Users/wangjia/Desktop/web前端/react脚手架/03_src

四、React Ajax

由于Ajax同源策略,涉及到跨域问题无法接收请求,使用代理配置--实现url转换。

方法一

在package.json中追加如下配置
"proxy":"http://localhost:5000"

说明:

1. 优点:配置简单,前端请求资源时可以不加任何前缀。
2. 缺点:不能配置多个代理。
3. 工作方式:上述方式配置代理,当请求了3000不存在的资源时,那么该请求会转发给5000 (优先匹配前端资源)

方法二

1. 第一步:创建代理配置文件
   在src下创建配置文件:src/setupProxy.js

2. 编写setupProxy.js配置具体代理规则:
   const { createProxyMiddleware } = require("http-proxy-middleware")
   module.exports = function(app) {
     app.use(
       createProxyMiddleware('/api1', { //api1是需要转发的请求(所有带有/api1前缀的请求都会转发给5000)
         target: 'http://localhost:5000',              //配置转发目标地址(能返回数据的服务器地址)
         changeOrigin: true,                           //控制服务器接收到的请求头中host字段的值
         /*
             changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
             changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:3000
             changeOrigin默认值为false,但我们一般将changeOrigin值设为true
         */
         pathRewrite: {'^/api1': ''}

                //去除请求前缀,保证交给后台服务器的是正常请求地址(必须配置)
       })
     )
   }
   ```

说明:

1. 优点:可以配置多个代理,可以灵活的控制请求是否走代理。
2. 缺点:配置繁琐,前端请求资源时必须加前缀。

props---实现组件通信

App.js

export default class App extends Component {
  
  state = {
    users:[],//users初始值为数组
    isFirst:true,//是否为第一次打开页面
    isLoading:false,//标示是否处于加载中
    err:''//存储请求相关的错误信息
  
  } 
  // 通用 -- 更新App的state
  updateAppState = (stateObj) => {
    this.setState(stateObj)
  }
  render() {
    return (
        <div className="container">
             <Search updateAppState={this.updateAppState}/>
             <List {...this.state}/>
      </div>
    )
  }
}

Search.js

export default class Search extends Component {

    search = () => {
        // 1、获取用户的输入  -- 连续解构赋值
        const{keyWordElement:{value:keyWord}} = this
        //  发送请求前通知App更新状态
        this.props.updateAppState({isFirst:false,isLoading:true})
        // 2、发送网络请求 拿到返回的数据    给谁发?url  用啥方法?method 带啥参数? params  站在3000给5000发请求 - 配代理
        // 站在3000给3000发,3000有代理转发给5000
        axios.get(`http://localhost:3000/api1/search/users2?q=${keyWord}`).then(
            response => {
                //请求成功后通知App更新状态
                this.props.updateAppState({isLoading:false,users:response.data.items})
            },
            error => {
                 //请求失败后通知App更新状态
                 this.props.updateAppState({isLoading:false,err:error.message})
            }
        )}
   render() {
     return (
       <section className="jumbotron">
            <h3 className="jumbotron-heading">Search Github Users</h3>
            <div>
                
            <input  ref={cur => this.keyWordElement = cur} type="text" placeholder="enter the name you search"/>&nbsp;
            <button onClick={this.search}>搜索</button>
            </div>
        </section>
     )
   }

List.js

export default class List extends Component {
  render() {
    const {users,isFirst,isLoading,err} = this.props
    return (
        // JSX使用三元表达式,不可以判断语句  多个条件要判断使用连续三元表达式
      <div className="row">
         {
            isFirst ? <h2>欢迎使用,输入关键字,随后点击搜索</h2> :
            isLoading ? <h2>Loading.......</h2> :
            err ? <h2 style={{color:'red'}}>{err}</h2> :
            users.map((userObj)=>{
                return(
                    <div key={userObj.id} className="card">
                        <a rel="noreferrer" href={userObj.html_url} target="_blank">
                            <img alt="head_portrait" src={userObj.avatar_url} style={{width: '100px'}}/>
                        </a>
                        <p className="card-text">{userObj.login}</p>
                    </div>
                )
            })
         }
    </div>

1、axios-发送HTTP请求

Axios 是一个基于 promise 网络请求库。

fetch用于请求,内置的。

xhr用于发送http请求,jQuery与axios都是对xhr的封装。底层还都是xhr。只不过xhr的API太繁琐。所以要使用就要安装jQuery与axios。

也就是用来发送Ajax请求时使用的网络请求库。也就是发送HTTP请求的

const axios = require("axios");
​
// 向给定 ID 的用户发起请求
axios
  .get("/user?ID=12345")
  .then(function (response) {
    //处理成功情况
    console.log(response);
  })
  .catch(function (error) {
    //处理错误情况
    console.log(error);
  })
  .then(function () {
    //总是会执行
  });

2、消息订阅机制-组件通信

消息订阅与取消 -- 在组件完成挂载时接收消息、在组件卸载时取消订阅

接收消息:PubSub.subscribe(mag,function())

// 订阅消息--接收消息
  componentDidMount(){
    this.token = PubSub.subscribe('atguigu',(_,stateObj)=>{
      this.setState(stateObj)
    })
  }
  // 取消订阅
  componentWillUnmount(){
    PubSub.unsubscribe(this.token)
  }

发送消息PubSub.publish(mag,data)

PubSub.publish('atguigu',{isFirst:false,isLoading:true})
PubSub.publish('atguigu',{isLoading:false,err:error.message})

使用fetch发送请求,我这个java程序员,就不深入学喽。

五、React-router

1、路由基本概念

路由工作原理:

之前是多页面更新,(多个.html),一次刷新就要整个页面全部刷新,重新挂载dom。

如今页面更新方式,采用单页面多组件,刷新也只是页面局部刷新。

路由:就是一对映射关系(key : value)

key为路径;value为function或component

路由分类:

2、React-router-dom(前端路由)

1、路由组件基本使用

React的插件库。

使用路由套路:1、导航区在哪?(导航区内选项即为路由链接)  2、展示区在哪?

详细过程:点击导航区内选项,引起路径变化; 路径变化被前端路由器监测到,并匹配组件,从而展示。

    1.明确好界面中的导航区、展示区
    2.导航区的a标签改为Link标签
    	<Link to="/xxxx">Demo</Link>
    3.展示区写Route标签进行路径的匹配
    	<Route path='/xxxx’ component={Demo}/>
    4. <App>的最外侧包襄了一个<BrowserRouter>或<HashRouter>

1、编写路由链接

<Link className="list-group-item" to="/about">About</Link>
<Link className="list-group-item" to="/home">Home</Link>

2、注册路由

<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>

3、使用唯一的BrowserRouter 监听

为了使唯一的监听器能够监听到 路由链接切换并注册路由,以及其他事情,将BrowserRouter直接放在index.js挂载组件的标签外

<BrowserRouter>

<App />

</BrowserRouter>

* 原生HTML中,靠<a>跳转不同的页面

 <a className="list-group-item" href="./about.html">About</a>

* 在React中靠路由链接实现切换组件

<BrowserRouter>

<Link className="list-group-item" to="/about">About</link>

</BrowserRouter>

路由组件与一般组件

路由组件:存储在pages文件夹下

                   使用路由匹配引用  <Route path="/home" component={Home}/>

                   路由组件接收到路由器传送的props中三个固定属性:history、location、match

一般组件:存储在components文件夹下

                  使用标签引用  <Header/>

                  一般组件标签内传啥,props就包含啥

路由组件关键三个属性

history:
    go: function go(n)​​
    goBack: function goBack()​​
    goForward: function goForward()
    ​​push: function push(path, state)​​
    replace: function replace(path, state)​​
​location:
    pathname: "/home"
    search: ""
    ​​state: undefined
​match:
    ​​params: Object {  }
    ​​path: "/home"
    ​​url: "/home"

组件封装 :使用 一般组件 封装 路由组件

向组件属性传值

<MyNavLink to="/about">About</MyNavLink>

<MyNavLink to="/home">Home</MyNavLink>

被封装的组件直接使用...this.props接收(固定值直接写死,变化值使用this.props传输)

<NavLink activeClassName="atguigu" className="list-group-item" {...this.props}/>

注意:标签体内容是特殊的标签属性

标签体内容this.props.children可以直接在标签属性中使用children代替。

<GGB>this.props.children</GGB>   <=>  <GGB children></GGB>

使用Switch组件提高(注册路由)匹配效率

一般情况,路由器监测到路径改变后,就会与所有注册路由匹配,匹配成功后依然匹配,效率低!

使用Switch组件后,匹配成功停止匹配。

注册路由内path与component是一一对应,使用Switch进行单一匹配。

<Switch>

<Route path="/about" component={About}/>

<Route path="/home" component={Home}/>

<Route path="/home" component={Test}/>

</Switch>

严格匹配与模糊匹配

 路由链接与注册路由在匹配时,默认开启的是模糊匹配。只要路由链接开始就包含注册路由,依然可以匹配成功。

        <MyNavLink to="/home/a/b">Home</MyNavLink>

        <Route path="/home" component={Home}/> 

当有exact时,即开启了严格匹配

        <MyNavLink to="/home/a/b">Home</MyNavLink>

        <Route exact path="/home" component={Home}/> 

路由一旦开启严格匹配,那么其子路由全部作废,无法匹配

因此对于多级路由,根路由不可开启严格匹配

重定向默认匹配

刚打开时,localhost:3000/  其中/ 与注册路由逐一匹配,失败后就啥也不显示,但是希望可以上来就有一个默认显示的。

使用Redirect重定向,执行路由链接与注册路由逐一匹配时,当全部匹配失败,就执行Redirect,后面跟上默认匹配的注册路由,进行展示。

Redirect写在所有注册路由最下方。

{/* 注册路由 */}

<Switch>

<Route path="/about" component={About}/>

<Route path="/home" component={Home}/>

<Redirect to="/home"/>

</Switch>

2、嵌套路由---多级路由

1、子路由的链接与注册均要写上父路由的path值---也就是多级路由一定要完整写出。

2、路由的匹配是按照路由的注册顺序尽心匹配。先进行父路由的匹配,再进行子路由的完整匹配

<ul className="nav nav-tabs">

        <li>

<MyNavLink to="/home/news">News</MyNavLink>

        </li>

        <li>

<MyNavLink to="/home/message">Message</MyNavLink>

        </li>

</ul>

<Switch>

        <Route path="/home/news" component={News}/>

        <Route path="/home/message" component={Message}/>

        <Redirect to="/home/message"/>

</Switch>

3、传递路由参数

也就是在路由链接后面加上要传递到目的组件的参数。有params、search、state三大类参数

1、params参数  

{/* 向路由组件传递params参数  --- 在链接路由路径后 携带参数*/}
<Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>

{/* 声明接收params参数 --- 在路由路径后直接声明接收参数 */}
<Route path='/home/message/detail/:id/:title' component={Detail}/>

// 接收params参数
const {id,title} = this.props.match.params

2、search参数

 {/* 向路由组件传递Search参数 */}
<Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link>

{/* 无需 声明接收Search参数 */}
<Route path='/home/message/detail' component={Detail}/>

//接受Search参数 --- 需要将字符串转换为key-value
const {search} = this.props.location
const {id,title} = qs.parse(search.slice(1))

3、state参数 

此state不是组件的状态,就是history的location下的state属性!

{/* 向路由组件传递state参数 -- 是个对象!!!! */}
<Link to={{pathname:'/home/message/detail',state:{id:msgObj.id,title:msgObj.title}}}>{msgObj.title}</Link> 

{/* 无需 声明接收state参数 */}
<Route path='/home/message/detail' component={Detail}/>

//接受state参数
const {id,title} = this.props.location.state

4、路由跳转俩模式push&replace

4、编程式路由导航

5、withRouter

withRouter可以加工一般组件,使其具备路由组件所特有的API,比如this.props.history

import React, { Component } from 'react'
import { withRouter } from 'react-router-dom/cjs/react-router-dom.min'
class Header extends Component {
    back = () => {
        this.props.history.goBack()
    }
    forward = () => {
        this.props.history.goForward()
    }
    go = () => {
        this.props.history.go(-2)
    }
    render() {
        console.log(this.props.history)
    return (
         
        <div className="page-header">
            <h2>React Router Demo</h2>
            <button onClick={this.back}>回退</button>&nbsp;
            <button onClick={this.forward}>前进</button>&nbsp;
            <button onClick={this.go}>go</button> 
        </div>
    )
  }
}
export default withRouter(Header)

六、BrowserRouter和HashRouter区别

六、React UI组件库

ant-design  前端UI组件库

七、redux

1、redux理解

定义:专门用作状态管理的js库(不是React插件)

作用:集中式管理React应用中多个组件共享的状态。

啥时候用?

共享:某个组件的状态,可以让其他组件随时拿到。

通信:一个组件需要改变另一个组件的状态。

使用原则:能不用就不用。实在是使用消息订阅或者props吃力才使用。

2、redux原理

action

        动作的对象

包含2个属性:

  1. type:标识属性, 值为字符串, 唯一, 必要属性
  2. data:数据属性, 值类型任意, 可选属性

例子:{ type: 'ADD_STUDENT',data:{name: 'tom',age:18} }

reducer

  1. 用于初始化状态、加工状态。
  2. 加工时,根据旧的stateaction 产生新的state纯函数

store

state action 、reducer联系在一起的对象  如何得到此对象?
  • import {createStore} from 'redux'
  • import reducer from './reducers'
  • const store = createStore(reducer)

此对象的功能?

  1. getState(): 得到state
  2. dispatch(action): 分发action, 触发reducer调用, 产生新的state
  3. subscribe(listener): 注册监听, 当产生了新的state时, 自动调用

 八、扩展

1、setState更新状态的2种写法

总结:

1.对象式的setState是函数式的setState的简写方式(语法糖)
2.使用原则:
        (1).如果新状态不依赖于原状态 ===> 使用对象方式
        (2).如果新状态依赖于原状态 ===> 使用函数方式
        (3).如果需在setState()执行后获取最新状态数据,要在第二个callback函数中读取

1.setState(stateChange, [callback])------对象式setState

  • stateChange为状态改变对象(该对象可以体现出状态的更改)
  • callback可选的回调函数, 它在状态更新完毕、界面也更新后(render调用后)才被调用
import React, { Component } from 'react'

export default class Demo extends Component {

	state = {count:0}

	add = ()=>{
		//对象式的setState
		//1.获取原来的count值
		const {count} = this.state
		//2.更新状态
		this.setState({count:count+1},()=>{
			console.log(this.state.count);//1
		})
		console.log('12行的输出',this.state.count); //0
	}

	render() {
		return (
			<div>
				<h1>当前求和为:{this.state.count}</h1>
				<button onClick={this.add}>点我+1</button>
			</div>
		)
	}
}

2.setState(updater, [callback])------函数式setState

  • updater为返回stateChange对象的函数。
  • updater可以接收到stateprops
  • callback是可选的回调函数, 它在状态更新、界面也更新后(render调用后)才被调用
import React, { Component } from 'react'

export default class Demo extends Component {

	state = {count:0}

	add = ()=>{
		//函数式的setState
		this.setState( (state,props) => ({count:state.count+1}),()=>{
			//回调中拿到的是render之后的新数据
			console.log(state,props);
		})
	}

	render() {
		return (
			<div>
				<h1>当前求和为:{this.state.count}</h1>
				<button onClick={this.add}>点我+1</button>
			</div>
		)
	}
}

2. lazyLoad

路由组件的lazyLoad   懒加载--将页面显示优先加载,资源懒加载,提高页面展示速度

	//1.通过React的lazy函数配合import()函数动态加载路由组件 ===> 路由组件代码会被分开打包
	const Login = lazy(()=>import('@/pages/Login'))
	
	//2.通过<Suspense>指定在加载得到路由打包文件前显示一个自定义loading界面
	<Suspense fallback={<h1>loading.....</h1>}>
        <Switch>
            <Route path="/xxx" component={Xxxx}/>
            <Redirect to="/login"/>
        </Switch>
    </Suspense>

 3、Hooks

 State Hook
(1). State Hook让函数组件也可以有state状态, 并进行状态数据的读写操作
(2). 语法: const [xxx, setXxx] = React.useState(initValue)  
(3). useState()说明:
        参数: 第一次初始化指定的值在内部作缓存
        返回值: 包含2个元素的数组, 第1个为内部当前状态值, 第2个为更新状态值的函数
(4). setXxx()2种写法:
        setXxx(newValue): 参数为非函数值, 直接指定新的状态值, 内部用其覆盖原来的状态值
        setXxx(value => newValue): 参数为函数, 接收原本的状态值, 返回新的状态值, 内部用其覆盖原来的状态值
function Demo(){
    const [count,setCount] = React.useState(0)
    //加的回调
	function add(){
		//setCount(count+1) //第一种写法
		setCount(count => count+1 )
	}
    return (
		<div>
			<button onClick={add}>点我+1</button>
		</div>
	)
}
export default Demo
Effect Hook
(1). Effect Hook 可以让你在函数组件中执行副作用操作(用于模拟类组件中的生命周期钩子)
(2). React中的副作用操作:
        发ajax请求数据获取
        设置订阅 / 启动定时器
        手动更改真实DOM
(3). 语法和说明: 
        useEffect(() => { 
          // 在此可以执行任何带副作用操作
          return () => { // 在组件卸载前执行
            // 在此做一些收尾工作, 比如清除定时器/取消订阅等
          }
        }, [stateValue]) // 如果指定的是[], 回调函数只会在第一次render()后执行
    
(4). 可以把 useEffect Hook 看做如下三个函数的组合
        componentDidMount()
        componentDidUpdate()
    	componentWillUnmount() 

 

 Ref Hook
(1). Ref Hook可以在函数组件中存储/查找组件内的标签或任意其它数据
(2). 语法: const refContainer = useRef()
(3). 作用:保存标签对象,功能与React.createRef()一样

4、render props

如何向组件内部动态传入带内容的结构(标签)?

Vue中: 
	使用slot技术, 也就是通过组件标签体传入结构  <A><B/></A>
React中:
	使用children props: 通过组件标签体传入结构
	使用render props: 通过组件标签属性传入结构,而且可以携带数据,一般用render函数属性

children props

<A>
  <B>xxxx</B>
</A>
{this.props.children}
问题: 如果B组件需要A组件内的数据, ==> 做不到 

render props

<A render={(data) => <C data={data}></C>}></A>
A组件: {this.props.render(内部state数据)}
C组件: 读取A组件传入的数据显示 {this.props.data} 

 

5、组件通信方式总结

组件间的关系:

  • 父子组件
  • 兄弟组件(非嵌套组件)
  • 祖孙组件(跨级组件)

几种通信方式:

	1.props:
		(1).children props
		(2).render props
	2.消息订阅-发布:
		pubs-sub、event等等
	3.集中式管理:
		redux、dva等等
	4.conText:
		生产者-消费者模式

比较好的搭配方式:

	父子组件:props
	兄弟组件:消息订阅-发布、集中式管理
	祖孙组件(跨级组件):消息订阅-发布、集中式管理、conText(开发用的少,封装插件用的多)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1062606.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言数据结构2 1.2 算法

算法的基本概念 算法的定义 算法是对特定问题求解步骤的一种描述&#xff0c;它是指定的有限序列&#xff0c;其中的每条指令表示一个或多个操作。 例、 算法的特性 &#xff08;5个&#xff09; 1.有穷性 一个算法总在执行有穷步之后结束&#xff0c;且每一步都可以在有穷…

医疗器械标准目录汇编2022版共178页(文中附下载链接!)

为便于更好地应用医疗器械标准&#xff0c;国家药监局医疗器械标准管理中心组织对现行1851项医疗器械国家和行业标准按技术领域&#xff0c;编排形成《医疗器械标准目录汇编&#xff08;2022版&#xff09;》 该目录汇编分为通用技术领域和专业技术领域两大类&#xff0c;通用…

计算机网络 第三章数据链路层

文章目录 1、数据链路层概述 1、数据链路层概述

C语言:选择+编程(每日一练Day9)

目录 选择题&#xff1a; 题一&#xff1a; 题二&#xff1a; 题三&#xff1a; 题四&#xff1a; 题五&#xff1a; 编程题&#xff1a; 题一&#xff1a;自除数 思路一&#xff1a; 题二&#xff1a;除自身以外数组的乘积 思路二&#xff1a; 本人实力有限可能对…

2.2.3 vim操作合集

1 vim VIM 是 Linux 系统上一款文本编辑器,学习 VIM 最好的文档,应该是阅读学习 VIM 的帮助文档,可以使用本地的帮助文件(vim--->:help),或者使用在线帮助文档。同时针对vim的使用,相应的相书籍也很多,如下 2 vim操作模式 命令模式:默认模式,该模式下可以移动光标…

ChatGPT付费创作系统V2.3.4独立版 +WEB端+ H5端 + 小程序最新前端

人类小徐提供的GPT付费体验系统最新版系统是一款基于ThinkPHP框架开发的AI问答小程序&#xff0c;是基于国外很火的ChatGPT进行开发的Ai智能问答小程序。当前全民热议ChatGPT&#xff0c;流量超级大&#xff0c;引流不要太简单&#xff01;一键下单即可拥有自己的GPT&#xff0…

LVGL_基础控件checkbox

LVGL_基础控件checkbox 1、创建checkbox /* 创建一个 checkbox 部件(对象) */ lv_obj_t * cb lv_checkbox_create(lv_scr_act()); // 创建一个 switch 部件(对象),他的父对象是活动屏幕对象 lv_checkbox_set_text(cb, "100ASK LVGL Tutorial" LV_SYMBOL_PLAY);…

qml保姆级教程四:按钮组件

&#x1f482; 个人主页:pp不会算法v &#x1f91f; 版权: 本文由【pp不会算法v】原创、在CSDN首发、需要转载请联系博主 &#x1f4ac; 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦 QML系列教程 QML教程一&#xff1a;布局组件 文章目录 AbstractButton…

汽车类、TPS7B8225QDGNRQ1、TPS7B8233EPWPRQ1、TPS7B8601QKVURQ1 40V、低压降 (LDO) 线性稳压器

一、TPS7B82-Q1 汽车类 300mA、高压、超低 IQ 低压降稳压器 &#xff08;介绍&#xff09;在汽车电池连接应用中&#xff0c;低静态电流 (IQ) 对于省电和延长电池寿命而言至关重要。对于始终开启的系统&#xff0c;必须要实现超低 IQ。 TPS7B82-Q1 是一款旨在在 3V 至 40V&…

Java毕业设计 SpringBoot 网上体育商城系统 商城系统

Java毕业设计 SpringBoot 网上体育商城系统 商城系统 SpringBoot 网上体育商城系统 功能介绍 首页 图片轮播 搜索 用户登录注册 商品信息 商品分类 商品详情 收藏 评论 添加到购物车 立即购买 购物车 确认下单 公告信息 留言反馈 个人中心 修改个人信息 我的订单 退款 我的地…

地图资源下载工具2.0

一、简介 地图资源工具是一款用于GIS数据下载的工具&#xff0c;用于GIS数据矢量、遥感数据的查询、下载及浏览。下载数据包括&#xff1a;哨兵&#xff08;Sentinel&#xff09;系列&#xff0c;LANDSAT系列&#xff0c;MODIS系列、ASTER系列、GOES系列、OPENSTREETMAP数据…

传输层协议—TCP协议

传输层协议—TCP协议 文章目录 传输层协议—TCP协议TCP协议段格式四位首部长度TCP协议如何根据目的端口号将数据传输给指定进程&#xff1f;32位序列号和32位确认序列号可靠性问题 TCP报头标志位16位紧急指针16位检验和确认应答机制超时重传机制再谈三次握手四次挥手 连接管理机…

XC5013 马达驱动和充电集成一体的控制芯片 一档输出芯片

XC5013 是一款应用于马达驱动或 LED 驱动的控制芯片&#xff0c;集成了锂电池充电管理系统&#xff0c;设定一档高电平输 出&#xff0c;并带有对不同状态的 LED 指示功能。 XC5013 集成了涓流充电、恒流充电和恒压充电全过程的充电方式&#xff0c;浮充电压精度在全温度范…

GEE16: 区域日均降水量计算

Precipitation 1. 区域日均降水量计算2. 降水时间序列3. 降水数据年度时间序列对比分析 1. 区域日均降水量计算 今天分析一个计算区域日均降水量的方法&#xff1a; 数据信息&#xff1a;   Climate Hazards Group InfraRed Precipitation with Station data (CHIRPS) is a…

国庆假期作业6

一、ARM的工作模式 1、非特权模式 user模式&#xff1a;非特权模式&#xff0c;大部分任务执行在这种模式 2、特权模式 异常模式&#xff1a; FIQ : 当一个快速&#xff08;fast) 中断产生时将会进入这种模式 IRQ : 当一个通用&#xff08;normal) 中断产生时将会进入这种模式…

物联网系统中物模型定义的简要说明

物模型由若干条“参数”组成,参数按描述的功能类型不同,又分为属性、方法和事件。 标准参数 为了实现设备功能的统一理解。 说的直白一些的理解&#xff0c;可以这样去理解&#xff1a; 属性&#xff0c;就是定义的由设备端规律性的定期上报的数据。 事件&#xff0c;就是定…

【在凸多边形的图像中查找顶点】估计具有已知顶点数的像素化凸多边形角点研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

2.2.3.1vim + ctags + cscope + taglist

在window下,我们一般用Source Insight来查看代码而在linux下,使用vim来查看代码,vim是一个简单的文本浏览/编辑器,它可以通过插件的形式,搭建一个完全的类Source Insight环境,通过快捷键的形式,快速查看、定位变量/函数,本文就是基于vim,通过ctags+cscope+taglist+Ner…

剑指offer——JZ77 按之字形顺序打印二叉树 解题思路与具体代码【C++】

一、题目描述与要求 按之字形顺序打印二叉树_牛客题霸_牛客网 (nowcoder.com) 题目描述 给定一个二叉树&#xff0c;返回该二叉树的之字形层序遍历&#xff0c;&#xff08;第一层从左向右&#xff0c;下一层从右向左&#xff0c;一直这样交替&#xff09; 数据范围&#x…

【计算机视觉|人脸建模】学习从4D扫描中获取的面部形状和表情的模型

本系列博文为深度学习/计算机视觉论文笔记&#xff0c;转载请注明出处 标题&#xff1a;Learning a model of facial shape and expression from 4D scans 链接&#xff1a;Learning a model of facial shape and expression from 4D scans | ACM Transactions on Graphics Pe…