返回顶部
首页 > 资讯 > 前端开发 > 其他 >Vue中什么是JSX?什么时候用?怎么用?
  • 461
分享到

Vue中什么是JSX?什么时候用?怎么用?

JSX前端Vue.jsJavaScript 2023-05-14 21:05:15 461人浏览 泡泡鱼
摘要

Vue中什么是jsX?下面本篇文章给大家了解一下Vue中的JSX,介绍一下什么时候使用JSX、在Vue2中的基本使用,希望对大家有所帮助!JSX简介JSX是一种javascript的语法扩展,即具备了Javascript的全部功能,同时又兼

Vue中什么是jsX?下面本篇文章给大家了解一下Vue中的JSX,介绍一下什么时候使用JSX、在Vue2中的基本使用,希望对大家有所帮助!

Vue中什么是JSX?什么时候用?怎么用?

JSX简介

JSX是一种javascript的语法扩展,即具备了Javascript的全部功能,同时又兼具html的语义化和直观性。它可以让我们在JS中写模板语法:

const el = <div>Vue 2</div>;

上面这段代码既不是 HTML 也不是字符串,被称之为 JSX,是 JavaScript 的扩展语法。JSX 可能会使人联想到模板语法,但是它具备 Javascript 的完全编程能力。【相关推荐:vuejs视频教程WEB前端开发

什么时候使用JSX

当开始写一个只能通过 level prop 动态生成标题 (heading) 的组件时,你可能很快想到这样实现:

<script type="text/x-template" id="anchored-heading-template">
<h1 v-if="level === 1"> 
    <slot></slot> 
</h1> 
<h2 v-else-if="level === 2"> 
    <slot></slot> 
</h2> 
<h3 v-else-if="level === 3"> 
    <slot></slot> 
</h3> 
</script>

这里用template模板并不是最好的选择,在每一个级别的标题中重复书写了部分代码,不够简洁优雅。如果尝试用 JSX 来写,代码就会变得简单很多:

const App = {
  render() {
    const tag = `h${this.level}`
    return <tag>{this.$slots.default}</tag>
  }
}

或者如果你写了很多 render 函数,可能会觉得下面这样的代码写起来很痛苦:

createElement(  
    'anchored-heading', {  
        props: {  
            level: 1  
        }  
    }, [  
    createElement('span', 'Hello'),  
        ' world!'  
    ]  
)

特别是对应的模板如此简单的情况下:

<anchored-heading :level="1">  
    <span>Hello</span> world!  
</anchored-heading>

这时候就可以在 Vue 中使用 JSX 语法,它可以让我们回到更接近于模板的语法上:

import AnchoredHeading from './AnchoredHeading.vue'  
  
new Vue({  
    el: '#demo',  
    render: function (h) {  
        return (  
            <AnchoredHeading level={1}>  
                <span>Hello</span> world!  
            </AnchoredHeading>  
        )  
    }  
})

开发过程中,经常会用到消息提示组件Message,可能的一种写法是这样的:

Message.alert({
  messge: '确定要删除?',
  type: 'warning'
})

但是希望message可以自定义一些样式,这时候你可能就需要让Message.alert支持JSX了(当然也可以使用插槽/html等方式解决)

Message.alert({
  messge: <div>确定要删除<span style="color:red">xxx</span>的笔记?</div>,
  type: 'warning'
})

此外,一个 .vue 文件里面只能写一个组件,这个在一些场景下可能不太方便,很多时候写一个页面的时候其实可能会需要把一些小的节点片段拆分到小组件里面进行复用,这些小组件其实写个简单的函数组件就能搞定了。平时可能会由于SFC的限制让我们习惯于全部写在一个文件里,但不得不说可以尝试一下这种方式。

// 一个文件写多个组件
const Input = (props) => <input {...props} />
export const Textarea = (props) => <input {...props} />
export const PassWord = (props) => <input type="password" {...props} />

export default Input

