侧边栏壁纸
博主头像
woku博主等级

成功的路上并不拥挤

  • 累计撰写 50 篇文章
  • 累计创建 13 个标签
  • 累计收到 3 条评论

JSX

woku
2022-07-19 / 0 评论 / 0 点赞 / 117 阅读 / 6,803 字

JSX是什么

const rEl = <h2 className="my-h2">this is a jsx experience</h2>
ReactDOM.render(rEl, document.getElementById('app'))

上面的rEl就是一段JSX

  • 一种标签语法,JS进行的语法扩展(在JS文件中写类似HTML结构)
  • 不是字符串,也不是HTML
  • 描述UI呈现与交互的直观体现
  • 生成React元素

createElement与JSX的对比

  • 使用createElement创建React元素
const rEl = React.createElement('h2', {
  className: 'my-h2'
}, 'this is a jsx experience')
ReactDOM.render(rEl, document.getElementById('app'))
  • 使用JSX创建React元素
const rEl = <h2 className="my-h2">this is a jsx experience</h2>
ReactDOM.render(rEl, document.getElementById('app'))

使用JSX的方式更简洁,更直观,更利于维护和开发

JSX的简单使用

class MyButton extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      count: 0
    }
  }
  addCount = () => {
    this.setState({
      count: this.state.count + 1
    })
  }
  render() {
    return (
      <div className="wrapper">
        <p className="num">{ this.state.count}</p>
        <button onClick={this.addCount}>增加1</button>
      </div>
    )
  }
}

ReactDOM.render(React.createElement(MyButton),
 document.getElementById('app')
)

为什么React不把视图标记和逻辑分开呢?

  1. 渲染和UI标记是有逻辑耦合(放在一起能直观的体现视图和逻辑之间的关系)
  2. 即使是这样的耦合,也能实现关注点的分离(render函数和其他的逻辑部分还是分开了的)

JSX在编译后,会转成React元素,然后是一个普通的对象

const rEl = <h2 className="my-h2">this is a h2</h2>
const rEl2 = React.createElement('h2', {
  className: 'my-h2'
}, 'this is a h2')
console.log(rEl)
console.log(rEl2)

转成普通的对象
image.png

JSX中的插值表达式

在jsx中可以在{}来使用js表达式
表达式:一切有效的,符合JS编程逻辑的表达式

  • 基本使用
const name = 'zs'
const age = 18
const title = (
  <h1>
    姓名:{name}, 年龄:{age}
  </h1>
)
  • 可以访问对象的属性
const car = {
    brand: '玛莎拉蒂'
}
const title = (
  <h1>
    汽车:{car.brand}
  </h1>
)
  • 可以访问数组的下标
const friends = ['张三', '李四']
const title = (
  <h1>
    汽车:{friends[1]}
  </h1>
)
  • 可以使用三元运算符
const gender = 18
const title = (
  <h1>
    性别:{age >= 18? '是':'否'}
  </h1>
)
  • 可以调用方法
function sayHi() {
  return '你好'
}
const title = <h1>姓名:{sayHi()}</h1>
  • JSX本身
const span = <span>我是一个span</span>
const title = <h1>盒子{span}</h1>
  • JSX中的注释
{/* 这是jsx中的注释 */}   推荐快键键 ctrl + /
  • 不要出现语句,比如if for

条件渲染

在react中,一切都是javascript,所以条件渲染完全是通过js来控制的

  • 通过判断if/else控制
const isLoding = false
const loadData = () => {
  if (isLoding) {
    return <div>数据加载中.....</div>
  } else {
    return <div>数据加载完成,此处显示加载后的数据</div>
  }
}

const title = <div>条件渲染:{loadData()}</div>
  • 通过三元运算符控制
const isLoding = false
const loadData = () => {
  return isLoding ? (
    <div>数据加载中.....</div>
  ) : (
    <div>数据加载完成,此处显示加载后的数据</div>
  )
}
  • 逻辑运算符
const isLoding = false
const loadData = () => {
  return isLoding && <div>加载中...</div>
}

const title = <div>条件渲染:{loadData()}</div>

综合练习:

