vue2.x中h函数(createElement)与vue3中的h函数详解

目录
  • 1. vue2.x的 h 函数(createElement)
  • 2. vue3 h函数配置项
    • 2.1 v-model实现(以下开始为官网实现)
    • 2.2 v-on
    • 2.3 事件修饰符
    • 2.4 插槽
    • 2.5 component 和 is
    • 2.6 自定义指令
    • 2.7 内置组件
    • 2.8 渲染函数的返回值
    • 2.9 JSX
    • 总结

1. vue2.x的 h 函数(createElement)

  • 使用方法及介绍:(参考官网提取)
  • h函数第一个是标签名字 或者是组件名字,第二个参数是配置项,第三个参数是 innerText ,不会帮你转换节点,如果需要转换成节点(v-html)请去第二个参数中的 domProps 配置 innerHTML
  • 当第二个参数是字符串的时候则会直接当 innerText 渲染(相当于配置项参数为空对象)【h(‘span’, ‘姓名’)】
  • 第三个参数如果为字符串的时候可以理解为默认值!(innerText的默认值)如果同时设置了这两个则配置中的权重更高
  • 第三个参数也是该元素的子集合、插槽设置的地方。
  • 温馨提示:vue2.x的h函数跟vue3.x的有点不一样,第二个参数配置项格式变了,第三个参数为函数返回,具体情况看本文第二要点
  • 以下为常见的常规配置
import SelectEdit from './SelectEdit'
export default {
  data() {
  	return {
  	  name: ''
  	}
  },
  render(h) {
  	// 如果使用原生的则
  	// return h('div', {
  	// 这个是挂载组件
  	return h(SelectEdit, {
  		// 此处是给 SelectEdit 组件传值的(props传值)
 		props: {
	      value: 1,
	      type: 'on'
	    },
	    // class可以数组的形式也可以对象的形式
	    // class: ['speci-class'],
	   	class: {
		  'speci-class': true
		},
		// 样式有-的注意小驼峰 或者使用 string 模式
		style: {
		  color: 'red',
		  fontSize: '14px',
		  // 或者这样
		  'font-size': '14px'
		},
		// 普通的 HTML attribute
		attrs: {
		  placeholder: '这是给原生html赋值placeholder属性'
		},
		// DOM property
		domProps: {
    	  innerHTML: 'DOM property',
    	  // 这个参数等同于h函数的第三个参数
    	  innerText: 'xxxxxxx'
  		},
	    // 这里是挂载方法的但不再支持如 `v-on:keyup.enter` 这样的修饰器
	    on: {
	      // 方法名可以自定义(组件内 $emit('xxxchange', {name: 'zs'}))
	      'xxxchange': val => {
	        this.name = val.name;
	      },
	      'click': val => {
	        this.name = val.name;
	      },
	    },
	    // 仅用于组件,用于监听原生事件,而不是组件内部使用
	    // `vm.$emit` 触发的事件。
	    nativeOn: {
	      click: this.nativeClickHandler
	    },
	    // 自定义指令。注意,你无法对 `binding` 中的 `oldValue`
	    directives: [
	      {
	        name: 'my-custom-directive',
	        value: '2',
	        expression: '1 + 1',
	        arg: 'foo',
	        modifiers: {
	          bar: true
	        }
		  }
		],
		// 作用域插槽的格式为
		scopedSlots: {
	     default: props => createElement('span', props.text)
	    },
	     // 如果组件是其它组件的子组件,需为插槽指定名称
	    slot: 'name-of-slot',
	    // 其它特殊顶层 property
	    key: 'myKey',
	    ref: 'myRef',
	    // 如果你在渲染函数中给多个元素都应用了相同的 ref 名,
  	    // 那么 `$refs.myRef` 会变成一个数组。
	    refInFor: true
	 }, '这里是显示文本')
  }
}

举例子了:如果你想要实现以下效果(v-model)

	<div class="row zs active info" name="zs">
		<span style="background-color: red;font-size: 16px;" @click="handleName">姓名:</span>
		<i >{{ name }}</i>
		<input v-model="name" />
	</div>