比如这里封装了一个 Input 组件,我们希望同时导出 Password 组件和 Textarea 组件来方便用户根据实际需求使用,而这两个组件本身内部就是用的 Input 组件,只是定制了一些 props。在 JSX 里面就很方便,写个简单的函数组件基本上就够用了,通过 interface 来声明 props 就好了。但是如果是用模板来写,可能就要给拆成三个文件,或许还要再加一个 index.js 的入口文件来导出三个组件。

由于 JSX 的本质就是 JavaScript,所以它具有 JavaScript 的完全编程能力。再举个例子,我们需要通过一段逻辑来对一组 DOM 节点做一次 reverse,如果在模板里面写,那估计要写两段代码。

虽然这个例子可能不太常见,但是不得不承认,在一些场景下,JSX 还是要比模板写起来更加顺手。

从 Vue 2 开始,template 在运行之前,会被编译成 JavaScript 的 render function

image.png

Vue 推荐在绝大多数情况下使用 template 来创建你的 HTML。然而在一些场景中,就需要使用 render 函数,它比 template 更加灵活。这些 render function 在运行时阶段,就是传说中的 Virtual DOM

image.png

JSX在Vue2中的基本使用

配置

在 Vue 2 中,JSX 的编译需要依赖 @vue/babel-preset-jsx@vue/babel-helper-vue-jsx-merge-props 这两个包。前面这个包来负责编译 JSX 的语法,后面的包用来引入运行时的 mergeProps 函数。

npm install @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props

并在babel.config.js中添加配置:

module.exports = {
  presets: ['@vue/babel-preset-jsx'],
}

文本插值

模板代码里文本插值默认是用双大括号:

<h1>{{ msg }}</h1>

在JSX中则需要使用单大括号:

const name = 'Vue'
const element = <h1>Hello, { name }</h1>

和模板语法中的文本插值一样,大括号内支持任何有效的JS表达式,比如:2 + 2user.firstNamefORMatName(user)等。

条件与循环渲染

在模板代码里面我们通过v-for去遍历元素,通过v-if去判断是否渲染元素,在JSX中,对于v-for,可以使用for循环或者array.map来代替,对于v-if,可以使用if-else语句,三元表达式等来代替

使用if-else语句

const element = (name) => {
  if (name) {
    return <h1>Hello, { name }</h1>
  } else {
    return <h1>Hello, Stranger</h1>
  }
}

使用三元表达式

const element = icon ? <span class="icon"></span> : null;

使用数组的map方法

const list = ['java', 'c++', 'javascript', 'C#', 'PHP']
return (
  <ul>
  {list.map(item => {
   return <li>{item}</li>
  })}
  </ul>
)

属性绑定

在模板代码中,一般通过 v-bind:prop="value":prop="value"来给组件绑定属性,在JSX里面就不能继续使用v-bind指令了,而是通过单大括号的形式进行绑定:

const href = 'https://xxx.com'
const element = <a href={href}>xxx</a>
const properties = {a: 1, b: 2}

此外,模板代码中能通过<div v-bind="properties"></div>批量绑定标签属性。

在JSX中也有相应的替换方案:<div {...properties}></div>

class绑定同样也是使用单大括号的形式

const element = <div className={`accordion-item-title ${ disabled ? 'disabled' : '' }`}></div>
const element = <div class={
    [ 'accordion-item-title', disabled && 'disabled' ]
  }
>Item</div>

style绑定需要使用双大括号

const width = '100px'
const element = <button style={{ width, fontSize: '16px' }}></button>

事件绑定

在模板代码中通过v-on指令监听事件,在JSX中通过on + 事件名称的大驼峰写法来监听,且绑定事件也是用大括号,比如click事件要写成onClick,mouseenter事件要写成onMouseenter

const confirm = () => {
  // 确认提交
}
<button onClick={confirm}>确定</button>

