找回密码
 立即注册
首页 业界区 业界 通过重写组件轻松掌握用JSX写Vue项目

通过重写组件轻松掌握用JSX写Vue项目

仲水悦 2025-11-6 22:05:00
前言

因工作原因,最近接手一个Vue的后台管理项目,发现它使用的不是Vue官网推荐的标准写法,而是使用JSX,我以前也有在Vue项目中使用过JSX,但那都是二年前的事了,忘的差不多了,今天特意抽时间写文章记录一下
今天的做法是我先用Vue标准模板语法实现一个组件,组件尽量用到Vue开发最常用的功能,再用JSX语法重写该组件,以此知道二者区别的同时掌握用JSX写Vue项目
JSX?

JSX(JavaScript XML)是一种 JavaScript 的语法扩展,允许我们在 JavaScript 代码中编写类似 HTML 的结构。它最初由 React 团队提出,用于更直观地描述 UI 组件
标准模板语法写法

下面是我用Vue标准模板语法实现的一个组件,关键代码如下:
  1. <template>
  2.   
  3.     <h3>Props: {{ msg }}</h3>
  4.     <h3 :>Step: {{ step }} - Count: {{ count }}</h3>
  5.     <h3 :>Double Count: {{ doubleCount }}</h3>
  6.     <input
  7.       type="text"
  8.       v-model.number="step"
  9.       v-highlight
  10.     />
  11.    
  12.       <button @click="increment">增加会冒泡</button>
  13.       <button @click.stop="increment">增加阻止冒泡</button>
  14.    
  15.     <button @click="toggle">显示与隐藏</button>
  16.     <ul v-if="state.isActive">
  17.       <li v-for="item in state.items" :key="item">{{ item }}</li>
  18.     </ul>
  19.     <slot name="footer" :msg="msg"></slot>
  20.   
  21. </template>
复制代码
实现的效果如下:
1.gif

用JSX重写

实现一个功能一模一样的同样功能组件,但是是使用JSX语法重写,关键代码如下:
  1. import { defineComponent, ref, reactive, computed, onMounted, watch, withModifiers, withDirectives } from 'vue'
  2. import styles from './HelloWorldJsx.module.css'
  3. // 定义自定义指令
  4. const vHighlight = {
  5.   mounted(el) {
  6.     console.log('vHighlight mounted')
  7.     el.style.border = '2px solid blue';
  8.   }
  9. }
  10. export default defineComponent({
  11.   props: {
  12.     msg: String
  13.   },
  14.   directives: {
  15.     highlight: vHighlight
  16.   },
  17.   setup(props, { emit, slots }) {
  18.     // setup中定义指令
  19.     // const vHighlight = {
  20.     //   mounted(el) {
  21.     //     console.log('vHighlight mounted')
  22.     //     el.style.border = '2px solid blue';
  23.     //   }
  24.     // }
  25.     const state = reactive({
  26.       items: ['Vue', 'JSX', 'Composition'],
  27.       isActive: true
  28.     })
  29.     const toggle = () => {
  30.       state.isActive = !state.isActive
  31.     }
  32.     const count = ref(0)
  33.     const step = ref(1)
  34.     // 计算属性
  35.     const doubleCount = computed(() => count.value * 2)
  36.     // 事件处理函数
  37.     const increment = () => {
  38.       console.log('---- increment ----:', );
  39.       count.value += step.value
  40.       emit('count-change', count.value)
  41.     }
  42.     const parentClick = () => {
  43.       console.log('---- parentClick ----:', );
  44.       alert('parent click')
  45.     }
  46.     // 监听 count 的变化
  47.     watch(() => count.value, (newVal, oldVal) => {
  48.       console.log(`${props.msg} count changed from ${oldVal} to ${newVal}`)
  49.     })
  50.     // 生命钩子
  51.     onMounted(() => {
  52.       console.log(`${props.msg} 组件已经挂载`)
  53.     })
  54.     return () => (
  55.       
  56.         <h3>Props: {props.msg}</h3>
  57.         <h3 style={{color: state.isActive ? 'blue' : 'black'}}>Step: {step.value} - Count: {count.value}</h3>
  58.         <h3 class={[state.isActive ? styles['double-count-activejsx'] : '']}>Double Count: {doubleCount.value}</h3>
  59.         {/* setup中定义指令使用
  60.         {withDirectives(
  61.           <input
  62.             type="text"
  63.             v-model={[step.value, ['number']]}
  64.           />
  65.         , [[ vFocus, true]])} */}
  66.         <input
  67.             type="text"
  68.             v-model={[step.value, ['number']]}
  69.             v-highlight
  70.           />
  71.         
  72.           <button onClick={increment}>增加会冒泡</button>
  73.           <button onClick={withModifiers(() => increment(),['stop'])}>增加阻止冒泡</button>
  74.         
  75.         <button onClick={toggle}>显示与隐藏</button>
  76.         {
  77.           state.isActive && <ul>
  78.           {state.items.map(item => (
  79.               <li key={item}>{item}</li>
  80.             ))}
  81.           </ul>
  82.         }
  83.         {slots.footer && slots.footer({msg: props.msg})}
  84.       
  85.     )
  86.   }
  87. })
