vue3开发技巧

494 阅读3分钟

1.善用h(createVNode)和render 函数

h 函数本质上是用了 Vue 内置函数 —— createVNode()、render() 实现的

createVNode —— 创建虚拟 DOM:

  • @param 参数1 创建元素类型,必选
  • @param 参数2 创建元素属性
  • @param 参数3 创建元素内容

render —— 渲染虚拟 DOM:

  • @param 参数1 要被渲染的虚拟 DOM,必选
  • @param 参数2 要渲染的位置,必选

h() 函数的使用方式:

// 除了类型必填以外,其他的参数都是可选的
h('div')
h('div', { id: 'foo' })

// attribute 和 property 都能在 prop 中书写
// Vue 会自动将它们分配到正确的位置
h('div', { class: 'bar', innerHTML: 'hello' })

// 可以添加.prop 和 .attr等修饰符
// 分别带有 '.' 和 `^' 前缀 
h('div', { '.name': 'some-name', '^width': '100' })

// 类与样式可以像在模板中一样
// 用数组或对象的形式书写
h('div', { class: [foo, { bar }], style: { color: 'red' } })

// 事件监听器应以 onXxx 的形式书写
h('div', { onClick: () => {} })

// children 可以是一个字符串
h('div', { id: 'foo' }, 'hello')

// 没有 props 时可以省略不写
h('div', 'hello')
h('div', [h('span', 'hello')])

// children 数组可以同时包含 vnodes 与字符串
h('div', ['hello', h('span', 'hello')])

h() 函数 接收的参数

  • type —— 元素的类型,必选
  • propsOrChildren —— 数据对象(props、attrs、dom、class、style、...)
  • children —— 子节点,可以包含混合的 VNode 和 字符串 除类型 type 之外,所有参数都是可选的 得到的 vnode 为如下形式:
const vnode = h('div', { id: 'foo' }, [])

vnode.type // 'div'
vnode.props // { id: 'foo' }
vnode.children // []
<template>
  <div></div>
</template>
 
<script lang="ts" setup>
import { createVNode, render } from 'vue'
 
/**
 * createVNode —— 创建虚拟 DOM
 * @param 参数1 创建元素类型,必选
 * @param 参数2 创建元素属性
 * @paran 参数3 创建元素内容
 * @description 虚拟 DOM 创建完成后,需要使用 render 函数,才能在页面中渲染
 */
const testDiv = createVNode('div', { id: "myDivId" }, 'Lyrelion');
 
/**
 * render —— 渲染虚拟 DOM
 * @param 参数1 要被渲染的虚拟 DOM,必选
 * @param 参数2 要渲染的位置,必选
 * @description 虚拟 DOM 创建完成后,需要使用 render 函数,才能在页面中渲染
 */
render(testDiv, document.body);
</script>

2.善用JSX/TSX

JSX 是 JavaScript 的一个类似 XML 的扩展,有了它,我们可以用以下的方式来书写代码:

const vnode = <div>hello</div>

在 JSX 表达式中,使用大括号来嵌入动态值:

const vnode = <div id={dynamicId}>hello, {userName}</div>

下面我们提供了几个常见的用等价的渲染函数 / JSX 语法,实现模板功能的案例:

v-if

模板:

<div> 
    <div v-if="ok">yes</div>
    <span v-else>no</span>
</div>

等价于使用如下渲染函数 / JSX 语法:

h('div', [ok.value ? h('div', 'yes') : h('span', 'no')])
<div>{ok.value ? <div>yes</div> : <span>no</span>}</div>

v-for

模板:

<ul>
  <li v-for="{ id, text } in items" :key="id">
    {{ text }}
  </li>
</ul>

等价于使用如下渲染函数 / JSX 语法:

h(
  'ul',
  // assuming `items` is a ref with array value
  items.value.map(({ id, text }) => {
    return h('li', { key: id }, text)
  })
)

<ul>
  {items.value.map(({ id, text }) => {
    return <li key={id}>{text}</li>
  })}
</ul>

v-on

以 on 开头,并跟着大写字母的 props 会被当作事件监听器。比如,onClick 与模板中的 @click 等价。

h(
  'button',
  {
    onClick(event) {
      /* ... */
    }
  },
  'click me'
)
<button
  onClick={(event) => {
    /* ... */
  }}
>
  click me
</button>

事件修饰符

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

h('input', {
  onClickCapture() {
    /* 捕捉模式中的监听器 */
  },
  onKeyupOnce() {
    /* 只触发一次 */
  },
  onMouseoverOnceCapture() {
    /* 单次 + 捕捉 */
  }
})
<input
  onClickCapture={() => {}}
  onKeyupOnce={() => {}}
  onMouseoverOnceCapture={() => {}}
/>

组件

在给组件创建 vnode 时,传递给 h() 函数的第一个参数应当是组件的定义。这意味着使用渲染函数时不再需要注册组件了 —— 可以直接使用导入的组件:

import Foo from './Foo.vue'
import Bar from './Bar.jsx'

function render() {
  return h('div', [h(Foo), h(Bar)])
}

function render() {
  return (
    <div>
      <Foo />
      <Bar />
    </div>
  )
}

动态组件在渲染函数中也可直接使用:

import Foo from './Foo.vue'
import Bar from './Bar.jsx'

function render() {
    return ok.value ? h(Foo) : h(Bar)
}
function render() {
  return ok.value ? <Foo /> : <Bar />
}

3.善用依赖注入(Provide / Inject)

在vue中,我们套用依赖注入的概念,其实就是在父组件中声明依赖,将他们注入到子孙组件实例中去,可以说是能够很大程度上代替全局状态管理的存在

4.善用Composition API抽离通用逻辑

4.善用Composition API抽离通用逻辑

4.善用Composition API抽离通用逻辑