前端成长仔一枚,最近的一个项目中,遇到了一个bug,虽然不是很大,但是足够灵异。借此记录一下。

项目背景:项目首页使用的el-tree和el-tab-pane,没有使用路由,全部在一个根路由下由v-if控制显示。实习小白也不懂为什么这样,但是入乡随俗,我新增页面、tree结构和tab页的时候也用的这种方式。(事实证明,跟着前辈走方便又快捷。之前不信邪,非得用路由跳转,纠结到心脏病发,熬夜到十二点也解决不了问题)。

问题背景:本来欢快的使用v-if控制页面显示足够,但是产品提出新的需求,在A页面中设置按钮,点击按钮的时候可以新增一个tab展示B页面,并且将参数带过去。

解决办法一:不用路使用eventBus,由于A、B页面毫无关系,建立一个bus.js,用$emit传递要携带的参数,新打开的页面使用$on接收。

新建一个eventBus文件,取名为bus.js用于接收数据。

import Vue from "vue"
export default new Vue()

发送数据的组件在methods方法中新增方法:

import bus from "./bus.js"
methods:{
   //发送的是单个数据时:
   sendFormData(){
      bus.$emit("dataName", dataValue)
   }
  //发送的是多个数据时:
   sendFormData(){
      bus.$emit("dataName", dataValue1, dataValue2)
   }
}

接收数据的组件在methods方法中新增方法为:

import bus from "./bus"
methods:{
   recvFormData(){
       //接收单个数据
       bus.$on("dataName",msg=>{
          console.log(msg)
       })
   }
   //接收多个数据:
  在template中的写法为:@recvFormData=recvFormData(arguments)
   recvFormData(values){
       bus.$on("dataName",values=>{
          console.log(values)
       })
   }
}

然鹅,$emit传递的时候,那边新的页面已经在created周期中了,$on接收不到。看过网友的建议后,可以将$emit写在beforeDestroy阶段,好死不死,该需求就是在关闭 B的tab页面还能回到A的tab页面。该方法不行。

解决办法二:使用路由携带参数跳转。直接在根目录下创建新的children。然而,由于element-ui新增标签页给定的代码中写死了tab的content内容部分且是字符串的形式。如下:

methods: {
  addTab(targetName) {
    let newTabName = ++this.tabIndex + '';
    this.editableTabs.push({
    title: 'New Tab',
    name: newTabName,
    content: 'New Tab content'
   });
    this.editableTabsValue = newTabName;
  },
}

 首先,要将content设置为组件的形式,才能将新的页面传递进去。

改写content的方式:

1、引入要展示的组件:

import Admin from "@/components/views/Admin.vue"

2、将addTab方法中的content字段的值改为组件名字:

methods: {
  addTab(targetName) {
    let newTabName = ++this.tabIndex + '';
    this.editableTabs.push({
    title: 'New Tab',
    name: newTabName,
    content:"Admin"
   });
    this.editableTabsValue = newTabName;
  },
}

完成。

也是因为这种方式,当我们的路由从A页面跳转的时候,会展示Admin组件中的内容。为了避免内容的重复,可以将这个组件设为一个空组件。便可解决问题,这是一个投机取巧得方式,更加优化得方式有待学习。

由于解决办法二过于妖娆(繁琐),所以想到了可以用vuex做传值。

解决办法三:使用vuex,将要携带的参数写在state中。在A组件中点击按钮新增tab页面的同时,使用mutations修改state中的值。在module中新建一个js文件并设置命名空间namespaced:true。

(如果项目不大,可以不建模块。)

const state={
   dataName1:"",
   dataName2:"",
}
const mutations={
    changeData1(state,value){
        state.dataName1=value,
    },
    changeData2(state, value){
        state.dataName2=value
    }    
}
const actions={
    //一些异步调用
    funtion1(){
        return new Promise((resolve,reject)=>{...})
    }
}
 
export default{
    namespaced:true,
    state,
    mutations,
    actions
}

在A页面中,引入vuex仓库中的state和mutations,修改state中的值。

import {mapState, mapMutations} form "vuex"
export default{
    comoputed(){
        ...mapState('name',["dataName1", "dataName2"])
    }
    methods:{
        ...mapMutations("name",["changeData1", "changeData2"])
        //具体的业务逻辑代码(也就是点击事件)
        clickFn(){
            this.changeData1(value1)
            this.changeData2(value2)
        }
    }
}

在B页面中,如果B页面只被调用这一次,则可以不引入mutations,在本业务逻辑中,其他地方还需使用B页面,并且相应的参数为默认值,因此我的写法为:

import {mapState, mapMutations} from "vuex"
export default{
    computed(){
        ...mapState("name", ["dataName1","dataName2"])
    }
    mounted(){
        this.localData1 = this.dataName1
        this.localData2 = this.dataName2
    },
    /*由于其他页面会调用该页面,因此在这个页面离开时,要将vuex的值设为空,
    以免其他情况下的数据受到影响*/
    beforeDestroy(){
        this.changeData1("")
        this.changeData2("")
    },
    methods:{
        ...mapMutations("name", ["changeData1", "changeData2"])     
    }
}

Logo

前往低代码交流专区

更多推荐