有时候我们希望可以监听一个组件根元素上面的原生事件,这时候会用到.native修饰符,但是在JSX中同样也不能使用,不过也有替代方案,监听原生事件的规则与普通事件是一样的,只需要将前面的on替换为nativeOn,如下

 render() {
    // 监听下拉框根元素的click事件
    return <CustomSelect nativeOnClick={this.handleClick}></CustomSelect>
  }

除了上面的监听事件的方式之外,我们还可以使用对象的方式去监听事件

  render() {
    return (
      <ElInput
        value={this.content}
        on={{
          focus: this.handleFocus,
          input: this.handleInput
        }}
        nativeOn={{
          click: this.handleClick
        }}
      ></ElInput>
    )
  }

对于 .passive.capture.once 这些事件修饰符,Vue 提供了相应的前缀可以用于 on

image.png

例如:

on: {  
    '!click': this.doThisInCapturingMode,  
    '~keyup': this.doThisOnce,  
    '~!mouseover': this.doThisOnceInCapturingMode  
}

对于所有其它的修饰符,私有前缀都不是必须的,因为你可以在事件处理函数中使用事件方法:image.png具体可查阅Vue规范文档。

v-show与v-model

大多数指令并不能在JSX中使用,对于原生指令,只有v-show是支持的。

v-modelVue提供的一个语法糖,它本质上是由 value属性(默认) + input事件(默认)组成的,所以,在JSX中,我们便可以回归本质,通过传递value属性并监听input事件来手动实现数据的双向绑定:

export default {
  data() {
    return {
      name: ''
    }
  },
  methods: {
    // 监听 onInput 事件进行赋值操作
    handleInput(e) {
      this.name = e.target.value
    }
  },
  render() {
    // 传递 value 属性 并监听 onInput事件
    return <input value={this.name} onInput={this.handleInput}></input>
  }
}

此外,在脚手架vue-cli4中,已经默认集成了对v-model的支持,可以直接使用<input v-model={this.value}>,如果项目比较老,也可以安装插件babel-plugin-jsx-v-model来进行支持。

同样的,在JSX中,对于.sync也需要用属性+事件来实现,如下代码所示:

export default {
  methods: {
    handleChangeVisible(value) {
      this.visible = value
    }
  },
  render() {
    return (
      <ElDialog
        title="测试.sync"
        visible={this.visible}
        on={{ 'update:visible': this.handleChangeVisible }}
      ></ElDialog>
    )
  }
}

插槽

(1)默认插槽:

使用element-uiDialog时,弹框内容就使用了默认插槽,在JSX中使用默认插槽的用法与普通插槽的用法基本是一致的,如下

 render() {
    return (
      <ElDialog title="弹框标题" visible={this.visible}>
        {}
        <div>这里是弹框内容</div>
      </ElDialog>
    )
  }

自定义默认插槽:

Vue的实例this上面有一个属性$slots,这个上面就挂载了一个这个组件内部的所有插槽,使用this.$slots.default就可以将默认插槽加入到组件内部

export default {
  props: {
    visible: {
      type: Boolean,
      default: false
    }
  },
  render() {
    return (
      <div class="custom-dialog" vShow={this.visible}>
        {}
        {this.$slots.default}
      </div>
    )
  }
}

(2)具名插槽

有时候我们一个组件需要多个插槽,这时候就需要为每一个插槽起一个名字,比如element-ui的弹框可以定义底部按钮区的内容,就是用了名字为footer的插槽

 render() {
    return (
      <ElDialog title="弹框标题" visible={this.visible}>
        <div>这里是弹框内容</div>
        {}
        <template slot="footer">
          <ElButton>确定</ElButton>
          <ElButton>取消</ElButton>
        </template>
      </ElDialog>
    )
  }

自定义具名插槽: 在上节自定义默认插槽时提到了$slots,对于默认插槽使用this.$slots.default,而对于具名插槽,可以使用this.$slots.footer进行自定义

render() {
    return (
      <div class="custom-dialog" vShow={this.visible}>
        {this.$slots.default}
        {}
        <div class="custom-dialog__foolter">{this.$slots.footer}</div>
      </div>
    )
  }

