编译在运行时作为道具接收的 Vuetify 标签/模板 [英] Compile Vuetify tags/template received as prop in runtime

查看:18
本文介绍了编译在运行时作为道具接收的 Vuetify 标签/模板的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想向组件发送一个模板"道具,然后渲染它.如果我发送一个普通的 HTML 它可以工作,但是如果我发送一个像 <v-btn>test</v-btn> 这样的 Vuetify 标签,模板不会被编译.

我知道我不应该通过 props 传递模板,但这是一个特殊情况:父组件作为模板构建器"工作;并且子组件用作结果查看器",因此我必须将创建的模板传递给子组件,以便它可以编译并显示它.

这是我一直在尝试的:

main.js

从'vue'导入Vue从'./App.vue'导入应用程序//这里有一些导入...从 './plugins/vuetify' 导入 vuetify;新的 Vue({验证,渲染:h =>h(应用程序)}).$mount('#app')

App.vue

<模板><v-app id="app";style="padding-top: 64px;"><v-app-bar应用程序颜色=蓝色"><v-btn 压抑的颜色=白色"class="black--text";click=addBtn">按钮</v-btn></v-app-bar><dynamic :template='template'></dynamic></v-app>

解决方案

在动态组件内部尝试使用传递的模板渲染 vue 组件:

var dynamic = {道具:['模板'],数据:() =>({模板渲染:空,}),渲染(h){如果(!this.template){return h('div', '加载中...');} else {//如果有模板,我会展示出来return h(Vue.component('dynamic-render', {template:this.template}));}},}

完整示例

var dynamic = {道具:['模板'],数据:() =>({模板渲染:空,}),渲染(h){如果(!this.template){return h('div', '加载中...');} else {//如果有模板,我会展示出来return h(Vue.component('动态渲染', {模板:this.template}));}},}var app = new Vue({el: '#app',vuetify: 新的 Vuetify(),数据:() =>({计数:1,模板:`<v-row><v-col><v-btn class="pa-2 primary white--text">Test</v-btn></v-col><v-col><v-btn class="pa-2 primary white--text">Test</v-btn></v-col><v-col><v-btn class="pa-2 primary white--text">Test</v-btn></v-col></v-row>`,}),组件: {动态的,},方法: {更改内容(){this.count = this.count + 1this.template = '';setTimeout(() => {//模拟加载状态this.template = `<v-col><v-btn class="pa-2 primary white--text">Btn ${this.count}</v-btn></v-col>`}, 2000);}}})

<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet"><link href="https://cdn.jsdelivr.net/npm/@mdi/font@5.x/css/materialdesignicons.min.css" rel="stylesheet"><link href="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css" rel="stylesheet"><script src="https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js"></script><script src="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js"></script><script src="https://unpkg.com/axios/dist/axios.min.js"></script><div id="应用程序"><v-app id="inspire"><v-btnpressed color="primary" class="black--text" @click="changeContent">更改内容</v-btn><dynamic :template='template'></dynamic></v-app>

I want to send a 'template' prop to a component then render it. If I send a plain HTML it works, but if I send a Vuetify tag like <v-btn>test</v-btn> the template does not get compiled.

I know i shouldn't pass a template via props, but this is a specific case: The parent component works as a "template builder" and the child components works as the "result viewer", so I have to pass the created template to the child so that it can compile and show it.

Here's what I've been trying:

main.js

import Vue from 'vue'
import App from './App.vue'
// Some imports here ...
import vuetify from './plugins/vuetify';

new Vue({
    vuetify,
    render: h => h(App)
}).$mount('#app')

App.vue

<script>

import Vue from 'vue'

// eslint-disable-next-line
var staticRenderFns = [];

var dynamic = {
  props: ['template'],
  data: () => ({
      templateRender: null,
  }),
  render(h) {
    if (!this.templateRender) {
      return h('div', 'loading...');
    } else { // If there is a template, I'll show it
      return this.templateRender();
    }
  },
  watch: {
    // Every time the template prop changes, I recompile it to update the DOM
    template:{
      immediate: true, // makes the watcher fire on first render, too.
      handler() {
        var res = Vue.compile(this.template);

        this.templateRender = res.render;
        
        // staticRenderFns belong into $options, 
        // appearantly
        this.$options.staticRenderFns = []
        
        // clean the cache of static elements
        // this is a cache with the results from the staticRenderFns
        this._staticTrees = []
        
        // Fill it with the new staticRenderFns
        for (var i in res.staticRenderFns) {
          //staticRenderFns.push(res.staticRenderFns[i]);
          this.$options.staticRenderFns.push(res.staticRenderFns[i])
        }
      }
    }
  },
}

export default {
  name: 'App',
  data: () => ({
    template:`
            <v-row>
              <v-col>
                <v-btn class="pa-2 primary white--text">Test</v-btn>
              </v-col>
              <v-col>
                <v-btn class="pa-2 primary white--text">Test</v-btn>
              </v-col>
              <v-col>
                <v-btn class="pa-2 primary white--text">Test</v-btn>
              </v-col>
            </v-row>
    `,
  }),
  components:{
    dynamic,
  },
};
</script>
<template>
  <v-app id="app" style="padding-top: 64px;">
    <v-app-bar
      app
      color="blue"
    >
      <v-btn depressed color="white" class="black--text" click="addBtn">Button</v-btn>
    </v-app-bar>

    <dynamic :template='template'></dynamic>
  </v-app>
</template>

解决方案

Inside the dynamic component try to render a vue component using the passed template :

var dynamic = {
  props: ['template'],
  data: () => ({
      templateRender: null,
  }),
  render(h) {
    if (!this.template) {
      return h('div', 'loading...');
    } else { // If there is a template, I'll show it
      return h(Vue.component('dynamic-render', {template:this.template}));
    }
  },
}

Full Example

var dynamic = {
  props: ['template'],
  data: () => ({
    templateRender: null,
  }),
  render(h) {
    if (!this.template) {
      return h('div', 'loading...');
    } else { // If there is a template, I'll show it
      return h(Vue.component('dynamic-render', {
        template: this.template
      }));
    }
  },
}

var app = new Vue({
  el: '#app',
  vuetify: new Vuetify(),
  data: () => ({
    count: 1,
    template: `
            <v-row>
              <v-col>
                <v-btn class="pa-2 primary white--text">Test</v-btn>
              </v-col>
              <v-col>
                <v-btn class="pa-2 primary white--text">Test</v-btn>
              </v-col>
              <v-col>
                <v-btn class="pa-2 primary white--text">Test</v-btn>
              </v-col>
            </v-row>
    `,
  }),
  components: {
    dynamic,
  },
  methods: {
    changeContent() {
      this.count = this.count + 1
      this.template = '';
      setTimeout(() => { //simulate loading status
        this.template = `<v-col>
                <v-btn class="pa-2 primary white--text">Btn ${this.count}</v-btn>
              </v-col>`
      }, 2000);

    }
  }


})

<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@5.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css" rel="stylesheet">

<script src="https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js"></script>

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<div id="app">
  <v-app id="inspire">
    <v-btn depressed color="primary" class="black--text" @click="changeContent">change content</v-btn>
    <dynamic :template='template'></dynamic>


  </v-app>
</div>

这篇关于编译在运行时作为道具接收的 Vuetify 标签/模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