IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> React -> 正文阅读

[JavaScript知识库]React

一:见:react 一

jsx 更多写法

cnpm install --save react babel-standalone react-dom
运算操作( js学到的所有运算符 )同样可以进行

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="node_modules/react/umd/react.development.js"></script>
    <script src="node_modules/react-dom/umd/react-dom.development.js"></script>
    <script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
    <div id="demodiv"></div>
    <script type="text/babel">
        let a=1;
        let b=2;
        let bool=false;

        let el=(
            <div>
                <h1>{a+b}</h1>
                <h1>{bool?"你好":"你坏"}</h1>
            </div>
        )

        ReactDOM.render(el,document.getElementById("demodiv"))

    </script>
</body>
</html>

属性插变量

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="node_modules/react/umd/react.development.js"></script>
    <script src="node_modules/react-dom/umd/react-dom.development.js"></script>
    <script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
    <div id="demodiv"></div>
    <script type="text/babel">
        let ahref="http://www.baidu.com"
        let atext="点我去百度"

        let el=(
            <div>
                <h1>属性插变量</h1>
                {/*属性查变量  直接可以使用 大括号包裹变量*/}
                
                <a href={ahref}>{atext}</a>
            </div>
        )

        ReactDOM.render(el,document.getElementById("demodiv"))

    </script>
</body>
</html>

行内样式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="node_modules/react/umd/react.development.js"></script>
    <script src="node_modules/react-dom/umd/react-dom.development.js"></script>
    <script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
    <div id="demodiv"></div>
    <script type="text/babel">
 

        let el=(
            <div>
                <h1>行内样式的设置</h1>
                {/*
                 jsx中如果要设置行内样式  那么必须使用对象来生命
                下面的代码  外层大括号是jsx解析js的语法  里面的大括号是对象的语法

                如果样式是多个单词 那么-变大写
                */}
                <h1 style={{color:"red",backgroundColor:"pink"}}>设置我的样式</h1>
            </div>
        )

        ReactDOM.render(el,document.getElementById("demodiv"))

    </script>
</body>
</html>

类名设置

设置样式的时候 使用类名来进行样式的设置

传统的时候设置类名使用的html属性是 class属性

在react中如设置类名时 , 必须使用className来设置(原因是因为class是es6类的关键字)

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Document</title>
   <script src="node_modules/react/umd/react.development.js"></script>
   <script src="node_modules/react-dom/umd/react-dom.development.js"></script>
   <script src="node_modules/babel-standalone/babel.js"></script>
   <style>
       .demoh{
           color:yellow;
           background-color: blueviolet;
       }
   </style>
</head>
<body>
   <div id="demodiv"></div>
   <script type="text/babel">
    

       let el=(
           <div>
               <h1 className="demoh">我想使用类样式设置我的样子</h1>
               
           </div>
       )

       ReactDOM.render(el,document.getElementById("demodiv"))

   </script>
</body>
</html>

jsx总结扩展

1.style行内样式 使用对象来描述 所以有两个{{}}

2.类样式 不能使用class 而是要使用className

3.html中有一个value的属性 需要写成 defaultValue

4.html中有一个checked的属性 需要写成 defaultChecked

react 列表遍历数组(遍历展示)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="node_modules/react/umd/react.development.js"></script>
    <script src="node_modules/react-dom/umd/react-dom.development.js"></script>
    <script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
    <div id="demodiv"></div>
    <script type="text/babel">

        let arr=[111,2222,3333,4444,5555,66666]

        // 1.基本便利
        let el=(
            <div>
                <ul>
                    {
                        arr.map((v,i)=>{
                            return (
                                <li key={i}>{v}</li>
                            )
                        })
                    }
                </ul>
            </div>
        )

        ReactDOM.render(el,document.getElementById("demodiv"))

    </script>
</body>
</html>
遍历数组对象
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="node_modules/react/umd/react.development.js"></script>
    <script src="node_modules/react-dom/umd/react-dom.development.js"></script>
    <script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
    <div id="demodiv"></div>
    <script type="text/babel">

        // 2.便利数组对象
            let obj=[
                {name:"xixi1",age:171},
                {name:"xixi2",age:172},
                {name:"xixi3",age:173},
                {name:"xixi4",age:174},
                {name:"xixi5",age:175},
                {name:"xixi7",age:176}
            ]

            let newel=obj.map((v,i)=>{
                return (
                    <tr key={i}>
                        <td>{v.name}</td>    
                        <td>{v.age}</td>    
                        
                    </tr>
                )
            })
            let el=(
                <div>
                    <table border="1">
                        <tbody>
                            {newel}
                        </tbody>
                    </table>    
                    
                </div>
            )
        ReactDOM.render(el,document.getElementById("demodiv"))

    </script>
</body>
</html>

除了map方式还有什么方式可以进行循环便利??

react 列表便利对象

知识点回顾

对象转成数组

object.Keys() 返回一个数组 数组的内容就转换对象的key

object.Values() 返回一个数组 数组的内容就转换对象的value

object.entrise()返回一个数组 数组的内容就转换对象的key与value 他是一个二维数组


       let obj={name:"xixi",age:18};

       console.log(Object.keys(obj));
       console.log(Object.values(obj));
       console.log(Object.entries(obj));

对象怎么取值


       let newage="age"
       // 在实际项目中 有些使用你取对象的值时候  key可能是一个变量  那么就要用[]取值
       console.log(obj[newage]);

便利对象

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Document</title>
   <script src="node_modules/react/umd/react.development.js"></script>
   <script src="node_modules/react-dom/umd/react-dom.development.js"></script>
   <script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
   <div id="demodiv"></div>
   <script type="text/babel">
       let obj={name:"xixi",age:18,sex:"nan"};

       let newel=Object.keys(obj).map((v,i)=>{
           return (
               <h1 key={i}>{obj[v]}</h1>
           )
       })

       let el=(
           <div>
               {newel}
           </div>
       )

       ReactDOM.render(el,document.getElementById("demodiv"))

   </script>
</body>
</html>

因为我们便利出来的v是一个变量但是在对象取值的方式中打点不能取变量所以要用另外一种取值方式 [ ]

组件

无状态组件/函数组件/工厂函数组件

首先是一个函数 但是函数的首字母必须大写首字母必须大写首字母必须大写首字母必须大写
里面return一段你当前组件的jsx

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="node_modules/react/umd/react.development.js"></script>
    <script src="node_modules/react-dom/umd/react-dom.development.js"></script>
    <script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
    <div id="demodiv"></div>
    <script type="text/babel">

        function Mycom(){
            return (
                <div>
                    <h1>我是一个函数组件1</h1>    
                    <h1>我是一个函数组件2</h1>    
                    <h1>我是一个函数组件3</h1>    
                </div>
            )
        }
 
        function Fu(){
            return (
                <div>
                    <Mycom/>
                    <Mycom/>
                    <Mycom/>
                    <Mycom/>
                    <Mycom/>
                </div>
            )
        }

        ReactDOM.render(<Fu/>,document.getElementById("demodiv"))

    </script>
</body>
</html>

props传值

props是当前组件对外的一个接口,可以方便从组件外部向组件内部传递参数数据
props是只读,peops是不能修改的

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="node_modules/react/umd/react.development.js"></script>
    <script src="node_modules/react-dom/umd/react-dom.development.js"></script>
    <script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
    <div id="demodiv"></div>
    <script type="text/babel">

         function Mycom(props){
             return (
                 <div>
                     <h1>我是一个函数组件1----{props.title}</h1>    
                     <h1>我是一个函数组件2----{props.age}</h1>    
                     <h1>我是一个函数组件3</h1>    
                 </div>
             )
         }
 
         function Fu(){
             return (
                 <div>
                     <Mycom age="我是传递的age" title="我是传递的title"/>
                     <Mycom/>
                     <Mycom/>
                     <Mycom/>
                     <Mycom/>
                 </div>
             )
         }


      
    </script>
</body>
</html>

使用es6新语法来完成传值,props是一个对象 可以使用对象解构

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="node_modules/react/umd/react.development.js"></script>
    <script src="node_modules/react-dom/umd/react-dom.development.js"></script>
    <script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
    <div id="demodiv"></div>
    <script type="text/babel">

        // 使用es6新语法来完成

        // props是一个对象   可以使用对象解构

        function Mycom(props){
            let {title,age,sex}=props;
            return (
                <div>
                    <h1>我是一个函数组件1----{title}</h1>    
                    <h1>我是一个函数组件2----{age}</h1>    
                    <h1>我是一个函数组件3----{sex}</h1>    
                </div>
            )
        }
        // 如果在传值的时候props由很多个 那么我们可以使用 ... es6扩展运算符来完成
        let obj={
            title:"新的title",
            age:999,
            sex:"男"
        }
        function Fu(){
            return (
                <div>
                    <Mycom {...obj}/>
                    <Mycom/>
                    <Mycom/>
                    <Mycom/>
                    <Mycom/>
                </div>
            )
        }
        ReactDOM.render(<Fu/>,document.getElementById("demodiv"))
    </script>
</body>
</html>

props验证

在react15.5之前 props验证使用的是react核心库中带的 propTypes来进行

在react15.5之后 props验证移植到了一个propTypes库中

使用 下载:

npm install --save prop-types

使用的时候注意单词大小写

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="node_modules/react/umd/react.development.js"></script>
    <script src="node_modules/react-dom/umd/react-dom.development.js"></script>
    <script src="node_modules/babel-standalone/babel.js"></script>
    <script src="node_modules/prop-types/prop-types.js"></script>
</head>
<body>
    <div id="demodiv"></div>
    <script type="text/babel">

        function Mycom(props){
            let {title}=props
            return (
                <div>
                    <h1>我是一个函数组件1---{title}</h1>    
                    
                </div>
            )
        }
        // props验证
        // 组件名.propTypes={
        //     你要验证的props:PropTypes.string
        // }
        Mycom.propTypes={
            title:PropTypes.number
        }
        let obj={
            title:"1234"
        }
        function Fu(){
            return (
                <div>
                    <Mycom {...obj}/>
                </div>
            )
        }

        ReactDOM.render(<Fu/>,document.getElementById("demodiv"))

    </script>
</body>
</html>

props默认值

defaultProps 来是先props的默认值

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="node_modules/react/umd/react.development.js"></script>
    <script src="node_modules/react-dom/umd/react-dom.development.js"></script>
    <script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
    <div id="demodiv"></div>
    <script type="text/babel">

        function Mycom(props){
            return (
                <div>
                    <h1>我是一个函数组件1--{props.title}</h1>      
                </div>
            )
        }
    // props的默认值    有值使用传递的值  没有值使用默认值
        // 组件名.defaultProps={
        //     要设置默认值的内容:默认值
        // }
        Mycom.defaultProps={
            title:"我是title的默认值么么哒"
        }
        function Fu(){
            return (
                <div>
                    <Mycom title="我是传递的值"/>
                </div>
            )
        }

        ReactDOM.render(<Fu/>,document.getElementById("demodiv"))

    </script>
</body>
</html>

类组件

基本的创建

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="node_modules/react/umd/react.development.js"></script>
    <script src="node_modules/react-dom/umd/react-dom.development.js"></script>
    <script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
    <div id="demodiv"></div>
    <script type="text/babel">
        // 创建类组件
        class Mycom extends React.Component{
            render(){
                return (
                    <div>
                        我是一个类组件    
                    </div>
                )
            }
        }
        class Fu extends React.Component{
            render(){
                return (
                    <div>
                        
                        <Mycom/><Mycom/><Mycom/><Mycom/><Mycom/><Mycom/>
                    </div>
                )
            }
        }

        ReactDOM.render(<Fu/>,document.getElementById("demodiv"))

    </script>
</body>
</html>

props 传值

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="node_modules/react/umd/react.development.js"></script>
    <script src="node_modules/react-dom/umd/react-dom.development.js"></script>
    <script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
    <div id="demodiv"></div>
    <script type="text/babel">
        // 类组件使用props
        // class Mycom extends React.Component{
        //     render(){
        //         return (
        //             <div>
        //                 我是一个类组件---{this.props.title}    
        //                 我是一个类组件---{this.props.age}    
        //                 我是一个类组件---{this.props.sex}    
        //             </div>
        //         )
        //     }
        // }
        // class Fu extends React.Component{
        //     render(){
        //         return (
        //             <div>
                        
        //                 <Mycom title="ttttt" age="aaaaa" sex="ssssss"/>
        //             </div>
        //         )
        //     }
        // }



        class Mycom extends React.Component{
            render(){
                let {title,age,sex}=this.props
                return (
                    <div>
                        我是一个类组件---{title}    
                        我是一个类组件---{age}    
                        我是一个类组件---{sex}    
                    </div>
                )
            }
        }
        class Fu extends React.Component{
            render(){
                let obj={
                    title:"tttt1",
                    age:6666,
                    sex:"naan"
                }
                return (
                    <div>
                        
                        <Mycom {...obj}/>
                    </div>
                )
            }
        }

        ReactDOM.render(<Fu/>,document.getElementById("demodiv"))

    </script>
</body>
</html>

props验证

同上面

props默认值

同上面

组件整理

组件分为函数组件与类组件

他们两者在使用的时候语法有区别

props

函数组件是吧props当成一个函数的形参来进行接收 使用的时候直接用props这个形参.xxxxx

类组件简单一些 想在那用 直接在哪里this.props.xxxx 来直接使用

state 状态机

在react之前的内容中 我们如果修改了数据中的内容 那么页面会跟着改变吗?

不会改变

state 基本概念

在react中我们只需要关心数据,数据改变我们需要让页面跟着改变,所以就需要使用到state状态机制(状态等同于数据变量)状态改变了,那么react就会着视图自动发生变化。

state使用

首选函数组件不能使用state,因为函数组件是无状态组件

类组件

创建使用:this.state={}
读取使用:this.state.XXX
修改必须用 this.setState()

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="node_modules/react/umd/react.development.js"></script>
    <script src="node_modules/react-dom/umd/react-dom.development.js"></script>
    <script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
    <div id="demodiv"></div>
    <script type="text/babel">

            class Mycom extends React.Component{
                constructor(props){
                   super(props) 
                //    1.创建state
                    this.state={
                       text:"我是state的变量数据",
                       arr:[1111,222,333]
                    }
                }

                fun=()=>{
                    // 3.state的修改
                    // 如果要修改state必须必须必须必须必须调用this.setState()来进行修改
                    this.setState({
                        text:"我变了"
                    })
                }

                render(){
                    return (
                        <div>
                            
                            <h1>state使用</h1>    
                            {/*2.读取*/}
                            <h1>{this.state.text}</h1>
                            {/*3.修改*/}
                            <button onClick={this.fun}>点我修改</button>
                        </div>
                    )
                }
            }

  
            ReactDOM.render(<Mycom/>,document.getElementById("demodiv"))
       
     

    </script>
</body>
</html>

setState()

setState的作用就是用来更新state数据的

特点

setState()是异步的 并且会自动触发render重新渲染

setState 是异步的
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="node_modules/react/umd/react.development.js"></script>
    <script src="node_modules/react-dom/umd/react-dom.development.js"></script>
    <script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
    <div id="demodiv"></div>
    <script type="text/babel">

            class Mycom extends React.Component{
                constructor(props){
                    super(props)
                    this.state={
                        num:6666
                    }
                }

                fun=()=>{
                    this.setState({
                        num:9527
                    })
                    // 打印之后会发现数据还是原来的6666就表明setState是异步的
                    console.log(this.state.num);
                }
                render(){
                    return (
                        <div>
                            <h1>setState是异步的</h1>    
                            <h1>{this.state.num}</h1>
                            <button onClick={this.fun}>点我修改</button>
                        </div>
                    )
                }
            }

  
            ReactDOM.render(<Mycom/>,document.getElementById("demodiv"))
       
     

    </script>
</body>
</html>
setstate 的回调

setState第二个参数是一个回调函数

this.setState({
                        num:999
                    },()=>{
                        console.log("我会在setState这个异步操作执行完毕后 自动被调用"+this.state.num)
                    })