class Login extends React.Component {
  constructor(props) {
    super(props)
  }
  state = {
    userName: '',
    password: ''
  }
  changeUserName = e => {
    this.setState({
      userName: e.target.value,
    })
  }
  changePassword = e => {
    this.setState({
      password: e.target.value
    })
  }
  doLogin = () => {
    const { userName, password } = this.state
    if (!userName || !password) {
      alert('用户名密码不能为空')
      return
    }
    this.props.login(userName, password)
  }
  render() {
    return (
      <div>
        <p>用户名</p>
        <input type="text" onChange={this.changeUserName}/>
        <p>密码</p>
        <input type="password" onChange={this.changePassword}/>
        <button onClick={this.doLogin}>登录</button>
      </div>
    )
  }
}
class Welcome extends React.Component {
  constructor(props) {
    super(props)
  }
  render() {
    return (
      <div>
        <h2>欢迎您,尊敬的用户</h2>
        <button onClick={this.props.loginOut}>退出登录</button>
      </div>
    )
  }
}
class Tip extends React.Component {
  constructor(props) {
    super(props)
  }
  render() {
    return (
      <div>
        {
           this.props.isShowTip ? <p>this is a tip</p> : null
        }
      </div>

    )
  }
}
class App extends React.Component {
  constructor(props) {
    super(props)
  }
  state = {
    isLogin: false,
    count: NaN,
    isShowTip: false
  }
  login = (userName, password) => {
    if (userName === '123' && password === '123') {
      this.setState({
        isLogin: true
      })
    } else {
      alert('用户名密码错误')
    }
  }
  loginOut = () => {
    this.setState({
      isLogin: false
    })
  }
  render() {
    const { isLogin, count, isShowTip } = this.state
    return (
      <div>
        {/* 如果是0和NaN会显示出来0和NaN,不会显示后面的标签
        可以使用toString来转换 */}
        { count && <p>count为{ count }</p> }
        { count.toString() && <p>count为{ count }</p> }
        { isLogin && <p>欢迎欢迎呀~~~</p>}
        {
          isLogin ? <Welcome loginOut={this.loginOut}/> : <Login login={this.login} />
        }
        <Tip isShowTip={ isShowTip }/>
      </div>
    )
  }
}
ReactDOM.render(<App />, document.getElementById('app'))



列表渲染

我们经常需要遍历一个数组来重复渲染一段结构

在react中,通过map方法进行列表的渲染

  • 列表的渲染
const songs = ['温柔', '倔强', '私奔到月球']

const list = songs.map(song => <li>{song}</li>)

const dv = (
  <div>
    <ul>{list}</ul>
  </div>
)
  • 直接在JSX中渲染
const songs = ['温柔', '倔强', '私奔到月球']

const dv = (
  <div>
    <ul>{songs.map(song => <li>{song}</li>)}</ul>
  </div>
)
  • key属性的使用
const dv = (
  <div>
    <ul>
      {songs.map(song => (
        <li key={song}>{song}</li>
      ))}
    </ul>
  </div>
)

注意:列表渲染时应该给重复渲染的元素添加key属性,key属性的值要保证唯一

注意:key值避免使用index下标,因为下标会发生改变

样式处理

行内样式-style

const dv = (
  <div style={{ color: 'red', backgroundColor: 'pink' }}>style样式</div>
)

类名-className

// 导入样式
import './base.css'
const dv = <div className="title">style样式</div>

base.css样式文件

.title {
  text-align: center;
  color: red;
  background-color: pink;
}

动态控制className

如果className是动态的

import ReactDOM from 'react-dom/client';
import './index.css'
const isRed = false
const element = (
  <ul>
    <li>
       <div className={isRed ? 'red box' : 'box'}>aaa</div>
    </li>
  </ul>
)
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(element);

在上面的结构中,red这个类名是根据isRed来控制的,如果isRed为真,则具有red这个类,为假则没有。
box类名,不管isRed是真还是假,都会有。

也可以这样写:


import ReactDOM from 'react-dom/client';
import './index.css'
const isRed = false
const element = (
  <ul>
    <li>
       <div className={`${isRed ? 'red': ''} box`}>aaa</div>
    </li>
  </ul>
)
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(element);


box类名不用写2次。

相比于vue来说,react的这种完全由js控制的类名的写法相对较繁琐。(如果有多个动态类名)
我们可以使用

<div className={{'box': true, 'red': isRed, 'pink': isPink}}>aaa</div>

react本身是不支持这种写法的

封装classNames方法


import ReactDOM from 'react-dom/client';
import './index.css'
const isRed = true
const isPink = true
function classNames(obj) {
  return Object.keys(obj).filter(x => obj[x]).join(' ')
}
const element = (
  <ul>
    <li>
       <div className={classNames({'box': true, 'red': isRed, 'pink': isPink})}>aaa</div>
    </li>
  </ul>
)
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(element);


使用第三方库classnames

  • npm i classnames

import ReactDOM from 'react-dom/client';
import classNames from 'classnames';
import './index.css'
const isRed = true
const isPink = true
const element = (
  <ul>
    <li>
       <div className={classNames('box', {red: isRed, pink: isPink})}>aaa</div>
    </li>
  </ul>
)
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(element);


项目中,大量处理类名的才使用这个classnames库

注意

在render之前
所有的JSX都会转成字符串
所有输入的内容都会进行转义

  • JSX必须要有一个根节点, <></>  <React.Fragment></React.Fragment>
  • 没有子节点的元素可以使用/>结束
  • JSX中语法更接近与JavaScript
    • class =====> className
    • for========>  htmlFor
  • JSX可以换行,如果JSX有多行,推荐使用()包裹JSX
0

评论区