• 解决v-html无法理解vue模版的问题-动态获取模版,动态插入app并使用当下app状态数据需求


    很多情况下,我们需要使用动态的html作为某个dom元素的inner html,如果这个内容是标准的html的话,则v-html能够圆满满足需求,而如果内容包含了vue组件,则使用v-html就不能达到你希望的目标了。

    我研究有两种方案来解决,一种原生使用v-if提供的compile和mount特性;第二种类则使用render函数带来的特殊能力实现这一点。

    其中render函数的方案有一个现成的vue组件作为参考. v-runtime-template.

    该组件产生的背景:

    在项目开发中需要从server上接收template string.比如,即允许用户自己通过拖拽来设计接口风格的程序中,通常被保存为vue template code,而该code会使用由前端工程师开发好的预定义组件。这些组件将通过api调用请求数据并且填充页面的一个部分。

    正如上面所说的,v-html很大程度上能够部分满足需求:

    <template>
      <div>
        <div v-html="template"></div>
      </div>
    </template>
    
    <script>
    export default {
      data: () => ({
        template: `
          <h2>Howdy Yo!</h2>
          <a href="croco-fantasy">Go to the croco-fantasy</a>
        `
      }),
    };
    </script>

    上面的template字符串可以从server ajax call中获得。问题是,如果该template string中包含了vue template code,则无能为力!

    export default {
      data: () => ({
        template: `
          <app-title>Howdy Yo!</app-title>
          <vue-router to="/croco-fantasy">Go to the croco-fantasy</vue-router>
        `
      }),
    };

    v-html并不能理解vue-router这个tag,因此将会丢弃很多重要功能。

    这时作者就需要开发一个能够解决该类问题的"proxy"组件

    v-runtime-template的实现原理是: 自动获得v-runtime-template的父组件的context并且使得vue编译并且attach.

    render(h) {
        if (this.template) {
          const parent = this.parent || this.$parent
          const {
            $data: parentData = {},
            $props: parentProps = {},
            $options: parentOptions = {}
          } = parent;
          const {
            components: parentComponents = {},
            computed: parentComputed = {},
            methods: parentMethods = {}
          } = parentOptions;
          const {
            $data = {},
            $props = {},
            $options: { methods = {}, computed = {}, components = {} } = {}
          } = this;
          const passthrough = {
            $data: {},
            $props: {},
            $options: {},
            components: {},
            computed: {},
            methods: {}
          };
    
          //build new objects by removing keys if already exists (e.g. created by mixins)
          Object.keys(parentData).forEach(e => {
            if (typeof $data[e] === "undefined")
              passthrough.$data[e] = parentData[e];
          });
          Object.keys(parentProps).forEach(e => {
            if (typeof $props[e] === "undefined")
              passthrough.$props[e] = parentProps[e];
          });
          Object.keys(parentMethods).forEach(e => {
            if (typeof methods[e] === "undefined")
              passthrough.methods[e] = parentMethods[e];
          });
          Object.keys(parentComputed).forEach(e => {
            if (typeof computed[e] === "undefined")
              passthrough.computed[e] = parentComputed[e];
          });
          Object.keys(parentComponents).forEach(e => {
            if (typeof components[e] === "undefined")
              passthrough.components[e] = parentComponents[e];
          });
    
          const methodKeys = Object.keys(passthrough.methods || {});
          const dataKeys = Object.keys(passthrough.$data || {});
          const propKeys = Object.keys(passthrough.$props || {});
          const templatePropKeys = Object.keys(this.templateProps);
          const allKeys = dataKeys.concat(propKeys).concat(methodKeys).concat(templatePropKeys);
          const methodsFromProps = buildFromProps(parent, methodKeys);
          const finalProps = merge([
            passthrough.$data,
            passthrough.$props,
            methodsFromProps,
            this.templateProps
          ]);
          const provide = this.$parent._provided;
    
          const dynamic = {
            template: this.template || "<div></div>",
            props: allKeys,
            computed: passthrough.computed,
            components: passthrough.components,
            provide: provide
          };
    
          return h(dynamic, { props: finalProps });
        }
      }

    以上代码就是v-runtime-template的核心render函数.

    <template>
      <div>
        <v-runtime-template :template="template"/>
      </div>
    </template>
    
    <script>
    import VRuntimeTemplate from "v-runtime-template";
    import AppTitle from "./AppTitle";
    
    export default {
      data: () => ({
        template: `
          <app-title>Howdy Yo!</app-title>
          <vue-router to="/croco-fantasy">Go to the croco-fantasy</vue-router>
        `
      }),
    components: {
        AppTitle
      }
    };
    </script>

    上面就是使用v-runtime-template核心用法代码。有一点需要额外指出的是,它还可以访问父组件的scope,意味着任何通过data,props,computed或者methods能够访问的都能用.这样你就可以拥有dynaimc templates的能力:可被父组件访问的活跃reactive数据.

    比如:

    export default {
      data: () => ({
        animal: "Crocodile",
        template: `
          <app-title>Howdy {{animal}}!</app-title>
          <button @click="goToCrocoland">Go to crocoland</button>
        `
      }),
      methods: {
        goToCrocoland() {
          // ...
        }
      }

    如果你需要动态地应用从server端返回的template,并能插入vue app中获得对应的scope context访问能力,那么v-runtime-template是一个非常不错的选择!~

    https://alligator.io/vuejs/v-runtime-template/

  • 相关阅读:
    [leetcode] 18. 四数之和
    [leetcode] 17. 电话号码的字母组合
    [leetcode] 16. 最接近的三数之和
    [leetcode] 15. 三数之和
    [leetcode] 14. 最长公共前缀
    [leetcode] 13. 罗马数字转整数
    [leetcode] 12. 整数转罗马数字
    [leetcode] 11.盛最多水的容器
    分布式系统中的缓存——笔记整理
    图解HTTP
  • 原文地址:https://www.cnblogs.com/kidsitcn/p/11353120.html
Copyright © 2020-2023  润新知