VueJS 渲染 VNode

扫码查看
本文介绍了VueJS 渲染 VNode的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定一个 VueJS VNode 对象,我如何获取渲染后生成的 HTML 元素?

Given a VueJS VNode object, how do I get the HTML element that would be generated if it were rendered?

例如:

> temp1
VNode {tag: "h1", data: undefined, children: Array(1), text: undefined, elm: undefined, …}
> temp1.children[0]
VNode {tag: undefined, data: undefined, children: undefined, text: "Test", elm: undefined, …}
> doSomething(temp1)
<h1>Test</h1>

目标

我正在尝试围绕 DataTables.net 库构建一个小型 VueJS 包装器.

Goal

I'm attempting to build a small VueJS wrapper around the DataTables.net library.

为了在我的标记中模仿 HTML 表格的行为,我想要如下内容:

To mimic the behavior of HTML tables in my markup, I want something like the following:

<datatable>
    <thead>
        <tr>
            <th>Name</th>
            <th>Age</th>
            <th>Salary</th>
        </tr>
    </thead>
    <tbody>
        <datatable-row v-for="person in people">
            <td>{{ person.name }}</td>
            <td>{{ person.age }}</td>
            <td>{{ person.salary }}</td>
        </datatable-row>
    </tbody>
</datatable>

到目前为止我做了什么

我已经开始按如下方式实施:

What I've done so far

I've started to implement this as follows:

DataTable.vue

<template>
    <table ref="table" class="display table table-striped" cellspacing="0" width="100%">
        <slot></slot>
    </table>
</template>

<script>
/* global $ */
export default {
    data: () => ({
        instance: null
    }),
    mounted() {
        this.instance = $(this.$refs.table).dataTable();
        this.$el.addEventListener("dt.row_added", function(e) {
            this.addRow(e.detail);
        });
    },
    methods: {
        addRow(row) {
            // TODO <-----
            console.log(row);
        }
    }
};
</script>

DataTableRow.vue

<script>
/* global CustomEvent */
export default {
    mounted() {
        this.$nextTick(() => {
            this.$el.dispatchEvent(new CustomEvent("dt.row_added", {
                bubbles: true,
                detail: this.$slots.default.filter(col => col.tag === "td")
            }));
        });
    },
    render() { return ""; }
};

目前的作用:

  • 当页面加载时,DataTable 被初始化.所以列标题格式正确,我在左下角看到显示 0 到 0 个条目,共 0 个条目"
  • CustomEvent 能够冒泡通过 并被 DataTable 元素成功 捕获strong>(规避了 VueJS 中不能在 slot 上监听事件的限制)
  • What this currently does:

    • When the page loads, the DataTable is initialized. So the column headers are properly formatted and I see "Showing 0 to 0 of 0 entries" in the bottom left
    • The CustomEvent is able to bubble up past the <tbody> and be caught by the DataTable element successfully (circumventing the limitation in VueJS that you can't listen to events on slots)
      • 实际添加行

      我的事件给了我一组 VNode 对象.在我的行中,每列有一个 VNode.DataTables API 有一个 addRow 函数,可以这样调用:

      My event is giving me an array of VNode objects. There's one VNode per column in my row. The DataTables API has an addRow function which can be called like so:

      this.instance.row.add(["col1", "col2", "col3"]);
      

      就我而言,我希望 VNode 渲染的结果元素成为该数组中的元素.

      In my case, I want the resultant element from the rendering of the VNode to be the elements in this array.

      var elems = [];
      for (var i = 0; i < row.length; i++)
          elems[i] = compile(row[i]);
      this.instance.row.add(elems);
      

      不幸的是,这个 compile 方法避开了我.我尝试浏览 VueJS 文档并尝试谷歌搜索它,但没有骰子.我尝试手动传递 createElement 函数(传递给 render 方法的参数),但这引发了错误.如何在不将结果注入 DOM 的情况下让 VueJS 渲染 VNode?

      Unfortunately this compile method eludes me. I tried skimming the VueJS documentation and I tried Googling it, but no dice. I tried manually passing the createElement function (the parameter passed to the render method) but this threw an error. How can I ask VueJS to render a VNode without injecting the result into the DOM?

      推荐答案

      我遇到了同样的问题,想要对 DataTables.net 的行详细信息模板做基本相同的事情.

      I ran into the same issue wanting to do basically the same thing with a row details template for DataTables.net.

      一种解决方案可能是创建一个通用组件来呈现 VNode 并以编程方式对其进行实例化.这是我使用数据表的 row.child() API 插入的动态详细信息行的设置方法.

      One solution could be to create a generic component that renders out a VNode and instantiate that programmatically. Here is how my setup for a dynamic detail row that I insert using datatable's row.child() API.

      RenderNode.js

      export default {
          props: ['node'],
          render(h, context) {
              return this.node ? this.node : ''
          }
      }
      

      Datatables.vue

      包含上面的渲染器组件

      import Vue from 'vue'
      import nodeRenderer from './RenderNode'
      

      实例化并挂载渲染器以获取编译后的 HTML

      Instantiate and mount the renderer to get the compiled HTML

      // Assume we have `myVNode` and want its compiled HTML
      
      const DetailConstructor = Vue.extend(nodeRenderer)
      
      const detailRenderer = new DetailConstructor({
          propsData: {
              node: myVNode
          }
      })
      
      detailRenderer.$mount()
      // detailRenderer.$el is now a compiled DOM element
      row.child(detailRenderer.$el).show()
      

      这篇关于VueJS 渲染 VNode的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-04 01:22
查看更多