JSX语法

本文共--字 阅读约--分钟 | 浏览: -- Last Updated: 2021-05-26

JSX:在JS中可以混合写入HTML,用于简化React.createElement()方法创建虚拟DOM。但是本质上还是转换成了React.createElement()的形式,只是简化了开发人员的写法。

如何启用JSX语法

1、安装依赖

npm i babel-core babel-loader babel-plugin-transform-runtime -D

npm i babel-preset-env babel-preset-stage-0 -D # preset:语法

# 用来将jsx语法转换成React.createElement()的形式
npm i babel-preset-react -D

2、配置webpack.config.js

// 因为webpack只能打包处理.js文件 像.vue .png无法主动处理 所以需要配置第三方loader

module.exports= {
  // ...
  module: {
    rule: [
      {
        test: /\.js|jsx$/, // 应用在哪些文件
        use:'babel-loader', // 使用哪种loader 多个用数组表示
        exclude:'/node_modules/' // 排除项
      }
    ]
  }
}

3、在项目根目录中创建babel.config.js文件。

module.exports = {
  "presets": ["env","stage-0","react"],
  "plugins": ["transform-runtime"]
}

4.在index.js文件中使用,底层会被babel转换成React.createElement()的形式

var myDiv = <div id="myDiv">这是一个div</div>

// 或者在render函数之中直接使用
ReactDOM.render(
  <div>
    hello wrold
  </div>, document.getElementById('app'))

使用jsx语法

1、使用变量 用大括号包住

let a = 1;
let bool = true;
// 属性使用变量
let str = "这是一个title"
//使用元素
const myh1 = <h1>hello wrold</h1>;

// 使用元素数组
const arr = [
  <h2>this is h2</h2>,
  <h3>this is h3</h3>
]

ReactDOM.render(
  <div>
    { a + 2 }
    <hr/>
    <p title={str}>{ bool ? '真' : '假' }</p>
    <hr/>
    { myh1 }
    <hr/>
    { arr }
  </div>, document.getElementById('app'))

2、在jsx中使用for循环

const arr = ['111','222','333'];

//省略了return 
ReactDOM.render(<div>
  {
    arr.map(item=><h1 key={item}> { item } </h1>) 
  }
</div>, document.getElementById('app'))

3、使用class属性 或者label标签的for属性时

// 为了避免关键字 应该这么使用 className代替class htmlFor代替for
ReactDOM.render(<div>
  <p className="red">1111</p>
  <label htmlFor="name"></label>
</div>, document.getElementById('app'))

创建组件

1、第一种,直接创建

// 在组件构造函数中 使用props形参来接受 形参可以随意取名 但是建议使用props 组件名称首字符必须是大写
function Hello (props){
  // 必须要有return 如果不想渲染任何东西也要return null

  // 常规需要return一个合法的虚拟DOM元素

  // props 都是只读的
  // props.name = 'timo' 报错
  return  <div>hello world {props.name} say {props.hello}</div>
}

const dog = {
  name: "旺财",
  say: "wangwang"
}

// 在组件中传递数据
ReactDOM.render(<div>
  <Hello name={dog.name} hello={dog.say}></Hello>
</div>, document.getElementById('app'))

// 使用...扩展运算符来简化
ReactDOM.render(<div>
  <Hello {...dog}></Hello>
</div>, document.getElementById('app'))
// 这样写之后 就不能使用props.hello去接受 一定要使用props.say

2、第二种,抽离组件为单独的jsx文件

// ./src/components/Hello.jsx
// 在单独的组件文件中必须要导入React
import React from 'react'

export default function Hello (props) {
  return  <div>hello world {props.name} say {props.hello}</div>
}

// 在webpack.config.js中配置resolve可以省略后缀 和src别名
// {
//     resolve:{
//         extensions:['.js','.jsx'],
//         alias:{
//          '@':path.join(__dirname,'./src')
//         }
//     }
// }

// index.jsx 在使用的地方导入
import Hello from '@/components/Hello'

const dog = {
  name: "旺财",
  say: "wangwang"
}

ReactDOM.render(<div>
    <Hello {...dog}></Hello>
</div>, document.getElementById('app'))

