Evan's blog Evan's blog
首页
关于
  • 分类
  • 标签
  • 归档
  • H5&CSS3
  • JS
  • TS
  • Node
  • Webpack
  • Vue2
  • Vue3
  • 微信小程序
  • Andorid
  • Flutter
推荐
GitHub (opens new window)

conanan

真相只有一个
首页
关于
  • 分类
  • 标签
  • 归档
  • H5&CSS3
  • JS
  • TS
  • Node
  • Webpack
  • Vue2
  • Vue3
  • 微信小程序
  • Andorid
  • Flutter
推荐
GitHub (opens new window)
  • 基础

  • 组件

  • 动画

  • Composition Api

  • 高级语法

    • h 函数 & JSX
      • h 函数 🔥
        • 介绍
        • 参数 🔥
        • type
        • props
        • children
        • h 函数的基本使用
        • render 函数实现计数器
        • setup 函数实现计数器
        • 组件和插槽的使用
      • JSX 🔥
        • 入门
        • JSX 计数器案例
    • 自定义指令
    • Teleport
    • 插件
    • nextTick与eventloop
    • historyApiFallback
  • Vue源码

  • VueCLI&Vite

  • VueRouter

  • Vuex

  • 项目

  • Vue3.x
  • 高级语法
xugaoyi
2022-02-04
目录

h 函数 & JSX

# h 函数 & JSX

# h 函数 🔥

# 介绍

返回一个”虚拟节点“,通常缩写为 VNode:一个普通对象,其中包含向 Vue 描述它应在页面上渲染哪种节点的信息,包括所有子节点的描述。它的目的是用于手动编写的渲染函数 (opens new window):

Vue推荐在绝大数情况下使用模板来创建你的HTML,然后一些特殊的场景,你真的需要JavaScript的完全编程的能力,这个时候你可以使用 h 渲染函数 ,它比模板更接近编译器;

  • 前面我们讲解过VNode和VDOM的改变:Vue在生成真实的DOM之前,会将我们的节点转换成VNode,而VNode组合在一起形成一颗树结构,就是虚拟DOM(VDOM);

  • 事实上,我们之前编写的 template 中的HTML 最终也是使用渲染函数生成对应的VNode;

  • 那么,如果你想充分的利用JavaScript的编程能力,我们可以自己来编写 createVNode 函数,生成对应的VNode;

那么我们应该怎么来做呢?使用 h()函数:

  • h() 函数是一个用于创建 VNode 的一个函数;
  • 其实更准备的命名是 createVNode() 函数,但是为了简便在Vue将之简化为 h() 函数;
render() {
  return h('h1', {}, 'Some title')
}
1
2
3

# 参数 🔥

接收三个参数:type,props 和 children

# type

  • 类型:String | Object | Function

  • 详细:

    HTML 标签名、组件、异步组件或函数式组件。使用返回 null 的函数将渲染一个注释。此参数是必需的。

# props

  • 类型:Object

  • 详细:

    一个对象,与我们将在模板中使用的 attribute、prop 和事件相对应。可选。

# children

  • 类型:String | Array | Object

  • 详细:

    子代 VNode,使用 h() 生成,或者使用字符串来获取“文本 VNode”,或带有插槽的对象。可选。

    h('div', {}, [
      'Some text comes first.',
      h('h1', 'A headline'),
      h(MyComponent, {
        someProp: 'foobar'
      })
    ])
    
    1
    2
    3
    4
    5
    6
    7

# h 函数的基本使用

h函数可以在两个地方使用:

  • render函数选项中;

    <script>
      import { h } from 'vue';
    
      export default {
        render() {
          return h("h2", {class: "title"}, "Hello Render")
        }
      }
    </script>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
  • setup函数选项中(setup本身需要是一个函数类型,函数再返回h函数创建的VNode);

    <script>
      import { h } from 'vue';
    
      export default {
        setup() {
          return () => h("h2", {class: "title"}, "Hello Render")
        }
      }
    </script>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9

# render 函数实现计数器

<script>
  import { h } from 'vue';

  export default {
    data() {
      return {
        counter: 0
      }
    },
    render() {
      return h("div", {class: "app"}, [
        h("h2", null, `当前计数: ${this.counter}`),
        h("button", {
          onClick: () => this.counter++
        }, "+1"),
        h("button", {
          onClick: () => this.counter--
        }, "-1"),
      ])
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

太麻烦了,可以使用JSX替代。

# setup 函数实现计数器

<script>
  import { ref, h } from 'vue';

  export default {
    setup() {
      const counter = ref(0);
      
      return () => {
        return h("div", {class: "app"}, [
          h("h2", null, `当前计数: ${counter.value}`),
          h("button", {
            onClick: () => counter.value++
          }, "+1"),
          h("button", {
            onClick: () => counter.value--
          }, "-1"),
        ])
      }
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 组件和插槽的使用

App.vue

<script>
import { h } from 'vue'
import HelloWorld from './HelloWorld.vue'

export default {
  render() {
    return h('div', null, [
      h(HelloWorld, null, {
        // default 插槽;作用域插槽
        default: (props) =>
          h('span', null, `app传入到HelloWorld中的内容: ${props.name}`),
      }),
    ])
  },
}
</script>

<style scoped></style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

HelloWorld.vue

<script>
import { h } from 'vue'

export default {
  render() {
    return h('div', null, [
      h('h2', null, 'Hello World'),
      // default 插槽;
      this.$slots.default
        ? this.$slots.default({ name: 'coderwhy' })
        : h('span', null, '我是HelloWorld的插槽默认值'),
    ])
  },
}
</script>

<style lang="scss" scoped></style>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# JSX 🔥

# 入门

如果我们希望在项目中使用jsx,那么我们需要添加对jsx的支持:

  • jsx我们通常会通过Babel来进行转换(React编写的jsx就是通过babel转换的);
  • 对于Vue来说,我们只需要在Babel中配置对应的插件即可(当前版本无需配置);

(根据是否需要配置)安装Babel支持Vue的jsx插件:

 npm install @vue/babel-plugin-jsx -D
1

(根据是否需要配置)在babel.config.js配置文件中配置插件

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

1
2
3
4
5
6

# JSX 计数器案例

App.vue

<script>
  import HelloWorld from './HelloWorld.vue';

  export default {
    data() {
      return {
        counter: 0
      }
    },

    render() {
      const increment = () => this.counter++;
      const decrement = () => this.counter--;

      return (
        <div>
          <h2>当前计数: {this.counter}</h2>
          <button onClick={increment}>+1</button>
          <button onClick={decrement}>-1</button>
          <HelloWorld>
          </HelloWorld>
        </div>
      )
    }
  }
</script>

<style lang="scss" scoped>

</style>
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
28
29
30

HelloWorld.vue

<script>
  export default {
    render() {
      return (
        <div>
          <h2>HelloWorld</h2>
          {this.$slots.default ? this.$slots.default(): <span>哈哈哈</span>}
        </div>
      )
    }
  }
</script>

<style scoped>

</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
编辑 (opens new window)
上次更新: 2022/03/24, 16:45:21
其他
自定义指令

← 其他 自定义指令→

最近更新
01
重点
04-12
02
搭建项目
04-04
03
TS补充
03-30
更多文章>
Theme by Vdoing | Copyright © 2019-2022 conanan | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式