state的联系,视图跟着模型变


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="node_modules/react/umd/react.development.js"></script>
    <script src="node_modules/react-dom/umd/react-dom.development.js"></script>
    <script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
    <div id="demodiv"></div>
    <script type="text/babel">
            class Mycom extends React.Component{
                constructor(props){
                    super(props)
                    this.state={
                        inputval:""
                    }
                }
                fun=(e)=>{
               
                    // console.log(e.target.value);
                     //e.target.value代表下面input的值,在触发输入框的事件的时候,将上面inputval的内容改变为输入框的内容
                    this.setState({
                        inputval:e.target.value
                    })
                }
                render(){
                    return (
                        <div>
                            
                            <h1>state小练习</h1>   
                            <input type="text" onInput={this.fun}/>
                            <br/>
                            <h1>输入框的内容是------{this.state.inputval}</h1> 
                        </div>
                    )
                }
            }
    
  
            ReactDOM.render(<Mycom/>,document.getElementById("demodiv"))
       
     

    </script>
</body>
</html>

扩展----插入字符串html标签

dangerouslySetInnerHTML={{__html(双底杠):你要渲染的变量l}}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="node_modules/react/umd/react.development.js"></script>
    <script src="node_modules/react-dom/umd/react-dom.development.js"></script>
    <script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
    <div id="demodiv"></div>
    <script type="text/babel">
    
        class Fu extends React.Component{
            constructor(props){
                super(props)
                this.state={
                    newhtml:"<h1>我是一个h1</h1>"
                }
            }
            render(){
                return (
                    <div>
                      <div>{this.state.newhtml}</div>

                      <div dangerouslySetInnerHTML={{__html:this.state.newhtml}}></div>
                    </div>
                )
            }
        }

        ReactDOM.render(<Fu/>,document.getElementById("demodiv"))

    </script>
</body>
</html>

ref 转发

ref 就是标识组件内部的元素内容 (给组件中的dom起个名字)

react中由于无状态组件/函数组件没有实例 所以不能使用ref

创建ref

React.createRef()

react16.3新增的 当前方法也是通过ref属性进行挂载 但是在找寻当前dom的时候要使用current来进行dom的选取

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="node_modules/react/umd/react.development.js"></script>
    <script src="node_modules/react-dom/umd/react-dom.development.js"></script>
    <script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
    <div id="demodiv"></div>
    <script type="text/babel">
    
        class Fu extends React.Component{
            constructor(props){
                super(props)
                this.state={
                
                }
                // 1.创建出ref对象
                this.demoref=React.createRef()
            }
            fun=()=>{
                
                this.demoref.current.style.color="yellow"
            }
            render(){
                return (
                    <div>
                       {/*2.绑定*/}
                        <h1 ref={this.demoref}>我是createref的方式</h1>
                        <button onClick={this.fun}>点我修改他的颜色</button>
                    </div>
                )
            }
        }

        ReactDOM.render(<Fu/>,document.getElementById("demodiv"))

    </script>
</body>
</html>


回调函数方式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="node_modules/react/umd/react.development.js"></script>
    <script src="node_modules/react-dom/umd/react-dom.development.js"></script>
    <script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
    <div id="demodiv"></div>
    <script type="text/babel">
    
        class Fu extends React.Component{
            constructor(props){
                super(props)
                this.state={
                
                }
            }
            funa=()=>{
                // 读取ref
                this.refs.demoh.style.color="pink"
            }
            funb=()=>{
                this.refh.style.color="red";
            }
            render(){
                return (
                    <div>
                        {/*创建*/}
                        <h1 ref="demoh">我是ref字符串方式</h1>
                        <button onClick={this.funa}>点我修改他的颜色</button>

                        {/*
                        回调函数方式
                        ref={(demo随便写 代表的是当前的dom元素)=>{this.创建一个变量=形参}}
                        */}
                        <h1 ref={(demohb)=>{this.refh=demohb}}>我是ref回调函数方式</h1>
                        <button onClick={this.funb}>点我修改他的颜色</button>
                    </div>
                )
            }
        }

        ReactDOM.render(<Fu/>,document.getElementById("demodiv"))

    </script>
</body>
</html>

字符串方式

不推荐

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="node_modules/react/umd/react.development.js"></script>
    <script src="node_modules/react-dom/umd/react-dom.development.js"></script>
    <script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
    <div id="demodiv"></div>
    <script type="text/babel">
    
        class Fu extends React.Component{
            constructor(props){
                super(props)
                this.state={
                
                }
            }
            funa=()=>{
                // 读取ref
                this.refs.demoh.style.color="pink"
            }
            render(){
                return (
                    <div>
                        {/*创建*/}
                        <h1 ref="demoh">我是ref字符串方式</h1>
                        <button onClick={this.funa}>点我修改他的颜色</button>
                    </div>
                )
            }
        }

        ReactDOM.render(<Fu/>,document.getElementById("demodiv"))

    </script>
</body>
</html>

事件处理

react如果想要绑定事件 使用小驼峰命名法。
在函数调用的时候不加 (),加了()函数就会自动执行

事件修饰

阻止事件默认行为 preventDefault()

react 中阻止事件默认行为 阻止事件传播 都是js原生的语法

函数实参传递

在react中调用函数不加()但是不加了 那么实参写在哪?

方式:
1.通过bind()进行传递实参

<button onClick={this.funa.bind(this,"参数1","参数2")}>我是bind传递方式</button>

接收:

 funa=(numa,numb)=>{
                console.log(numa + "----" + numb);
            }

2.通过箭头函数调用函数传参

<button onClick={()=>{this.funb("参数666")}}>我是箭头函数调用函数的方式</button>
  funb=(num)=>{
                console.log(num)
            }

this指向修改


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="node_modules/react/umd/react.development.js"></script>
    <script src="node_modules/react-dom/umd/react-dom.development.js"></script>
    <script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
    <div id="demodiv"></div>
    <script type="text/babel">
    
        class Fu extends React.Component{
            constructor(props){
                super(props)
                this.state={
                    num:"我是state的变量"
                }
                // 提前绑定this
                this.func=this.func.bind(this)
            }

            fun=function(){
                console.log(this.state.num);
            }
            funa=function(){
                console.log(this.state.num);
            }
            funb=function(){
                console.log(this.state.num);
            }
            func=function(){
                console.log(this.state.num);
            }
            render(){
                return (
                    <div>
                        <h1>this指向</h1>
                        <button onClick={this.fun}>点我看错误的写法</button>
                        <br/>
                        <button onClick={this.funa.bind(this)}>点我看bind绑定的写法</button>
                        <br/>
                        <button onClick={()=>{console.log(this.state.num)}}>事件直接调用箭头函数</button>
                        <br/>
                        <button onClick={()=>{this.funb()}}>用箭头函数调用函数</button>
                        <br/>
                        <button onClick={this.func}>在constructor中提前bind绑定</button>
                    </div>
                )
            }
        }

        ReactDOM.render(<Fu/>,document.getElementById("demodiv"))




    </script>
</body>
</html>

以上每一个方式的详细
1.在创建函数的时候使用箭头函数

2.通过bind绑定

 <button onClick={this.funa.bind(this)}>点我看bind绑定的写法</button>
  
  	 funa=function(){
                console.log(this.state.num);
            }

3.事件直接调用箭头函数

 <button onClick={()=>{console.log(this.state.num)}}>事件直接调用箭头函数</button>

4,使用箭头函数调用函数

<button onClick={()=>{this.funb()}}>用箭头函数调用函数</button>

5,.在constructor中提前使用bind绑定

  constructor(props){
                super(props)
                this.state={
                    num:"我是state的变量"
                }
                // 提前绑定this
                this.func=this.func.bind(this)
            }

ToDolist的添加删除修改


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="node_modules/react/umd/react.development.js"></script>
    <script src="node_modules/react-dom/umd/react-dom.development.js"></script>
    <script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
    <div id="demodiv"></div>
    <script type="text/babel">
            class Mycom extends React.Component{
                constructor(props){
                    super(props)
                    this.state={
                        arr:[
                            "ez",
                            "MF",
                            "NOC",
                            "vn"
                        ]
                    }
                    this.inputval=React.createRef()
                
                }
                // 便利生成
                showel=()=>{
                    return this.state.arr.map((v,i)=>{
                        return (
                            <li key={i}>{v}------- <span onClick={()=>{this.del(i)}} style={{color:"red"}}>x</span><button onClick={this.update.bind(this,i)}>点我修改</button></li>
                        )
                    })
                }
                update=function(i){
                    let upinput=prompt("请您输入修改的内容")
                    if(upinput==null){
                        alert("您放弃了修改")
                    }else{
                        let newarr=this.state.arr
                        newarr[i]=upinput

                        this.setState({
                            arr:newarr
                        })
                    }

                }
                add=()=>{
                    console.log(this.inputval.current.value)

                    let newarr=this.state.arr

                    newarr.push(this.inputval.current.value)

                    this.setState({
                        arr:newarr
                    })

                    this.inputval.current.value=""
                }
                del=(i)=>{
                    if(window.confirm("是否删除吗?"+i)){
                        console.log("用户点击了确定")

                        let newarr=this.state.arr

                        newarr.splice(i,1)

                        this.setState({
                            arr:newarr
                        })
                    }else{
                        console.log("用户点击了取消")
                    }
                }
            
                // 1.todolist---添加
                // 1-1.先完成页面搭建
                // 1-2创建数据生成初始化展示页面
                // 1-3在点击之后调用函数在函数中得到输入框的值
                // 1-4 开始需要向state中的arr插入push新数据
                //    1-4-1 新建一个变量用来保存state中的原始数据
                //    1-4-2 向这个新数据中push内容 
                //    1-4-3 把这个新数据的值赋值给原始数据

                // 删除
                // 2-1 先给页面内容添加删除按钮
                // 2-2给叉叉添加点击事件并且弹出弹框
                // 2-3 要知道删除谁
                // 2-4开始删除

                // 修改
                // 3-1 点击之后弹出一个带有输入框的弹出框
                // 3-2 把便利的下标传入当前函数中  知道我点击是谁
                // 3-3 在方法中弹出弹出框  并且得到弹出框中输入框的值
                render(){
                    return (
                        <div>
                            <input type="text" ref={this.inputval}/>
                            <button onClick={this.add}>添加</button>
                            <ul>
                                {this.showel()}   
                            </ul>
                        </div>
                    )
                }
            }
    
  
            ReactDOM.render(<Mycom/>,document.getElementById("demodiv"))
       
     

    </script>
</body>
</html>
    </script>
</body>
</html>

四 脚手架

create-react-app CRA

cra 是facebook官方出品

创建

1.全局下载(除了你重装node了或者是重装系统了)

npm install -g create-react-app

2.查看版本 看看是否安装ok了 create-react-app --version

3.切换路径 需要把cmd的路径切换到你想下载项目的路径下 cd到指定路径下

4 创建项目 create-react-app 项目名

5启动 npm start

组件创建

在components下 rcc创建出组件 在需要展示的地方引用使用

props

同本地模式

props.children

this.props.children 代表的就是当前组件的所有子节点

import React, { Component,Fragment } from 'react'

export default class userzi extends Component {
    render() {
        return (
            <Fragment>
                <h1>我是userzi1</h1>
                <h1>我是userzi2</h1>
                {this.props.children}
                <h1>我是userzi3</h1>
                <h1>我是userzi4</h1>
            </Fragment>
        )
    }
}

this.props.children值有三种可能

1.如果当前没有插入子节点 他就是 undefined

2.只插入了一个子节点 他就是 object

3.插入了多个子节点 他就是 array

state

同本地模式

事件与this

同本地模式

扩展—空标签

因为在jsx中要求多行标签必须有父节点包裹 但是这个时候可能就会出现很多冗余的没有代码

解决方式

空标签来完成

1 使用<></>来包裹

import React, { Component } from 'react'

export default class userzi extends Component {
    render() {
        return (
            <>
                <h1>我是userzi1</h1>
                <h1>我是userzi2</h1>
                <h1>我是userzi3</h1>
                <h1>我是userzi4</h1>
            </>
        )
    }
}

2 Fragment 来添加空标签

import React, { Component,Fragment } from 'react'

export default class userzi extends Component {
    render() {
        return (
            <Fragment>
                <h1>我是userzi1</h1>
                <h1>我是userzi2</h1>
                <h1>我是userzi3</h1>
                <h1>我是userzi4</h1>
            </Fragment>
        )
    }
}

组件样式怎么设置

注意类名的写法 className

引用使用 import “你的样式文件路径”

扩展----强制刷新

forceUpdate() 强制刷新 — 重新调用render进行渲染

import React, { Component } from 'react'

export default class demoa extends Component {
    constructor(){
        super()
        this.text="你好"
    }
    fun=function(){
        this.text="你坏"
        // 强制刷新 --- 重新调用render进行渲染
        this.forceUpdate()
        console.log(this.text)
    }
    render() {
        return (
            <div>
                <h1>强制刷新</h1>
                {/* 如果数据没有在state中我们修改了这个数据 那么页面是不会更新 */}
                <h1>{this.text}</h1>
                <button onClick={()=>{this.fun()}}>点我修改</button>
            </div>
        )
    }
}

组件传值

正向传值

props

逆向传值

是通过事件调用一个父组件传递过来的函数,并在子组件中传入对应的实参,从而完成的逆向传值
父组件

import React, { Component } from 'react'
import Zi from "./zi.jsx"
export default class fu extends Component {
    fufun=(text)=>{
        console.log(text)
    }
    render() {
        return (
            <div>
                父组件
                <Zi zifun={this.fufun}/>
            </div>
        )
    }
}

子组件

import React, { Component } from 'react'

export default class zi extends Component {
    render() {
        return (
            <div>
                子组件
                <button onClick={this.props.zifun.bind(this,"我是子组件的数据")}>点我逆向传值</button>
            </div>
        )
    }
}

同胞传值 pubsub-js

下载: npm install --save pubsub-js

使用
在需要传递的组件之上,进行自定义事件的抛出 pubsub.pulish(“自定义事件名”,“你要传递的数据”)

import React, { Component } from 'react'

import PubSub from "pubsub-js"

export default class zia extends Component {
    fun=()=>{
        // 1.抛出自定义事件 并且携带传递的数据
        PubSub.publish("ziapao","我是zia的数据么么哒")

    }
    render() {
        return (
            <div>
                zia
                <button onClick={this.fun}>点我抛出自定义事件</button>
            </div>
        )
    }
}

在需要接收的组件中使用 pubsub.subscribe(“你要监听的自定义事件”,(a你监听的事件名,b数据)=>{})

import React, { Component } from 'react'
import PubSub from "pubsub-js"
export default class zib extends Component {


    // 生命周期的钩子函数
    // 渲染完毕
    componentDidMount() {
        PubSub.subscribe("ziapao",(a,b)=>{
            console.log(a);
            console.log(b);
        })
    }
    

    render() {
        return (
            <div>
                zib
            </div>
        )
    }
}

跨组件传值

因为react的组件传值是通过props向下一层层的传值 是单向传递的 从父组件中可以一层层的传给下面的子孙组件 但是一层层的传值后期维护分麻烦。

1.上下文对象 context

context可以很好的解决react中跨组件传值的复杂度,可以快速的进行组件与组件之间跨层级的传值

要使用context对象必须要通过一个createContext()方法来进行上下文对象的创建

创建出context对象之后会有两个属性方法帮助我们进行传值:

Provider对象 用来生产数据的 生产者

Consumer对象 用来使用数据的 消费者

使用

1.新建文件与文件夹来容纳上下文对象

2.创建一个组件 并且设置this.props.children

import React, { Component } from 'react'

export default class Mycontext extends Component {
    render() {
        return (
            <div>
                    {/* 在组件中使用this.this.props..children 来标识当前组件的所有子组件 */}
                    {this.props.children}
            </div>
        )
    }
}

