React

1. 概述

2. 安装配置

操作系统:MAC OS
开发工具:VS CODE

2.1 安装工具

  1. node
    官网下载安装:https://nodejs.org/en/
    安完后,就可以使用npm命令了

  2. cnpm

    npm命令下载的包,都是境外的,速度不够,可用cnpm命令从镜像下载
    命令:sudo npm install -g cnpm --registry=https://registry.npm.taobao.org --verbose

2.2 配置

  1. 创建目录A,用于后续练习操作

  2. 进入目录A,配置webpack

    1. 快速初始化,会创建一个package.json文件
      cnpm init -y
      image-20201029113552773

    2. 安装webpack及其客户端(用于打包)

      测试时发现最新版间有不兼容,导致运行web-dev-server时出错:Cannot find module 'webpack-cli/bin/config-yargs'
      这里给出一个版本匹配:
      	cnpm i webpack@4.44.2 webpack-cli@3.3.12 webpack-dev-server@3.11.0 -D
      安装最新版(不指定版本,可能会不兼容):
        cnpm i webpack webpack-cli webpack-dev-server -D
      

      image-20201029164257632
      这里的WARN 和 “gyp: No Xcode or CLT version detected!”,可以忽略

    3. 查看webpack版本
      $ node_modules/.bin/webpack -v

3. 开发使用

