element-plus源码解读7——vue 渲染函数 API

17 阅读2分钟

vue官方文档地址:cn.vuejs.org/api/render-…

<template>
  <div class="app-wrapper">
    <h1 style="text-align: center; color: #303133">
      Vue 3 渲染函数 (h() API) 学习示例
    </h1>
    <AppComponent />
  </div>
</template>

<script setup>
import AppComponent from './app.js'
</script>

<style scoped>
.app-wrapper {
  max-width: 800px;
  margin: 0 auto;
  padding: 20px;
}

:deep(.app-container) {
  padding: 20px;
}

:deep(.btn) {
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  transition: all 0.3s;
}

:deep(.btn-primary) {
  background-color: #409eff;
  color: white;
}

:deep(.btn-primary:hover) {
  background-color: #66b1ff;
}

:deep(.btn-danger) {
  background-color: #f56c6c;
  color: white;
}

:deep(.btn-danger:hover) {
  background-color: #f78989;
}

:deep(.btn-active) {
  background-color: #67c23a;
  color: white;
}
</style>

import { defineComponent, h, ref, computed } from 'vue'

/**
 * 使用 h() 函数创建虚拟 DOM 节点的示例组件
 * h() 是 Vue 3 的渲染函数 API,用于创建虚拟 DOM 节点 (vnode)
 */
export default defineComponent({
  name: 'AppComponent',
  setup() {
    // 响应式数据
    const count = ref(0)
    const message = ref('Hello Vue 3 Render Function!')
    const items = ref(['Item 1', 'Item 2', 'Item 3'])
    const isActive = ref(true)

    // 计算属性
    const doubleCount = computed(() => count.value * 2)

    // 方法
    const increment = () => {
      count.value++
    }

    const decrement = () => {
      count.value--
    }

    const toggleActive = () => {
      isActive.value = !isActive.value
    }

    // 返回渲染函数
    return () => {
      // h() 函数的基本语法:
      // h(tag, props, children)
      // - tag: 标签名、组件或异步组件
      // - props: 属性对象(可选)
      // - children: 子节点(可选)

      return h('div', { class: 'app-container' }, [
        // 1. 创建简单的 HTML 元素
        h(
          'h1',
          {
            class: 'title',
            style: { color: '#409eff', marginBottom: '20px' },
          },
          message.value
        ),

        // 2. 创建带事件处理的按钮
        h('div', { class: 'button-group' }, [
          h(
            'button',
            {
              onClick: increment,
              class: 'btn btn-primary',
              style: { marginRight: '10px', padding: '8px 16px' },
            },
            '增加 (+1)'
          ),

          h(
            'button',
            {
              onClick: decrement,
              class: 'btn btn-danger',
              style: { marginRight: '10px', padding: '8px 16px' },
            },
            '减少 (-1)'
          ),

          h(
            'button',
            {
              onClick: toggleActive,
              class: ['btn', { 'btn-active': isActive.value }],
              style: { padding: '8px 16px' },
            },
            isActive.value ? '禁用' : '启用'
          ),
        ]),

        // 3. 显示响应式数据
        h('div', { class: 'counter-section', style: { marginTop: '20px' } }, [
          h(
            'p',
            { style: { fontSize: '18px', fontWeight: 'bold' } },
            `计数: ${count.value}`
          ),
          h(
            'p',
            { style: { color: '#67c23a' } },
            `双倍计数: ${doubleCount.value}`
          ),
        ]),

        // 4. 条件渲染
        h('div', { class: 'status-section', style: { marginTop: '20px' } }, [
          isActive.value
            ? h(
              'p',
              {
                style: { color: '#67c23a', fontSize: '16px' },
              },
              '✅ 状态: 激活'
            )
            : h(
              'p',
              {
                style: { color: '#f56c6c', fontSize: '16px' },
              },
              '❌ 状态: 禁用'
            ),
        ]),

        // 5. 列表渲染
        h('div', { class: 'list-section', style: { marginTop: '20px' } }, [
          h(
            'h2',
            { style: { fontSize: '20px', marginBottom: '10px' } },
            '列表项:'
          ),
          h(
            'ul',
            {
              style: { listStyle: 'none', padding: 0 },
            },
            items.value.map((item, index) =>
              h(
                'li',
                {
                  key: index,
                  style: {
                    padding: '8px',
                    margin: '4px 0',
                    backgroundColor: '#f0f2f5',
                    borderRadius: '4px',
                  },
                },
                `${index + 1}. ${item}`
              )
            )
          ),
        ]),

        // 6. 嵌套组件结构
        h(
          'div',
          {
            class: 'card',
            style: {
              marginTop: '20px',
              padding: '20px',
              border: '1px solid #dcdfe6',
              borderRadius: '4px',
              backgroundColor: '#fff',
            },
          },
          [
            h('h3', { style: { marginTop: 0 } }, '卡片标题'),
            h(
              'p',
              { style: { color: '#606266' } },
              '这是一个使用 h() 函数创建的卡片组件示例'
            ),
          ]
        ),

        // 7. 使用插槽(通过函数传递子节点)
        h(
          'div',
          {
            class: 'footer',
            style: { marginTop: '20px', color: '#909399' },
          },
          '使用 Vue 3 h() API 创建的虚拟 DOM'
        ),
      ])
    }
  },
})