前端成长仔一枚,最近的一个项目中,遇到了一个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"])
}
}
版权归原作者 廖漂亮 所有, 如有侵权,请联系我们删除。