Pressidian
花园入口
笔记
项目
关于
实验室
GitHub
花园入口
笔记
项目
关于
实验室
GitHub

KNOWLEDGE PATHS

笔记库
当前位置
笔记库

Vue 组件与 Render 函数

12 分钟阅读 · Vue

目录树 578 篇

    • 笔记目录
    • CLAUDE.md
    • Vue 组件与 Render 函数

关联笔记 1

↗Vue.js 响应式原理正文关联
  • Vue 组件与 Render 函数

Vue 组件与 Render 函数

个人博客,展示我的前端学习笔记 使用 VuePress 和 Obsidian 编辑的 md 作为博客的技术栈和内容来源,所以起这个项目名

组件意义

没有组件时,一般以一个 html 作为一个开发单元,随着现代前端的需求,这样的开发单元过大,不便管理,当有重复使用的功能时,开发会更加的低效。使用组件能够:

  • 开发粒度、难度降低
  • 减少重复代码,避免重轮子
  • 利于团队协作开发
  • 抽离为组件库

组件概念

每一个 vue 组件本质是一个 js 对象,通过 SFC(Single File Component)单文件组件.vue的形式表示

在vue.createApp()中传入的根组件,本质就是一个包含了很多子组件的组件(对象)

<!DOCTYPE html>
<html lang="">
    <head>
        <meta charset="UTF-8" />

        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>functional component</title>
    </head>
    <body>
        <div id="dano">
                 
            <!--
      这之中的内容可以在template中编辑
      <div>{{ double }}</div>
      <button @click="printff">click me</button>
	  -->
        </div>
        <script type="module">
            import { createApp } from 'vue'
            createApp({
                methods: {
                    printff() {
                        this.count++
                        console.log(this.count)
                    },
                },
                data() {
                    return {
                        count: 3,
                    }
                },
                computed: {
                    double() {
                        return this.count * 2
                    },
                },
                template: /*html*/ `
          <div>{{ double }}</div>
          <button @click="printff">click me</button>
        `,
            }).mount('#dano')
        </script>
    </body>
</html>

在这种情况下,可以将传入的对象以 js 模块的形式导出

// main.js
import { createApp } from 'vue'
import com from '/src/component.js'
createApp(com).mount('#dano')

在将component.js视为component.vue的情况下,上面的写法就与 Vue 的 SFC 形式无异。这种写法和选项式 API 很像。学了 Vue2 就能够很方便的编写内联结构(或者称作 js 渲染方式、Non-Single File Component)的组件。需要特别注意的是在使用这些变量的时候要加==this==,因为这是在 js 中

// component.js
export default {
    methods: {
        printff() {
            this.count++
            console.log(this.count)
        },
    },
    data() {
        return {
            count: 3,
        }
    },
    computed: {
        double() {
            return this.count * 2
        },
    },
    template: /*html*/ `
          <div>{{ double }}</div>
          <button @click="printff">click me</button>
        `,
}

无论是通过 createApp 中的对象,还是通过 .vue 文件定义组件,它们最终都在 Vue 内部被转换成了 组件选项对象(Component Options Object) Vue 组件的核心。在 .vue 文件中,Vue 的构建工具(比如 Vue CLI 或 Vite)会自动将模板、脚本和样式解析并组合成一个 组件选项对象,然后 Vue 内部会处理这些内容并渲染:

  1. template 部分的处理:编译为 render 函数

    • 编译过程:在 .vue 文件中,template 部分会被 Vue 编译成一个 render 函数。这是因为 Vue 需要将 template 转换为 虚拟 DOM(VNode) 的描述,而 render 函数正是 Vue 渲染虚拟 DOM 的核心部分。
    • 工作原理:Vue 使用 模板编译器 将 template 转换为渲染函数。这个渲染函数将描述如何根据组件的状态(data、props、computed 等)渲染组件的视图。
  2. script 部分的处理:解析成组件选项script 部分是用于定义 Vue 组件逻辑的地方,其中包含组件的 data、methods、computed、props 等内容。Vue 会在构建过程中将 script 部分提取出来并解析成组件选项对象。

  3. style 部分的处理:样式预处理和作用域style 部分包含组件的样式,它可以有不同的处理方式:

    • 常规样式:如果没有任何作用域相关的指令(如 scoped),这些样式将会被处理成普通的 CSS,并被加载到页面中。通常,Webpack 会处理它们,将 CSS 提取到单独的 CSS 文件中,或者将其作为内联样式嵌入到 HTML 中。
    • scoped 样式:如果样式部分包含 scoped 属性(<style scoped>),Vue 会使用一种特殊的机制,将样式的作用域限制在当前组件中,防止样式影响到其他组件。