(3)作用域插槽

有时让插槽内容能够访问子组件中才有的数据是很有用的,这时候就需要用到作用域插槽,在JSX中,因为没有v-slot指令,所以作用域插槽的使用方式就与模板代码里面的方式有所不同了。比如在element-ui中,我们使用el-table的时候可以自定义表格单元格的内容,这时候就需要用到作用域插槽

data() {
    return {
      data: [
        {
          name: 'xxx'
        }
      ]
    }
  },
  render() {
    return (
      {}
      <ElTable data={this.data}>
        <ElTableColumn
          label="姓名"
          scopedSlots={{
            default: ({ row }) => {
              return <div style="color:red;">{row.name}</div>
            }
          }}
        ></ElTableColumn>
      </ElTable>
    )
  }

自定义作用域插槽:

使用作用域插槽不同,定义作用域插槽也与模板代码里面有所不同。加入我们自定义了一个列表项组件,用户希望可以自定义列表项标题,这时候就需要将列表的数据通过作用域插槽传出来。

render() {
    const { data } = this
    // 获取标题作用域插槽
    const titleSlot = this.$scopedSlots.title
    return (
      <div class="item">
        {}
        {titleSlot ? titleSlot(data) : <span>{data.title}</span>}
      </div>
    )
  }

使用自定义组件

只需要导入进来,不用再在components属性声明了,直接写在jsx中:

import MyComponent from './my-component'

export default {
  render() {
    return <MyComponent>hello</MyComponent>
  },
}

在method里返回JSX

我们可以定义method,然后在method里面返回JSX,然后在render函数里面调用这个方法,不仅如此,JSX还可以直接赋值给变量,比如:

 methods: {
    renderFooter() {
      return (
        <div>
          <ElButton>确定</ElButton>
          <ElButton>取消</ElButton>
        </div>
      )
    }
  },
  render() {
    const buttons = this.renderFooter()
    return (
      <ElDialog visible={this.visible}>
        <div>内容</div>
        <template slot="footer">{buttons}</template>
      </ElDialog>
    )
  }

用JSX实现简易聊天记录

假设该消息聊天记录的消息类型只有三种:文本,图片,引用。一条消息里面可以包括任意类型的内容,引用类型消息内部可以不断嵌套引用其他任意类型消息。效果图大致如下:

image.png

消息数据结构如下:

message: [
      // 每个数组的第一个参数为消息类型:0:文本 1:图片 2:引用。第二个参数为具体内容
      [
        0,
        '文本'
      ],
      [
        1,
        '图片链接xxx'
      ],
      [
        2,
        [
          [
            0,
            '引用文本文本文本'
          ],
          [
            1,
            '引用图片链接xxx'
          ]
        ]
      ]
    ]

主要有两个思路:

1、思路一:在render里返回一段用array.map渲染的消息模板,对于三种消息类型,使用if-else进行判断分别渲染,对于引用类型的消息,可以封装一个方法进行渲染,方法里面如果还有引用类型消息就继续递归渲染。

methods: {
    // 展示引用消息
    showQuote (msg) {
      return (
        <div class="content-quote">
          <span class="quote-title">引用:</span>
          {msg.map(item => {
            if (item[0] === 0) {
              return <p class="content-text">{item[1]}</p>
            } else if (item[0] === 1) {
              return (
                <el-image
                  class="content-img"
                  src={item[1]}
                  preview-src-list={[item[1]]}>
                </el-image>
              )
            } else {
              return this.showQuote(item[1])
            }
          })}
        </div>
      )
    }
  },
  render (h) {
    return (
      <ul class="chat-record-list">
        {this.recordList.map(item => {
          return (
            <li
              class="chat-record-item"
              key={item.timeStamp}
            >
              <div class="title">
                <span class="person-info">
                  { `${item.sendUserNick}(${item.sendUserNet}) → ${item.receiverNick}(${item.receiverNet})` }
                </span>
                <span class="sendtime">
                  { this.formatTime('YYYY-mm-dd HH:MM:SS', item.timeStamp) }
                </span>
              </div>
              <div class="content">
                {item.message.map(msg => {
                  if (msg[0] === 0) {
                    return <p class="content-text">{msg[1]}</p>
                  } else if (msg[0] === 1) {
                    return (
                      <el-image
                        class="content-img"
                        src={msg[1]}
                        preview-src-list={[msg[1]]}>
                      </el-image>
                    )
                  } else {
                    // 递归渲染引用类型消息
                    return this.showQuote(msg[1])
                  }
                })}
              </div>
            </li>
          )
        })}
      </ul>
    )
  }

