如何跨多个文件中的多个 Vue 实例正确使用 Vue 3 composition-api
How to correctly use Vue 3 composition-api across multiple Vue instances in multiple files
tl;dr 在基础 js 文件中导入 Vue3,然后在其他独立的 js 文件中使用 Vue 的组合 - api 的正确方法是什么在该基本文件之后加载?
我正在使用 Vue 来增强特定页面的用户体验。例如,在注册页面中执行 ajax 请求并在不重新加载页面的情况下显示服务器错误。简而言之,MPA 内的迷你 SPA...
在 Vue2 中,在基础文件中导入 Vue,然后实例化一个新的 Vue 实例并在后续文件中使用 Vue 的选项-api 没有问题。后续文件的大小保持最小,因为它们只包含该文件所需的逻辑。
但是由于Vue3的composition-api需要导入ref, reactive, watch, onMount...etc
,导致后面的文件需要重新导入Vue。我尝试克服这个问题如下:
// register.blade.php (contains)
<div id="root">
<input type="text" name="first_name" v-model="FirstName">
<input type="text" name="last_name" v-model="LastName">
// (before edit) <script src="main.js"></script>
// (before edit) <script src="register.js"></script>
<script src="{{ mix('/main.js') }}"></script>
<script src="{{ mix('/register.js') }}"></script>
</div>
// main.js (contains)
// (before edit) import Vue from 'node_modules/vue/dist/vue.js';
// (before edit) window.Vue = Vue;
window.Vue = require('vue');
// register.js (contains)
const app = Vue.createApp({
setup() {
const FirstName = Vue.ref('');
const LastName = Vue.ref('');
const FullName = Vue.computed(() => FirstName.value + ' ' + LastName.value);
return {
FirstName, LastName, FullName
}
}
});
app.mount('#root');
这对于这个简单的例子来说效果很好,但我想知道使用 Vue.
作为前缀的方法是否正确?是否可以使用该方法访问 Vue 为 setup() 方法公开的所有函数?
编辑:
我正在使用由 laravel mix 包装的 webpack,为了简单起见,我从初始代码中删除了它,但我认为它被证明是相关的。对最初提供的代码中的编辑进行了注释以避免混淆。
// webpack.mix.js (contains)
mix.webpackConfig({
resolve: {
alias: {
'vue$': path.resolve(__dirname, 'node_modules/vue/dist/vue.esm-bundler.js'),
}
}
});
mix.js('resources/main.js', 'public/main.js')
.js('resources/register.js', 'public/register.js')
.version();
你可以使用Vue.ref
或ref
如果你这样解构import {ref,reactive} from 'vue/dist/vue.js';
这应该不是必需的:
window.Vue = Vue;
只要您在每个文件中使用 import Vue from 'vue/dist/vue.js';
,例如 register.js
(或解构版本)。即使您有多个导入,也不意味着它会 re-included 多次。打包器只会添加一次 Vue(或部分 Vue 库)。
从 Vue 3(ref
、watch
、computed
…)导入每个 .js
文件中的单独部分时,应该没有额外的开销.事实上,如果您使用的是捆绑器,这将有助于 tree shaking 过程使生成的文件更小 (great explanation by Evan You)。
导入所有 Vue 并按照您当前的方式使用它没有任何问题,类似于您在 Vue 2 中的方式。如果语法困扰您,您可以解构您使用的内容,即
// register.js (contains)
const { ref, computed } = Vue;
const app = Vue.createApp({
setup() {
const FirstName = ref('');
const LastName = ref('');
const FullName = computed(() => FirstName.value + ' ' + LastName.value);
return {
FirstName, LastName, FullName
}
}
});
app.mount('#root');
编辑:
我不熟悉 Laravel Mix,但也许你可以尝试这样的操作:
// webpack.mix.js (contains)
const jsfiles = [
'resources/main.js',
'public/main.js',
'resources/register.js',
'public/register.js',
];
mix.js(...jsFiles).extract(['vue']).webpackConfig({
resolve: {
alias: {
'vue$': path.resolve(__dirname, 'node_modules/vue/dist/vue.esm-bundler.js'),
}
}
}).version();
// now in your `register.js` and `main.js` use `import`, not `require`
//
// import Vue from 'vue';
tl;dr 在基础 js 文件中导入 Vue3,然后在其他独立的 js 文件中使用 Vue 的组合 - api 的正确方法是什么在该基本文件之后加载?
我正在使用 Vue 来增强特定页面的用户体验。例如,在注册页面中执行 ajax 请求并在不重新加载页面的情况下显示服务器错误。简而言之,MPA 内的迷你 SPA...
在 Vue2 中,在基础文件中导入 Vue,然后实例化一个新的 Vue 实例并在后续文件中使用 Vue 的选项-api 没有问题。后续文件的大小保持最小,因为它们只包含该文件所需的逻辑。
但是由于Vue3的composition-api需要导入ref, reactive, watch, onMount...etc
,导致后面的文件需要重新导入Vue。我尝试克服这个问题如下:
// register.blade.php (contains)
<div id="root">
<input type="text" name="first_name" v-model="FirstName">
<input type="text" name="last_name" v-model="LastName">
// (before edit) <script src="main.js"></script>
// (before edit) <script src="register.js"></script>
<script src="{{ mix('/main.js') }}"></script>
<script src="{{ mix('/register.js') }}"></script>
</div>
// main.js (contains)
// (before edit) import Vue from 'node_modules/vue/dist/vue.js';
// (before edit) window.Vue = Vue;
window.Vue = require('vue');
// register.js (contains)
const app = Vue.createApp({
setup() {
const FirstName = Vue.ref('');
const LastName = Vue.ref('');
const FullName = Vue.computed(() => FirstName.value + ' ' + LastName.value);
return {
FirstName, LastName, FullName
}
}
});
app.mount('#root');
这对于这个简单的例子来说效果很好,但我想知道使用 Vue.
作为前缀的方法是否正确?是否可以使用该方法访问 Vue 为 setup() 方法公开的所有函数?
编辑: 我正在使用由 laravel mix 包装的 webpack,为了简单起见,我从初始代码中删除了它,但我认为它被证明是相关的。对最初提供的代码中的编辑进行了注释以避免混淆。
// webpack.mix.js (contains)
mix.webpackConfig({
resolve: {
alias: {
'vue$': path.resolve(__dirname, 'node_modules/vue/dist/vue.esm-bundler.js'),
}
}
});
mix.js('resources/main.js', 'public/main.js')
.js('resources/register.js', 'public/register.js')
.version();
你可以使用Vue.ref
或ref
如果你这样解构import {ref,reactive} from 'vue/dist/vue.js';
这应该不是必需的:
window.Vue = Vue;
只要您在每个文件中使用 import Vue from 'vue/dist/vue.js';
,例如 register.js
(或解构版本)。即使您有多个导入,也不意味着它会 re-included 多次。打包器只会添加一次 Vue(或部分 Vue 库)。
从 Vue 3(ref
、watch
、computed
…)导入每个 .js
文件中的单独部分时,应该没有额外的开销.事实上,如果您使用的是捆绑器,这将有助于 tree shaking 过程使生成的文件更小 (great explanation by Evan You)。
导入所有 Vue 并按照您当前的方式使用它没有任何问题,类似于您在 Vue 2 中的方式。如果语法困扰您,您可以解构您使用的内容,即
// register.js (contains)
const { ref, computed } = Vue;
const app = Vue.createApp({
setup() {
const FirstName = ref('');
const LastName = ref('');
const FullName = computed(() => FirstName.value + ' ' + LastName.value);
return {
FirstName, LastName, FullName
}
}
});
app.mount('#root');
编辑:
我不熟悉 Laravel Mix,但也许你可以尝试这样的操作:
// webpack.mix.js (contains)
const jsfiles = [
'resources/main.js',
'public/main.js',
'resources/register.js',
'public/register.js',
];
mix.js(...jsFiles).extract(['vue']).webpackConfig({
resolve: {
alias: {
'vue$': path.resolve(__dirname, 'node_modules/vue/dist/vue.esm-bundler.js'),
}
}
}).version();
// now in your `register.js` and `main.js` use `import`, not `require`
//
// import Vue from 'vue';