3、使用class创建组件 + 传值

// index.jsx
import React, { Component } from 'react'
import ReactDOM from 'react-dom'

class App extends Component {
  // render作用于渲染当前组件对应的虚拟DOM结构

  // 在class中如果要使用传递过来的数据 不需要使用形参props
  // 直接使用this.props.xxx
  // this表示当前组件的实例对象
  render(){
    // 一定要有return
    return <div>hello wrold {this.props.name}</div>
  }
}

const obj = {
  name: "aaa",
  age: 10
}

ReactDOM.render(<div>
  <App {...obj}></App> 
</div>, document.getElementById('app'))

// 这里的App标签就相当于是App类的一个实例对象

4、创建组件的区别

// 使用class创建的组件有自己的私有数据和生命周期函数--有状态组件
// 使用function创建的组件 没有自己的私有数据和生命周期函数 -- 无状态组件
// 无状态组件会比有状态组件运行效率高一点 但是使用不多


class App extends Component {
  constructor(){
    super()
    this.state = {
      msg: '' // 相当于vue中的data(){return { msg:''}}
    }
  }
  render(){
    this.state.msg = 'hi' // 可以修改 但是props在哪都不能修改
    return <div>
      hello wrold {this.props.name}
      <hr/>
      {this.state.msg}
    </div>
  }
}

const obj = {
  name: "aaa",
  age: 10
}

ReactDOM.render(<div>
    <App {...obj}></App> 
</div>, document.getElementById('app'))

propsstate之间的区别

  • props 都是从外界传递过来的,都是只读的
  • state 都是组件私有的或者请求后台得到的,可读可写

使用组件

import React,{ Component } from 'react'
import ReactDOM from 'react-dom'

class CmtList extends Component {
  constructor() {
    super()
    this.state = {
      list:[
        {id:1,name:'zhangsan',age:18},
        {id:2,name:'lisi',age:19},
        {id:3,name:'wangwu',age:20},
      ]
    }
  }

  render() {
    return (
      <div>
        <h1>这是一个列表</h1>
        {
          this.state.list.map(item=><div key={item.id}>
            <h1>{item.name}</h1>
            <h2>{item.age}</h2>
        </div>)
        }
      </div>
    )
  }
}

ReactDOM.render(<div>
  <CmtList></CmtList> 
</div>, document.getElementById('app'))

1、在上面的基础上进行抽离为父子组件

import React,{ Component } from 'react'
import ReactDOM from 'react-dom'

class CList extends Component{
  render(){
    return (
      <div>
        <h1>{ this.props.name}</h1>
        <h2>{ this.props.age}</h2>
      </div>
    )
  }
}

// 这里的CList 没有状态 可以使用无状态组件来提高运行效率 但是一般不用
// function CList (props) {
//   // 需要使用形参props
//   return (
//     <div>
//       <h1>{ props.name}</h1>
//       <h2>{ props.age}</h2>
//     </div>
//   )
// }

class CmtList extends Component {
  constructor(){
    super()
    this.state = {
      list:[
        {id:1,name:'zhangsan',age:18},
        {id:2,name:'lisi',age:19},
        {id:3,name:'wangwu',age:20},
      ]
    }
  }

  render(){
    return (
      <div>
        <h1>这是一个列表</h1>
        {
          this.state.list.map(item=><CList {...item} key={item.id}></CList>)
        }
      </div>
    )
  }
}

ReactDOM.render(<div>
  <CmtList></CmtList> 
</div>, document.getElementById('app'))

2、把子组件抽离出去 并使用样式

// CList.jsx
import React, { Component } from 'react'
import ReactDOM from 'react-dom'

// 也可以使用一个样式对象的变量
const h2Style = { color:'grenen', fontSize:"20px" }

class CList extends Component{
  render() {
    // 行内样式不能像vue那样在template中直接使用 style="color:red;font-size:25px"
    // 在jsx语法中 要使用双大括号包着 传递一个对象
    // zIndex这种可以直接传数字
    return (
      <div>
        <h1 style= {{ color:'red', fontSize:"25px", zIndex:1 }}>{ this.props.name }</h1>
        <h2 style= { h2Style }> { this.props.age }</h2>
      </div>
    )
  }
}
export default CList