目测没问题

	data() {
		return {
			name: ''
		}
	},
	render(h) {
		return h('div', {
					class: ['row zs', 'active', 'info'],
					attrs: {
					  name: 'zs'
					}
				}, [
					h('span', {
						style: {
							backgroundColor: red,
							'font-size': '16px'
						},
						on: {
							click: handleName
						}
					}, '姓名:'),
					h('i', '张三'),
					h('input', {
						domProps: {
      						value: this.name
					    },
					    on: {
					      input: function (event) {
					        this.$emit('input', event.target.value)
					      }
					    }
					})
				  ]
				)
	}

2. vue3 h函数配置项

  • 与2.x相比,第一个参数格式没有更变,第二个参数格式更变了,第三个参数变为建议使用函数返回了
  • 第三个参数如果为字符串的时候可以理解为默认值!(innerText的默认值)如果同时设置了这两个则配置中的权重更高
  • 第三个参数也是该元素的子集合、插槽设置的地方。
  • 第三个参数不使用函数会有一个vue警告(所以说直接函数吧)
  • 具体使用如下:
import { h } from 'vue';
import { ElButton } from 'element-plus'
h(
  ElButton,
  {
    type: 'primary',
    innerText: '修改11',
    onClick: () => {
      console.log(11);
    }
  },
  () => '修改'
)

2.1 v-model实现(以下开始为官网实现)

props: ['modelValue'],
emits: ['update:modelValue'],
render() {
  return h(SomeComponent, {
    modelValue: this.modelValue,
    'onUpdate:modelValue': value => this.$emit('update:modelValue', value)
  })
}

自己搞忘记后重新弄的踩坑记录:

  • 双向绑定实现:2.x中是value,但是到了3.x中不是value了而是modelValue
  • onUpdate:modelValue 相当于就是 v-model,只不过这个变成了函数,在这个函数里面需要你自己给绑定元素赋值。不赋值则会出现双向绑定失效的问题!

2.2 v-on

给定有效的事件名称,例如(onClick, onChange)或自定义的名称

render() {
  return h('div', {
    onClick: $event => console.log('clicked', $event.target)
  })
}

2.3 事件修饰符

对于 .passive 、.capture 和 .once 事件修饰符,可以使用驼峰写法将他们拼接在事件名后面:

render() {
  return h('input', {
    onClickCapture: this.doThisInCapturingMode,
    onKeyupOnce: this.doThisOnce,
    onMouseoverOnceCapture: this.doThisOnceInCapturingMode
  })
}

对于所有其它的修饰符,私有前缀都不是必须的,因为你可以在事件处理函数中使用事件方法:

这里是一个使用所有修饰符的例子:

render() {
  return h('input', {
    onKeyUp: event => {
      // 如果触发事件的元素不是事件绑定的元素
      // 则返回
      if (event.target !== event.currentTarget) return
      // 如果向上键不是回车键,则终止
      // 没有同时按下按键 (13) 和 shift 键
      if (!event.shiftKey || event.keyCode !== 13) return
      // 停止事件传播
      event.stopPropagation()
      // 阻止该元素默认的 keyup 事件
      event.preventDefault()
      // ...
    }
  })
}

2.4 插槽

你可以通过 this.$slots 访问静态插槽的内容,每个插槽都是一个 VNode 数组:

render() {
  // `<div><slot></slot></div>`
  return h('div', {}, this.$slots.default())
}
props: ['message'],
render() {
  // `<div><slot :text="message"></slot></div>`
  return h('div', {}, this.$slots.default({
    text: this.message
  }))
}

渲染函数将插槽传递给子组件

render() {
  // `<div><child v-slot="props"><span>{{ props.text }}</span></child></div>`
  return h('div', [
    h(
      resolveComponent('child'),
      {},
      // 将 `slots` 以 { name: props => VNode | Array<VNode> } 的形式传递给子对象。
      {
        default: (props) => h('span', props.text)
      }
    )
  ])
}

