• vue中的h函数与JSX语法


    vue不仅像react一样实现了jsx,而且还借助jsx发挥了javascript动态画的优势,了解学习jsx可以让你更灵活的开发需求。

    一、 h函数

    在聊vue中的JSX之前,需要简单介绍一下 h 函数,理解了 h 函数,会更好的理解JSX。

    1.h函数概念

    h()是一个用于创建VNode的实用程序,你可以理解为createVNode(),但因为它频繁的被使用,所以简称为h函数。

    // @returns {VNode}
    h(
        // {String | Object | Function} tag
        // 一个 HTML 标签名、一个组件、一个异步组件或一个函数式组件。
        // 必需的。
        'div',
    
        // {Object} props
        // 与 attribute、prop 和事件相对应的对象,这会在模板中用到。
        // 可选的(在开发时。建议传,实在没有传的时候,传入 null)
        {},
    
        // {String | Array | Object} children
        // 子 VNodes, 使用 `h()` 构建,
        // 或使用字符串获取 "文本 VNode" 或者
        // 有插槽的对象。
        //
        // 可选的。
        [
            'Some text comes first.',
            h('h1', 'A headline'),
            h(MyComponent, {
                someProp: 'foobar'
            })
        ]
    )
    //             这里不理解就先看下面的例子
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    2.理解h函数

    vue3的项目中,template是默认的写法,vue运行时会把template解析为render函数,之后,组件运行的时候通过render函数去返回h函数的运行结果去构造虚拟DOM

    在这里插入图片描述
    上面的图片是我随意运行了一个demo,打开vue调试工具得到的源码,_sfc_render 就是template解析成js之后的结果

    所以在vue中,我们除了可以使用template写法之外,还可以直接写render函数

    render函数跟h函数又有什么关系?

    h函数的使用场景

    下面先举一个小例子,有这样一个需求:通过一个变量(1~6)去渲染标题组件比的标签等级(h1~h6)。

    如果我们使用template语法的话,利用v-if,可以实现出来,代码如下:

      <h1 v-if="num==1">{{title}}</h1>
      <h2 v-if="num==2">{{title}}</h2>
      <h3 v-if="num==3">{{title}}</h3>
      <h4 v-if="num==4">{{title}}</h4>
      <h5 v-if="num==5">{{title}}</h5>
      <h6 v-if="num==6">{{title}}</h6>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    明显可以发现这样的代码太冗余,显得也很不专业,所以这里可以使用Vue中的h函数实现这个需求。

    因为 render函数可以直接返回虚拟DOM,因而我们就不在需要template。在目录下新建一个文件Heading.jsx

    Heading.jsx

    import { defineComponent, h } from 'vue'
    
    export default defineComponent({
      props: {
        level: {
          type: Number,
          required: true
        }
      },
      setup(props, { slots }) {
        return () => h(
          'h' + props.level, // 标签名
          {}, // prop 或 attribute
          slots.default() // 子节点
        )
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在上面的代码中,使用defineComponent定义一个组件,组件内部配置了propssetup,这里的setup函数的返回值也是一个函数,就是上面说的render函数,render函数返回的是h函数的执行结果。

    然后,在主界面中,我们使用下面代码中的 import 语法来引入 Heading,之后使用 level 传递标签的级别,这样就实现了level与标签等级的同步

     <template>
      <Heading :level="3">hello geekbang</Heading>
    </template>
    
    <script setup>
    import Heading from './components/Head.jsx'
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    运行:
    在这里插入图片描述

    手写h函数的优缺点

    const p = h('p', {}, 'Hello, world!')
    
    • 1

    这个函数的优点是它可以简化创建 Virtual DOM 节点的过程,并且能够帮助开发人员避免拼写错误。它还可以自动将某些属性或属性值转换为合法的 HTML,从而帮助开发人员避免安全漏洞。

    h 函数的缺点是它不够灵活。因为它是一个函数,所以无法提供额外的抽象层,因此无法像其他框架或库那样提供高级功能。

    总的来说就是在复杂的场景中,h 函数写起来就显得非常繁琐,需要自己把所有的属性都转变成对象。并且组件嵌套的时候,对象也会变得非常复杂。

    不过,因为 h 函数也是返回虚拟 DOM 的,所以有没有更方便的方式去写 h 函数呢?答案是肯定的,这个方式就是 JSX

    JSX

    JSX的概念

    JSX 来源自 React 框架,他是一种 JavaScript 语法扩展,允许开发人员在 JavaScript 代码中写入类似于 HTML 的语法。

    const button = <button type="button">Click me!</button>
    
    • 1

    上面的代码直接在 JavaScript 环境中运行时,会报错。

    JSX 的本质就是下面代码的语法糖,h 函数内部也是调用 createVnode 来返回虚拟 DOM。在下面的内容中,对于那些创建虚拟 DOM 的函数,我们统一称为 h 函数。

    const element = createVnode('h1',{id:"app"}, 'hello Geekbakg')
    
    • 1

    使用JSX

    安装插件

    npm install @vitejs/plugin-vue-jsx -D
    
    • 1

    配置babel,这里我需要打开 vite.config.js 文件去修改 vite 配置。

    import vue from '@vitejs/plugin-vue'
    import vueJsx from '@vitejs/plugin-vue-jsx';
    
    export default defineConfig({
      plugins: [vue(),vueJsx()]
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    然后,我们进入 src/componentns/Heading.jsx 中,把 setup 函数的返回函数改成下面代码中所示的内容,

      setup(props, { slots }) {
        const tag = 'h'+props.level
        return () => <tag>{slots.default()}</tag>
      }
    
    • 1
    • 2
    • 3
    • 4

    使用 JSX 的本质,还是在写 JavaScript,Element3 组件库设计中很多酒用到JSX,比如时间轴Timeline、表格Table等,时间轴Timeline中就有一个倒序渲染的属性,我们可以看一下它是怎么实现的

    export const Timeline = (props)=>{
        const timeline = [
            <div class="start">8.21 开始自由职业</div>,
            <div class="online">10.18 专栏上线</div>
        ]
        if(props.reverse){
            timeline.reverse()
        }
        return <div>{timeline}</div>
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    通过数组的 reverse 方法直接进行数组反转,实现逆序渲染。类似这种动态性要求很高的场景,template 是较难实现的。

    三、JSX 和 Template的区别

    仔细思考,vue中的模版语法,实现的都是固定场景的需求,例如v-if、v-for,若遇到了有多种渲染逻辑的复杂场景,这个时候用v-if就无法满足了,而 JSX 只是 h 函数的一个语法糖,本质就是 JavaScript,想实现条件渲染可以用 if else,也可以用三元表达式,还可以用任意合法的 JavaScript 语法。

    1. JSX 可以支持更动态的需求。而 template 则因为语法限制原因,不能够像 JSX 那样可以支持更动态的需求。
    2.JSX 可以在一个文件内返回多个组件

    export const Button = (props,{slots})=><button {...props}>slots.default()</button>
    export const Input = (props)=><input {...props} />
    export const Timeline = (props)=>{
      ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    总的来说,一般情况就使用tamplate模版语法,动态性要求较高的组件使用JSX实现

  • 相关阅读:
    【allegro 17.4软件操作保姆级教程五】布线前准备之过孔、差分对、布线集合添加
    杰理之涂鸦APP显示连接的设备【篇】
    MySQL 基础知识(九)之视图
    【Java高级技术】动态代理
    基于Java实现的GRE(美国研究生入学考试)学习系统
    Disruptor-源码解读
    活字格低代码开发平台怎么样?靠谱吗?
    理德名人故事:巴菲特传记,“股神”巴菲特的一生
    基于51单片机交通灯仿真_紧急开关+黄灯倒计时+可调时间(proteus+代码+报告+讲解视频)
    shell-运算符
  • 原文地址:https://blog.csdn.net/NGUP_LEE/article/details/128207449