我正在尝试编写带有自定义选项的vue插件。我这样做是遵循官方的vue准则(https://vuejs.org/v2/guide/plugins.html),但是找不到定义自定义选项的方法。这些选项应由普通的javascript读取,然后由javascript导出vue组件使用的对象。
我的文件夹结构是这样的:
/src
factory.js
CustomComponent.vue
factory.js
import Vue from "vue";
import ImgixClient from "imgix-core-js";
var imgixClient = new ImgixClient({
domain: CUSTOM_OPTION_URL <-- important bit
domain: Vue.prototype.$imgixBaseUrl //tried it like this
});
export { imgixClient };
我已经尝试通过在安装方法中利用Vue.prototype设置此自定义位,但似乎无法使其工作
export function install(Vue, options) {
if (install.installed) return;
install.installed = true;
Vue.prototype.$imgixBaseUrl = options.baseUrl;
Vue.component("CustomComponent", component);
}
答案 0 :(得分:1)
恐怕这将不是您一直希望得到的简单答案……这里有很多要取消的地方。
让我们从factory.js
开始。那不是工厂。这是一个单身人士。单例在依赖项,配置和实例化时间方面存在问题,而这正是您要解决的问题。稍后再讨论。
现在让我们看一下插件。首先,这两行:
if (install.installed) return;
install.installed = true;
那不是必须的。 Vue已经自动执行此操作,应该确保您的插件仅安装一次。也许这来自旧的教程?看一下Vue.use
的源代码,没有太多东西了:
深入Vue源代码是一个很好的习惯。有时候,它会融化您的思想,但是有些像这样的东西并不难理解。一旦习惯了,不透明的部分就会变得更加清晰。
返回插件。
Vue.prototype.$imgixBaseUrl = options.baseUrl;
尚不清楚为什么要将其添加到原型中。
我假设您已经熟悉JavaScript函数原型的工作原理。
组件实例实际上是Vue
的实例。因此,添加到Vue.prototype
的任何属性都将被您的组件继承,几乎没有任何开销。考虑以下简单组件:
<template>
<div @click="onClick">
{{ $imgixBaseUrl }}
</div>
</template>
<script>
export default {
methods: {
onClick () {
const url = this.$imgixBaseUrl
// ...
}
}
}
</script>
由于$imgixBaseUrl
是继承的属性,因此可以在onClick
中通过this.$imgixBaseUrl
使用。此外,模板将标识符解析为当前Vue实例的属性,因此{{ $imgixBaseUrl }}
也将访问this.$imgixBaseUrl
。
但是,如果您不需要访问组件中的$imgixBaseUrl
,则无需将其放在Vue原型上。您不妨直接将其转储到Vue
上:
Vue.imgixBaseUrl = options.baseUrl;
在上面的代码中,我放弃了$
,因为不再存在与组件实例属性冲突的风险,而这正是使用原型时激发$
的原因。
所以,回到核心问题。
正如我已经提到的,单例在创建时间和配置方面存在重大问题。 Vue具有自己的内置解决方案,可以针对这些“从头开始”的场景。那就是插件。但是,关键功能是插件在您调用install
之前不会执行任何操作,从而使您可以控制时间。
原始代码的问题在于,factory.js
的内容将在文件导入后立即运行。那将是在安装插件之前,因此尚未设置Vue.prototype.$imgixBaseUrl
。 ImgixClient
实例将立即创建。它不会等到有人尝试使用它。随后将Vue.prototype.$imgixBaseUrl
设置为不会产生任何影响的正确值时,为时已晚。
解决此问题的一种方法(虽然不一定是最好的方法)是延迟实例化ImgixClient
。可能看起来像这样:
import Vue from "vue";
import ImgixClient from "imgix-core-js";
var imgixClient = null;
export function getClient () {
if (!imgixClient) {
imgixClient = new ImgixClient({
domain: Vue.prototype.$imgixBaseUrl
});
}
return imgixClient;
}
只要在安装插件之前没有任何人调用getClient()
,它就应该起作用。但是,这是一个很大的条件。错误地调用它太容易了。除了由此产生的时间耦合外,还通过Vue
共享配置来创建更多直接耦合。尽管在自己的小文件中包含ImgixClient
实例化代码的想法是很合理的,但只有它独立于Vue才真正值得审查。
相反,我可能只是将实例化移动到插件中,如下所示:
import ImgixClient from "imgix-core-js";
export default {
install (Vue, options) {
Vue.imgixClient = Vue.prototype.$imgixClient = new ImgixClient({
domain: options.baseUrl
});
Vue.component("CustomComponent", component);
}
}
我使用default
导出并将函数包装在对象中进行了一些表面上的更改,但是如果您更喜欢原始代码中的处理方式,则可以忽略这些更改。
如果组件中需要客户端,则可以通过从原型继承的属性$imgixClient
访问该客户端。对于需要访问客户端的任何其他代码,可以从组件中传递,也可以(更可能是)直接从Vue.imgixClient
中获取。如果这些用例都不适用,则可以删除插件的相关部分。