render函数

278 阅读1分钟

学习了coderwhy的vue3+ts视频课的笔记

1. 认识h函数

  • Vue推荐在绝大数情况下使用模板来创建你的HTML,然后一些特殊的场景,你真的需要JavaScript的完全编程的能力,这个时候你可以使用 渲染函数,它比模板更接近编译器;
    • 前面我们讲解过VNode和VDOM的改变(跳转链接)
    • Vue在生成真实的DOM之前,会将我们的节点转换成VNode,而VNode组合在一起形成一颗树结构,就是虚拟DOM(VDOM);
    • 事实上,我们之前编写的 template 中的HTML 最终也是使用渲染函数生成对应的VNode;
    • 那么,如果你想充分的利用JavaScript的编程能力,我们可以自己来编写 createVNode 函数,生成对应的 VNode。
  • 那么我们应该怎么来做呢?使用 h()函数
    • h() 函数是一个用于创建 vnode 的一个函数;
    • 其实更准备的命名是 createVNode() 函数,但是为了简便在Vue将之简化为 h() 函数。

2. h()函数如何使用呢?

  • h()函数 如何使用呢?它接受三个参数:

image.png

  • 注意事项:
    • 如果没有props,那么通常可以将children作为第二个参数传入;
    • 如果会产生歧义,可以将null作为第二个参数传入,将children作为第三个参数传入。

3. h函数的基本使用

  • h函数可以在两个地方使用:
    • render函数选项中;
    • setup函数选项中(setup本身需要是一个函数类型,函数再返回h函数创建的VNode)。

image.png

// .vue文件
<script>
  import { h } from 'vue';

  export default {
    render() {
      return h("h2", {class: "title"}, "Hello Render")
    }
  }
</script>

<style scoped>

</style>

4. h函数计数器案例

// .vue文件
<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>

<style scoped>

</style>
// .vue文件——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>

<style scoped>

</style>

5. 函数组件和插槽的使用

image.png

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

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

<style scoped>

</style>
// HelloWorld.vue
<script>
  import { h } from "vue";

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

<style lang="scss" scoped>

</style>

6. jsx

和上面的代码相比较,下面的代码逻辑更加清晰明了。

image.png

// 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>
// HelloWorld.vue
<script>
  export default {
    render() {
      return (
        <div>
          <h2>HelloWorld</h2>
          {this.$slots.default ? this.$slots.default(): <span>哈哈哈</span>}
        </div>
      )
    }
  }
</script>

<style scoped>

</style>