首页 > 解决方案 > 是否可以从单个文件 comp 向全局 Vue 组件添加内容?

问题描述

我已经制作了一个全局组件,它将呈现我们想要的内容。

这个组件非常简单

<template>
  <section
    id="help"
    class="collapse"
  >
    <div class="container-fluid">
      <slot /> 
    </div>
  </section>
</template>

<script>
  export default {
    name: 'VHelp',
  };
</script>

我在我的基本模板中使用它

<v-help />

我正在尝试从另一个使用的单个文件组件向此组件槽添加内容。

<v-help>
  <p>esgssthsrthsrt</p>
</v-help>

但这在逻辑上创建了我的 comp 的另一个实例,其中包含 p 标记。这不是我想做的正确事情。

所以我尝试使用虚拟 DOM 和渲染功能,在我的comp中slot替换。<v-elements-generator :elements="$store.state.help.helpElements" />VHelp

storehelpElements是一个简单的数组,里面有对象。

{
   type: 'a',
   config: {
     class: 'btn btn-default',
   },
   nestedElements: [
     {
       type: 'span',
       value: 'example',
     },
     {
       type: 'i',
     },
   ],
},

然后在我的VElementsGeneratorcomp里面我有一个渲染函数,它在虚拟DOM中的渲染元素来自一个对象

<script>
  import {
    cloneDeep,
    isEmpty,
  } from 'lodash';

  export default {
    name: 'VElementsGenerator',
    props: {
      elements: {
        type: Array,
        required: true,
      },
    },
    methods: {
      iterateThroughObject(object, createElement, isNestedElement = false) {
        const generatedElement = [];

        for (const entry of object) {
          const nestedElements = [];
          let elementConfig = {};

          if (typeof entry.config !== 'undefined') {
            elementConfig = cloneDeep(entry.config);
          }

          if (entry.nestedElements) {
            nestedElements.push(this.iterateThroughObject(entry.nestedElements, createElement, true));
          }

          generatedElement.push(createElement(
            entry.type,
            isEmpty(elementConfig) ? entry.value : elementConfig,
            nestedElements
          ));

          if (typeof entry.parentValue !== 'undefined') {
            generatedElement.push(entry.parentValue);
          }
        }

        if (isNestedElement) {
          return generatedElement.length === 1 ? generatedElement[0] : generatedElement;
        }

        return createElement('div', generatedElement);
      },
    },
    render(createElement) {
      if (this.elements) {
        return this.iterateThroughObject(this.elements, createElement);
      }

      return false;
    },
  };
</script>

第二种方法效果很好,但是如果我想渲染复杂的数据,渲染函数中使用的对象非常长并且读取起来很复杂。

因此,我试图找到另一种方法来将内容添加到基础布局中使用的全局组件,仅当我希望在子组件上使用它时。

我不能VHelp直接在子组件中使用这个组件,因为 HTML 页面架构是完全错误的。

我想知道是否可以从单个文件 comp 将内容(最好是 HTML)添加到组件槽,而无需重新创建组件的新实例?

此外,我认为将 HTML 保存为 Vuex 商店中的字符串非常难看。所以我什至不知道这是否可能,以及我是否需要完全改变我尝试这样做的方式。

有任何想法吗 ?

标签: javascriptvue.jsvuejs2vue-component

解决方案


在商店中,您应该只存储数据而不是 HTML 结构。解决这个问题的方法是将 v-help 组件内容的当前状态存储在 store 中。然后,您将拥有一个v-help带有插槽的组件(就像您已经提出的那样)。您应该根据商店中的状态传递不同的内容。这是一个抽象的例子:

<v-help>
  <content-one v-if="$store.state.content === 'CONTENT_ONE' />
  <content-two v-else-if="$store.state.content === 'CONTENT_TWO' />
  <content-fallback v-else />
</v-help>

其他地方的子元素:

<div>
  <button @click="$store.commit('setContentToOne')">Content 1</button>
</div>

Vuex商店:

state: {
  content: null
},
mutations: {
  setContentToOne(state) {
    state.content = 'CONTENT_ONE';
  }
}

当然,这取决于您的要求,尤其是如果这是实现此目标的最佳方式,则取决于使用了多少不同的场景。如果我理解正确,您正在将帮助元素保存到商店。您还可以在其中保存一组当前选择的帮助元素,然后直接在v-help组件中显示它们。


编辑

当然,您也可以只将静态组件(或其名称)保存在商店中。然后,您可以在子组件中动态决定哪些内容显示在v-help. 这是一个例子:

<v-help>
  <component :is="$store.state.helpComponent" v-if="$store.state.helpComponent !== null" />
</v-help>

测试组件:

<template>
  test component
</template>

<script>
export default {
  name: 'test-component'
};
</script>

其他地方的子元素(变体 1,将名称存储在 Vuex 中)

<div>
  <button @click="$store.commit('setHelpComponent', 'test-component')">Set v-help component to 'test-component'</button>
</div>

其他地方的子元素(变体 2,将整个组件存储在 Vuex 中)

<template>
  <button @click="$store.commit('setHelpComponent', testComponent)">Set v-help component to testComponent (imported)</button>
</template>

<script>
import TestComponent from '@/components/TestComponent';

export default {
  name: 'some-child-component',
  computed: {
    testComponent() {
      return TestComponent;
    }
  }
};
</script>

其他地方的子元素(变体 3,存储名称,从导入的组件派生,在 Vuex 中;我会使用这个变体

<template>
  <button @click="$store.commit('setHelpComponent', testComponentName)">Set v-help component to 'test-component'</button>
</template>

<script>
import TestComponent from '@/components/TestComponent';

export default {
  name: 'some-child-component',
  computed: {
    testComponentName() {
      return TestComponent.name;
    }
  }
};
</script>

Vuex商店:

state: {
  helpComponent: null
},
mutations: {
  setHelpComponent(state, value) {
    state.helpComponent = value;
  }
}

另请参阅动态组件的文档(<component :is="">语法):https ://vuejs.org/v2/guide/components.html#Dynamic-Components


推荐阅读