【问题标题】:In Vue, what parameters does createElement() actually get?在 Vue 中,createElement() 实际获取的参数是什么?
【发布时间】:2019-12-05 07:05:54
【问题描述】:

(这是这个问题之后的另一个问题:In Vue, what is the relationship of template, render, VNode?

找到createElement()的源代码(来自here):

function createElement (
    context,
    tag,
    data,
    children,
    normalizationType,
    alwaysNormalize
) { ... }

代码

ma​​in.js: (部分)

import App from './App.vue'

new Vue({
  el: '#app',
  render: h => h(App),
  router
})

App.vue:

<template>
  <div id="content">
    <!--    <img src="./assets/logo.png" alt="">-->
    <router-view></router-view>
  </div>
</template>

<script>
  export default {}
</script>

问题

  • A.App.vue 中,export default {} 会返回一个空对象,对吗?
  • B.main.js
    • B-1. import App from './App.vue',会将App 绑定到空对象,对吗?
    • B-2. render: h =&gt; h(App),如果前两个问题的答案都是肯定的,那么这里h (这是vue的createElement()函数的别名)会得到context 的单个参数,其值为空对象,对吗?
    • B-3. 但是,这没有多大意义,因为在我的测试中,模板实际上是在浏览器中呈现的,它不是空的。
  • C.那么,在上面的代码中,有多少个参数传递给createElement(),每个参数的值是多少?
  • D. 我在上面的描述中误解了VueES6 的哪一部分?

【问题讨论】:

    标签: javascript vue.js ecmascript-6 vuejs2


    【解决方案1】:

    单文件组件,即.vue文件,经过Vue Loader的特殊处理。见:

    https://vue-loader.vuejs.org/#what-is-vue-loader

    这将干扰export/import 进程,以便一切按预期工作。

    所以:

    App.vue 中,export default {} 会返回一个空对象,对吗?

    它适用于.js 文件。但是对于 .vue 文件,它不会,一旦通过 Vue Loader 就不会。

    尝试控制台在main.js 中记录App 的值,以查看实际导入的内容。您应该会看到一个 render 函数(从您的模板编译而来)以及其他一些小的支持部分。

    更新

    回答 cmets 的后续问题。

    createElement 只是创建一个 VDOM 节点。它不会为该节点创建组件实例。 Vue 从render 返回后进一步处理 VDOM 节点树,并创建它需要的任何子组件实例。然后它会在这些组件上调用 render 以生成它们需要的 VDOM 节点,依此类推,直到所有内容都被渲染。

    我创建了一个小例子来说明这一点。它由一个父级和两个子级组成。请注意,在调用createElement 时,创建和渲染子组件的日志不会立即发生。相反,它发生在 render 函数返回之后。

    const child = {
      render (createElement) {
        console.log('rendering the child')
        return createElement('div', null, ['hello'])
      },
      
      created () {
        console.log('child is created')
      }
    }
    
    new Vue({
      el: '#app',
      
      components: {
        child
      },
      
      created () {
        console.log('parent is created')
      },
      
      render (createElement) {
        console.log('rendering the parent')
        
        const children = [
          createElement('child'),
          createElement('child')
        ]
        
        const root = createElement('div', null, children)
        
        console.log('finished calling createElement')
        
        return root
      }
    })
    <script src="https://unpkg.com/vue@2.6.10/dist/vue.js"></script>
    <div id="app"></div>

    【讨论】:

    • 检查打印的App 后,看起来App 上的render 函数将被createElement() 调用以最终创建VNode,但不确定是不是这样。
    • @EricWang 从您的评论中不清楚您指的是哪个 VNode,但 createElement 不会调用 render。我用一个例子更新了我的答案,试图说明什么时候会发生什么。
    【解决方案2】:

    在 App.vue 中,export default {} 会返回一个空对象,对吗?

    不,.vue 文件是由vue-loader 编译的Single File Components

    B.在 main.js 中: B-1。 import App from './App.vue',会把App绑定到空对象,对吗?

    不,见上文。

    B-2。 render: h => h(App),如果前两个问题的答案是肯定的,那么这里的 h(它是 vue 的 createElement() 函数的别名)将得到一个参数,对于值为空对象的上下文,是对吗?

    没有。 App 是一个准备附加到 Vue 实例的组件。 import App 只是将编译后的文件作为 ES6 模块导入。

    C.那么,在上面的代码中,createElement() 传递了多少个参数,每个参数的值是多少?

    如果您console.log(App),您将看到已编译的模块(至少):

    {
      render: function render() {}
      staticRenderFns: Array[0]
      _compiled: true
      beforeCreate: Array[2]
      __file: "/src/App.vue"
      beforeDestroy: Array[1]
      _Ctor: Object
    }
    

    D.我在上面的描述中误解了 Vue 或 ES6 的哪一部分?

    两者兼而有之。 Vue 文件被编译成 Vue 实例。 ES6 模块封装了各种功能,并将这些功能作为库公开给其他 JavaScript 文件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-04
      • 2017-09-09
      • 1970-01-01
      相关资源
      最近更新 更多