2、思路二:第一种思路中封装的showQuote里面的代码与render中渲染消息内容的代码基本相似,因此其实现方式不够优雅。其实可以将整个消息的渲染封装成一个组件,在该组件内引入自己,然后再渲染自己。由于具体细节代码与上述类似,这里只给出思路代码,具体细节请忽略

// 当前组件就是RecordMessage组件,自己引入自己
import RecordMessage from './RecordMessage.vue'

export default {
    props: {
        message: {
            type: Array,
            default: () => []
        }
    },
    render () {
        const parseMessage = msg => {
            const type = msg[0]
            if (type === 0) {
                // 文本
            } else if (type === 2) {
                // 图片
            } else {
                // 引用类型
                return (
                    <div>
                        <div>引用:</div>
                        {
                            msg[1].map(subMsg => (
                                // 自己递归渲染自己
                                <recored-message>
                                </recored-message>
                            ))
                        }
                    </div>
                )
            }
        }
        return parseMessage(this.message)
    }

学习视频分享:vuejs入门教程、编程基础视频)

以上就是Vue中什么是JSX?什么时候用?怎么用?的详细内容,更多请关注编程网其它相关文章!

--结束END--

本文标题: Vue中什么是JSX?什么时候用?怎么用?

本文链接: https://lsjlt.com/news/206842.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Vue中什么是JSX?什么时候用?怎么用?
    Vue中什么是JSX?下面本篇文章给大家了解一下Vue中的JSX,介绍一下什么时候使用JSX、在Vue2中的基本使用,希望对大家有所帮助!JSX简介JSX是一种Javascript的语法扩展,即具备了Javascript的全部功能,同时又兼...
    99+
    2023-05-14
    JSX 前端 Vue.js JavaScript
  • vue是什么时候发布的
    这篇“vue是什么时候发布的”除了程序员外大部分人都不太理解,今天小编为了让大家更加理解“vue是什么时候发布的”,给大家总结了以下内容,具有一定借鉴价值,内容详细步骤清晰,细节处理妥当,希望大家通过这篇文章有所收获,下面让我们一起来看看具...
    99+
    2023-06-06
  • Vue下使用JSX的方法是什么
    这篇文章主要介绍了Vue下使用JSX的方法是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Vue下使用JSX的方法是什么文章都会有所收获,下面我们一起来看看吧。Vue.js 具有简单的 API 和几个选项,...
    99+
    2023-07-04
  • java中什么时候用this?
    this只存在于方法内部,用来代表调用改方法的对象。可以理解为每一个方法内部都有一个局部变量叫this,每当初始化一个对象时,就把该对象的地址传递给了该对象每一个方法中的this变量,从而可以在方法内部使用这个的对象。java中什么时候用t...
    99+
    2022-04-17
    java教程 java this
  • es6中promise什么时候用
    本教程操作环境:windows7系统、ECMAScript 6版、Dell G3电脑。Promise的含义Promise是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6将其写进了...
    99+
    2022-11-22
    javascript promise ES6
  • 怎么在Vue中使用JSX
    本篇内容主要讲解“怎么在Vue中使用JSX”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么在Vue中使用JSX”吧!简介先举一个例子来说明为什么 JSX 是好...
    99+
    2024-04-02
  • java中什么时候使用static
    什么时候使用:当一个方法或者变量需要初始化加载,或者是经常被调用的时候可以加上static。用static修饰的方法可以用类名直接调用,不用的一定要先实例化一个对象然后才可以调用。不足之处:初始化加载,比较占内存,所以不经常用的方法,不建议...
    99+
    2017-08-26
    java static 使用
  • c++中endl什么时候使用
    std::endl 用于将换行符写入流,通常在需要显式结束行时使用。它强制刷新流并避免缓冲行为。替代方法包括直接写入 '\n' 字符或使用 std::flush 手动刷新流。 什么时候...
    99+
    2024-04-28
    c++
  • java什么时候用this
    this只存在于方法内部,用来代表调用改方法的对象。可以理解为每一个方法内部都有一个局部变量叫this,每当初始化一个对象时,就把该对象的地址传递给了该对象每一个方法中的this变量,从而可以在方法内部使用这个的对象。第一种情况 ...
    99+
    2017-01-02
    java入门 java
  • 什么时候使用flags
    这篇文章主要讲解了“什么时候使用flags”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“什么时候使用flags”吧!   Possible flags:(...
    99+
    2024-04-02
  • java中什么时候使用事务
    什么时候使用事务?如果实际的业务中,需要将一条数据同时存放到两张表中, 并且要求两张表中的数据同步,那么此时就需要使用事务管理机制,保证数据同步。如果出现错误情况,比如表一插入数据成功,表二插入数据失败,那么就回滚,终止数据持久化操作。金融...
    99+
    2016-07-06
    java教程 java 使用 事务
  • HTML div什么时候使用
    本篇内容主要讲解“HTML div什么时候使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“HTML div什么时候使用”吧! 1、div:作为布局以及样式化...
    99+
    2024-04-02
  • O_SYNC什么时候起作用?
    本篇文章给大家分享《O_SYNC什么时候起作用?》,覆盖了Golang的常见基础知识,其实一个语言的全部知识点一篇文章是不可能说完的,但希望通过这些问题,让读者对自己的掌握程度有一定的认识(B 数)...
    99+
    2024-04-05
  • JSX原理是什么
    本篇内容介绍了“JSX原理是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成! ...
    99+
    2024-04-02
  • win10什么时候上线 win10什么时候推出
    北京时间10月1日消息,微软公司今天在旧金山发布了自己的最新产品win10,直接跳过了win9,那么win10什么时候上线?win10什么时候出?一起来跟小编看一下吧。 现在还没有Windows 10系统发布的准确时间...
    99+
    2023-06-07
    win10
  • javascript是什么时候出的
    这篇文章给大家分享的是有关javascript是什么时候出的的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。 javascript是1995年出的;Ja...
    99+
    2024-04-02
  • vue什么时候会出现白屏
    本教程操作环境:windows7系统、vue3版,DELL G3电脑。vue出现白屏现象主要几种原因和解决办法第一种:由于把路由模式mode设置成history了,默认是hash。解决方法:改为hash或者直接删除模式配置,如果非要用的话,...
    99+
    2023-05-14
    Vue
  • JavaScript 中什么时候使用 Map 更好
    目录Map 用作 Hash Map性能基准测试的实现细节字符串类型的键整数类型的键数值类型的键内存使用总结浏览器兼容性笔记Map 用作 Hash Map ES6 给我们带来了&nbs...
    99+
    2024-04-02
  • JavaScript 什么时候使用回调
    JavaScript 什么时候使用回调,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。 JavaScript 何时使用回调? ...
    99+
    2024-04-02
  • 什么时候使用Lambda函数?
    原文来自:1前言Python 中定义函数有两种方法,一种是用常规方式 def 定义,函数要指定名字,第二种是用 lambda 定义,不需要指定名字,称为 Lambda 函数。Lambda 函数又称匿名函数,匿名函数就是没有名字的函数,函数没...
    99+
    2023-06-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作