背景
在大型和复杂的业务中,如何让独立的 JavaScript 文件能够轻松地与当前 Vue 实例进行交互是一个关键问题。本文将介绍一种简单而有效的解决方案,以实现 JavaScript 文件与 Vue 实例的无缝交互。我们将以一个示例演示该方案,并展示如何在业务逻辑中灵活应用。
1. 定义 ctx 对象
- view
- AxiosView.vue
- ctx
- config.js
- controller.js
- service.js
- ctx.js
- enums.js
首先,我们需要定义一个 ctx
对象,在其中引入各种服务。
javascript
// ctx.js
import config from "./config";
import controller from "./controller";
import enums from "./enums";
import service from "./service";
// eslint-disable-next-line no-unused-vars
// let vm = null;
const ctx = {
init(vmInstance) {
// vm = vmInstance;
controller.init(vmInstance);
service.init(vmInstance);
enums.init(vmInstance);
return this;
},
controller,
service,
config,
enums,
};
export default ctx;
controller
使用service.js
,config.js
中的函数或数据demo(其他js文件与controller.js类似写法)
ini
// controller.js
let vm = null;
export default {
init(vmInstance) {
vm = vmInstance;
},
getMessage() {
console.log(vm.$data.message); // 组件的实例有一个名为 message 的属性
},
setMessage(newMessage) {
let res = vm.ctx.service.updateMessage();
vm.$data.message =
newMessage + " " + res.data + " " + vm.ctx.config.TIME_OUT;
},
async getCat() {
vm.$data.imageUrl = "";
let params = {
limit: vm.$data.limit,
};
// 使用其他服务
let res = await vm.ctx.service.getCat(params);
vm.$data.imageUrl = res[0].url;
},
async getDog() {
vm.$data.imageUrl = "";
let res = await vm.ctx.service.getDog();
vm.$data.imageUrl = res.message;
},
};
2. 在 Vue 实例中引入 ctx 文件
在 Vue 实例中引入 ctx.js
文件,并在 created
钩子中将当前实例传入 ctx.init()
方法。
xml
// AxiosView.vue
<template>
<div>
<!-- Vue 实例模板内容 -->
</div>
</template>
<script>
import ctx from "./ctx/ctx";
export default {
data(){
return {
ctx: null
}
},
created() {
// 在初始化时将当前 Vue 实例传递给 ctx
this.ctx = Object.freeze(ctx.init(this));
}
};
</script>
3. 在 Vue 模板中使用 ctx 的服务
现在,我们可以在 Vue 模板中使用 ctx
对象中的服务了。
xml
// AxiosView.vue
<template>
<div>
<p>{{ message }}</p>
<select name="" id="">
<option value="">--Please choose an option--</option>
<option
v-for="item in ctx.enums.accountList()"
:key="item.label"
:value="item.value"
>
{{ item.value }}
</option>
</select>
<div>
<button @click="ctx.controller.getCat">getCat</button>
<button @click="ctx.controller.getDog">getDog</button>
</div>
<div style="width: 200px; height: 200px; margin: auto">
<div style="width: 100%; height: 100%; background: #ccc" v-if="!imageUrl">
loading
</div>
<img v-else :src="imageUrl" alt="" style="width: 100%; height: 100%" />
</div>
</div>
</template>
<script>
import ctx from "./ctx/ctx";
export default {
data() {
return {
ctx: null,
message: "Hello, World!",
limit: 1,
imageUrl: "",
};
},
created() {
// 在初始化时将实例传递给 ctx
this.ctx = Object.freeze(ctx.init(this));
// ctx.controller.getMessage();
// ctx.controller.setMessage("Hello, Vue!");
// ctx.controller.getMessage();
// console.log(this.ctx.enums.accountList());
},
};
</script>
结论
通过上述示例,我们展示了如何在 Vue 单文件组件中让独立的 JavaScript 文件能够轻松地与当前 Vue 实例进行交互。这种方案简单易行,同时保持了代码的清晰和可维护性。您可以根据自己的业务需求,灵活地组织和使用 ctx
对象中的各种服务,以实现复杂业务逻辑的开发。

仓库地址:github.com/shouheyuan/...
(TODO)项目案例:
在我的项目中 「项目背景」 「服务拆分」
- preview-table.vue
allocation.js
// 收集所有模块数据,使用分配算法得到分配数据,传回实例中渲染batch-edit.js
// 批量编辑预览广告数据,编辑后调用分配函数,传回实例中渲染ad-submit.js
// 基于实例数据,按接口格式提交