插槽以函数的形式传递,允许子组件控制每个插槽内容的创建。任何响应式数据都应该在插槽函数内访问,以确保它被注册为子组件的依赖关系,而不是父组件。相反,对 resolveComponent 的调用应该在插槽函数之外进行,否则它们会相对于错误的组件进行解析。

// `<MyButton><MyIcon :name="icon" />{{ text }}</MyButton>`
render() {
  // 应该是在插槽函数外面调用 resolveComponent。
  const Button = resolveComponent('MyButton')
  const Icon = resolveComponent('MyIcon')

  return h(
    Button,
    null,
    {
      // 使用箭头函数保存 `this` 的值
      default: (props) => {
        // 响应式 property 应该在插槽函数内部读取,
        // 这样它们就会成为 children 渲染的依赖。
        return [
          h(Icon, { name: this.icon }),
          this.text
        ]
      }
    }
  )
}

如果一个组件从它的父组件中接收到插槽,它们可以直接传递给子组件。

render() {
  return h(Panel, null, this.$slots)
}

也可以根据情况单独传递或包裹住。

render() {
  return h(
    Panel,
    null,
    {
      // 如果我们想传递一个槽函数,我们可以通过
      header: this.$slots.header,

      // 如果我们需要以某种方式对插槽进行操作,
      // 那么我们需要用一个新的函数来包裹它
      default: (props) => {
        const children = this.$slots.default ? this.$slots.default(props) : []

        return children.concat(h('div', 'Extra child'))
      }
    }
  )
}

2.5 component 和 is

在底层实现里,模板使用 resolveDynamicComponent 来实现 is attribute。如果我们在 render 函数中需要 is 提供的所有灵活性,我们可以使用同样的函数:

const { h, resolveDynamicComponent } = Vue

// ...

// `<component :is="name"></component>`
render() {
  const Component = resolveDynamicComponent(this.name)
  return h(Component)
}

就像 is, resolveDynamicComponent 支持传递一个组件名称、一个 HTML 元素名称或一个组件选项对象。

通常这种程度的灵活性是不需要的。通常 resolveDynamicComponent 可以被换做一个更直接的替代方案。

例如,如果我们只需要支持组件名称,那么可以使用 resolveComponent 来代替。

如果 VNode 始终是一个 HTML 元素,那么我们可以直接把它的名字传递给 h:

// `<component :is="bold ? 'strong' : 'em'"></component>`
render() {
  return h(this.bold ? 'strong' : 'em')
}

同样,如果传递给 is 的值是一个组件选项对象,那么不需要解析什么,可以直接作为 h 的第一个参数传递。

与 < template > 标签一样,< component > 标签仅在模板中作为语法占位符需要,当迁移到 render 函数时,应被丢弃。

2.6 自定义指令

可以使用 withDirectives 将自定义指令应用于 VNode:

const { h, resolveDirective, withDirectives } = Vue

// ...

// <div v-pin:top.animate="200"></div>
render () {
  const pin = resolveDirective('pin')

  return withDirectives(h('div'), [
    [pin, 200, 'top', { animate: true }]
  ])
}

resolveDirective是模板内部用来解析指令名称的同一个函数。只有当你还没有直接访问指令的定义对象时,才需要这样做

2.7 内置组件

诸如 < keep-alive >、< transition >、< transition-group > 和 < teleport > 等内置组件默认并没有被全局注册。这使得打包工具可以 tree-shake,因此这些组件只会在被用到的时候被引入构建。不过这也意味着我们无法通过 resolveComponent 或 resolveDynamicComponent 访问它们。

在模板中这些组件会被特殊处理,即在它们被用到的时候自动导入。当我们编写自己的 render 函数时,需要自行导入它们:

const { h, KeepAlive, Teleport, Transition, TransitionGroup } = Vue
// ...
render () {
  return h(Transition, { mode: 'out-in' }, /* ... */)
}

2.8 渲染函数的返回值

在我们目前看过的所有示例中,render 函数返回的是单个根 VNode。但其实也有别的选项。

返回一个字符串时会创建一个文本 VNode,而不被包裹任何元素:

render() {
  return 'Hello world!'
}

