vue項目詳情頁返回列表,記錄之前信息

需求場景:

我們在開發(fā)后臺管理系統(tǒng)的時候,經(jīng)常會遇到這樣的問題,我剛通過篩選條件篩選出來了一批數(shù)據(jù),然后我點擊到了第二頁,點擊進入了對應數(shù)據(jù)的詳情頁,查看完數(shù)據(jù)后,返回列表,這個時候之前篩選的信息不見了,頁碼也回到了第一頁;這個時候如果需要再篩選,再重復操作的話,這樣的體驗是非常差的,很浪費時間;最好的體驗是:我去詳情之前是怎樣的頁面,詳情返回后就是怎樣的頁面,保留之前的篩選條件、列表數(shù)據(jù)、分頁信息等,甚至刷新也都保存之前的篩選條件;但是如果我從其他模塊進入,我希望篩選條件等是清空的,從第一頁開始;

具體展示如下:

image

解決方案:

方案一:將篩選條件與分頁信息放到url鏈接中

因為該方案較簡單,也是最易懂的,所以這邊就不多贅述;

優(yōu)點:

1、簡單粗暴;

2、刷新后也是能保存篩選的條件

缺點:

1、如果篩選條件比較多,鏈接會很長;

2、因為鏈接中有很多信息,不太安全與美觀;

3、對于面包屑導航欄不好實現(xiàn);因為面包屑導航欄中不光是對應的路由,還要把對應參數(shù)都要拼接上去,會非常麻煩

方案二:使用子路由實現(xiàn),一層一層覆蓋上去

因為該方案也是比較簡單,所以這邊也不多贅述;

優(yōu)點:

1、是最簡單的,不需要做什么其他操作

缺點:

1、如果該模塊有好幾層,那路由設計時候就會很復雜,而且必須層層嵌套;嵌套多層會有性能問題

2、刷新之后就恢復之前的數(shù)據(jù)了;如果做本地存儲的話會非常麻煩

方案三:采用keep-alive

該方案能記錄所有的操作,但是去復原會是非常麻煩的一個事情;意思就是:我不同模塊切換,需要重制對應模塊的篩選條件,這個時候必須手動去清數(shù)據(jù);網(wǎng)上也有說使用keep-alive的 incloud來切換需要緩存的組建;但是在自己親測后,發(fā)現(xiàn)存在緩存錯亂的問題;也使用過離開后調用$destroy 銷毀組建,但是一旦銷毀過一次后,之后都不會緩存了;并且刷新后是不會保存之前的篩選條件與內(nèi)容的;所以棄用

方案四:

最終還是使用vuex + mixins來實現(xiàn)這樣的效果,并且是非常簡單;

思路:

1、剛開始想每個組件的篩選參數(shù)都存一份,把所有的篩選信息、分頁信息、列表信息等都存到單獨模塊的store中,每次修改的時候去更新store信息;但是后來發(fā)現(xiàn),如果模塊很多,邏輯會非常復雜,代碼量也會非常多;后來做了統(tǒng)一存儲在一個store中,然后需要的時候去存,不需要的時候去刪,根據(jù)對應頁面的routeName來做區(qū)分;

2、寫一個專門用來處理該邏輯的mixins文件,里面放各個模塊都會用到的生命周期函數(shù)與method函數(shù);然后統(tǒng)一在函數(shù)中做更新數(shù)據(jù)的操作;

3、如何判斷從store中拿已存儲的值還是說拿初始值?這個判斷是在beforeRouteEnter這個路由生命周期函數(shù)中進行,在該生命周期中通過to與from的path,判斷了路由是前進還是后退,如果是前進,那拿默認的初始值,并且銷毀store中存儲的信息;如果是返回,則取store中存儲的值;關于如何判斷,待會兒會詳細說明;

4、關于參數(shù)初始值,為了方便管理與復用,所以拉到了一個單獨的js文件中,做統(tǒng)一管理;

5、所有需要實現(xiàn)這樣功能的頁面都引入該mixins文件,然后單個組件該怎么搞就怎么搞,不需要做特殊處理;

說了這么多屁話,直接擼代碼:

具體實現(xiàn):

各個列表,需要實現(xiàn)該功能的所有列表請求參數(shù)都放到該js文件中,方便統(tǒng)一管理并且賦值;

reqDataList.js

// 角色管理列表請求參數(shù)初始化數(shù)據(jù)
export let roleManageReqData = {
  type: '',
  searchContent: '',
  page: 1,
  pageSize: 10
}

// 角色詳情列表請求參數(shù)初始化數(shù)據(jù)
export let roleDetailReqData = {
  type: '',
  searchContent: '',
  page: 1,
  pageSize: 10
}

// 用戶管理列表請求參數(shù)初始化數(shù)據(jù)
export let userManageReqData = {
  type: '',
  searchContent: '',
  page: 1,
  pageSize: 10
}

這邊路由設計是平級路由,但是path的命名是按模塊嵌套來的,這樣設計可以較方便的判斷是前進還是后退;

routerMap.js