3.在index.js中 让上下文对象变成所有组件的父组件

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Home from './components/pubsub/fu.jsx';
import reportWebVitals from './reportWebVitals';
// 引用上下文对象
import Mycontext from "./context"
ReactDOM.render(
  <Mycontext>
    <Home />
  </Mycontext>,
  document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

4.开始创建上下文对象 与生产者和消费者

// 1.引用createContext
import React, { Component,createContext } from 'react'

// 2.创建上下文对象
let context=createContext()
// 3.创建除生产与消费者
let {Provider,Consumer}=context
// 5.修改暴露在最下面
class Mycontext extends Component {
    render() {
        return (
            <div>
                {/* 4.使用生产者创建数据 使用value属性创建数据*/}
                    
                 <Provider value={9527}>
                     {/* 在组件中使用this.this.props..children 来标识当前组件的所有子组件 */}
                       {this.props.children}
                 </Provider>
                  
            </div>
        )
    }
}
export {Mycontext,Consumer}

5.需要修改之前的引用

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Home from './components/pubsub/fu.jsx';
import reportWebVitals from './reportWebVitals';
// 引用上下文对象
// 修改引用
import {Mycontext} from "./context"
ReactDOM.render(
  <Mycontext>
    <Home />
  </Mycontext>,
  document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

6.在你想用的组件上使用consumer来消费数据

import React, { Component } from 'react'
import Zia from "./zia.jsx"
import Zib from "./zib.jsx"
// 使用上下文对象的值
import {Consumer} from "../../context/index.js"
export default class fu extends Component {
    render() {
        return (
            <div>
                {/* 使用数据 */}
                <Consumer>
                    {
                        (value)=>{
                            return (
                                <h1>{value}</h1>
                            )
                        }
                    }

                </Consumer>



                <h1>同胞传值</h1>
                <Zia/>
                <Zib/>
            </div>
        )
    }
}

2.redux

后续再说

条件渲染

就是根据指定的条件来进行指定的内容渲染

三元运算符

import React, { Component,Fragment } from 'react'

export default class demoa extends Component {
    constructor(){
        super()
        this.state={
            bool:false
        }
    }
    fun=function(){
        this.setState({
            bool:!this.state.bool
        })
    }
    render() {
        return (
            <Fragment>
                <h1>条件渲染</h1>
                <h2>三元运算符</h2>
                <button onClick={this.fun.bind(this)}>点我切换显示</button>
                {
                    this.state.bool? <p>你好</p>:<p>你坏</p>
                }
               
                
            </Fragment>
        )
    }
}

if方式

if这种条件渲染的方式不能写在jsx中

import React, { Component } from 'react'

export default class demob extends Component {
    render() {
            let newel;
            // if不能写在jsx中
            if(false){
                newel=<p>你好</p>
            }else{
                newel=<p>你坏</p>
            }



        return (
            <React.Fragment>
                <h1>条件渲染</h1>
                {
                  newel
                }
            </React.Fragment>
        )
    }
}

逻辑与(&&)

import React, { Component } from 'react'

export default class democ extends Component {
    render() {
        return (
            <div>
            {/* &&与  左边为真右边才执行   左边为假右边不执行 */}
            {  false && <p>你好</p>}
            </div>
        )
    }
}

高阶组件—HOC

在react中创建项目的时候 经常会有一些需求 就是一类功能需要被不同的组件使用,需要对一些代码进行复用,把一些特定的功能抽离并且封装起来,方便其它组件使用

HOC—参数是一个组件返回值还是一个组件

Hoc—也是react中组件重用的一个高阶技术
但是HOC不是reactAPI中的内容 而是在现有语法之上进行的一个升级

创建

import React, { Component } from 'react'
// 引用入参是一个组件  所以首字母大写
let hocdemo=(El)=>{
    return class index extends Component {
        render() {
            return (
                <div>
                    我是复用的内容么么哒
                    <El/>
                </div>
            )
        }
    }
}


export default hocdemo

使用

1,修改使用组件的,暴漏在最下面
2,引用高阶组件
3,在暴漏位置引用使用的Hoc(你的组件)

import React, { Component } from 'react'
import hoc from "../hoc/index.js"
class hocdemo extends Component {
    render() {
        return (
            <div>
                <h1>HOC高阶组件</h1>
            </div>
        )
    }
}
export default hoc(hocdemo)

高阶组件HOC—反向继承

反向继承最核心的就是----渲染拦截(拦截了渲染可以让我们在高阶组件中进行条件渲染)

高阶组件的反向继承就是在高阶组件中进行条件渲染

import React, { Component } from 'react'

let hocb=(Hehe,num)=>{
    // 注意注意注意   如果你要反向继承  那么当前的返回组件 就不能继承react.component
    return class indexb extends Hehe {
        render() {

            if(num>18){
                return (
                    <Hehe></Hehe>
                )
            }else{
                return (
                    <h1>未满18不能访问!!!!</h1>
                )
            }
        }
    }
    
}

export default hocb
import React, { Component } from 'react'
import hocb from "../hoc/indexb.js"
class hocdemob extends Component {
    render() {
        return (
            <div>
                <h1>反向继承</h1>
            </div>
        )
    }
}
export default hocb(hocdemob,19)

路由

根据url的不同来切换对应的组件页面

用来实现SPA单页面应用的技术 整个项目只有一个页面 并且在页面切换的时候不会刷新 没有屏幕闪烁

小拓展

react路由分类

1。React-Router 只提供了路由的核心API
2.react-router-dom 除了这些基本的API之外还提供了一些遍历的API方法

react路由模式

1,HashRouter url带有#号
2.BrowerRouter 类似于HistoryRouter不带 # 号 上线之后刷新404.

基本一级路由创建

1,下载 npm install --save react-router-dom
2,设置路由模式
2-1 需要在index.js中进行设置 引用react-router-dom
2-2 设置路由模式

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/hocdemob.jsx';
import reportWebVitals from './reportWebVitals';

// 1.引用路由
import {BrowserRouter} from "react-router-dom"
ReactDOM.render(
  // 2.配置路由模式
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

3.新建router文件夹用来存放路由的配置 在新建views文件夹来存放路由页面

4.编写路由文件

4-1 引用Route

4-2 引用路由页面组件

4-3 配置出口与规则

import React, { Component } from 'react'
// 1.新建一个组件文件
// 2.引用你想设置路由的组件页面
import Home from "../views/home.jsx"
import Phone from "../views/phone.jsx"
import Shop from "../views/shop.jsx"
import User from "../views/user.jsx"
// 3.设置路由出口与规则
import {Route} from "react-router-dom"
export default class index extends Component {
 render() {
     return (
         <React.Fragment>
             {/* 4.开始配置 */}
             {/* <Route path="/路径" component={组件}/> */}
             <Route path="/home" component={Home}/>
             <Route path="/phone" component={Phone}/>
             <Route path="/shop" component={Shop}/>
             <Route path="/user" component={User}/>
         </React.Fragment>
     )
 }
}

5.配置路由文件与项目关系

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
// 配置当前的路由文件为主出口
// 配置当前的路由文件为主出口
// 配置当前的路由文件为主出口
// 配置当前的路由文件为主出口
import App from './router/index.js';
import reportWebVitals from './reportWebVitals';

// 1.引用路由
import {BrowserRouter} from "react-router-dom"
ReactDOM.render(
// 2.配置路由模式
<BrowserRouter>
 <App />
</BrowserRouter>,
document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

路由导航

声明式

Link to属性设置去哪里的路径

NavLink to属性设置去哪里的路径 会在选中的导航上添加一个avtive的类名

小问题:

NavLink会添加一个active的类名 但是这个类名 太常用了 外衣出现了冲突很麻烦 所以如何修改这个类名呢?

使用 activeClassName的属性来修改

 <NavLink to="/user" activeClassName="xiaoming">user</NavLink>

编程式

this.props.history.push("/去哪里")

import React, { Component } from 'react'

export default class phone extends Component {
    fun=()=>{
        // 编程式导航
        this.props.history.push("/user")
    }
    render() {
        return (
            <div>
                phone
                <button onClick={this.fun}>点我去user</button>
            </div>
        )
    }
}

报错

TypeError: Cannot read property ‘push’ of undefined

出现这个错的原因是因为 如果当前使用编程式导航的页面 不是被路由所管理的 那么这个页面就没有路由的history属性 从而也就没有了push这个跳转的方法

如果我就是想让不是被路由所管理的页面也要使用编程式跳转 怎么办呢?

withRouter 高阶组件------让不是被路由管理的页面页具有history属性,如下
1,引入withRouter
注意:声明式跳转用Link或NavLink时也要引入

// 3.设置路由出口与规则
import {Route,Link,NavLink,withRouter} from "react-router-dom"

2,修改暴漏到最下面

export default withRouter(index)//括号里面为当前组件名

如此即可完成让不是被路由管理的页面页具有history属性,可跳转

更多的跳转

replace() 替换

goBack() 后退

goforward() 前进

404页面

写在规则的最下面 不要path

import React, { Component } from 'react'
import Home from "../pages/home.jsx"
import Phone from "../pages/phone.jsx"
import Shop from "../pages/shop.jsx"
import User from "../pages/user.jsx"
import No from "../pages/no.jsx"

import {Route} from "react-router-dom"

export default class index extends Component {
    render() {
        return (
            <div>
                
               <Route path="/home" component={Home}/> 
               <Route path="/phone" component={Phone}/> 
               <Route path="/shop" component={Shop}/> 
               <Route path="/user" component={User}/> 
               {/* 404页面 必须在最下面*/}
               <Route component={No}/>
            </div>
        )
    }
}

但是你会发现当我们设置了404页面之后 每个页面都会出现 404页面,解决如下:

switch 唯一匹配

为了解决router的多渲染问题 所以我们需要使用switch来进行唯一渲染 保证每次只渲染一个路由

是唯一渲染 匹配到指定路由后就会停止渲染

import React, { Component } from 'react'
import Home from "../pages/home.jsx"
import Phone from "../pages/phone.jsx"
import Shop from "../pages/shop.jsx"
import User from "../pages/user.jsx"
import No from "../pages/no.jsx"
//注意,使用就要引入
import {Route,Switch} from "react-router-dom"

export default class index extends Component {
    render() {
        return (
            <div>
              {/* 唯一渲染   */}
            <Switch>  
               <Route path="/home" component={Home}/> 
               <Route path="/phone" component={Phone}/> 
               <Route path="/shop" component={Shop}/> 
               <Route path="/user" component={User}/> 
               {/* 404页面 必须在最下面*/}
               <Route component={No}/>
            </Switch>
            </div>
        )
    }
}

重定向 redirect

exact 精准匹配

import React, { Component } from 'react'
import Home from "../pages/home.jsx"
import Phone from "../pages/phone.jsx"
import Shop from "../pages/shop.jsx"
import User from "../pages/user.jsx"
import No from "../pages/no.jsx"

import {Route,Switch,Redirect} from "react-router-dom"

export default class index extends Component {
    render() {
        return (
            <div>
              {/* 唯一渲染   */}
            <Switch>  
                {/* <Redirect from="从哪来" to="去哪里"/> */}
                {/* exact精准匹配     严格路径匹配 */}
                <Redirect from="/" to="/home" exact/>
               
               
               
               <Route path="/home" component={Home}/> 
               <Route path="/phone" component={Phone}/> 
               <Route path="/shop" component={Shop}/> 
               <Route path="/user" component={User}/> 

          

               {/* 404页面 必须在最下面*/}
               <Route component={No}/>
            </Switch>
            </div>
        )
    }
}

多级路由创建

1, 创建二级路由页面
2,需要在对应的一级路由中引用二级路由,并在引用他的父级路由中配置规则与出口
3,使用Router来配置对应的二级路由的规则与出口

import React, { Component } from 'react'
import Bb from "../components/bottombar.jsx"
// 引用二级路由
import Era from "../pages/era.jsx"
import Erc from "../pages/erc.jsx"

import {Route,Link} from "react-router-dom"
export default class user extends Component {
    render() {
        return (
            <div>
                user
                <Bb/>
                <Link to="/user/era">era</Link>
                <Link to="/user/erc">erc</Link>
                {/* 配置规则与出口 */}
                <Route path="/user/era" component={Era}/>
                <Route path="/user/erc" component={Erc}/>
            </div>
        )
    }
}

路由传参

params方式
1.在路由规则中配置接收参数

 {/* params方式传参第一步配置接收参数 */}
 <Route path="/all/:xiaoming" component={All}/> 

2.开始发参

声明式发参

 <Link to="/all/我是params传递的参数么么哒!!!!"></Link>

编程式发参

 this.props.history.push("/all/我是params传递的参数么么哒!!!!")

3,需要参数接受的页面

this.props.match.params.xxx
import React, { Component } from 'react'

export default class all extends Component {
    componentWillMount() {
        console.log(this.props.match.params.xiaoming)
    }
    

    componentDidMount() {
        
    }
    
    render() {
        return (
            <div>
                <h1>我是详情页</h1>
                <p>我是来测试路由传参的---{this.props.match.params.xiaoming}</p>
            </div>
        )
    }
}

总结

params:
传递的数据会在url中进行展示 刷新依然存在

但是只能传递字符串 并且传递太多的话 url不太好看

state方式

1.发送参数

声明式发参

<Link to={{pathname:"/all",state:{xiaoming:"我是state发送的数据么么哒###"}}}></Link>

编程式

 fun=()=>{
        // this.props.history.push("/all/我是params传递的参数么么哒!!!!")
        this.props.history.push({pathname:"/all",state:{xiaoming:"我是state发送的数据么么哒###"}})
    }

2 接收的页面
this.props.location.state.key

import React, { Component } from 'react'

export default class all extends Component {
    componentWillMount() {
        // console.log(this.props.match.params.xiaoming)
        console.log(this.props.location.state.xiaoming)
    }
    

    componentDidMount() {
        
    }
    
    render() {
        return (
            <div>
                <h1>我是详情页</h1>
                {/* <p>我是来测试路由传参的---{this.props.match.params.xiaoming}</p> */}
                <p>我是来测试路由传参的---{this.props.location.state.xiaoming}</p>
            </div>
        )
    }
}

总结

传递数据的时候在url中不显示传递的数据,并且不params只能传递字符串 statre可以传递对象

刷新地址 数据丢失
注意:传参的时候同一页面只能用一种传参方式,两种传参方式一起用的话会相互影响,并且用state传参的时候要删除接受参数的路由后面配置的接受规则,否则会404

render渲染路由

在路由跳转的时候 可以编写一些逻辑来判断具体渲染那个路由的组件页面

import React, { Component } from 'react'
import Home from "../pages/home.jsx"
import Phone from "../pages/phone.jsx"
import Shop from "../pages/shop.jsx"
import User from "../pages/user.jsx"
import No from "../pages/no.jsx"
import All from "../pages/all.jsx"

import {Route,Switch,Redirect} from "react-router-dom"

export default class index extends Component {
    fun=()=>{
       if(false){
            return <Shop/>
       }else{
           return <Redirect to="/no"/>
       }
    }
    render() {
        return (
            <div>
              {/* 唯一渲染   */}
            <Switch>  
                {/* <Redirect from="从哪来" to="去哪里"/> */}
                {/* exact精准匹配     严格路径匹配 */}
                <Redirect from="/" to="/home" exact/>
               
               
               
               <Route path="/home" component={Home}/> 
               <Route path="/phone" component={Phone}/> 
               {/* render写法 */}
               <Route path="/shop" render={this.fun}/> 
               <Route path="/user" component={User}/> 
               {/* params方式传参第一步配置接收参数 */}
               {/* <Route path="/all/:xiaoming" component={All}/>  */}
               <Route path="/all" component={All}/> 

          

               {/* 404页面 必须在最下面*/}
               <Route component={No}/>
            </Switch>
            </div>
        )
    }
}

数据请求

axios

同vue 但是建议用async await来封装

async和await

字面意思来理解。async 是“异步”的简写(可以理解为parmise的语法糖),而 await 可以认为是 async wait 的简写。所以应该很好理解 async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。
await 只能出现在 async 函数中。
async 函数返回的是一个 Promise 对象。如果在函数中return 一个值,async 会把这个值通过 Promise.resolve() 封装成 Promise 对象。

 <script>
       async function fun(){
            return "你好么么哒"
        }
        console.log(fun());
    </script>

async 函数返回的是一个 Promise 对象,所以then() 来处理这个 Promise 对象

  async function fun(){
            return "你好么么哒"
        }
       
        // 既然async返回的是一个promise对象  那么我们就可以打点then取值
        fun().then((ok)=>{
            console.log(ok)
        })

一般来说,都认为 await 是在等待一个 async 函数完成。不过按语法说明,await 等待的是一个表达式,这个表达式的计算结果是 Promise 对象或者其它值
因为 async 函数返回一个 Promise 对象,所以 await 可以用于等待一个 async 函数的返回值

用async和await封装api请求

引入拦截器
import service from "../util/server.js"
async function getlink (url){
    return await service.request({
                    url,
                    method:"GET"
                 })
}

export default getlink

页面中同原来一样

export default class login extends Component {
     //类似于vue中的mounted钩子函数
    componentDidMount() {
        getlink("http://api.artgoer.cn:8084/artgoer/api/v1/user/324380/v3/topic/topicHomeByLabel?pageIndex=1&token=b544cd63-6d42-46fe-a96c-3cf96bae3113&topicId=62187").then((ok)=>{
            console.log(ok)
        })
    }
    
    render() {
        return (
            <div>
                
            </div>
        )
    }
}

fetch

XMLHttpRequest的一个替代技术 w3c最新标准的一个数据请求技术 (有兼容性问题)
使用:

fetch("请求数据".then((ok)=>{
	你的逻辑
})
import {useEffect,useState} from "react"
let Home=()=>{
    let [val,setval]=useState([])

    useEffect(()=>{
        // fetch使用
        fetch("http://api.artgoer.cn:8084/artgoer/api/v1/user/324380/v3/topic/topicHomeByLabel?pageIndex=1&token=b544cd63-6d42-46fe-a96c-3cf96bae3113&topicId=62187")
        .then(res=>res.json())
        
        .then((ok)=>{
            console.log(ok.data.commentList)

            setval(val=ok.data.commentList)

        })
    })

    return (
        <div>
            <h1>使用fetch</h1>
            <ul>
                {
                    val.map((v,i)=>{
                        return (
                            <li key={i}>{v.commentTxt}</li>
                        )
                    })
                }
            </ul>
        </div>
    )
}

export default Home

发送数据
get

fetch("地址/key=val&key=val",{method:"GET"}).then((ok)=>{
	console.log(ok)
}).catch((err)=>{
	console.log(err)
})

post

fetch("地址",{
	method:"POST",
	headers:{"Content-Type":"application/x-www-form-urlencoded"},
	body:"key-val&key=val"
}).then((ok)=>{
	console.log(ok)
}).catch((err)=>{
   console.log(err)
})

ajax fetch axios 区别

传统的ajax是基于XMLHttpRequest对象 是一个早期新出现的请求方式 属于原生的js 通过这个xhr可通过前后台的数据交互 但是如果出现多个请求嵌套的话就会出现回调地狱的问题 jquery的ajax对象也是基于xhr对象, 只是在他的基础上进行了数据的封装简化了语法提高了兼容性

axios也是基于 xhr 对象的 也是在此基础上进行了封装 只是使用了promise来进行的封装,让它符合最新的ES规范

**fetch **他和XHR对象没有半毛钱关系 他是原生js最新的一个数据请求的标准

JSON-server (模拟数据)

注意:它不像vue只能用于vue,它的话不仅用于react,也能用于vue
用来进行模拟数据的

下载 npm install -g json-server

测试版本 json-server --version

新建文件夹(mock)与.json文件编写模拟数据

{
    "user":[
        {"name":"xixi1","age":181},
        {"name":"xixi2","age":182},
        {"name":"xixi3","age":183},
        {"name":"xixi4","age":184},
        {"name":"xixi5","age":185},
        {"name":"xixi6","age":1865}
    ],
{
    "userbb":[
        {"name":"xixi12","age":181},
        {"name":"xixi22","age":182},
        {"name":"xixi33","age":183},
        {"name":"xixi44","age":184},
        {"name":"xixi55","age":185},
        {"name":"xixi66","age":1865}
    ],
    "xixi":{
        "xx222222":"xx11111"
    }
}
    "xixi":{
        "xx222222":"xx11111"
    }
}

cd到mock文件夹下 使用 json-server --watch json文件名 --port 端口号(会编译出模拟数据的地址)

跨域

http://www.weather.com.cn/data/cityinfo/101320101.html 带有跨域的试验测试地址

1.找到项目目录下/node_modules/react-scripts/config/webpackDevServer.config.js

2.在112行修改文件 跨域内容同vue

弹射 eject

刚才在解决跨域的时候配置文件隐藏过深非常麻烦。

命令 npm run eject

如果报错 使用git 提交一次项目 在 npm run eject

redux

redux是为了解决组件与组件之间跨层级关系传值的一个技术 帮助我们简化了传值的过程

redux是什么?

redux是一个js库 主要用于状态管理的一个工具
集中的管理redux多个组件的状态
redux是一个状态库(他是一个第三方的库,也可以在vue中使用)

redux特点/三大原则

1,单一数据源 整个redux的应用中只有一个store对象
2,state是只读的:想要改变state中的数据不能直接修改 而是要通过一个action的方法进行改变。
3.使用纯函数来进行修改:为了使用action来修改state的数据 我们需要编写一些reducers的纯函数来进行修改

基本使用

1,下载 npm install --save redux
2.创建store文件夹并创立文件来容纳redux代码
3.创建store对象并且暴漏

// 1引用redux  结构出创建store对象的方法  createStore方法
import {createStore} from "redux"

// 2.创建store对象
let store=createStore()

// 3.暴露store对象
export default store

4,传递对应参数

// 1引用redux  结构出创建store对象的方法  createStore方法
import {createStore} from "redux"

// 7创建数据
let data={
    name:"xixi",
    age:18,
    arr:[111,2222,333,444]
}
// 5.创建reducer  state是数据  action 是修改的那些动作
// 8 把刚才创建的数据 用es6函数型材默认值的方式传递给state
let reducer=(state=data,action)=>{
    // 6.返回初始化数据
    return state
}

// 2.创建store对象
// 4 给store对象中传入reducer (在其中包含了数据与数据的修改)
let store=createStore(reducer)

// 3.暴露store对象
export default store

5.读取数据 getState()获取redux中的state数据

import React, { Component } from 'react'
// 1.引用
import store from "../store/index.js"
export default class home extends Component {
    constructor(){
        super()
        this.state={
            // 2.通过getState把store中的数据获取出来
            text:store.getState().name
        }
    }
    render() {
        return (
            <div>
                {/* 3.使用state中的数据 */}
                home---{this.state.text}
            </div>
        )
    }
}

修改

1,创建修改动作

import {createStore} from "redux"

let data={
    name:"xixi",
    age:18,
    arr:[111,2222,333,444]
}
let reducer=(state=data,action)=>{
    // 1.修改的动作都在action中
   switch (action.type) {
    //    2.创建两个修改任务
       case "ADD_LISTDATA_USERDATA":
           return {...state,age:state.age+1}
           break;
       case "DEL_LISTDATA_USERDATA":
        return {...state,age:state.age-1}
           break;
   
       default:
         return state
           break;
   }
}
let store=createStore(reducer)

export default store

2页面中触发修改动作

import React, { Component } from 'react'
// 1.引用
import store from "../store/index.js"
export default class home extends Component {
    constructor(){
        super()
        this.state={
            // 2.通过getState把store中的数据获取出来
            text:store.getState().name
        }
    }
    render() {
        return (
            <div>
                {/* 3.使用state中的数据 */}
                home---{this.state.text}
            </div>
        )
    }
}

但是发现redux的数据改变了 但是页面没有更新 没有更新的原因是没有在组件中触发render渲染

3,subscribe()监听器
监听redux中state的数据改变 当redux中state发生了改变 那么sbuscribe就会触发

import React, { Component } from 'react'
import store from "../store/index.js"
export default class shop extends Component {
    constructor(){
        super()
        this.state={
            age:store.getState().age
        }
    }

    componentDidMount() {
        // 设置监听触发页面的render渲染
        store.subscribe(()=>{
           this.setState({
               age:store.getState().age
            }
           )
        })
    }

    add=()=>{
        // 触发redux中的修改动作使用dispatch来进行
        store.dispatch({type:"ADD_LISTDATA_USERDATA"})
    }
    del=()=>{
        store.dispatch({type:"DEL_LISTDATA_USERDATA"})
    }
    render() {
        return (
            <div>
                shop---{this.state.age}
                <br />
                <button onClick={this.add}>+1</button>
                <button onClick={this.del}>-1</button>
            </div>
        )
    }
}

4.也可以在调用的时候给actions传递参数 只需要在dispatch(传递)即可

redux拆分写法

actionCreator—拆分派发动作

redux希望有一个专门文件用来存放我们的派发动作
1.在store文件夹下新建一个文件 actionCreator.js用来存放派发动作

export let ADD_LISTDATA_USERDATA=()=>{
    return {
        type:"ADD_LISTDATA_USERDATA",num:10
    }
}
export let DEL_LISTDATA_USERDATA=()=>{
    return {
        type:"DEL_LISTDATA_USERDATA",num:10
    }
}

2,在组件中修改原有的dispatch中调用的动作

import React, { Component } from 'react'
import store from "../store/index.js"
全部引用
全部引用
全部引用
全部引用
全部引用
import  * as actioncreator  from "../store/actioncreator.js"
export default class shop extends Component {
    constructor(){
        super()
        this.state={
            age:store.getState().age
        }
    }

    componentDidMount() {
        // 设置监听触发页面的render渲染
        store.subscribe(()=>{
           this.setState({
               age:store.getState().age
            }
           )
        })
    }

    add=()=>{
        // 触发redux中的修改动作使用dispatch来进行
        使用封装的actioncreator动作
           使用封装的actioncreator动作
              使用封装的actioncreator动作
                 使用封装的actioncreator动作
                    使用封装的actioncreator动作
                    
                
        store.dispatch(actioncreator.ADD_LISTDATA_USERDATA())
    }
    del=()=>{
        store.dispatch(actioncreator.DEL_LISTDATA_USERDATA())
    }
    render() {
        return (
            <div>
                shop---{this.state.age}
                <br />
                <button onClick={this.add}>+1</button>
                <button onClick={this.del}>-1</button>
            </div>
        )
    }
}

封装动作名

因为我们dispath的动作中type的名字出现了两次 后期不方便管理所以进行封装

1.新建一个actiontype.js的文件

2.开始封装

export const ADD_LISTDATA_USERDATA="ADD_LISTDATA_USERDATA"
export const DEL_LISTDATA_USERDATA="DEL_LISTDATA_USERDATA"

3.在派发动作 与 store修改的位置使用

// 1.引用封装名字的文件
import * as actiontype from "./actiontypes.js"
export let ADD_LISTDATA_USERDATA=()=>{
    return {
        // 使用
        type:actiontype.ADD_LISTDATA_USERDATA,num:10
    }
}
export let DEL_LISTDATA_USERDATA=()=>{
    return {
        type:actiontype.DEL_LISTDATA_USERDATA,num:10
    }
}

注意store的修改动作中也要如上的引用使用

封装reducer

今后的项目体积会越来越大 数据和修改也会越来越多 那么这个时候如果reducer写在一个文件中后期就没有办法进行维护了 所以我们需要把组件自己的reducer单独剥离出来 一个组件一个reducer 或者多个组件一个reducer 方便后期维护与管理
使用:
1.新建文件夹与文件用来存放每个组件的reducer(数据与修改)

2.把原有写在一起的数据与修改单独提取出来
例如将文件名为home和shop的进行封装,只存放各自的数据,代码如下:
Home里面

let homedata={
    text:"我是home的数据"
}

let homereducer=(state=homedata,action)=>{
    return state
}

export default homereducer

Shop里面

import * as actiontypes from "../actiontypes.js"
let data={
        name:"xixi",
        age:18,
        arr:[111,2222,333,444]
    }
    let shopreducer=(state=data,action)=>{
        // 1.修改的动作都在action中
       switch (action.type) {
        //    2.创建两个修改任务
           case actiontypes.ADD_LISTDATA_USERDATA:
               console.log({...state,age:state.age})
               return {...state,age:state.age+action.num}
               break;
           case actiontypes.DEL_LISTDATA_USERDATA:
            return {...state,age:state.age-action.num}
               break;
       
           default:
             return state
               break;
       }
    
        
    }
    export default shopreducer

注意:封装reducer就是类似于vuex的moddule,为每个组件创建一个自己的模块(.js文件),里面写入需要的数据,方便后期维护与管理。

// 1.引用封装名字的文件
import * as actiontype from "./actiontypes.js"
export let ADD_LISTDATA_USERDATA=()=>{
    return {
        // 使用
        type:actiontype.ADD_LISTDATA_USERDATA,num:10
    }
}
export let DEL_LISTDATA_USERDATA=()=>{
    return {
        type:actiontype.DEL_LISTDATA_USERDATA,num:10
    }
}

3合并reducer很重要

3合并reducer很重要

3合并reducer很重要

3合并reducer很重要

3合并reducer很重要

新建一个文件用来存放合并reducer的代码

// 1.引用合并的方法 combineReducers就是合并多个reducer成一个
import {combineReducers} from "redux"
// 2.把你要合并的所有reducers一个个引进来
import homereducer from "./reducers/homer.js"
import shopreducer from "./reducers/shopr.js"
// 3.开始合并
let reducer=combineReducers({
    homereducer,
    shopreducer
})
// 4.暴露
export default reducer

4.在store下的index.js中使用刚才合并的reducer

// 1引用redux  结构出创建store对象的方法  createStore方法
import {createStore} from "redux"
// 使用合并的reducer
import reducer from "./reducer.js"
// 2.创建store对象  传入合并的reducer
let store=createStore(reducer)

// 3.暴露store对象
export default store

5.发现没报错 但是数据不见了 因为我们现在拆分了reducer所以读取数据的时候有点变化

原始:store.getState().xxxx

新的: store.getState().模块名.xxxx
注意注意 模块名就是在合并时的模块名是啥就是啥,如下

import {combineReducers} from "redux"
// 2.把你要合并的所有reducers一个个引进来
import homereducer from "./reducers/homer.js"
import shopreducer from "./reducers/shopr.js"
// 3.开始合并
let reducer=combineReducers({//里面的内容便是读取数据时的模块名,
    homereducer,
    shopreducer
})
// 4.暴露
export default reducer

react-redux

是一个专为react开发的redux插件
之前使用redux的时候在react组件中与redux的耦合度太高了 (在react的组件中有大量的store对象出现)并且让代码更简洁

使用

1.下载 npm install --save react-redux

2.你先要老老实实的把原来的redux的数据创建等先写出来

读取

3.使用react-redux读取数据

Provider-----把store对象传递给所有的子组件 方便其使用 在index.js中进行

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/demo.jsx';
import reportWebVitals from './reportWebVitals';
// 1.引用provider
import {Provider} from "react-redux"
// 2.引用store对象
import store from "./store/index.js"
ReactDOM.render(
  // 3.包裹与传递store对象
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

4.让组件与redux进行关联

connect() 是一个函数当这个函数被调用的时候他是一个高阶组件 用来关联组件与redux进行连接

import React, { Component } from 'react'
// 1.引用
import {connect} from "react-redux"
class reactdemo extends Component {
    render() {
        return (
            <div>
                <h1>使用react-redux读取数据</h1>
            </div>
        )
    }
}
// connect()  是一个函数当这个函数被调用的时候他是一个高阶组件
export default connect()(reactdemo)

5.需要向当前组件传递出相关的数据

import React, { Component } from 'react'
// 1.引用
import {connect} from "react-redux"
class reactdemo extends Component {
    render() {
        return (
            <div>
                <h1>使用react-redux读取数据</h1>
                <h1>{this.props.state.demoreducer.name}</h1>
            </div>
        )
    }
}
// connect()  是一个函数当这个函数被调用的时候他是一个高阶组件
export default connect(state=>({state}))(reactdemo)

修改

import React, { Component } from 'react'
// 1.引用
import {connect} from "react-redux"
import {UPDATA_DEMO} from "../store/actioncreator.js"
class reactdemo extends Component {
    fun=()=>{
        this.props.dispatch(UPDATA_DEMO())
    }
    render() {
        return (
            <div>
                <h1>使用react-redux读取数据</h1>
                <h1>{this.props.state.demoreducer.name}</h1>
                <button onClick={this.fun}>点我修改</button>
            </div>
        )
    }
}
// connect()  是一个函数当这个函数被调用的时候他是一个高阶组件
export default connect(state=>({state}))(reactdemo)


生命周期与性能优化

1,constructor()中完成了React数据的初始化

2,componentWillMount()一般使用较少,他更多的是在服务器渲染时使用。它代表的过程是组件已经经历了constructor()初始化数据后,但是还未渲染DOM时。
3,render()进行渲染

4,componentDidMount():组件第一次渲染完成,此时dom节点已经生成,可以在这里调用ajax请求,返回数据 setState后组件会重新渲染
5 componentWillUnmount在组件从 DOM 中移除之前立刻被调用。

更新
6,componentWillReceiveProps (nextProps)
在组件接收到一个新的prop时被调用。初始化不触发.

7,shouldComponentUpdate 判定组件是否要更新html 主要用于性能优化(部分更新)唯一用于控制组件重新渲染的生命周期,由于在react中,setState以后,state发生变化,组件会进入重新渲染的流程,在这里return false可以阻止组件的更新

8 componentWillUpdate()
组件即将更新html时候调用shouldComponentUpdate返回true以后,组件进入重新渲染的流程

9 componentDidUpdate 在组件完成更新后立即调用。

10 render()函数会插入jsx生成的dom结构,react会生成一份虚拟dom树,在每一次组件更新时,在此react会通过其diff算法比较更新前后的新旧DOM树,比较以后,找到最小的有差异的DOM节点,并重新渲染。

子组件操作父组件传递过来的数据(点击变色)

父组件

import React, { Component } from 'react'
import Zi from "./zi.jsx"
export default class fu extends Component {
    constructor(props){
        super(props)
        this.state={
            arr:[
                {title:"aa1",style:false},
                {title:"aa2",style:false},
                {title:"aa3",style:false},
                {title:"aa4",style:false},
                {title:"aa5",style:false},
                {title:"aa6",style:false},
            ]
        }
    }
    fun=(num)=>{
        console.log(num)
        //父组件收到子组件传过来的下标进行修改
        let newarr=this.state.arr;
        newarr[num].style=! newarr[num].style
        this.setState({
            arr:newarr,
        })
    }
    render() {
        return (
            <React.Fragment>
                    {
                        this.state.arr.map((v,i)=>{
                            return (
                               <Zi numfun={this.fun} key={i} title={v.title} style={v.style} num={i}></Zi>
                            )
                        })
                    }
                <p>父组件</p>
                
            </React.Fragment>
        )
    }
}

子组件

import React, { Component } from 'react'

export default class zi extends Component {
    render() {
        let  {title,style,num,numfun}=this.props
      
        return (
            <div>
            //核心:
              //子组件通过onChange事件将父组件传递过来的下标返回给父组件,告诉父组件要修改的当前元素的下标              
                <input type="checkbox" onChange={numfun.bind(this,num)}/>
                <span style={{color:style?'red':''}}>{title}</span>

            </div>
        )
    }
}

性能优化

因为是在子组件中遍历的,所以在子组件中设置性能优化

shouldComponentUpdate
 // nextProps新的props
    // nextState新的state
    shouldComponentUpdate(nextProps, nextState) {
        // 为真更新    在新传递的props和旧的props不同的时候
        // 为假不更新

        return nextProps.style!==this.props.style
    }
import React, { Component } from 'react'

export default class zi extends Component {
    // 性能优化
      // 性能优化
        // 性能优化
          // 性能优化
            // 性能优化
              // 性能优化
                // 性能优化
    shouldComponentUpdate(nextProps, nextState) {
        // 为真更新    在新传递的props和旧的props不同的时候
        // 为假不更新

        return nextProps.style!==this.props.style
    }
    // 性能优化
    render() {
        let  {title,style,num,numfun}=this.props
         console.log("我是字")
        
        return (
            <div>
              
                <input type="checkbox" onChange={numfun.bind(this,num)}/>
                <span style={{color:style?'red':''}}>{title}</span>

            </div>
        )
    }
}

纯组件 PureComponent的性能优化

PureComponent是react技术优化中比较重要 组件在更新的时候 如果props或者是state没有发生改变的时候,就不让当前组件重新render渲染,减少更新次数提高性能

省去了在重新渲染的时候 dom的比对 就是让react帮我们自动是做了一个新数据与旧数据之间的对比(因为他只比较了props和state的内存地址 如果内存地址相同那个让shouldComponentUpdate返回一个false 反之返回true)

// 1,首先引入PureComponent
import React, { Component,PureComponent } from 'react'
//2,将原来的Component替换为PureComponent,即可完成优化
// export default class zi extends Component
export default class zi extends PureComponent {

 
    
    render() {
        let  {title,style,num,numfun}=this.props
         console.log("我是字")
        
        return (
            <div>
              
                <input type="checkbox" onChange={numfun.bind(this,num)}/>
                <span style={{color:style?'red':''}}>{title}</span>

            </div>
        )
    }
}

函数组件的性能优化

React.memo()

umi

umi是蚂蚁金服的一个前端框架 是一个可以扩展性的企业级前端框架 umi是以路由为基础的 同时它支持了配置时路由约定式路由 保证了我们在react中使用路由的便捷性

什么时候不能用umi

ie8以下

react16.8之前

node10以下

umi与creater-react-app的区别

create-react-app 脚手架 是不包含路由等拓展功能的他是一个容器 用来方便我们开发react
umi是一个基于react的第三方框架 在其中包含了很多方便我们开发的第三方依赖

使用

电脑上必须有node10以上

yarn

脸书公司退出的一款 包管理工具 npm和他干的是一件事

安装yarn npm install -g yarn

https://blog.csdn.net/qq_40963664/article/details/82768227

由于下载的服务器在国外 所以建议大家把yarn的下载源切换成淘宝镜像

yarn config set registry https://registry.npm.taobao.org

使用umi

1.全局下载umi npm install -g umi yarn global add umi

2.查看版本 umi -v

3.创建项目 cd到指定路径下 npm 或者 yarn create @umijs/umi-app

4.下载依赖 npm install yarn

5.启动 npm start yarn start

组件创建

可以手工正常配置

命令方式创建组件

umi g page 组件名 创建出来的是js文件

umi g page 组件名 --typescript --less 创建的是ts+less

路由配置

如果需要写路由 额请在.umirc.ts文件中进行路由配置

import { defineConfig } from 'umi';

export default defineConfig({
  nodeModulesTransform: {
    type: 'none',
  },
  routes: [
    { path: '/', component: '@/pages/index' },
    // 配置路由
    { path: '/home', component: '@/pages/home.jsx' },
  ],
  fastRefresh: {},
});

title属性

  // title属性就是给当前的页面起个页面标题
    { path: '/home', component: '@/pages/home.jsx',title:"我是title" },

页面导航

编程式和声明式

声明式 使用LInk 来进行页面的跳转(同react的Link,需引入)

编程式 通过history来进行页面的跳转

import React, { Component } from 'react'
// 不要忘了引用history
import {history} from "umi"
export default class home extends Component {
    fun=()=>{
        history.push("/")
    }
    render() {
        return (
            <div>
                你好么么哒
                <button onClick={this.fun}>点我去首页</button>
            </div>
        )
    }
}

重定向

redirect

// redirect 设置重定向
    // exact 精准匹配
    { path: '/',redirect:"/index",exact:true },

二级路由

使用 routes配置二级路由

import { defineConfig } from 'umi';

export default defineConfig({
  nodeModulesTransform: {
    type: 'none',
  },
  routes: [
    // redirect 设置重定向
    // exact 精准匹配
    { path: '/',redirect:"/index",exact:true },
    { path: '/index', component: '@/pages/index' },
    // 配置路由
    // title属性就是给当前的页面起个页面标题
    { 
      path: '/home',
      component: '@/pages/home.jsx',
      title:"我是title",
      // 二级路由配置
      routes:[
        { path: '/home/era', component: '@/pages/er/era.jsx' },
        { path: '/home/erc', component: '@/pages/er/erc.jsx' },
      ]
    },
     


    { path: '/shop', component: '@/pages/shop.js',title:"我是title" },
  ],
  fastRefresh: {},
});

千万不要忘

千万不要忘

千万不要忘

千万不要忘 在一级路由页面中设置二级路由的出口

  {this.props.children}

约定式路由

除了配置式路由外 umi也支持约定式路由 就是不需要我们去手写路由配置 umi会自动根据文件夹里面的文件自动生成路由规则 完成路由

dva

在开发大型应用的时候,组件与组件之间的数据通信是一个大问题,但dva就可以高效快速的完成统一的状态管理。

dva是什么?

dva 是一个react的框架 主要是使用简单的api快速的帮助我们实现 react-router+redux-saga

创建

1.全局下载 npm install dva-cli -g

2.查看版本 dva -v

3.dva new 项目名 创建项目

4.cd到项目下 npm start 自动项目

路由

路由页面创建在 routes文件夹下 路由的配置在 router.js中创建的

路由模式

hash 模式

默认就是

BrowerRouter模式

下载一个叫做historyd的一个模块 npm install --save hsitory

数据的状态管理

1,新建文件管理模块(在models下建立数据模块)

export default {

    namespace: 'example',
  
    state: {
        text:"你好",
        num:19,
        sex:},
  
  };
  

2.在index.js中建立关系

app.model(require('./models/homer').default);
  1. 在组件中使用
import React, { Component } from 'react'
// 1.引入connect链接
import {connect} from "dva" 
 class home extends Component {
    render() {
        return (
            <div>
                {/* this.props.state.模块名.xxxx */}
                我是home组件页面----{this.props.state.homer.text}
            </div>
        )
    }
}
// 传入state
export default connect(state=>({state}))(home)


在dva中修改数据都是定义在reducers中

export default {

    namespace: 'homer',
  
    state: {
        text:"你好",
        num:19,
        sex:"男"
    },
    // 修改
    reducers:{
        add(state,payload){
          return {...state,num:state.num+payload.data}  
        }
    }
  
  };
  

在组件中通过dispatch调用

 fun=()=>{
         this.props.dispatch({
            //  type:"命名空间的名字/你要调用的reducers的名字"
            type:"homer/add",
            data:9
         })
     }
异步操作

effect dva中进行异步操作的区域

effects:{
        *fun({payload},{put,call}){
            yield console.log("我是effects")
        }
    }

组件中通过一个点击事件调用

funa=function(){
         this.props.dispatch({
             //  type:"命名空间的名字/你要调用的effects的名字"
             type:"homer/fun"
         })
     }
      <p><button onClick={this.funa.bind(this)}>点击调用</button></p>
请求

在services文件夹中创建自己的请求js,services就是封装的请求,类似于api

import request from '../utils/request';

export function query() {
  return request('/api/users');
}

在想使用的组件中 引用 使用

func=()=>{
        query().then((ok)=>{
            console.log(ok)
        })
     }
跨域

在.webpackrc文件中写入同vue一样的proxy即可

 "proxy":{
        "/api":{
        "target":"http://www.weather.com.cn/",
        "changeOrigin":true,
        "pathRewrite":{
            "^/api":"/"
        }
        }
       
    }

小闭环 effect请求数据

models下的数据模块中通过dispath调用effects

//发请求就要引入封装的请求
import {query} from "../services/homerequest.js"
 *demoa({payload},{put,call}){
            // 请求需要在call中进行接收与操作
           let api= yield call(query)
           console.log(api)
        }

大闭环 请求数据并且修改展示到页面中

subscriptions

订阅 就是dva中model的一个监听器 监听各种变化

组件中

import React, { Component } from 'react'
import {connect} from "dva"
class shop extends Component {
    fun=()=>{
        this.props.dispatch({
            type:"shopr/req"
        })
    }
    render() {
        return (
            <div>
                shop我是--{this.props.state.shopr.num}
                <button onClick={this.fun}>点我发送请求修改数据</button>
            </div>
        )
    }
}
export default connect(state=>({state}))(shop)

数据模块中(models下的.js文件)

import {query} from "../services/homerequest.js"
export default {

    namespace: 'shopr',
  
    state: {
       num:18 
    },
  
    reducers:{
        update(state,payload){
            return {...state,num:payload.data}
        }
    },
  
    effects: {
        *req({payload},{put,call}){
              let api =yield call(query)
              console.log(api.data.weatherinfo.city);
            //   调用reducers
              yield put({
                type:"update",
                data:api.data.weatherinfo.city
              })
        }
    }
  
  };

十一

TypeScript 开发环境搭建

1.下载Node.js

  • 64位:https://nodejs.org/dist/v14.15.1/node-v14.15.1-x64.msi
  • 32位:https://nodejs.org/dist/v14.15.1/node-v14.15.1-x86.msi

2,安装node

3.使用npm全局安装typescript

  • 进入命令行
  • 输入:npm i -g typescript
  • tsc -v 命令用来测试是否安装成功

4 创建一个ts文件

5.使用tsc对ts文件进行编译

  • 进入命令行
  • 进入ts文件所在目录
  • 执行命令:tsc xxx.ts

通过配置编译

每次写完ts文件都要输入一次命令是不是很麻烦呢,能不能保存文件时就自动编译运行ts文件呢

  • cd到项目下
  • 使用 tsc -init 会生成tsconfig.json 文件 ( tsconfig.json文件与TypeScript编译器(tsc)的配置相对应 是 TypeScript 使用 tsconfig.json 文件作为其配置文件 用来 指定待编译文件和定义编译选项。 )
  • 直接使用tsc命令即可编译

为什么要使用这个文件

通常我们可以使用 tsc 命令来编译少量 TypeScript 文件

但如果实际开发的项目,很少是只有单个文件,当我们需要编译整个项目时,就可以使用 tsconfig.json 文件,将需要使用到的配置都写进 tsconfig.json 文件,这样就不用每次编译都手动输入配置,另外也方便团队协作开发

常见配置

{
"compilerOptions": {
    "target": "ES5",             // 目标语言的版本
    "module": "commonjs",        // 指定生成代码的模板标准
    "noImplicitAny": true,       // 不允许隐式的 any 类型
    "removeComments": true,      // 删除注释 
    "preserveConstEnums": true,  // 保留 const 和 enum 声明
    "sourceMap": true,            // 生成目标文件的sourceMap文件(简单说,Source map就是一个信息文件,里面储存着位置信息。也就是说,转换后的代码的每一个位置,所对应的转换前的位置。有了它,出错的时候,除错工具将直接显示原始代码,而不是转换后的代码。这无疑给开发者带来了很大方便)
    "outDir":"./out/"           //编译输出的文件夹
  },
  "files": [   // 指定待编译文件(files 配置项值是一个数组,用来指定了待编译文件,即入口文件。入口文件依赖其他文件时,不需要将被依赖文件也指定到 files 中,因为编译器会自动将所有的依赖文件归纳为编译对象,即 index.ts 依赖 user.ts 时,不需要在 files 中指定 user.ts , user.ts 会自动纳入待编译文件。)
    "./src/index.ts"  
  ]
}
常见配置 以下大概了解

compilerOptions

  • 编译选项是配置文件中非常重要也比较复杂的配置选项

  • 在compilerOptions中包含多个子选项,用来完成对编译的配置

    • 项目选项

      • target

        • 设置ts代码编译的目标版本

        • 可选值:

          • ES3(默认)、ES5、ES6/ES2015、ES7/ES2016、ES2017、ES2018、ES2019、ES2020、ESNext
        • 示例:

          • "compilerOptions": {
                "target": "ES6"
            }
            
          • 如上设置,我们所编写的ts代码将会被编译为ES6版本的js代码

      • lib

        • 指定代码运行时所包含的库(宿主环境)

        • 可选值:

          • ES5、ES6/ES2015、ES7/ES2016、ES2017、ES2018、ES2019、ES2020、ESNext、DOM、WebWorker、ScriptHost …
        • 示例:

          • "compilerOptions": {
                "target": "ES6",
                "lib": ["ES6", "DOM"],
                "outDir": "dist",
                "outFile": "dist/aa.js"
            }
            
      • module

        • 设置编译后代码使用的模块化系统

        • 可选值:

          • CommonJS、UMD、AMD、System、ES2020、ESNext、None
        • 示例:

          • "compilerOptions": {
                "module": "CommonJS"
            }
            
      • outDir

        • 编译后文件的所在目录

        • 默认情况下,编译后的js文件会和ts文件位于相同的目录,设置outDir后可以改变编译后文件的位置

        • 示例:

          • "compilerOptions": {
                "outDir": "dist"
            }
            
          • 设置后编译后的js文件将会生成到dist目录

      • outFile

        • 将所有的文件编译为一个js文件

        • 默认会将所有的编写在全局作用域中的代码合并为一个js文件,如果module制定了None、System或AMD则会将模块一起合并到文件之中

        • 示例:

          • "compilerOptions": {
                "outFile": "dist/app.js"
            }
            
      • rootDir

        • 指定代码的根目录,默认情况下编译后文件的目录结构会以最长的公共目录为根目录,通过rootDir可以手动指定根目录

        • 示例:

          • "compilerOptions": {
                "rootDir": "./src"
            }
            
      • allowJs

        • 是否对js文件编译
      • checkJs

        • 是否对js文件进行检查

        • 示例:

          • "compilerOptions": {
                "allowJs": true,
                "checkJs": true
            }
            
      • removeComments

        • 是否删除注释
        • 默认值:false
      • noEmit

        • 不对代码进行编译
        • 默认值:false
      • sourceMap

        • 是否生成sourceMap
        • 默认值:false
    • 严格检查

      • strict
        • 启用所有的严格检查,默认值为true,设置后相当于开启了所有的严格检查
      • alwaysStrict
        • 总是以严格模式对代码进行编译
      • noImplicitAny
        • 禁止隐式的any类型
      • noImplicitThis
        • 禁止类型不明确的this
      • strictBindCallApply
        • 严格检查bind、call和apply的参数列表
      • strictFunctionTypes
        • 严格检查函数的类型
      • strictNullChecks
        • 严格的空值检查
      • strictPropertyInitialization
        • 严格检查属性是否初始化
    • 额外检查

      • noFallthroughCasesInSwitch
        • 检查switch语句包含正确的break
      • noImplicitReturns
        • 检查函数没有隐式的返回值
      • noUnusedLocals
        • 检查未使用的局部变量
      • noUnusedParameters
        • 检查未使用的参数
    • 高级

      • allowUnreachableCode
        • 检查不可达代码
        • 可选值:
          • true,忽略不可达代码
          • false,不可达代码将引起错误
      • noEmitOnError
        • 有错误的情况下不进行编译
        • 默认值:false

以上大概了解

自动编译

vscode 自动编译

需要 监视tsconfig.json文件:

**步骤:点击终端—》运行任务——>选择typescript——>选择监视tsconfig.json文件 **

命令自动编译
  • 编译文件时,使用 -w 指令后,TS编译器会自动监视文件的变化,并在文件发生变化时对文件进行重新编译。

  • 示例:

    • tsc xxx.ts -w
      

基本类型

变量

注意:let变量不能重复声明
注意:const它拥有与 let相同的作用域规则,但是不能对它们重新赋值。
注意:除了下划线 _ 和美元 $ 符号外,不能包含其他特殊字符,包括空格

类型声明

  • 类型声明是TS非常重要的一个特点

  • 通过类型声明可以指定TS中变量(参数、形参)的类型

  • 指定类型后,当为变量赋值时,TS编译器会自动检查值是否符合类型声明,符合则赋值,否则报错

  • 简而言之,类型声明给变量设置了类型,使得变量只能存储某种类型的值
    语法:

let 变量: 类型;

let 变量: 类型 =;

function fn(参数: 类型, 参数: 类型): 返回值类型{
    ...
}

自动类型判断

TS拥有自动的类型判断机制

当对变量的声明和赋值是同时进行的,TS编译器会自动判断变量的类型

所以如果你的变量的声明和赋值时同时进行的,可以省略掉类型声明

类型:

类型例子描述
number1, -33, 2.5任意数字
string‘hi’, “hi”, hi任意字符串
booleantrue、false布尔值true或false
any*任意类型,不需要检查类型(没有类型检查就没有意义了,跟写JS一样。很不安全)
unknown*类型安全的any
void空值(undefined)没有值(或undefined)
never没有值类型表示永远不会有值的一种类型。
object{name:‘孙悟空’}任意的JS对象
array[1,2,3]任意JS数组
tuple(元组)[4,5]元组,TS新增类型,元组类型用来表示已知元素数量和类型的数组,各元素的类型不必相同,对应位置的类型需要相同(赋值的顺序不能变)
enumenum{A, B}枚举,TS中新增类型 使用枚举类型可以为一组数值赋予友好的名字。枚举表示的是一个命名元素的集合值

number:

let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;
let big: bigint = 100n;

boolean

let isDone: boolean = false;

string

let color: string = "blue";
color = 'red';

let fullName: string = `Bob Bobbington`;
let age: number = 37;
let sentence: string = `Hello, my name is ${fullName}.

I'll be ${age + 1} years old next month.`;

any

在一些情况下,如果我们无法确定变量的类型时(或者无需确认类型时),我们可以将其指定为 any 类型。 TS中对于被标记为 any 类型的变量,是没有进行类型检查而直接通过编译阶段的检查。 在我们的系统中还是应当尽量避免使用 any 类型,以尽可能的保证系统健壮性。

let d: any = 4;
d = 'hello';
d = true;

unknown

TypeScript 3.0 引入了新的unknown 类型,它是 any 类型对应的安全类型。 unknownany 的主要区别是 unknown 类型会更加严格:

let demo:unknown="你好";
let demoa:unknown=1;
let demob:unknown=true;



let num:any=demo
// unknown 类型只能被赋值给 any 类型和 unknown 类型本身。
// 只有能够保存任意类型值的容器才能保存 unknown 类型的值。毕竟我们不知道变量 value 中存储了什么类型的值。
let numb:string=demo;//出错

void

? 没有返回值的函数,其返回值类型为 void

function fun(): void {
    console.log("你好");
}

申明为 void 类型的变量,只能赋予 undefinednull

let unusable: void = undefined;

never

类型表示永远不会有值的一种类型。

object

let obj: object = {};

array

let list: number[] = [1, 2, 3];
let list: Array<number> = [1, 2, 3];

tuple元组

已知数量与数据类型的数组

let x: [string, number];
x = ["hello", 10]; 

enum 枚举

TS中新增类型 使用枚举类型可以为一组数值赋予友好的名字。枚举表示的是一个命名元素的集合值

就是给一组数据起一个友好的名字

数字枚举类型和字符串枚举类型;

enum user{xiaoming,xiaohong,xiaobai}
console.log(user.xiaohong)

// 设置值
enum user{xiaoming,xiaohong=99,xiaobai}
console.log(user.xiaohong)
console.log(user.xiaobai)

// 字符串枚举设置值
enum user{xiaoming,xiaohong="小红",xiaobai="小白"}
console.log(user.xiaohong)
console.log(user.xiaobai)

类型别名

类型别名用来给一个类型起个新名字,使用 type 创建类型别名,类型别名常用于联合类型。

在实际应用中,有些类型名字比较长或者难以记忆,重新命名是一个较好的解决方案

// 创建一个String别名
type xiaoming=String;
// 使用别名
let textCon:xiaoming="xixi";

console.log(textCon);//xixi

联合类型-Union Type

联合类型表示的值可能是多种不同类型当中的某一个联合类型放宽了类型的取值的范围,也就是说值的范围不再限于某个单一的数据类型同时,它也不是无限制地放宽取值的范围,如果那样的话,完全可以使用 any 代替。

// 给多个类型创建一个名字
type newType=String|Number;
// 可以在赋值的时候赋值字符串与数字
let demoText:newType="你好我可以创建字符串与number"

面向对象

面向对象是程序中一个非常重要的思想,它被很多同学理解成了一个比较难,比较深奥的问题,其实不然。面向对象很简单,简而言之就是程序之中所有的操作都需要通过对象来完成。

  • 举例来说:
    • 操作浏览器要使用window对象
    • 操作网页要使用document对象
    • 操作控制台要使用console对象

一切操作都要通过对象,也就是所谓的面向对象,那么对象到底是什么呢?这就要先说到程序是什么,计算机程序的本质就是对现实事物的抽象,抽象的反义词是具体,比如:照片是对一个具体的人的抽象,汽车模型是对具体汽车的抽象等等。程序也是对事物的抽象,在程序中我们可以表示一个人、一条狗、一把枪、一颗子弹等等所有的事物。一个事物到了程序中就变成了一个对象。

在程序中所有的对象都被分成了两个部分数据和功能,以人为例,人的姓名、性别、年龄、身高、体重等属于数据,人可以说话、走路、吃饭、睡觉这些属于人的功能。数据在对象中被成为属性,而功能就被称为方法。所以简而言之,在程序中一切皆是对象。

类(class)

要想面向对象,操作对象,首先便要拥有对象,那么下一个问题就是如何创建对象。要创建对象,必须要先定义类,所谓的类可以理解为对象的模型,程序中可以根据类创建指定类型的对象,举例来说:可以通过Person类来创建人的对象,通过Dog类创建狗的对象,通过Car类来创建汽车的对象,不同的类可以用来创建不同的对象。

  • 定义类:
class 类名 {
	属性名: 类型;
	//constructor 方法是类的构造函数,是一个默认方法,通过 new 命令创建对象实例时,自动调用该方法。一个类必须有 constructor 方法,如果没有显式定义,一个默认的 consructor 方法会被默认添加。所以即使你没有添加构造函数,也是会有一个默认的构造函数的。

	constructor(参数: 类型){
		this.属性名 = 参数;
	}
	
	方法名(){
		....
	}

}

示例

class Person{
    name: string;
    age: number;

    constructor(name: string, age: number){
        this.name = name;
        this.age = age;
    }

    sayHello(){
        console.log(`大家好,我是${this.name}`);
    }
}

使用类:

//通过new关键字可以方便的生产一个类的实例对象,这个生产对象的过程叫实例化
const p = new Person('孙悟空', 18);
p.sayHello();

面向对象的特点

封装

  • 对象实质上就是属性和方法的容器,它的主要作用就是存储属性和方法,这就是所谓的封装

  • 默认情况下,对象的属性是可以任意的修改的,为了确保数据的安全性,在TS中可以对属性的权限进行设置

  • 只读属性(readonly):

    • 如果在声明属性时添加一个readonly,则属性便成了只读属性无法修改
  • TS中属性具有三种修饰符:

    • public(默认值), 公开的,谁都能用 (默认public) 可以在类、子类和对象中修改
    • protected , 受保护的,仅仅类和类的子类能使用
    • private , 私有的,仅类自己里头才能使用

    示例:

  • public

class a{
    public name:String="xixi"
}
let demoa=new a()
// 因为name属性是使用public 谁都可以修改
demoa.name="haha"
console.log(demoa.name)

protected

class a{
    protected name:String="xixi"
    public showname(){
        console.log("因为name是使用protected修饰的只能在当前类和类的子类中使用"+this.name)
    }
}
let demoa=new a()
demoa.showname()

// 在外部是不能使用的
// console.log(demoa.name)

private

class a{
    private  name:String="xixi"
    public showname(){
        console.log("因为name是使用private仅类自己里头才能使用"+this.name)
    }
}
let demoa=new a()
demoa.showname()

// 在外部是不能使用的
// console.log(demoa.name)

静态属性

  • 静态属性(方法),也称为类属性。使用静态属性无需创建实例,通过类即可直接使用

  • 静态属性(方法)使用static开头
    示例:

class Tools{
    static PI:Number = 3.1415926;
    
  static sum(num1: number, num2: number){
        return num1 + num2
  }
}

console.log(Tools.PI);
console.log(Tools.sum(123, 456));

继承
继承是面向对象中的又一个特性
通过继承可以将其他类中的属性和方法引入到当前类中

示例:

class Animal{
    name: string;
    age: number;

    constructor(name: string, age: number){
        this.name = name;
        this.age = age;
    }
}

class Dog extends Animal{

    bark(){
        console.log(`${this.name}在汪汪叫!`);
    }
}

const dog = new Dog('旺财', 4);
dog.bark();

  • 通过继承可以在不修改类的情况下完成对类的扩展

  • 重写

    • 发生继承时,如果子类中的方法会替换掉父类中的同名方法,这就称为方法的重写

    • 示例:

class Animal{
    name: string;
    age: number;

    constructor(name: string, age: number){
        this.name = name;
        this.age = age;
    }

    run(){
        console.log(`父类中的run方法!`);
    }
}

class Dog extends Animal{

    bark(){
        console.log(`${this.name}在汪汪叫!`);
    }

    run(){
        console.log(`子类中的run方法,会重写父类中的run方法!`);
    }
}

const dog = new Dog('旺财', 4);
dog.bark();

在子类中可以使用super来完成对父类的引用

super

class A {}
class B extends A {
  constructor() {
    super();  // ES6 要求,子类的构造函数必须执行一次 super 函数,否则会报错。在 constructor 中必须调用 super 方法,因为子类没有自己的 this 对象,而是继承父类的 this 对象,然后对其进行加工,而 super 就代表了父类的构造函数。super 虽然代表了父类 A 的构造函数,但是返回的是子类 B 的实例,即 super 内部的 this 指的是 B
    console.log(this)
  }
}

接口(Interface)

接口的作用类似于抽象类,不同点在于接口中的所有方法和属性都是没有实值的,换句话说接口中的所有方法都是抽象方法。接口主要负责定义一个类的结构,接口可以去限制一个对象的接口,对象只有包含接口中定义的所有属性和方法时才能匹配接口。同时,可以让一个类去实现接口,实现接口时类中要保护接口中的所有属性。

接口是一种规范的定义,它定义了行为和动作的规范,在程序设计里面,接口起到一种限制和规范的作用

使用interface关键字定义 接口一般首字母大写 有的编程语言中会建议接口的名称加上 I 前缀

  • 示例(检查对象类型):
interface IUser{
    name:String,
    showname():void
}

  • 示例(实现)

  • 接口使用:使用:号接口名来进行使用
    注意:定义的变量比接口少了一些属性是不允许的,多一些属性也是不允许的。赋值的时候,变量的形状必须和接口的形状保持一致。

interface IUser{
    name:String,
    showname():void
}
let user:IUser={
    name:"xixi",
    showname(){
        console.log(`名字是${this.name}`)
    }
}
console.log(user.name)
user.showname()

可选属性

可选属性:可选属性的含义是该属性可以不存在 有时候不要完全匹配一个接口,那么可以用可选属性。使用?

interface IUser{
    name?:String,
    showname():void
}
let user:IUser={
    // 因为name是可选属性所以可以不用定义
    showname(){
        console.log(`名字是${this.name}`)
    }
}
console.log(user.name)
user.showname()

泛型(Generic)

定义一个函数或类时,有些情况下无法确定其中要使用的具体类型(返回值、参数、属性的类型不能确定),此时泛型便能够发挥作用。

泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
举个例子:

function test(arg: any): any{
   return arg;
}

上例中,test函数有一个参数类型不确定,但是能确定的时其返回值的类型和参数的类型是相同的,由于类型不确定所以参数和返回值均使用了any,但是很明显这样做是不合适的,首先使用any会关闭TS的类型检查,其次这样设置也不能体现出参数和返回值是相同的类型
类中使用泛型:

class MyClass<T>{
    prop: T;

    constructor(prop: T){
        this.prop = prop;
  }
}

这里的<T>就是泛型,T是我们给这个类型起的名字(不一定非叫T),设置泛型后即可在使用T来表示该类型。所以泛型其实很好理解,就表示某个类型

十二

React与TS

创建项目 create-react-app 项目名 --template typescript

扩展 npx

创建项目:npx create-react-app 项目名 --template typescript

在 npm version >= 5.2.0 开始,自动安装了npx。

npx 这条命令会临时安装所依赖的环境。命令完成后原有临时下载的会删掉,不会出现在 全局中。下次再执行,还是会重新临时安装。不用全局安装,不用担心长期的污染。

也就是说 npx 会自动查找当前依赖包中的可执行文件,如果找不到,就会去 PATH 里找。如果依然找不到,就会帮你安装

组件

创建一个tsx后缀名的文件
在这里插入图片描述

在需要的位置引用使用 但是引用的时候可能会出错

在这里插入图片描述
在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9Pl0NMXH-1629292032678)(.\img\6.png)]

在引用时候不要加后缀名

在这里插入图片描述

数据传递

使用传统的方式进行数据传递的时候发现会报错

在这里插入图片描述
在这里插入图片描述

在进行数据传递的时候要使用 interface接口对类型限制
在子组件中进行限制设定

在这里插入图片描述

状态

直接定义状态会出现问题

在这里插入图片描述

需要使用接口

在这里插入图片描述

逆向传值

在这里插入图片描述
在这里插入图片描述

React 的核心概念之一是组件。在这里,我们将引用 React v16.8 以后的标准组件,这意味着使用 Hook 而不是类的组件。

组件的创建

FC就是FunctionComponent的缩写ts+react编写组件的语法


// 后面的<>是范型 中间的{}是没有props state占位的
export let Home:React.FC<{}>=()=>{
    return (
        <div>我事一个函数组件</div>
    )
}

props的使用

interface IUser{
    title?:String
}

export let Home:React.FC<IUser>=(props)=>{
        return (
            <div>我事一个函数组件---{props.title}</div>
        )
    }

父组件正常传递

HOOK

React Hooks是React 16.8.0版本推出的新特性 主要的作用就是让无状态组件 可以使用状态和react的其他特性。(在react开发中状态的管理是必不可少的 以前为了进行状态管理需要使用类组件或者redux等来管理)

Hook在class中没有作用

useState

useState()就是React提供最基础、最常用的Hook,主要用来定义和管理本地状态。

useState返回的是一个数组(长度为2),数组的第一个对象表示当前状态的值,第二个对象表示用于更改状态的函数,类似于类组件的setState。

let [val(当前状态的值),setVal(改变状态的函数)]=useState(当前状态的初始值)

import {useState} from "react"


 let Home:React.FC<{}>=()=>{
    //  创建状态
    let [text,setText]=useState("你好")
        return (
            <div>
                使用useState数据---{text}
            </div>
           
        )
    }
    export default Home

修改

import {useState} from "react"


 let Home:React.FC<{}>=()=>{
    //  创建状态
    let [text,setText]=useState("你好")
    let fun=():void=>{
        // 修改状态
        setText(text="你坏")
    }
        return (
            <div>
                使用useState数据---{text}
                <button onClick={fun}>点我修改</button>
            </div>
           
        )
    }
    export default Home

多个状态怎么办

1.声明对象类型的状态

 let Home:React.FC<{}>=()=>{
    //  创建对象类型状态
    let [text,setText]=useState({
        a:"第1",
        b:"第2",
        c:"第3",
    })
   
        return (
            <div>
                使用useState数据---{text.a}----{text.b}---{text.c}
            
            </div>
           
        )
    }
    export default Home

修改

import {useState} from "react"


 let Home:React.FC<{}>=()=>{
    //  创建对象类型状态
    let [text,setText]=useState({
        a:"第1",
        b:"第2",
        c:"第3",
    })
    let fun=():void=>{
        // 修改状态
        setText({...text,a:"我变了"})
    }
        return (
            <div>
                使用useState数据---{text.a}----{text.b}---{text.c}
                <button onClick={fun}>点我修改a</button>
            </div>
           
        )
    }
    export default Home

2.多次声明

按照传统的方式写多次即可

useRef

hooks中可以通过 useRef()获取Dom节点

import {useRef} from "react"


 let Home:React.FC<{}>=()=>{
  
    let u:any=useRef(null)
    let fun=():void=>{

      u.current.style.color="red"
    }
        return (
            <div>
                <p ref={u}>修改我的颜色</p>
                <button onClick={fun}>点我修改a</button>
            </div>
           
        )
    }
    export default Home

useEffect

useEffect:函数组件中没有生命周期,那么可以使用 useEffect 来替代。可以把 useEffect Hook 看做 componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合。

import {useEffect} from "react"


 let Home:React.FC<{}>=()=>{
    useEffect(()=>{
        console.log("执行了");  
    })
    
        return (
            <div>
                <p>执行了</p>
               
            </div> 
        )
    }
    export default Home

useReducer

useReducer和redux没有关系。它主要就是修改数据的 他就是加强版的useState在处理多数据修改的时候降低复杂度

创建数据


import {useReducer} from "react"

 
 let Home:React.FC<{}>=()=>{
    let reducer:any=(state:Number,action:Object):Number=>{
        return state
    }
    //    1.初始化数据
    // state代表数据
    // dispatch代表修改动作
    // reducer修改数据的任务
    // 1 是初始化数据
    let [state,dispatch]=useReducer(reducer,fu n f z z z z)
    
        return (
            <div>
                <p>我是组件--{state}</p>
             
            </div> 
        )
    }
    export default Home

修改数据


import {useReducer} from "react"

 
 let Home:React.FC<{}>=()=>{
    let reducer:any=(state:any,action:any):Number=>{
        switch (action.type) {
            case "ADD":
                return state+1
                break;
        
            default:
                break;
        }
        return state
    }
    //    1.初始化数据
    // state代表数据
    // dispatch代表修改动作
    // reducer修改数据的任务
    // 1 是初始化数据
    let [state,dispatch]:any=useReducer(reducer,1)
    
    let fun=():void=>{
        dispatch({type:"ADD"})
    }
        return (
            <div>
                <p>我是组件--{state}</p>
                <button onClick={fun}>+1</button>
            </div> 
        )
    }
    export default Home

=()=>{
let reducer:any=(state:Number,action:Object):Number=>{
return state
}
// 1.初始化数据
// state代表数据
// dispatch代表修改动作
// reducer修改数据的任务
// 1 是初始化数据
let [state,dispatch]=useReducer(reducer,fu n f z z z z)

    return (
        <div>
            <p>我是组件--{state}</p>
         
        </div> 
    )
}
export default Home



修改数据

```js

import {useReducer} from "react"

 
 let Home:React.FC<{}>=()=>{
    let reducer:any=(state:any,action:any):Number=>{
        switch (action.type) {
            case "ADD":
                return state+1
                break;
        
            default:
                break;
        }
        return state
    }
    //    1.初始化数据
    // state代表数据
    // dispatch代表修改动作
    // reducer修改数据的任务
    // 1 是初始化数据
    let [state,dispatch]:any=useReducer(reducer,1)
    
    let fun=():void=>{
        dispatch({type:"ADD"})
    }
        return (
            <div>
                <p>我是组件--{state}</p>
                <button onClick={fun}>+1</button>
            </div> 
        )
    }
    export default Home

十三

webpack

是什么

1.模块打包工具,可以分析项目结构,
2.根据模块与模块的关联 把项目从每一个单独的模块合并成一个整体
3.把浏览器不认识的项目编译成浏览器可以识别的项目 typescript less scss等变成浏览器可以识别的

webpack的核心:入口 出口 加载器 插件

webpack与gulp与grunt的区别

webpack和gulp并没有太大的可比性 gulp/grunt是一个优化前端开发的一个工具 但是webpack是一个模块化的构建方案 他可以把一个项目看成是一个整体 根据入口文件层层分析从而把这个模块化项目进行转换

基本使用

1.下载

webpack 核心文件

webpack-cli是它的命令行

npm install -g webpack@4.39.3 webpack-cli@3

2.写一个模块化的内容 让html引用 发现不能运行(新建一个文件夹,里面是js文件和HTML)
a.js

export let text="hellow wotdd";

export  let fun=()=>{
    return "方法"
}

b.js

import * as demoa from "./a.js"

console.log(demoa.text);
console.log(demoa.fun());

Html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./b.js"></script>
</head>
<body>
    
</body>
</html>

3.使用webpack进行编译

? 3-1cd到项目路径下

? 3-2 输入命令 webpack 你要打包的文件 -o 打包后的文件名字自己起

4.把生成的文件引导html中 发现即可使用

问题

上面打包完发现 报了一个警告

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for 
this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/

出现的原因是 webpack需要我们指定打包模式 是 生产模式 压缩(production) 还是开发模式 不压缩(development)
如何制定模式

webpack --mode development 你要打包的文件 -o 打包后的文件名字自己起

简单的打包命令

首先你要打包的文件位置 必须必须必须必须 在src文件夹下 其次打包的入口文件必须要index.js

命令只需要输入 webpack --mode development

会生成一个dist文件夹 其中main.js就是打包之后的内容

配置文件

配置文件的名字必须必须必须在根路径下

webpack.config.js

入口出口

入口是 entry 出口是 output

module.exports={
    // entry入口文件
    entry:"./src/index.js",
    output:{
        // 文件夹路径
        path:__dirname+"/dist",
        // 打包后的文件名
        filename:"aa.js"
    }
}

然后在终端输入webpack

一次打包多个文件怎么办?

module.exports={
    // entry入口文件
    // entry:"./src/index.js",
    // 打包多个文件
    entry:{
        aa:"./src/index.js",
        bb:"./src/indexb.js"
    },
    output:{
        // 文件夹路径
        path:__dirname+"/dist",
        // 打包后的文件名
        // filename:"aa.js"
        // 打包多个文件出口文件需要用[name]来配置
        filename:"new[name].js"
    }
}

模式

module.exports={
    // entry入口文件
    // entry:"./src/index.js",
    // 打包多个文件
    entry:{
        aa:"./src/index.js",
        bb:"./src/indexb.js"
    },
    output:{
        // 文件夹路径
        path:__dirname+"/dist",
        // 打包后的文件名
        // filename:"aa.js"
        // 打包多个文件出口文件需要用[name]来配置
        filename:"new[name].js"
    },
    // 指定打包模式
    mode:"development"
}

加载器

插件plugins

下载:npm install --save-dev clean-webpack-plugin

插件 扩展webpack的功能 插件是用来让webpack来做与构建项目无关的事情

clean-webpack-plugin

地址:https://www.npmjs.com/package/clean-webpack-plugin

html-webpack-plugin

把打包好的内容自动移入到html中 不需要我们手动操作

dev-server

开发服务器

下载: npm install -g webpack-dev-server@3

cd到当前项目下 使用webpack-dev-server启动 打开浏览器输入 localhost:8080

自动开启

// 配置devserver
    devServer:{
        open:true,
        port:8888
    }

打包多个文件、模式指定、插件、配置dev-server代码综合如下(配置文件的名字必须必须必须在根路径下:webpack.config.js)

//引入插件
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports={
    // entry入口文件
    // entry:"./src/index.js",
    // 打包多个文件
    entry:{
        aa:"./src/index.js",
        cc:"./src/indexb.js"
    },
    output:{
        // 文件夹路径
        path:__dirname+"/dist",
        // 打包后的文件名
        // filename:"aa.js"
        // 打包多个文件出口文件需要用[name]来配置
        filename:"new[name].js"
    },
    // 指定打包模式
    mode:"development",
    // 插件
    plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            template:"./public/index.html",
            filename:"index.html",//打包后生成的html
            title:"你好么么哒",
            // 设置压缩和去除注释
            minify:{
                collapseWhitespace: true,
            
                removeComments: true,
            }
        })
    ],
    // 配置devserver
    devServer:{
        open:true,
        port:8888
    }
}

十四

loaders 加载器

让webpack支持更多的文件 typescript less scss 等内容 对上述内容进行翻译 变成浏览器可以识别的

style-loader 与 css-loader

官网:https://webpack.docschina.org/loaders/style-loader/

在vue中使用:下载 npm install less less-loader --save-dev(如果效果不展示,则降低下载版本)

但是注意版本,如果不能正常展示的话,就降版本

"devDependencies": {
    "@vue/cli-plugin-babel": "~4.5.0",
    "@vue/cli-plugin-eslint": "~4.5.0",
    "@vue/cli-plugin-router": "~4.5.0",
    "@vue/cli-service": "~4.5.0",
    "babel-eslint": "^10.1.0",
    "eslint": "^6.7.2",
    "eslint-plugin-vue": "^6.2.2",
    
    "less": "^3.1.1",//在此处降版本
    "less-loader": "^7.0.1",//在此处降版本
    "vue-template-compiler": "^2.6.11"
  }
"devDependencies": {
    "@webpack-cli/serve": "^1.5.2",
    "clean-webpack-plugin": "^4.0.0-alpha.0",
    "css-loader": "^4.2.0",
    "html-webpack-plugin": "^5.3.2",
    "style-loader": "^2"
  }

vue中使用时

<style lang="less">
@demo:red;
h1{
  color: @demo;
}
</style>

less-loader sass-loader

babel-loader

vue-loader

因为浏览器不认识.vue文件 就是把template翻译成html style翻译成css script 翻译成js

问题

webpack 有什么作用

1.打包

2.合并代码 把分散的代码块打包成一个大文件 减少了http的请求次数可以优化代码的传输效率 优化代码的体积

3.有各种功能 比如less-loader 翻译less babel-lader可以翻译es代码 vue-loader可以翻译vue文件等等

webpack打包原理

webpack会把一个项目当成是一个整体 我们组需要设置一个主入口文件 webpack既可以从这个主入口文件中开始去寻找它所依赖的各个模块文件 并且使用各种loader来对文件进行翻译 配合着个中plugins来打包成一个或者多个浏览器可以识别的文件

1.解析配置文件 寻找webpack。config。js文件来进行解析

2 注册配置文件中的各个插件并且做出对应的反应

3.解析entry入口文件 并且找出关联文件

4.通过递归的方式来去寻找各个模块 然后根据对应的loader匹配文件 进行转换

5.生成转换文件

6output输出

小程序

什么是小程序

触手可及 用完即走
2016 年1月 张小龙提出微信小程序

2016年9月 内测

2017年1月 第一批小程序公测上线

优势

1.无需下载

2.运行速度非常快 近似于原生app

3.构建速度快

4 体积不能超过2mb

开发

1.你要有微信号

2.下载工具

文件结构

1.pages是写页面的 一个页面由4个文件构成

js 写逻辑的

json 写页面配置的

wxml 就是html

wxss 就是css

json文件

页面内json

局部页面配置

app.json

全局页面配置

pages

用于指定小程序由哪些页面组成,每一项都对应一个页面的 路径(含文件名) 信息。文件名不需要写文件后缀,框架会自动去寻找对应位置的 .json, .js, .wxml, .wxss 四个文件进行处理。

未指定 entryPagePath 时,数组的第一项代表小程序的初始页面(首页)。

小程序中新增/减少页面,都需要对 pages 数组进行修改。

创建页面、

在pages下创建一个文件夹 在文件家中创建4个文件.json, .js, .wxml, .wxss 四个文件 但是文件的名字必须和文件夹相同

window

用于设置小程序的状态栏、导航条、标题、窗口背景色。

属性类型默认值描述最低版本
navigationBarBackgroundColorHexColor#000000导航栏背景颜色,如 #000000
navigationBarTextStylestringwhite导航栏标题颜色,仅支持 black / white
navigationBarTitleTextstring导航栏标题文字内容
navigationStylestringdefault导航栏样式,仅支持以下值: default 默认样式 custom 自定义导航栏,只保留右上角胶囊按钮。参见注 2。iOS/Android 微信客户端 6.6.0,Windows 微信客户端不支持
backgroundColorHexColor#ffffff窗口的背景色
backgroundTextStylestringdark下拉 loading 的样式,仅支持 dark / light
backgroundColorTopstring#ffffff顶部窗口的背景色,仅 iOS 支持微信客户端 6.5.16
backgroundColorBottomstring#ffffff底部窗口的背景色,仅 iOS 支持微信客户端 6.5.16
enablePullDownRefreshbooleanfalse是否开启全局的下拉刷新。 详见 Page.onPullDownRefresh
onReachBottomDistancenumber50页面上拉触底事件触发时距页面底部距离,单位为 px。 详见 Page.onReachBottom
pageOrientationstringportrait屏幕旋转设置,支持 auto / portrait / landscape 详见 响应显示区域变化2.4.0 (auto) / 2.5.0 (landscape)
tabbar

https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html#tabBar

十五

组件

wxml(WeiXin Markup Langyage)微信开发出的一套标签语言
提供了很多的内置组件

view

布局容器 等同于div

属性类型默认值必填说明最低版本
hover-classstringnone指定按下去的样式类。当 hover-class="none" 时,没有点击态效果1.0.0
hover-stop-propagationbooleanfalse指定是否阻止本节点的祖先节点出现点击态1.5.0
hover-start-timenumber50按住后多久出现点击态,单位毫秒1.0.0
hover-stay-timenumber400手指松开后点击态保留时间,单位毫秒1.0.0

text

文本。它也支持转义字符 \n换行 \t空格

属性类型默认值必填说明最低版本
selectablebooleanfalse文本是否可选 (已废弃)1.1.0
user-selectbooleanfalse文本是否可选,该属性会使文本节点显示为 inline-block2.12.1
spacestring显示连续空格1.4.0
decodebooleanfalse是否解码[1.4.0](

space 的合法值

说明最低版本
ensp中文字符空格一半大小
emsp中文字符空格大小
nbsp根据字体设置的空格大小

Bug & Tip

  1. tip: decode可以解析的有 < > & '
  2. tip: 各个操作系统的空格标准并不一致。
  3. tip:text 组件内只支持 text 嵌套。

icon

icon

基础库 1.0.0 开始支持,低版本需做兼容处理

图标。组件属性的长度单位默认为px,2.4.0起支持传入单位(rpx/px)。

属性类型默认值必填说明最低版本
typestringicon的类型,有效值:success, success_no_circle, info, warn, waiting, cancel, download, search, clear1.0.0
sizenumber/string23icon的大小1.0.0
colorstringicon的颜色,同css的color

image

image组件默认宽度320px、高度240px 小程序的图片样式 不能设置auto

swiper(轮播)

<!--pages/login/login.wxml-->
<text>这是login</text>



<swiper autoplay="true" interval="1000" indicator-dots="true" duration="500" circular="true" indicator-color="red">
   <swiper-item>
       <image src="../../img/2547d64181711139.jpg"></image>
   </swiper-item>
   <swiper-item>
       <image src="../../img/0314ff88d49e71bc.jpg"></image>
   </swiper-item>
   <swiper-item>
       <image src="../../img/2547d64181711139.jpg"></image>
   </swiper-item>
   <swiper-item>
       <image src="../../img/2547d64181711139.jpg"></image>
   </swiper-item>
</swiper>

地图(map)

<map longitude="108.882526" latitude="34.22411">//输入经纬度

navigator

页面链接。

open-type :

navigate 默认值 保留当前页面 并且跳转到非tabbar的页面

redirect 关闭当前页面跳转带其他非tabbar的页面

reLaunch 关闭所有页面跳转带其他非tabbar的页面

switchTab 关闭当前页面跳转到tabbar页面

navigateBank 关闭当前页面 回退到上一个页面

更多

https://developers.weixin.qq.com/miniprogram/dev/component/cover-image.html

自定义组件

一个组件也是由 wxml wxss js json4个文件构成

1.新建components文件夹 并且创建组件文件夹 与4个文件

2.在想使用的page页面的JSON来引用

{
  "usingComponents": {
    "com":"../../components/com/com"
  }
}

3.自定义标签使用组件

组件的生命周期

生命周期参数描述最低版本
created在组件实例刚刚被创建时执行1.6.3
attached在组件实例进入页面节点树时执行1.6.3
ready在组件在视图层布局完成后执行1.6.3
moved在组件实例被移动到节点树另一个位置时执行1.6.3
detached在组件实例被从页面节点树移除时执行1.6.3
errorObject Error每当组件方法抛出错误时执行
组件的生命周期(在组件的.js中)
// component/component.js
Component({
    /**
     * 组件的属性列表
     */
    created(){
        console.log(122);
    },
    attached(){
        console.log("进入节点树执行");
    },
    ready(){
        console.log("视图布局完成后执行");
    },
    moved(){
        console.log("从组件实例被移到另一个节点");
    },
    error(){
        console.log("错误");
    },
    properties: {

    },

    /**
     * 组件的初始数据
     */
    data: {

    },

    /**
     * 组件的方法列表
     */
    methods: {

    }
})

```|                                                              |

## 组件传值
**正向**

在需要数据的组件的propertries中设置接收数据与数据类型
```js
/**
   * 组件的属性列表
   */
  properties: {
    title:String
  },

在子组件中直接使用

使用{{定义的接收变量}}

在父组件传递数据 和vue一样 直接传递

<zi title="我是传递给子组件的数据"/>

逆向

事件触发一个函数 ( bindtap 手指触摸后马上离开事件)调用函数的时候不加()加了就自动执行了

<button bindtap="fun">点我逆向传值</button>

在函数中进行自定义事件的抛出

 methods: {
    fun(){
      // 自定义事件抛出
      // this.triggerEvent("自定义事件名","数据")
      this.triggerEvent("zipao","我是子组件的数据")
    }
  }

在子组件被调用的地方 接收 bind:你抛出的自定义事件

<zi title="我是传递给子组件的数据" bind:zipao="fufun"/>

需要定义父组件的函数 并且设置形参

methods: {
    fufun(el){
      console.log(el.detail);
    }
  }

优化—纯数据字段

在一个程序中 变量数据分为两种 第一种需要在页面展示的 第二种 不需要在页面展示仅仅是为了临时处理而创造的 页面展示的数据需要更快的进行渲染 那么在这个时候 小程序在处理变量的时候 就可以 把这两种变量分开处理 先在加载的时候加载需要展示的变量 然后等页面加载完毕后在慢慢的处理第二种变量

我们就需要使用纯数据字段来告诉小程序那种是要展示的那种是临时处理数据的

component构造器的第一层级使用options其中设置pureDataPattern设置一个正则来告诉小程序谁是纯数据

options:{
    pureDataPattern:/^_/
  },
  /**
   * 组件的初始数据
   */
  data: {
    text:"我是text",
    _textb:"我是textb"
  },

那么_textb因为变成了纯数据字段 所以就不会在页面展示了

数据监听----observers

就是监听data中的数据改变

 // 监听
  observers:{
    // "你要监听的数据,你要监听的数据2"(第一个监听数据的新值,第2个监听数据的新值){}



    "title"(newtitle){
      console.log(newtitle);
    }
  },

修改data数据

setData()来修改data数据

 updata(){
      this.setData({
        title:"我变了"
      })
    }

behaviors

组件之间的代码共享 可以把一些重复使用的变量 方法 生命周期等内容独立出来 方便复用

1.新建文件夹与文件

2.编写代码

let behavior=Behavior({
  // 变量
  data:{
    demo:"我是复用的变量"
  },
  methods:{
    demofun(){
      console.log("我是复用的方法");
    }
  }
})
export {behavior}

3.哪里用 哪里引 并且使用

// 1.引用
import {behavior} from "../../behaviors/index.js"

// components/com/com.js
Component({
// 2.调用
  behaviors:[behavior],
  

4.想怎么用怎么用

<view>{{demo}}</view>

wxss

WXSS(WeiXin style Sheet) 样式文件

wxss具有css的大部分特性 到那时为了方便开发小程序 做了些细微的改变

尺寸单位

rpx 小程序中自适应的一个长度单位

怎么计算rpx呢?

美工给我了一个设计稿 是1px 那我应该设置多少rpx

官方建议我们使用IPhone6为设计原稿

750/屏幕宽度

rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。

设备rpx换算px (屏幕宽度/750)px换算rpx (750/屏幕宽度)
iPhone51rpx = 0.42px1px = 2.34rpx
iPhone61rpx = 0.5px1px = 2rpx
iPhone6 Plus1rpx = 0.552px1px = 1.81rpx

建议: 开发微信小程序时设计师可以用 iPhone6 作为视觉稿的标准。

样式导入

使用@import语句可以导入外联样式表,@import后跟需要导入的外联样式表的相对路径,用;表示语句结束

便利(数据在data中)

wx:for="{{你要便利的内容}}"

<view wx:for="{{arr}}">
  <!-- 默认情况下   值是item   下标是index -->
  {{item}}-----{{index}}
</view>




<!-- 修改item和index -->
<view wx:for="{{arr}}" wx:for-item="v" wx:for-index="i">
  <!-- 默认情况下   值是item   下标是index -->
  {{v}}-----{{i}}
</view>

API

二维码

https://developers.weixin.qq.com/miniprogram/dev/api/device/scan/wx.scanCode.html
组件中

<button bindtap="code">点我扫码</button>

函数(methods)中

  code(){
            wx.scanCode({
              onlyFromCamera: true,
              success(ok){
                console.log(ok);
              }
            })
        }

注意:代码部分完成后,点击真机调试,扫码进行后续操作,该功能需要结合手机实现,扫码可搜索草料二维码生成一个

打电话(同二维码)

组件中

<button bindtap="code">点我打电话</button>

函数(methods)中

  code(){
          
            wx.makePhoneCall({
                phoneNumber: '10000'
              })
        }

**该功能还是需要配合手机使用,在手机上点击 “点我打电话可打给对应的号码” **

十六

便利—block

就是在渲染多个节点的时候作为一个包含块 但是他不参与渲染 仅仅是包裹的作用

<block wx:for="{{arr}}">
  <text>{{item}}</text>
  <text>{{index}}</text>
</block>

便利—wx:key

当数据改变触发页面重新渲染的时候 他会比较带有key的内容 小程序会保证这些内容重新进行排列 而不是重新的创建 ,那么这样一来就会确保组件保持自身的状态 提高渲染效率

<block wx:for="{{arr}}" wx:key="index">
  <text>{{item}}</text>
  <text>{{index}}</text>
</block>

条件渲染

wx:if true 显示 false隐藏

<view wx:if="{{bool}}">我是测试wx:if</view>

wx:else 当wx:if的条件不满足的时候生效

<view wx:if="{{bool}}">我是测试wx:if</view>
<view wx:else>我是测试wx:else</view>

wx:elif 多重if结构

<view wx:if="{{1==2}}">我是测试wx:if</view>
<view wx:elif="{{2==3}}">elifa</view>
<view wx:elif="{{2==4}}">elifb</view>
<view wx:elif="{{2==2}}">elifc</view>

<view wx:else>我是测试wx:else</view>

微信小程序的条件渲染也支持block

属性变量

小程序中如果属性插变量 那么直接使用 属性="{{变量}}"

事件

什么是事件?

就是页面到逻辑的通信方式

事件分类

冒泡事件

冒泡事件使用bind修饰 当触发事件之后 这个事件会向父节点进行传递

非冒泡事件

非冒泡事件使用catch修饰 当触发事件之后 这个事件不会向父节点进行传递

事件列表

类型触发条件最低版本
touchstart手指触摸动作开始
touchmove手指触摸后移动
touchcancel手指触摸动作被打断,如来电提醒,弹窗
touchend手指触摸动作结束
tap手指触摸后马上离开
longpress手指触摸后,超过350ms再离开,如果指定了事件回调函数并触发了这个事件,tap事件将不被触发1.5.0
longtap手指触摸后,超过350ms再离开(推荐使用longpress事件代替)
transitionend会在 WXSS transition 或 wx.createAnimation 动画结束后触发
animationstart会在一个 WXSS animation 动画开始时触发
animationiteration会在一个 WXSS animation 一次迭代结束时触发
animationend会在一个 WXSS animation 动画完成时触发
touchforcechange在支持 3D Touch 的 iPhone 设备,重按时会触发1.9.90

事件对象

谁触发这个事件事件对象指向的就是谁

属性类型说明基础库版本
typeString事件类型
timeStampInteger事件生成时的时间戳
targetObject触发事件的组件的一些属性值集合
currentTargetObject当前组件的一些属性值集合

路由导航

声明式

navigator

编程式

https://developers.weixin.qq.com/miniprogram/dev/api/route/wx.reLaunch.html

路由导航传参

如果在小程序的页面之间进行参数传递的话 我们可以使用如下方式
声明式

//<navigator url="../要去的页面?key=value"></navigator》
<navigator url="../all/all?xiaoming=345"></navigator>

编程式

   wx.navigateTo({
      url: '../all/all?xiaoming=123',
    })     

接收:

只需要在你想接收的页面中找到

onLoad: function (options) {
    console.log(options);
  },

响应到页面

这里需要点击才能渲染到页面

// pages/all/all.js
Page({

    /**
     * 页面的初始数据
     */
    data: {
        title:"",
    },

    /**
     * 生命周期函数--监听页面加载
     */
    onLoad: function (options) {
        console.log(options);
    },
    fun(){
       this.setData({
           title:this.options.xixi
       })
    },
    /**
     * 生命周期函数--监听页面初次渲染完成
     */
    onReady: function () {

    },

    /**
     * 生命周期函数--监听页面显示
     */
    onShow: function () {

    },

    /**
     * 生命周期函数--监听页面隐藏
     */
    onHide: function () {

    },

    /**
     * 生命周期函数--监听页面卸载
     */
    onUnload: function () {

    },

    /**
     * 页面相关事件处理函数--监听用户下拉动作
     */
    onPullDownRefresh: function () {

    },

    /**
     * 页面上拉触底事件的处理函数
     */
    onReachBottom: function () {

    },

    /**
     * 用户点击右上角分享
     */
    onShareAppMessage: function () {

    }
})

页面中点击

<!--pages/all/all.wxml-->
<text>详情----{{title}}</text>

<button bindtap="fun">点击修改</button>

数据请求

// pages/all/all.js
Page({

    /**
     * 页面的初始数据
     */
    data: {
        title:"",
        arr:[],
    },

    /**
     * 生命周期函数--监听页面加载
     */
    onLoad: function (options) {
        console.log(options);
    },
    fun(){
       this.setData({
           title:this.options.xixi
       })
    },
    func(){
        let that=this
           wx.request({
             url: 'http://api.artgoer.cn:8084/artgoer/api/v1/user/324380/v3/topic/topicHomeByLabel?pageIndex=1&token=b544cd63-6d42-46fe-a96c-3cf96bae3113&topicId=62187',
             success(ok){
                 console.log(ok.data.data.commentList);
                 that.setData({
                    arr:ok.data.data.commentList
                  })
             }
           }) 
          
    },
    /**
     * 生命周期函数--监听页面初次渲染完成
     */
    onReady: function () {

    },

    /**
     * 生命周期函数--监听页面显示
     */
    onShow: function () {

    },

    /**
     * 生命周期函数--监听页面隐藏
     */
    onHide: function () {

    },

    /**
     * 生命周期函数--监听页面卸载
     */
    onUnload: function () {

    },

    /**
     * 页面相关事件处理函数--监听用户下拉动作
     */
    onPullDownRefresh: function () {

    },

    /**
     * 页面上拉触底事件的处理函数
     */
    onReachBottom: function () {

    },

    /**
     * 用户点击右上角分享
     */
    onShareAppMessage: function () {

    }
})

页面中触发(func函数)并且渲染

<button bindtap="func">点我发送请求</button>
<view wx:for="{{arr}}" wx:key="index">
    {{item.commentTxt}}
</view>

wx.request()

https://developers.weixin.qq.com/miniprogram/dev/api/network/request/wx.request.html

问题

我们的地址是没有问题的 但是出现一下错误

http://api.artgoer.cn:8084 不在以下 request 合法域名列表中,请参考文档:https://developers.weixin.qq.com/miniprogram/dev/framework/ability/network.html

怎么跳过域名验证

在小程序开发工具中点击 右上角详情-=----》项目设置 —》勾选 不校验合法域名即可

页面生命周期

交互

页面的弹框

https://developers.weixin.qq.com/miniprogram/dev/api/ui/interaction/wx.showToast.html

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-25 12:06:48  更:2021-08-25 12:08:28 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 6:41:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计