vue通过js代码实例化组件

  • vue通过js代码实例化组件已关闭评论
  • 86 次浏览
  • A+
所属分类:Web前端
摘要

最近在写项目的一些公共组件(一些选择器),很多个地方都需要用,所以在main.js全局声明了,但发现子页面调用还是有挺多的地方需写。

最近在写项目的一些公共组件(一些选择器),很多个地方都需要用,所以在main.js全局声明了,但发现子页面调用还是有挺多的地方需写。

例如,要在template实例化组件,并用ref绑定,然后在js里的methods里写方法。

main.js 声明全局组件

vue通过js代码实例化组件

第一种方案

一开始想到的是用ref绑定组件,业务组件实例化公共组件,并赋予ref,然后通过这个ref绑定,直接调用公共组件的方法(为了一定能触发方法),例如  this.$refs.xxx.open()

如果用户在公共组件中,选择好数据操作完成后,公共组件触发emit方法,通过回调方法的方式通知业务组件,例如 this.$emit("getTableSelect",this.selection)

以下是相关代码:

公共组件

<template>   <div>     <el-dialog       v-loading="loading"       :before-close="cancel"       :close-on-click-modal="false"       :element-loading-text="loadingText"       :visible="dialogVisible"       append-to-body       title="科目选择器"       width="80%"     >       <el-form         ref="queryForm"         :inline="true"         :model="queryParams"         label-width="68px"         size="small"       >         <el-form-item label="名称" prop="name">           <el-input             v-model="queryParams.name"             clearable             placeholder="请输入名称"             @keyup.enter.native="handleQuery"           />         </el-form-item>         <el-form-item label="状态" prop="status">           <el-select             v-model="queryParams.status"             clearable             placeholder="请选择状态"           >             <el-option               v-for="dict in dict.type.sys_normal_disable"               :key="dict.value"               :label="dict.label"               :value="dict.value"             />           </el-select>         </el-form-item>         <el-form-item>           <el-button             icon="el-icon-search"             size="mini"             type="primary"             @click="handleQuery"             >搜索           </el-button>         </el-form-item>       </el-form>        <el-table         v-loading="loading"         :data="dataList"         @row-dblclick="rowDblclick"         @selection-change="handleSelectionChange"       >         <el-table-column align="center" type="selection" width="55" />         <el-table-column align="center" label="科目id" prop="subjectId" />         <el-table-column align="center" label="名称" prop="name" />         <el-table-column align="center" label="介绍" prop="intro" />         <el-table-column align="center" label="排序" prop="sort" />         <el-table-column align="center" label="状态" prop="status">           <template slot-scope="scope">             <dict-tag               :options="dict.type.sys_normal_disable"               :value="scope.row.status"             />           </template>         </el-table-column>         <el-table-column align="center" label="备注" prop="remark" />       </el-table>       <div slot="footer" style="text-align: center">         <el-button type="primary" @click="submitForm">确 定</el-button>         <el-button @click="cancel">关闭</el-button>       </div>     </el-dialog>   </div> </template> <script> import { listSubject } from "@/api/as/subject";  export default {   name: "TableSelect",   dicts: ["sys_normal_disable"],   data() {     return {       loading: false,       loadingText: "数据正在处理中...",       dialogVisible: false,       // 查询参数       queryParams: {         pageNum: 1,         pageSize: 10,         name: null,         status: null,       },       // 总条数       total: 0,       //表格数据       dataList: [],       //被选择的行       selection: [],     };   },    methods: {     /**      * 打开窗口      */     open(name) {       this.dialogVisible = true;       this.queryParams.name = name;       this.handleQuery();     },     /** 搜索按钮操作 */     handleQuery() {       this.queryParams.pageNum = 1;       this.getList();     },     /** 查询科目列表 */     getList() {       this.loading = true;       listSubject(this.queryParams).then((response) => {         this.dataList = response.rows;         this.total = response.total;         this.loading = false;       });     },     //取消     cancel() {       this.dialogVisible = false;       this.reset();     },     //确定     submitForm(row) {       if (row) {         this.$emit("getTableSelect", row);       } else if (this.selection.length > 0) {         this.$emit("getTableSelect", this.selection);       } else {         this.$message.warning("请选择");         return;       }        this.dialogVisible = false;       this.reset();     },     //重置信息     reset() {       this.queryParams = {         pageNum: 1,         pageSize: 10,         name: null,         status: null,       };       this.dataList = [];       this.selection = [];     },     //表格选择改变     handleSelectionChange(selection) {       this.selection = selection;     },     //双击     rowDblclick(row) {       this.submitForm(row);     },   }, }; </script> <style lang="scss" scoped></style>

业务组件(简化)

<template>   <div class="app-container">     <el-input       v-model="queryParams.name"       clearable       placeholder="回车搜索科目"       @keyup.enter.native="handleTableSelect"     />     <table-select ref="tableSelect" @getTableSelect="getTableSelect" />   </div> </template>  <script> export default {   name: "Chapter",    data() {     return {       // 遮罩层       loading: true,       // 查询参数       queryParams: {         name: null,       },     };   },    methods: {     //去打开窗口选择     handleTableSelect() {       this.$refs.tableSelect.open(this.queryParams.name);     },     //获取选择的行     getTableSelect(row) {       this.queryParams.name = row.name;     },   }, }; </script>

效果图

vue通过js代码实例化组件

 

vue通过js代码实例化组件

 

vue通过js代码实例化组件

 

第一种方案,虽然可以使用,但业务组件若要使用,则需要正确在4个地方写上对应的代码

即,1.实例化公共组件,并写上ref和getTableSelect的事件监听,2.输入框写上回车事件,3.回车事件里触发公共组件的方法,4.写getTableSelect事件监听的方法。

vue通过js代码实例化组件

 

若别的小伙伴一不小心,忘记了其中一个地方(大多数都是实例化组件,或者没写getTableSelect事件监听的方法,我们程序员,ctrl+c,ctrl+v,漏拷贝一点点方法,很正常吧),则会需排查原因,相对繁琐。

后面我想了一下,再通过百度,写了第二种方案。

第二种方案

为了减少出现拷贝少问题,我把第3步和第4步合并了(3.回车事件里触发公共组件的方法,4.写getTableSelect事件监听的方法),用Promise。

以下是相关的改动

公共组件改动情况

vue通过js代码实例化组件

 

vue通过js代码实例化组件

 业务组件改动情况

 

vue通过js代码实例化组件

 这样做了之后,好处就是,触发的事件和接收结果的方法在一起了,减少出错的概率,代码也更加方便理解了。第二种方案,也是我一直用的方案,

但第二种方案,依旧要写3个地方,即1.实例化公共组件,并写上ref,2.输入框写上回车事件,3.回车事件里触发公共组件的方法并接收值,

这种情况下,还是有小伙伴会出现拷贝少的问题(没有实例化公共组件),我也曾想过,怎么去除这个实例化的代码,用js代码实例化组件,但受限于个人水平不够,我也没想到什么好的方法解决这个问题,所以这个问题就一直搁置了。

直到今天(2023-9-16),我心血来潮,想看看有没有办法解决没有实例化公共组件问题,经过长时间的百度,和查看vue官方文档,终于找到了一种可以在js代码上实例化组件的方案,也就是现在的第三种方案。

第三种方案

公共组件没有任何改变

新增一个公共的js方法

import Vue from "vue";  /**  * 获取表格选择  * @param name 搜索值  */ export function getTableSelect(name) {   //获取公共里的实例   const MyComponent = Vue.component("TableSelect");   let myComponent = new MyComponent();   //挂载实例   let jbxxModal = myComponent.$mount();    return new Promise((resolve, reject) => {     jbxxModal       .open(name)       .then((row) => {         resolve(row);       })       .catch((res) => {         reject(res);       })       .finally(() => {         //销毁实例         myComponent.$destroy();       });   }); }

 

main.js,新增以下代码

vue通过js代码实例化组件

 业务组件改动情况

vue通过js代码实例化组件

 通过第三种方案,别的小伙伴只需要调用公共的js方法即可,不需要实例化了组件了,大大的减少了出错的概率了,

现在只需要1.输入框写上回车事件,2.回车事件里触发公共组件的方法并接收值。

通过这次学习,提升了个人的一丢丢前端知识,记录存档,方便以后还知道怎么解决这个问题,也方便给别的小伙伴一些参考,

若该文章帮助到了你,请帮忙点一下赞好吗,若有更好的方案,可以评论告诉我,让我也学习一下。