{
    path: '/userManage',
    name: 'userManage',
    title: '人員管理',
    meta: {},
    component: () => import('@/views/peopleManage/userManage/index.vue'),
  },
  {
    path: '/userManage/addUser',
    name: 'addUser',
    title: '新增用戶',
    meta: {},
    component: () => import('@/views/peopleManage/userManage/addUser/index.vue')
  },
  {
    path: '/roleManage/roleDetail',
    name: 'roleDetail',
    title: '角色詳情',
    meta: {},
    component: () => import('@/views/peopleManage/powerManage/roleManage/roleDetail/index.vue')
  },
  {
    path: '/roleManage/roleDetail/roleEdit',
    name: 'roleEdit',
    title: '角色編輯',
    meta: {},
    component: () => import('@/views/peopleManage/powerManage/roleManage/roleDetail/roleEdit/index.vue')
  },
  {
    path: '/roleManage',
    name: 'roleManage',
    meta: {},
    component: () => import('@/views/peopleManage/powerManage/roleManage/index.vue')
  },
  {
    path: '/roleManage/addRole',
    name: 'addRole',
    title: '新增角色',
    meta: {},
    component: () => import('@/views/peopleManage/powerManage/roleManage/addRole/index.vue')
  }

列表混合頁面;公共的一些函數(shù)、操作都放在這里面;這邊說明一下混合中的beforeRouteEnter與組件中的beforeRouteEnter執(zhí)行順序,如下圖:

image

所以在1中進行判斷采用緩存還是初始化的值,然后賦值給路由meta信息;2中拿到對應的meta中的參數(shù)信息,請求接口,請求成功后next,在3中做對應的組件內(nèi)部賦值等;在4中將對應組件的篩選條件的值賦值為第1步中的值;

pagitionMixin.js

import store from '@/store/index'
import * as reqDataList from '@/config/reqDataList'
export default {
  data() {
    return {
      reqData: {...reqDataList[this.$route.name + 'reqData']} // 根據(jù)當前routeName,獲取對應初始化的參數(shù)
    }
  },
  beforeRouteEnter (to, from, next) {
    // 是否是返回;這邊path設計是分層級的,如:列表的路由是:/list ,詳情就是:/list/detail;這樣就可以通過以下方式判斷,是前進還是后退了
    let isBack = from.path.indexOf(to.path) > -1
    // 從store里面拿到存儲的值
    let reqData = store.state.publicInfo.reqDataList[to.name]
    // 把reqData存儲到對應路由的meta信息中,供單個組件beforeRouteEnter生命周期使用,解決沒有next(),拿不到this的問題;
    to.meta.reqData = isBack && reqData ? reqData : {...reqDataList[to.name + 'reqData']}
    if (!isBack) {
      console.log('前進')
      // 如果是前進,則清除store中存儲的該組建的數(shù)據(jù)
      store.dispatch('uploadListParams', {
        routeName: to.name
      })
    } else {
      console.log('后退', store.state.publicInfo.reqDataList[to.name])
    }
    next(vm => {
      // 請求參數(shù)做賦值
      vm.reqData = to.meta.reqData
    })
  },
  methods: {
    /**
     * @func 列表搜索
     */
    search () {
      console.log('搜索')
      this.reqData.page = 1
      store.dispatch('uploadListParams', {
        routeName: this.$route.name,
        reqData: this.reqData
      })
      this.getList ()
    },
    /**
     * @func 列表分頁
     * @param val 當前第幾頁
     */
    currentChange (val) {
      console.log('分頁')
      this.reqData.page = val
      store.dispatch('uploadListParams', {
        routeName: this.$route.name,
        reqData: {
          ...this.reqData,
          page: val
        }
      })
      this.getList (val)
    }
  }
}

單個組件內(nèi)正常書寫,這邊只截取beforeRouterEnter中的代碼;這邊采用先請求,后next,是因為需要實現(xiàn)進度條效果;當該組件請求完成后,再切入到該路由中,可以達到與github一樣的效果;

roleManage/index****.vue

beforeRouteEnter (to, from, next) {
  getUserList(to.meta.reqData).then(res => {
    next(vm => {
      vm.tableData = res.data.list
      vm.totalCount = res.data.totalCount
    })
  })
}

在store中處理對應篩選條件,對應路由的name為key,篩選參數(shù)對象為value,存儲在reqDataList中;如果已經(jīng)存在則更新,如果不存在則新增;如果沒有傳遞reqData參數(shù),則表示刪除;每一次更新都同步一下sessionStorage中的數(shù)據(jù),這邊存儲用于刷新后還是可以保留之前的篩選條件

publicInfo/index.js

import * as actions from './actions'
import * as getters from './getters'
import * as types from './types'

const publicInfo = JSON.parse(sessionStorage.getItem('publicInfo'))
const state = Object.assign({
  reqDataList: {}
}, publicInfo);

const mutations = {
  /**
   * 更新列表請求參數(shù)
   *
   */
  [types.UPLOAD_LIST_PARAMS](state, data) {
    try {
      // 判斷是否有reqData,如果存在,表示是新增或者更新,不然則是刪除
      if (data.reqData) {
        state.reqDataList[data.routeName] = data.reqData
      } else {
        delete state.reqDataList[data.routeName]
      }

      // 更新后的數(shù)據(jù)存儲到本地
      sessionStorage.setItem('publicInfo', JSON.stringify(state));
    } catch (err) {
      console.log("存儲錯誤:" + err)
    }
  }
}

export default {
  state,
  getters,
  actions,
  mutations
}

這樣就能完美的實現(xiàn)該功能;具體的demo地址,請點擊這里;

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容