3.1 入门案例

  1. 在2.2节的目录A下创建:

    • 目录:src, dist (源代码、产品目录)
    • 文件:src/index.html, src/index.js, ./webpack.config.js

    index.js是打包入口路径

    webpack.config.js(若不配置,使用webpack打包时会报错):

    module.exports = {
        mode: "development",// 'development' or 'production'
    }
    // development为开发模式,不会压缩打包
    // production为产品模式,会压缩打包
    
  2. 首页index.html:

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="UTF-8">
        <title>first step</title>
        <script src="../../dist/main.js"></script>
    </head>
    
    <body>
        <h1>Home Page</h1>
    </body>
    
    </html>
    
  3. index.js:

    console.log("Hello,World!")
    
  4. 打包
    node_modules/.bin/webpack

    image-20201029113402131 会在./dist目录下,生产main.js文件 ![image-20201029114427678](https://star-pb.oss-cn-shanghai.aliyuncs.com/mkd/02_Java/03_%E5%89%8D%E7%AB%AF%E6%8A%80%E6%9C%AF/React/image-20201029114427678.png)
  5. 用浏览器打开index.html
    image-20201029114327638

3.2 自动打包

  1. 使用前面已安装的webpack-dev-server,可以实现自动打包

  2. 配置package.json
    添加运行脚本 "dev": "webpack-dev-server"
    image-20201029120338511

  3. 运行项目
    npm run dev
    image-20201029164515561

    上图给出了访问路径,打开它,看到的是项目目录:
    image-20201029164703414

    点击src目录:

    image-20201029171619741
  4. 此时修改index.js中打印日志的内容,发现网页控制台(Console)没有跟着变。
    因为webpack-dev-server将打包后的main.js放到了根目录,托管于内存,所以本地也是看不到的。
    修改index.html即可:
    image-20201029172120198

  5. webpack-dev-server命令,还支持很多参数

    • --open <browser_name>:自动打开浏览器,不指定名称时(如firefox),就是默认系统的浏览器
    • --port <prot_num>:指定运行端口
    • --hot:

3.3 首页内存化

我们在3.2节完成后,访问到的是项目目录,不是首页index.html。
下面,使用html-webpack-plugin实现自动打开首页。

  1. 安装html-webpack-plugin
    cnpm i html-webpack-plugin -D
    image-20201030110417180

  2. 修改webpack.config.js,添加插件的引用

    const path = require('path') // 引入路径
    const HtmlPlugin = require('html-webpack-plugin') // 引入html-webpack-plugin
    
    // 创建一个插件对象
    const htmlPlugin = new HtmlPlugin(
        {
            template: path.join(__dirname, './src/index.html'), // 指定来源文件
            filename: 'index.html' // 指定放到内存后的文件名
        }
    )
    
    module.exports = {
        mode: "development", // 'development' or 'production'
        plugins: [
            htmlPlugin // 配置插件
        ]
    }
    
    image-20201030111626935
  3. 运行项目: npm run dev

    此时可以自动打开首页index.html
    查看页面元素,可以发现body页签中多了一行,这是html-webpack-plugin所创建的脚本,所以,可以将前面自己定义的那行拿掉

    image-20201030111234513

3.4 React渲染

此小节介绍使用react完成页面的渲染

简单案例

  1. 安装react模块
    cnpm i react react-dom -S

  2. 修改index.html,添加一个div元素,并给定id
    image-20201030113555379

  3. 修改index.js,完成元素的创建及其渲染

    import React from 'react'
    import ReactDOM from 'react-dom'
    
    // 创建虚拟DOM元素
    // 参数1:字符串,元素类型
    // 参数2:对象,元素属性
    // 参数3:子节点
    // 参数n:其他子节点
    var myh3 = React.createElement('h3', { id: 'myh3' }, '只是个h3')
    
    // 渲染页面
    // 参数1:元素对象
    // 参数2:页面容器
    ReactDOM.render(myh3, document.getElementById('topDiv'))
    
  4. 运行项目,成功渲染:
    image-20201030113819955

元素嵌套

接着上面的案例,如果在topDiv下,同时存在一段文本,和一个h3标签,要怎么实现呢?

通过调用createElement第四个开始的参数即可

image-20201030114320905

效果:

image-20201030114350130

3.5 JSX语法

JSX语法:符合 xml 规范的 JS 语法,语法格式比HTML严谨很多

简单案例

3.4中讲述到的元素嵌套,需要我们手动创建一个元素对象,然后相互引用,最后再渲染。
这种方式可以更简化,我们直接写HTML即可。
简化方法需要通过babel工具完成转化,本质还是调用了createElement方法。

  1. 安装babel工具
    cnpm i @babel/core babel-loader @babel/plugin-transform-runtime -D
    cnpm i @babel/preset-env @babel/preset-stage-0 @babel/preset-react -D
    cnpm i @babel/plugin-proposal-class-properties -D

    ​ (不装最后一个会报错syntax 'class Properties' isn't currently enabled)

  2. 在项目根目录下创建babel的配置文件(json格式):.babelrc,来引用上面下载的工具

    {
        "presets": [
            "@babel/preset-env",
            "@babel/preset-react"
        ],
        "plugins": [
            "@babel/plugin-transform-runtime",
            "@babel/plugin-proposal-class-properties"
        ]
    }
    
  3. 修改index.js,直接使用HTML语言

    import React from 'react'
    import ReactDOM from 'react-dom'
    
    var mydiv = <div>只是个DIV</div>
    
    ReactDOM.render(mydiv, document.getElementById('topDiv'))
    
  4. 修改webpack.config.js,添加需要使用babel处理的规则:

    module.exports = {
        ...,
        // 配置第三方模块规则
        // webpack默认只打包js/jsx文件,png等无法处理
        module: {
            rules: [
                { test: /\.js|jsx/, use: 'babel-loader', exclude: /node_modules/ }
            ]
        }
    }
    

    test: 表示判定规则,这里是js、jsx结尾的文件
    use: 使用babel-loader处理
    exclude: 排除的文件(夹)

  5. 运行项目:
    image-20201030141828194

JSX中使用JS

如何在JSX中渲染变量呢?
使用花括号{}

import React from 'react'
import ReactDOM from 'react-dom'

var title = "啦啦啦"
var num = 2
var bool = false
var arrayOne = ["成龙", "李小龙", "释小龙"]
var arrayFinal = [];
arrayOne.forEach(item => {
    let temp = <h4>{item}</h4>
    arrayFinal.push(temp)
})

ReactDOM.render(<div>tttt<hr />
    
    <h3 title={title}>猜标题</h3><hr />
    
    <h3>{num * 10}</h3><hr />
    
    <h3>{bool ? "不是啊" : "是啊"}</h3><hr />
    
    {arrayFinal}<hr />
    
    {arrayOne.map(item => { return <h5>{item}</h5> })}<hr />
    
    {arrayOne.map(item => <h5>{item}</h5>)}
</div>, document.getElementById("topDiv"))

注意点

  • JSX中创建DOM时,必须由唯一根元素包裹
  • JSX中的标签必须成对,或自闭和,如<hr/>

3.6 组件

下面介绍两种创建组件的方式

JS对象

简单案例

​ 直接使用标签引用JS对象,即完成了组件化
​ JS对象必须有返回值

import React from 'react'
import ReactDOM from 'react-dom'

function Hello() {
    return <h3>Hello</h3>
}

ReactDOM.render(<div><Hello></Hello></div>, document.getElementById("topDiv"))
属性传递

​ 如何向组件传递属性呢?

import ...

function Hello(id) {
  	console.log(id)
    return <h3>Hello</h3>
}

ReactDOM.render(<div><Hello id="hello"></Hello></div>, document.getElementById("topDiv"))

​ 若属性很多,可以采用下示方法(...<对象>):

import ...

function Hello(props) {
  	console.log(props)
    return <h3>Hello</h3>
}

var dog = {
  	this.name: "阿黄",
  	age: 3
}

ReactDOM.render(<div><Hello ...dog></Hello></div>, document.getElementById("topDiv"))
组件抽离

​ 一般会将一个组件单独的抽离为一个文件,然后再引用即可。

  1. 创建./src/components/Hello.js

    import React from 'react'
    
    export default function Hello(props) {
        console.log(props)
        return <h3>Hello</h3>
    }
    
  2. 修改index.js

    import React from 'react'
    import ReactDOM from 'react-dom'
    import Hello from './components/Hello'
    
    var student = {
        name: "学生呢",
        age: 20,
        grade: 1
    }
    
    ReactDOM.render(<div><Hello {...student}></Hello></div>, document.getElementById("topDiv"))
    

    使用import,导入Hello.js

  3. 如果我们新建的组件文件名为Hello.jsx,在项目启动后就会报错,找不到该文件.
    需要在webpack.config.js中配置处理规则:

    module.exports = {
        ...,
        resolve: {
            extensions: [
                '.jsx', '.js',
            ]
        }
    }
    

    会按这里配置的扩展名,依次查找。

    或者在import时,就指定扩展名 import Hello from './components/Hello.jsx'

  4. 设置根目录
    在导入组件时,也可使用绝对路径

    • 修改webpack.config.js,指定路径别名

      module.exports = {
          ...,
          resolve: {
              ...,
              alias: {
                  '@': path.join(__dirname, './src')
              }
          }
      
    • 在导入时,使用别名@
      import Hello from '@/components/Hello'

属性/方法
function Teacher(name, age) {
    this.name = name // 实例属性
    this.age = age // 实例属性
}

Teacher.school = "宁海"  // 静态属性
console.log(Teacher.school)

var teacher = new Teacher("李老师", 22)
console.log(teacher)

// 实例方法
Teacher.prototype.teach = function () {
    console.log(this.name + "教学ing...")
}
teacher.teach()

// 静态方法
Teacher.teach = function () {
    console.log("教学ing...")
}
Teacher.teach()

​ 实例对象不能访问静态属性及方法

class对象

为了更方便开发,诞生了class关键字,其本质还是被转成上面的JS对象被处理

属性/方法

​ 有点类似java类
​ 在class内部,只能编写 构造器、静态属性、实例方法、静态方法

class Student {
  	// 构造器,初始化实例属性
    constructor(name, age) {
        this.name = name
        this.age = age
    }

  	// 静态属性
    static school = "宁海"

		// 实例方法
    study() {
        console.log(this.name + "学习ing...")
    }

		// 静态方法
    static study() {
        console.log("学习ing...")
    }
}

var student = new Student("小明", 10)

console.log(Student.school)
console.log(student)
student.study()
Student.study()
继承

class之间可以继承,与java一致

class Person {
    constructor(name, age) {
        this.name = name
        this.age = age
    }
}

class Student extends Person {
    constructor(name, age, school) {
        super(name, age)
      	this.school = school
    }
}

var student = new Student("小明", 10, '宁海')

console.log(student)
  • 继承关键字: extends
  • 要调用父类方法,需通过super关键字
  • super必须在this前面调用
创建组件

使用class关键字创建组件的规范:

// 继承Component
class <组件名> extends React.Component {
  // 必需有render方法
  render(){
    // 必需有返回值
    return ...
  }
}

示例

import React from 'react'
import ReactDOM from 'react-dom'

class Student extends React.Component {
    constructor(name, age) {
        this.name = name
        this.age = age
    }

    render() {
        return <h4>学习a </h4>
    }
}

var student = new Student("小明", 10)
console.log(student)

ReactDOM.render(<div><Student></Student></div>, document.getElementById("topDiv"))

image-20201030152400958

属性传递

与JS对象类似,不过class有个属性props,专门用来接收所有外部属性

import React from 'react'
import ReactDOM from 'react-dom'

class Student extends React.Component {
    constructor() {
        super()
    }

    render() {
        console.log(this)
        return <div><h4>学习a</h4><h4>{this.props.name + ":" + this.props.sex}</h4></div>
    }
}

var teacher = {
    name: "李老师",
    sex: "man"
}

ReactDOM.render(<div><Student {...teacher}></Student></div >, document.getElementById("topDiv"))
image-20201102215336515
this.state

前面介绍的属性传递,是外部向class传递属性。
如果需要定义class自己的属性,可以通过this.state实现

import React from 'react'
import ReactDOM from 'react-dom'

class Student extends React.Component {
    constructor() {
        super()
        this.state = {
            firstMsg: 'Welcome!'
        }
    }

    render() {
        console.log(this.state.firstMsg)
        return <div><h4>学习a</h4></div>
    }
}

ReactDOM.render(<div><Student></Student></div >, document.getElementById("topDiv"))
image-20201102220031096

<div onKeyDown={(e) => this.doEnter(e)}>
            <h1>Login</h1>
    <div className="form">
                <div className="item">
                    <i className="fa fa-user-circle-o" aria-hidden="true" />
                    <input type="text" placeholder="Username" ref="username" />
                </div>
                <div className="item">
                    <i className="fa fa-key" aria-hidden="true" />
                    <input type="password" placeholder="Password" ref="password" />
                </div>
            </div>
            <button onClick={() => this.doLogin()}>Login</button>
        </div>
posted @ 2022-12-29 21:46  水木夏  阅读(68)  评论(0编辑  收藏  举报