在Vue文件中创建根Vue实例

时间:2018-10-18 21:06:20

标签: javascript vue.js vuejs2

.vue文件是否有办法以单一文件组件模式负责创建自己的Vue实例?

这是Vue文件。

// MyComponent.vue
<template><div>Hello {{ name }}!</div></template>

<script>
const Vue = require('vue');

// what would usually be exports default
const componentConfig = {
    name: "my-component",
    props: {
        name: String,
    },
};

function create(el, props) {
    const vm = new Vue({
        el,
        render(h) {
            return h(componentConfig, { props });
        });
    vm.$mount();
    return vm;
}

module.exports = { create };
</script>

,然后在某些JS文件中使用:

// index.js
const MyComponent = require('./MyComponent.vue');

const el = '.container';
const props = {
    name: 'Jess',
};

MyComponent.create(el, props);
</script>

执行上述操作时,出现无法找到模板的错误。

[Vue warn]: Failed to mount component: template or render function not defined.

found in

---> <MyComponent>
       <Root>

本能地,我不理解Vue编译器将如何神奇地(希望从脚本标签中)推断出我想要引用上面声明的模板。是的有没有关于为什么我不能做到这一点的解释,或者有关于如何使它工作的想法?

2 个答案:

答案 0 :(得分:3)

您要描述的内容是通过Webpack和Vue Loader的预编译步骤完成的。 Vue编译器实际上并未解析Single File Components。 Vue编译器 可以解析的是组件的options对象中提供的模板。因此,如果您在template对象中提供componentConfig选项,那么您的示例将起作用。否则,您将必须使用Webpack和Vue Loader进行预编译步骤才能解析单个文件组件的模板。为此,您必须符合SFC结构defined in the spec。这是摘录..

  

模板

     
      
  • 每个*.vue文件最多可以包含一个<template>块   时间。
  •   
  • 内容将被提取并传递到vue-template-compiler和   预编译到JavaScript渲染函数中,最后注入   进入<script>部分中导出的组件中。
  •   
     

脚本

     
      
  • 每个*.vue文件一次最多可以包含一个块。
  •   
  • 该脚本作为ES模块执行。
  •   
  • 默认导出应为Vue.js component options object。   导出由Vue.extend()创建的扩展构造函数   支持,但首选普通对象。
  •   
  • .js文件(或扩展名)匹配的任何Webpack规则   由lang属性指定)将应用于   <script>也会阻止。
  •   

要使您的特定示例生效,您可以像这样重写main.js文件。

const MyComponent = require("./MyComponent.vue");

const el = ".container";
const data = {
  name: "Jess"
};

MyComponent.create(el, data);

还有您的MyComponent.vue文件(就像下面提到的@Ferrybig一样,这可能是js文件)..

<script>
const Vue = require('vue');

function create(el, data) {
  const componentConfig = {
    el,
    name: "my-component",
    data,
    template: `<div>Hello {{ name }}!</div>`
  };
  const vm = new Vue(componentConfig);
  return vm;
}

module.exports = { create };
</script>

查看此CodeSandbox

或者,如果您喜欢渲染功能,您的MyComponent.vue将看起来像这样..

<script>
const Vue = require('vue');

function create(el, data) {
  const componentConfig = {
    el,
    name: "my-component",
    data,
    render(h) { return h('div', 'Hello ' + data.name) } 
  };
  const vm = new Vue(componentConfig);
  return vm;
}

module.exports = { create };
</script>

CodeSandbox


要记住的最后一件事:在任何组件中,您都可以使用模板或渲染功能,但不能像示例中那样使用,但不能同时使用这两种功能。这是因为其中一个将覆盖另一个。例如,请参见JSFiddle Vue boilerplate,并注意如何when you add a render function覆盖模板。这可以解释您遇到的错误。渲染函数具有优先权,但是您向它提供了一个组件的options对象,该对象不提供要渲染的模板。

PS:尽管如此,我对这项练习的目的还是很感兴趣。当然,这不是在Vue中处理问题的推荐方法。

答案 1 :(得分:3)

您确实已经接近可行的解决方案,但是您缺少一些将所有内容组合在一起的“胶水”部分:

<template>
    <div>Hello {{ name }}!</div>
</template>
<script>
    import HelloWorld from "./components/HelloWorld";
    import Vue from "vue";

    const Component = {
        // Add data here that normally goes into the "export default" section
        name: "my-component",
        props: {
            name: String,
        },
        data() {
            return {
            };
        },

    };
    Component.create = function(el, props) {
        const vm = new Vue({
            el,
            render(h) {
                return h(Component, { props });
            },
        });
        vm.$mount();
        return vm;
    };
    export default Component;
</script>

然后可以在其他文件中如下使用它:

import App from "./App";
App.create("#app", {
    name: 'Hello World!',
});

关于代码框的示例:https://codesandbox.io/s/m61klzlwy