render 函数

Vue 会在内部自动将 template 编译成 render 函数。render 函数可以在 Vue 组件的选项对象中定义,通常是作为 template 的替代品。无论是通过 .vue 文件还是通过 createApp 中的对象方式,render 函数都属于 Vue 组件的渲染逻辑部分。[[响应式原理]]

  1. 灵活性和精确控制

    • 渲染函数(render)提供了更高的灵活性,让你可以精确地控制组件的渲染过程。在某些情况下,使用 template 语法会让你受到限制,特别是在你需要动态地生成组件、动态插入子组件或根据复杂的条件渲染元素时。render 函数可以让你完全控制渲染流程。
    • 在 TypeScript 环境下,render 函数允许你更加细致地定义组件的类型和行为,避免一些模板编译时的类型推断问题。
  2. 类型推导与类型安全

    • 在 TypeScript 中,render 函数能够让你充分利用 TypeScript 提供的类型推导和类型安全。通过 render 函数,你可以显式地控制每个元素的类型,避免模板中的一些类型不一致问题。
    • 对于复杂的项目,render 函数可以确保你可以直接使用类型检查工具来帮助你发现问题,而这在模板中可能会丧失一些类型检查的能力,尤其是在模板复杂的情况下。
  3. 性能优化

    • 在组件库中,性能通常是一个重要的考虑因素。使用 render 函数可以减少 Vue 的模板编译工作,从而提升性能。Vue 的模板需要经过编译阶段生成渲染函数,但使用 render 函数时,直接写代码进行渲染可以减少编译的负担。
    • 函数式组件,即没有实例的组件,使用 render 函数时通常会有更高的性能,尤其在需要频繁渲染且不依赖实例生命周期的情况下。
  4. 构建组件库时的需求

    • 在构建 Vue 组件库时,开发者通常倾向于使用 render 函数来实现组件,因为它使得组件库可以脱离 Vue 单文件组件(.vue 文件)的模板语法,而以纯 JavaScript 或 TypeScript 代码的形式提供更高的控制性和可复用性。
    • 使用 render 函数可以避免一些与模板相关的潜在问题,例如模板编译的复杂性或 Vue 编译器对模板中复杂表达式的限制。通过 render 函数,可以更方便地实现更加复杂的渲染逻辑,比如动态创建节点、条件渲染、递归渲染等。
  5. 函数式组件和 render 函数的协作

    • 函数式组件(Functional Components)是 Vue 的一种特殊组件,它们没有实例化,因此没有 data, computed, methods, 生命周期等。在函数式组件中,渲染逻辑完全依赖 render 函数,它允许你通过传入 props 渲染视图,而不会生成不必要的 Vue 实例。
    • 使用 TypeScript 时,函数式组件配合 render 函数能更好地进行类型推导,使得传递的 props 和返回的虚拟 DOM 元素具有明确的类型。

在 Vue 3 中,render 函数通常用 h(即 createElement)来生成虚拟 DOM,并且可以使用 setup 函数和 Composition API 更好地与 TypeScript 配合。

import { defineComponent, h } from 'vue'

const MyComponent = defineComponent({
    name: 'MyComponent',
    props: {
        msg: {
            type: String,
            required: true,
        },
    },
    render() {
        return h('div', this.msg) // 使用 `h` 函数来创建虚拟 DOM
    },
})

export default MyComponent

在这个例子中:

  • 使用了 defineComponent 来定义一个组件。
  • render 函数使用了 h(即 createElement)来生成虚拟 DOM。
  • this.msg 通过 props 获取组件的属性值。

命令式开发与声明式开发的区别

  • 声明式开发:在 Vue 中,通常你会声明 UI 元素如何根据数据变化(如 props、data、computed)来渲染。当数据发生变化时,Vue 会自动更新 UI。
<MyButton :label="buttonLabel" :disabled="isDisabled" />
  • 命令式开发:你直接控制组件的行为和状态,而不依赖 Vue 的响应式机制。你可能会在组件外部调用方法来控制组件,例如通过 refs 或通过调用暴露出来的方法来改变按钮的状态。
<MyButton ref="myButton" />
<button @click="handleClick">Change Button State</button>
最近更新: 2026/8/3 06:04