复制代码
HelloWorldJsx.css的样式代码如下
  1. .containerJsx{
  2.     background-color: red;
  3.     padding: 20px;
  4.     border-radius: 10px;
  5.     box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
  6.     width: 300px;
  7.     display: flex;
  8.     flex-direction: column;
  9.     justify-content: center;
  10.     align-items: center;
  11.     text-align: center;
  12. }
  13. .double-count-activejsx{
  14.     color: blue;
  15.     font-style: italic;
  16. }
复制代码
最后实现的效果如下:
2.gif

对比分析

JSX语法SFC模板语法() => (...)...{props.msg}{{ msg }}{count.value}{{count}}style={{color: state.isActive ? 'blue' : 'black'}}:class={[state.isActive ? 'double-count-activejsx' : '']}:onClick={increment}@click="increment"onClick.stop={increment}onClick={withModifiers(() => increment(),['stop'])}v-model={[step.value, ['number']]}v-model.number="step"{state.isActive && ...}v-if="state.isActive"{state.items.map(...)}v-for="item in state.items"{slots.footer && slots.footer({msg: props.msg})}import styles from './HelloWorldJsx.module.css'

  • 其中有用到自定义指令,如果是通过directives注册的当前组件或者全局的使用方式二者是一样的,但是如果你是定义在setup里的,那使用的时候你得依赖withDirectives来使用,具体查看JSX改写里的指令注释部分
  • 对于事件修饰符除了可以使用上面的withModifiers来实现,看着比较复杂但是是官方提供的方法,如果不想用,完全也是可以通过手写代码如e.stopPropagation()/e.preventDefault()等来实现
  • 标准的JSX在使用class的只能用className,但是在Vue项目中使用jsx并没有这个要求,正常使用 class即可
  • Vue默认就支持CSS模块化,style标签上增加scoped即可,JSX只能通过业务有名的CSS模块化方案,如CSS Modules/CSS in JS,此文介绍的是CSS Modules方案
如果你想跑一下测试demo,可以新建一个基础的Vue项目再把我写的二个组件的代码拷贝进去,或者可以拉取我的项目,再本地跑跑即可,仓库地址:https://gitee.com/github-9819409/vue-template-jsx
小结

本文是个人练习JSX写Vue项目的记录,并不是说JSX写法比Vue标准模板写法要好,具体是用Vue标准模板语法写法还是JSX,这个首先看个人喜好,其次开发经常会接手一些前辈的项目,考虑你接手的项目的写法
个人的知识和能力是有限的,应该还有一些JSX高级用法我没有提到,如果有不对的地方或者你有更好的建议,希望不吝留言分享,一起学习一起进步

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册