// CmtList.jsx
import React,{ Component } from 'react'
import ReactDOM from 'react-dom'
import CList from '@/components/CList'

class CmtList extends Component {
  constructor(){
    super()
    this.state = {
      list:[
        {id: 1, name: 'zhangsan', age:18},
        {id:2, name:'lisi', age:19 },
        {id:3, name: 'wangwu', age:20 },
      ]
    }
  }

  render() {
    return (
      <div>
        <h1>这是一个列表</h1>
        {
          this.state.list.map(item=><CList {...item} key={item.id}></CList>)
        }
      </div>
    )
  }
}

3、或者直接将样式对象抽离处理为一个js文件

// style.js

export default {
  h1Style: {
    color:"red"
  },
  h2Style: {
    color:"green"
  }
}

// CList.jsx
import React,{Component} from 'react'
import ReactDOM from 'react-dom'
import myStyle from './style.js' 

class CList extends Component{
  render(){
    return (
      <div>
        <h1 style= {myStyle.h1Style}>{ this.props.name}</h1>
        <h2 style= {myStyle.h2Style}>{ this.props.age}</h2>
      </div>
    )
  }
}
export default CList

4、抽离为css来使用样式

a) 安装 loader

npm i style-loader css-loader -D

b) 配置webpack.config.js

module.exports = {
  module:{
    rules:[
      // ...
      { test: /\.css$/, use: 'style-loader','css-loader'] }
      // 从右到左调用loader进行处理 
    ]
  }
}

c) 使用

/* style.css */
@import './dist/antd.css'; /* 导入第三方样式 */
 
.h1Class {
  color:"red",
  font-size:"25px"
}

.h2Class {
  color:"red",
  font-size:"25px"
}
// CList.jsx
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import './style.css'
// 在单个组件引入的样式表 也会变成全局的 因为样式没有模块作用域

class CList extends Component{
  render(){
    return (
      <div>
        <h1 className="h1Class">{ this.props.name}</h1>
        <h2 className="h2Class">{ this.props.age}</h2>
      </div>
    )
  }
}
export default CList

d) 使用模块化的css 类似于vue中的scope

// 配置webpack.config.js 中的module 给loader加参数?modules
// ?modules&[path]-[name]-[local]-[hash:5] 其他参数

// :global(.test){ color:'black' } 
// 用global包起来的类会作用于全局不再被模块化
module.exports = {
  module:{
    rules:[
      // ...
      { test: /\.css$/, use: ['style-loader','css-loader?modules'] }
      // 从右到左调用loader进行处理 
    ]
  }
}

其他位置的修改

/* style.css */
.h1Class {
  color:"red",
  font-size:"25px"
}

.h2Class {
  color:"green",
  font-size:"20px"
}

#myH3 {
  color:'blue'
}
// CList.jsx
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import cssObj from './style.css'
// 用变量来接受  定义的类 会出现在这个变量的属性上
// 实现私有化属性 
// css模块化 只针对类选择器 和 ID选择器

// 引入第三方类
import bootstrapCss from 'bootstrap/dist/css/bootstrap.css'

// 但是引入第三方类 写法太麻烦 
// 可以自己的样式表使用.scss来写 因为第三方的都是.css
// 给.scss配置模块化参数就行了 
// 使用.scss需要安装 npm i sass-loader node-sass -D
// 然后配置webpack.config.js中module的rule
// {t est:/\.scss$/, use:['style-loader','css-loader','sass-loader'] }

class CList extends Component{
  render() {
    return (
      <div>
        <h1 className={cssObj.h1Class}>{ this.props.name}</h1>
        <h2 className={cssObj.h2Class}>{ this.props.age}</h2>
        <h3 id={cssObj.myH3}>Test !!!</h3>
        <button className={[bootstrapCss.btn,bootstrapCss['btn-primary']].join(' ')}></button>
    </div>
    )
  }
}
// 如果两个类 className = {cssObj.h1class + ' test'} 第二个类要加一个空格
// 或者 className = {[cssObj.h1class,'test'].join(' ')} 使用数组join方法
export default CList