夜猫子的知识栈 夜猫子的知识栈
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《Web Api》
    • 《ES6教程》
    • 《Vue》
    • 《React》
    • 《TypeScript》
    • 《Git》
    • 《Uniapp》
    • 小程序笔记
    • 《Electron》
    • JS设计模式总结
  • 《前端架构》

    • 《微前端》
    • 《权限控制》
    • monorepo
  • 全栈项目

    • 任务管理日历
    • 无代码平台
    • 图书管理系统
  • HTML
  • CSS
  • Nodejs
  • Midway
  • Nest
  • MySql
  • 其他
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • Ajax
  • Vite
  • Vitest
  • Nuxt
  • UI库文章
  • Docker
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

夜猫子

前端练习生
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《Web Api》
    • 《ES6教程》
    • 《Vue》
    • 《React》
    • 《TypeScript》
    • 《Git》
    • 《Uniapp》
    • 小程序笔记
    • 《Electron》
    • JS设计模式总结
  • 《前端架构》

    • 《微前端》
    • 《权限控制》
    • monorepo
  • 全栈项目

    • 任务管理日历
    • 无代码平台
    • 图书管理系统
  • HTML
  • CSS
  • Nodejs
  • Midway
  • Nest
  • MySql
  • 其他
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • Ajax
  • Vite
  • Vitest
  • Nuxt
  • UI库文章
  • Docker
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 基础

  • 响应式

  • 组件

  • 过渡&动画

  • 可复用性

    • Mixin混入
    • 渲染函数
      • createElement参数(h参数)
        • vue2写法
        • vue3写法
      • v-if 和 v-for
      • v-model
      • v-on
        • 事件修饰符
      • 插槽
        • 静态插槽(子组件)
        • 作用域插槽(父组件)
      • JSX语法
      • 函数式组件
        • vue2
        • vue3
    • 全局API
    • Teleport
    • 组合式API
    • 引入css样式
    • 自定义hook
    • 自定义插件
    • 自定义事件
    • 自定义指令
  • 工具

  • 规模化

  • 路由(核心)

  • 组合式

  • Vuex

  • Pinia

  • 其他

  • Vue3 源码学习记录

  • 《Vue》笔记
  • 可复用性
夜猫子
2022-06-26
目录

渲染函数

# 渲染函数

简单的渲染函数:

render: function (createElement) {
  return createElement('h1', this.blogTitle)
}
//简化
render(){
    return h('h1',{},this.blogTitle)//{}中为 prop 或 attribute
}
1
2
3
4
5
6
7

等价于

<h1>{{ blogTitle }}</h1>
1

createElement:返回一个虚拟节点,来告诉页面需要如何渲染。

h 作为 createElement 的别名是 Vue 生态系统中的一个通用惯例。

如 view 中的 render:

render:(h, params)=>{
    return h('div', {style:{width:'100px',height:'100px',background:'#ccc'}}, '地方')
}
1
2
3

Vue3 的命名函数式组件

import { h } from 'vue'

const DynamicHeading = (props, context) => {
  return h(`h${props.level}`, context.attrs, context.slots)
}

DynamicHeading.props = ['level']

export default DynamicHeading
1
2
3
4
5
6
7
8
9
export default oneComponent
render () {
    return this.renderVN()
  }
1
2
3
4

# createElement参数(h参数)

参数1 {String | Object | Function}:一个 HTML 标签名、组件选项对象,或者 resolve 了上述任何一种的一个 async 函数。如:div

参数2 {Object}:一个与模板中 attribute 对应的数据对象。可选。如:

{
 'class': {/*class样式切换,foo类样式和bar类式样式的显示控制*/
    foo: true,
    bar: false
  },
 style: {/*样式*/
    color: 'red',
    fontSize: '14px'
  },
 attrs: {/*元素标签*/
    name: headingId,
    href: '#' + headingId
  },
 props: {/*组件prop*/
    myProp: 'bar'
  },
 on: {//事件监听器
    click: this.clickHandler
  },
 nativeOn: {/*`vm.$emit` 触发的事件*/
    click: this.nativeClickHandler
  },
 scopedSlots: {/*作用域插槽  格式为{ name: props => VNode | Array<VNode> }*/
    default: props => createElement('span', props.text)
  },
  // 如果组件是其它组件的子组件,需为插槽指定名称
  slot: 'name-of-slot',
  // 其它特殊顶层 property
  key: 'myKey',
  ref: 'myRef',
  refInFor: true//如果在渲染函数中给多个元素都应用了相同的 ref 名,开启后`$refs.myRef` 会变成一个数组。
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# vue2写法

更加的扁平化

{
  class: ['button', { 'is-outlined': isOutlined }],
  style: [{ color: '#34495E' }, { backgroundColor: buttonColor }],
  id: 'submit',
  innerHTML: '',
  onClick: submitForm,
  key: 'submit-button'
}
1
2
3
4
5
6
7
8

参数3 {String | Array}:子级虚拟节点(VNodes),由 createElement() 构建而成,可选。如:

createElement(
  // {String | Object | Function} //标签对象
     'div',
  // {Object} //标签的attr属性
[ //子级虚拟节点
    createElement('h1', '一则头条'),
    createElement(MyComponent, {
      props: {
        someProp: 'foobar'
      }
    })
  ]
1
2
3
4
5
6
7
8
9
10
11
12

# vue3写法

render 函数不再接收任何参数,相应的,其可以访问在作用域中声明的响应式状态和函数

() =>
      h(
        'div',
        {
          onClick: increment
        },
        state.count
      )
1
2
3
4
5
6
7
8

# v-if 和 v-for

只要在原生的 JavaScript 中可以轻松完成的操作,Vue 的渲染函数就不会提供专有的替代方法。比如,在模板中使用的 v-if 和 v-for:

<ul v-if="items.length">
  <li v-for="item in items">{{ item.name }}</li>
</ul>
<p v-else>No items found.</p>
1
2
3
4

这些都可以在渲染函数中用 JavaScript 的 if/else 和 map 来重写:

props: ['items'],
render: function (createElement) {
  if (this.items.length) {
    return createElement('ul', this.items.map(function (item) {
      return createElement('li', item.name)
    }))
  } else {
    return createElement('p', 'No items found.')
  }
}
1
2
3
4
5
6
7
8
9
10

# v-model

v-model 指令扩展为 modelValue 和 onUpdate:modelValue 在模板编译过程中,我们必须自己提供这些 prop:

props: ['modelValue'],
emits: ['update:modelValue'],
render() {
  return h(SomeComponent, {
    modelValue: this.modelValue,
    'onUpdate:modelValue': value => this.$emit('update:modelValue', value)
  })
}
1
2
3
4
5
6
7
8

# v-on

我们必须为事件处理程序提供一个正确的 prop 名称,例如,要处理 click 事件,prop 名称应该是 onClick。

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

# 事件修饰符

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

实例:

render() {
  return h('input', {
    onClickCapture: this.doThisInCapturingMode,
    onKeyupOnce: this.doThisOnce,
    onMouseoverOnceCapture: this.doThisOnceInCapturingMode
  })
}
1
2
3
4
5
6
7

其他修饰符,可以直接通过 event 使用

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

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()
      // ...
    }
  })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 插槽

# 静态插槽(子组件)

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

render() {
  // `<div><slot></slot></div>`
  return h('div', {}, this.$slots.default())
}
1
2
3
4

也可以通过 this.$scopedSlots 访问作用域插槽,每个作用域插槽都是一个返回若干 VNode 的函数:

props: ['message'],
render() {
  // `<div><slot :text="message"></slot></div>`//默认插槽容器,具有text属性,text属性内容为message
  return h('div', {}, this.$slots.default({
    text: this.message
  }))
}
1
2
3
4
5
6
7

# 作用域插槽(父组件)

如果要用渲染函数向子组件中传递作用域插槽:

其中 resolveComponent 是模板内部用来解析组件名称的同一个函数。

const { h, resolveComponent } = Vue

render() {
  // `<div><child v-slot="props"><span>{{ props.text }}</span></child></div>`//默认插槽模板,props为当前插槽容器的属性集合
  return h('div', [
    h(
      resolveComponent('child'),
      {},
      // 将 `slots` 以 { name: props => VNode | Array<VNode> } 的形式传递给子对象。
      {//只有默认插槽才能直接运用到组件中,否则必须放在template标签上
        default: (props) => h('span', props.text)
      }
    )
  ])
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# JSX语法

<anchored-heading :level="1">
  <span>Hello</span> world!
</anchored-heading>
1
2
3
import AnchoredHeading from './AnchoredHeading.vue'

new Vue({
  el: '#demo',
  render: function (h) {
    return (
      <AnchoredHeading level={1}>
        <span>Hello</span> world!
      </AnchoredHeading>
    )
  }
1
2
3
4
5
6
7
8
9
10
11

h 作为 createElement 的别名是 Vue 生态系统中的一个通用惯例

极简化写法:

render() {
  return <p>hello { this.message }</p>
}
1
2
3

# 函数式组件

# vue2

<script>
export default {
  functional: true,
  props: {
    render: {
      type: Function,
      required: true,
    },
    scope: {
      type: Object,
      required: true,
    },
  },
  render: (h, ctx) => {
    const VNode = ctx.props.render(h, ctx.props.scope);
    return VNode;
  },
};
</script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# vue3

import { h } from 'vue'
import type { SetupContext } from 'vue'
type FComponentProps = {
  render: (h:Function,scope:any)=>any
  scope:any
}

export function FComponent(
  props: FComponentProps,
  context: SetupContext<any>
) {
  const VNode = props.render(h, props.scope);
  return return VNode;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
编辑 (opens new window)
上次更新: 2024/6/19 17:09:56
Mixin混入
全局API

← Mixin混入 全局API→

最近更新
01
IoC 解决了什么痛点问题?
03-10
02
如何调试 Nest 项目
03-10
03
Provider注入对象
03-10
更多文章>
Copyright © 2019-2025 Study | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式