如何在Vue.js中创建可重用的组件

时间:2017-10-23 08:01:27

标签: typescript vue.js

我已经开始学习Vue.js了,这也是我在WebUI开发中的第一次经历,为什么,如果我告诉或做错了什么,我会抱歉。

确定。我正在寻找一个如何使用这个框架创建可重用组件的解决方案。我决定创建像树视图这样的东西,可以自定义渲染树项目。

首先,我决定实现 treeview 组件,如下所示:

enter image description here

tree.vue.html

<template>
    <div class="clt">
        <ul v-if="hasRoots">
            <tree-item-component v-for="rootNode in rootNodes"
                                 :content="rootNode"
                                 :itemViewName="itemViewName"
                                 :key="rootNode.id"/>
        </ul>
    </div>
</template>
<script src="./tree.ts"></script>

tree.ts

import Vue from 'vue'
import { Component } from 'vue-property-decorator'

import { ITreeItemContent } from './treeitem/treeitem'

@Component({
    components: {
        TreeItemComponent: require('./treeitem/treeitem.vue.html')
    },
    props: ['rootNodes', 'itemViewName', 'componentPath']
})
export default class TreeComponent extends Vue {
    rootNodes: ITreeItemContent[];
    itemViewName: string; // use this property to determine what component will be used to render tree item content

    get hasRoots(): boolean {
        return this.rootNodes && this.rootNodes.length > 0;
    }
};

treeitem.vue.html

<template>
    <li>
        <span v-if="hasSubNodes"
              @click="toggle">[{{isOpen ? '-' : '+'}}]</span>
        <span>
            <component v-if="itemViewName"
                       :is="itemViewName"
                       :itemData="itemData" />
        </span>
        <ul v-if="hasSubNodes" v-show="isOpen">
            <tree-item-component v-for="subNode in subNodes"
                                 :content="subNode"
                                 :itemViewName="itemViewName"
                                 :key="subNode.id" />
        </ul>
    </li>
</template>
<script src="./treeitem.ts"></script>

treeitem.ts

import Vue from 'vue'
import { Component, Prop } from 'vue-property-decorator'

interface ITreeItemContent {
    id: number;
    itemData: any;
    subNodes: ITreeItemContent[];
}

@Component
export default class TreeItemComponent extends Vue {
    @Prop()
    content: ITreeItemContent;

    @Prop()
    itemViewName: string; // use this property to determine what component will be used to render content

    @Prop()
    componentnPath: string;

    isOpen: boolean = true;

    get hasSubNodes(): boolean {
        return this.subNodes && this.subNodes.length > 0;
    }

    get subNodes(): ITreeItemContent[] {
        return this.content.subNodes;
    }

    get itemData(): any {
        return this.content.itemData;
    }

    toggle(): void {
        this.isOpen = !this.isOpen;
    }
}

export { ITreeItemContent };

我注册了我的组件:

Vue.component('tree-component', require('./components/tree/tree.vue.html'));

现在我想将它作为其他组件的一部分使用。我是这样做的:

categories.ts

import Vue from 'vue'
import { Component } from 'vue-property-decorator'
import { ITreeItemContent } from '../tree/treeitem/treeitem'
import { ITreeItemViewModel } from './treeitemview/treeitemview'

@Component({
    components: { // local registration of component what will be used to render tree item content
        TreeItemViewComponent: require('./treeitemview/treeitemview.vue.html')
    }
})
export default class CategoriesComponent extends Vue {
    itemViewName: string = 'tree-item-view-component';

    categories: ITreeItemContent[];

    data(): any {
        return { categories: testItemsData }
    }
}

let testItemsData: ITreeItemContent[] = [ /* test data */ ];

categories.vue.html

<template>
    <div class="clearfix">
        <tree-component :rootNodes="categories"
                        :itemViewName="itemViewName"></tree-component>
    </div>
</template>
<script src="./categories.ts"></script>

treeitemview.ts

import Vue from 'vue'
import { Component, Prop } from 'vue-property-decorator'

interface ITreeItemViewModel {
    msg: string;
    icon: string;
}

@Component
export default class TreeItemViewComponent extends Vue {
    @Prop({ required: true })
    itemData: ITreeItemViewModel;

    get msg(): string {
        return this.itemData.msg;
    }

    get _class(): string {
        return 'glyphicon glyphicon-' + this.itemData.icon;
    }
}

export { ITreeItemViewModel };

treeitemview.vue.html

<template>
    <span :class="_class">{{msg}}</span>
</template>
<script src="./treeitemview.ts"></script>

我想使用TreeItemViewComponent作为组件,在 treeview 中显示节点的内容为什么,我将其注册为CategoriesComponent的本地组件,但后来我运行了代码我发现错误:

[Vue warn]: Unknown custom element: <tree-item-view-component> - did you register the component correctly? For recursive components, make sure to provide the "name" option.

如果我将TreeItemViewComponent注册为全局组件,请执行以下操作:

Vue.component('tree-item-view-component', require('./components/categories/treeitemview/treeitemview.vue.html'));
一切顺利。我在Vue.js手册中阅读了有关组件注册的内容,但据我所知,嵌套组件不了解localy注册组件。换句话说,如果我将TreeItemViewComponent注册为CategoriesComponent的本地组件,我只能在TreeItemViewComponent模板中使用CategoriesComponent。我试图将TreeItemViewComponent组件作为TreeComponent的属性值传递,但我遇到了编译错误。

我也读过关于$.refs女巫有可能访问子女内部的父组件,但我不明白如何使用它。

最简单的解决方案是将TreeItemViewComponent注册为全局Vue.js组件,但我认为这不是正确的方法,因为我想创建多个组件,将使用TreeComponent并提供自己的TreeItemViewComponent {1}}并且每个TreeItemViewComponent的全局注册都会在功能上造成混淆。

是否存在其他解决方案,或者无法在Vue.js中创建可重用的组件?

1 个答案:

答案 0 :(得分:0)

我想你差不多了。我没有审查你的所有代码,但我可以告诉你一件事我必须要做的是使Vuejs组件在Typescript中工作。

而不是:TreeItemViewComponent: require('./treeitemview/treeitemview.vue.html')

在Tree.ts中使用:TreeItemViewComponent: Vue.component('tree-item-component', require('./treeitemview/treeitemview.vue.html'))

然后在Tree.vue.html中,您可以使用<tree-item-component></tree-item-component>