为我的所有渲染函数创建一个数组VueJS

时间:2017-05-18 11:04:31

标签: vue.js vuejs2 vue-component

澄清
我意识到我没有很好地写出我的问题(抱歉)。因此,我改写了我的问题和随附的例子。

我想使用VueJS中的渲染功能创建一些组件。每个函数基本上都是相同的格式,只是插入的数据会发生变化。在我看来,每次只是为了创建不同的组件(当每个组件的基本结构相同时)重写渲染函数,而不是重复(并且根本不是DRY)。

因此,我想要做的是创建一个数组,其中包含我想要用于各种不同组件的所有数据。然后,我想循环遍历该数据,每次都运行渲染函数。

例如,假设这是我的数据:

var components = [
        { name: 'label',
          props: ['tag', 'type', 'size', 'color', 'direction'],
          class: 'label',
          tagOption: true,
          tag: 'div'},

        { name: 'icon',
          props: ['type', 'size', 'color'],
          class: 'icon',
          tagOption: false,
          tag: 'i'}
    ]

对这些数据运行循环相当于按如下方式编写渲染函数两次:

标签组件

export label {
    props: ['tag', 'type', 'size', 'color', 'direction'],
    render(createElement) {
        let classes = ['ui', 'label']
        if (this.type) { classes.push(this.type) }
        if (this.size) { classes.push(this.size) }
        if (this.color) { classes.push(this.color) }
        if (this.direction) { classes.push(this.direction) }

        return createElement(
            this.tag || 'div',
            { class: classes },
            this.$slots.default
        );
    }
}

图标组件

export icon {
    props: ['type', 'size', 'color'],
    render(createElement) {
        let classes = ['ui', 'label']
        if (this.type) { classes.push(this.type) }
        if (this.size) { classes.push(this.size) }
        if (this.color) { classes.push(this.color) }

        return createElement(
            'i',
            { class: classes },
            this.$slots.default
        );
    }
}

总结

这就是我做想要做的事情: 有一个label.js(或label.vue)文件,它运行Render Function来创建一个标签组件和一个单独的icon.js文件,它运行基本上完全相同的渲染函数来创建一个图标组件

这是我想要做的事情: 有一个文件循环遍历数据数组,运行和导出数据,每个循环通过渲染函数。

这可能吗?如果是这样,关于如何做的任何想法?

感谢。

2 个答案:

答案 0 :(得分:1)

有几种方法可以做到这一点。这是一个注册组件作为全局组件。

for (let tmpl of components){
  let render = function(createElement){
    let classes = ["ui", tmpl.name]  
    const props = tmpl.props.slice(1)
    for (let prop of props)
      if (this[prop]) classes.push(this[prop])

    return createElement(tmpl.tag, {class: classes}, this.$slots.default)
  }

  Vue.component(`${tmpl.name}-component`,{
    props: tmpl.props,
    render
  })
}

new Vue({
  el:"#app"
})

示例模板:

<div id="app">
  <label-component direction="horizontal">stuff</label-component>
  <icon-component size="large" color="blue">Other stuff</icon-component>
</div>

Example

如果你不想要全局组件,你可以这样做。

let components = {}
for (let tmpl of componentTemplates){
  let render = function(createElement){
    let classes = ["ui", tmpl.name]  
    const props = tmpl.props.slice(1)
    for (let prop of props)
      if (this[prop]) classes.push(this[prop])

    return createElement(tmpl.tag, {class: classes}, this.$slots.default)
  }

  components[`${tmpl.name}-component`] = {
    props: tmpl.props,
    render 
  }
}

new Vue({
  el:"#app",
  components
})

Example

答案 1 :(得分:1)

您可以在Vue声明之外生成组件:

(我重命名了组件,因为当您使用labelicon等常用HTML标记名称作为组件名称时,Vue不喜欢它

&#13;
&#13;
const components = [
  { name: 'child1',
    props: ['tag', 'type', 'size', 'color', 'direction'],
    class: 'label',
    tagOption: true,
    tag: 'div'},
  { name: 'child2',
    props: ['type', 'size', 'color'],
    class: 'icon',
    tagOption: false,
    tag: 'i'}
];

// function to generate components
const generateComponents = components => components
  .map(c => Object.assign({[c.name] : {
    props: c.props,
    render: function(createElement) {
        const classes = ['ui', 'label'];
        classes.push(c.class); // I suppose you've forgot this?
        if (this.type) { classes.push(this.type) };
        if (this.size) { classes.push(this.size) };
        if (this.color) { classes.push(this.color) };
        if (this.direction) { classes.push(this.direction) };

        return createElement(
            c.tag || 'div',
            { class: classes },
            this.$slots.default
        );
      }
    }
  })).reduce((a, v) => Object.assign(a, v), {});

// here you are
const myComponents = generateComponents(components);

new Vue({
  el: '#app',
  components: myComponents
});
&#13;
.green { color: green; font-weight: bold }
.mytype { background-color: beige }
&#13;
<script src="https://unpkg.com/vue/dist/vue.js"></script>

<div id="app">
  <child1 type="mytype">hello</child1>
  <child2 color="green">hello again</child2>
</div>
&#13;
&#13;
&#13;