我们也可以返回一个子元素数组,而不把它们包裹在一个根结点里。这会创建一个片段 (fragment):

// 相当于模板 `Hello<br>world!`
render() {
  return [
    'Hello',
    h('br'),
    'world!'
  ]
}

可能是因为数据依然在加载中的关系,组件不需要渲染,这时它可以返回 null。这样我们在 DOM 中会渲染一个注释节点

2.9 JSX

如果你写了很多渲染函数,可能会觉得下面这样的代码写起来很痛苦:

h(
  'anchored-heading',
  {
    level: 1
  },
  {
    default: () => [h('span', 'Hello'), ' world!']
  }
)

特别是对应的模板如此简单的情况下:

<anchored-heading :level="1"> <span>Hello</span> world! </anchored-heading>

这就是为什么会有一个 Babel 插件,用于在 Vue 中使用 JSX 语法,它可以让我们回到更接近于模板的语法上。

import AnchoredHeading from './AnchoredHeading.vue'

const app = createApp({
  render() {
    return (
      <AnchoredHeading level={1}>
        <span>Hello</span> world!
      </AnchoredHeading>
    )
  }
})

app.mount('#demo')

有关 JSX 如何映射到 JavaScript 的更多信息,请参阅使用文档

参考链接

总结

到此这篇关于vue2.x中h函数(createElement)与vue3中的h函数详解的文章就介绍到这了,更多相关vue2.x与vue3中的h函数内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • vue3中h函数的常用使用方式汇总

    目录 前言 render VNode h 渲染组件 h函数中使用"v-model" 使用场景 总结 前言 一般情况下每个vue组件都用"<template>"写html, 但实际还可以在js代码中通过render函数生成dom. 最主要常见组件库也需要配合"h"使用. render render是组件的一个选项, 他的返回值会被作为组件的DOM结构. <script> import { defineComponent} f

  • vue2.x的深入学习--关于h函数的说明

    目录 解决方案, 总结: vue项目中.写在.vue文件的template里的代码需要借助webpack的模板解析器插件才能解析.单个.html文件引入vue文件时,该vue文件顺便把模板解析器引入进来了(缺点是体积大). 所以我们使用工程化开发项目时候,需要在package.json文件引入vue-template-compile,用于进行模板解析 如果没有模板解析器,就解析不了,但是vue-template-compile只能解析.vue文件里的模板,没办法解析.js文件里的模板: 所以当我

  • Vue3源码解析watch函数实例

    目录 引言 一.watch参数类型 1. 选项options 2. 回调cb 3. 数据源source 二.watch函数 三.watch的核心:doWatch 函数 引言 想起上次面试,问了个古老的问题:watch和computed的区别.多少有点感慨,现在已经很少见这种耳熟能详的问题了,网络上八股文不少.今天,我更想分享一下从源码的层面来区别这八竿子打不着的两者.本篇针对watch做分析,下一篇分析computed. 一.watch参数类型 我们知道,vue3里的watch接收三个参数:侦听

  • vue2.x中h函数(createElement)与vue3中的h函数详解

    目录 1. vue2.x的 h 函数(createElement) 2. vue3 h函数配置项 2.1 v-model实现(以下开始为官网实现) 2.2 v-on 2.3 事件修饰符 2.4 插槽 2.5 component 和 is 2.6 自定义指令 2.7 内置组件 2.8 渲染函数的返回值 2.9 JSX 总结 1. vue2.x的 h 函数(createElement) 使用方法及介绍:(参考官网提取) h函数第一个是标签名字 或者是组件名字,第二个参数是配置项,第三个参数是 inn

  • Vue3状态管理的使用详解

    背景 随着Vue3的逐步应用,对状态管理的需求越来越多.起初是基于Vuex4进行状态管理的,但是Vuex4也暴露了一些问题.从个人角度来说,Vuex4类似于过渡期产品,对TypeScript的支持性并不完整.如果使用TypeScript编写组件,需要遵循一定步骤后,才可以正确进行类型推断,并且对modules的使用上也并不友好.Vuex核心贡献者Kia King也表示Vuex5已经在计划中,并且能提供完整的TypeScript支持,那么在Vuex5面世之前,或者直接"舍弃"Vuex的话

  • Vue3 计算属性的用法详解

    目录 computed 计算属性说明 计算属性使用 总结 注意 上一篇博文说了 vue3 项目的 toRefs 函数和 toRef 函数,今天就稍微总结一下 vue3 的计算属性,其实学过 vue2 的宝子们应该都清楚,计算属性这个东西在项目开发过程中使用的还是比较频繁的,使用频率相对来说比较高,所以说咱今天稍微总结一下 vue3 项目中的计算属性,下面开始. computed 计算属性说明 computed 表示计算属性,通常的作用是用来进行数据处理,方便在末班中简化书写. 比如日常在模板中我

  • c++中.dll与.lib文件的生成与使用的详解

    c++中.dll与.lib文件的生成与使用的详解 -------------------------------------------------------------------------------- 两种库: • 包含了函数所在的DLL文件和文件中函数位置的信息(入口),代码由运行时加载在进程空间中的DLL提供,称为动态链接库dynamic link library.• 包含函数代码本身,在编译时直接将代码加入程序当中,称为静态链接库static link library.共有两种链

  • 浅谈tensorflow中Dataset图片的批量读取及维度的操作详解

    三维的读取图片(w, h, c): import tensorflow as tf import glob import os def _parse_function(filename): # print(filename) image_string = tf.read_file(filename) image_decoded = tf.image.decode_image(image_string) # (375, 500, 3) image_resized = tf.image.resize

  • vite2.0+vue3移动端项目实战详解

    一.涉及技术点 vite版本 vue3 ts 集成路由 集成vuex 集成axios 配置Vant3 移动端适配 请求代理 二.步骤 vite+ts+vue3只需要一行命令 npm init @vitejs/app my-vue-app --template vue-ts 配置路由 npm install vue-router@4 --save 在src下新建router目录,新建index.ts文件 import { createRouter, createWebHashHistory, Ro

  • Vue3生命周期函数和方法详解

     1. 概述 所谓生命周期函数,就是在某一条件下被自动触发的函数. 2. VUE3 生命周期函数介绍 2.1 beforeCreate 在 VUE 实例生成之前会自动执行的函数 2.2 created 在 VUE 实例生成之后会自动执行的函数 2.3 beforeMount 在组件内容被渲染到页面之前自动执行的函数 2.4 mounted 在组件内容被渲染到页面之后自动执行的函数 2.5 beforeUpdate 当data中的数据发生变化前执行的函数 2.6 updated 当data中的数据

  • Vue3插槽Slot实现原理详解

    目录 Vue官方对插槽的定义 Slot到底是什么 如何使用插槽 回顾组件渲染的原理 插槽的初始化原理 解析插槽中的内容 作用域插槽原理 具名插槽原理 默认内容插槽的原理 Vue官方对插槽的定义 Vue 实现了一套内容分发的 API,这套 API 的设计灵感源自 Web Components 规范草案,将 <slot> 元素作为承载分发内容的出口. Slot到底是什么 那么Slot到底是什么呢?Slot其实是一个接受父组件传过来的插槽内容,然后生成VNode并返回的函数. 我们一般是使用 <

  • Vue3 构建 Web Components使用详解

    目录 引言 构建 Web Components 属性 事件 插槽 子组件样式问题 方法 总结 引言 有时候想写一个无关框架组件,又不想用原生或者 Jquery 那套去写,而且还要避免样式冲突,用 Web Components 去做刚觉就挺合适的.但是现在 Web Components 使用起来还是不够灵活,很多地方还是不太方便的,如果能和 MVVM 搭配使用就好了. 早在之前 Angular 就支持将组件构建成 Web Components,Vue3 3.2+ 开始终于支持将组建构建成 Web

  • Vue3父子通讯方式及Vue3插槽的使用方法详解

    在Vue3中父子通讯方式 Vue3父传子(props) 父组件如下: <template> <div class="about"> <h1>This is an about page</h1> <children :num="num" age="30"></children> </div> </template> <script> impo

随机推荐