Vue 应用系列笔记 (六) 利用vuex掺和项目

既然加入了状态管理,就要用到尽,不用不就白浪费了。随着模块更新,持续更新

目录

一、顶部tag的应用

顶部tag的操作:

①如何开始定义模块

②定义模块所需状态值

③操作状态值

1、增加标签

2、删除标签

3、删除所有标签

4、删除其他标签

涉及的本地/会话存储:

为什么要用本地/会话存储?

判空方法

①存储

②获取某个

③删除某个

④获取全部

⑤清空全部

顺便掺和路由:

如何进行绑定?

①对router-plugin改造

② 对标签进行路由绑定

③对组件tag进行改造


一、顶部tag的应用

顶部tag的操作:

①如何开始定义模块

首先我们要给tag定义一个基本的属性(虽然这个属性是总体定义),某些规则适配业务与一般逻辑性。

eg: 例如tag仅剩一个时不能关闭

tips:

①下方 tags.js -->store/modules/tag.js

②下方tags.vue --> components/lay-out/tags.vue

// tag.js
//给 tag 标立一个基本对象属性
const tagObj = {
  label: '', //标题名称
  value: '', //标题的路径
  params: '', //标题的路径参数
  query: '', //标题的参数
  close: false //是否显示关闭按钮
};
​
//最后一个标签就不必存在关闭按钮了
let setFistTag = ((list) => {
  if (list.length == 1) {
    list[0].close = false;
  } else {
    list.some(a => {
      a.close = true
    })
  }
})
//tags.vue
​
//对应页面也要适配上去
<i class="el-icon-close tag-close" v-if="item.close"/>

②定义模块所需状态值

我们需要的状态值包括:

1、标签列表,以保证刷新后的数据能重新回填

2、当前tag的值

//tags.js
​
//作本地存储用,后面会贴出来
import {getStore, removeStore, setStore} from '@/util/store'
​
//若本地/会话存储内不存在,则为空,因为刷新后会清空内存
state: {
    tagList: getStore({name: 'tagList'}) || [],
    tag: getStore({name: 'tag'}) || tagObj
}

③操作状态值

下列操作仅需要同步操作即可,因故基本为 mutation,若有非此,会注释表明。

tips: 下方 默认存在 getStore, removeStore, setStore 方法,仅仅是封装了sessionStorage/localStorage,第四点会提及这个工具类

1、增加标签

新增的标签,通常是其他地方新增的页面,将最新的更替为当前值

①如果列表中没有,我们就新增,插入到列表中,如果存在,则无需插入

②保险起见,还是要调用上方 setFistTag 来校验一下

ADD_TAG: (state, action) => {
    state.tag = action;
    setStore({ name: 'tag', content: state.tag, type: 'session' });
    if (state.tagList.some(ele => isObjectValueEqual(ele, action))) return;
    state.tagList.push(action);
    setFistTag(state.tagList);
    setStore({ name: 'tagList', content: state.tagList, type: 'session' })
}

2、删除标签

整体是利用过滤器对传进来的标签进行判断

①如果传入的对象属于 object对象就可以对其解析,判断属性是否相同,如果存在则删除

②调用上方setFistTag 来校验

DEL_TAG: (state, action) => {
    state.tagList = state.tagList.filter(item => {
        if (typeof(action) === 'object') {
            let a = Object.assign({}, item);
            let b = Object.assign({}, action);
            delete a.close;
            //delete b.__ob__;  使用了asign 之后就不必要这句,复制后就木有了
            //__ob__:Observer这些数据是vue这个框架对数据设置的监控器,一般都是不可枚举的,木有了指的是这个
            return !isObjectValueEqual(a, b)//是最终用于判定每个属性是否相同的
        } else {
            return item.value !== action
        }
    });
    setFistTag(state.tagList);
    setStore({ name: 'tagList', content: state.tagList, type: 'session' })
}
​
//如果不喜欢这样,还有其他方法,例如自行遍历,但是要注意对比时如果全部属性,记得__ob__带来的问题
​

3、删除所有标签

就很直接,清空标签栏

DEL_ALL_TAG: (state) => {
    state.tagList = [];
    removeStore({ name: 'tagList' });
}

4、删除其他标签

这个是为了备选需要删除其他标签,仅仅留下当前标签的,也是很清晰

DEL_TAG_OTHER: (state) => {
    state.tagList = state.tagList.filter(item => item.value === state.tag.value);
    setFistTag(state.tagList);
    setStore({ name: 'tagList', content: state.tagList, type: 'session' })
}

上述 isObjectValueEqual方法

//主要用于判断对象中属性是否完全相同,逻辑如代码所示,简单判别格式化与字符串相等等
export const isObjectValueEqual = (a, b) => {
  let result = true;
  Object.keys(a).forEach(ele => {
    const type = typeof(a[ele]);
    if (type === 'string' && a[ele] !== b[ele]) result = false;
    else if (type === 'object' && JSON.stringify(a[ele]) !== JSON.stringify(b[ele])) result = false;
  })
  return result;
};
​

涉及的本地/会话存储:

为什么要用本地/会话存储?

① vuex存储在内存(刷新GG),localstorage(本地存储)则以文件的方式存储在本地,永久保存;sessionstorage( 会话存储 ) ,临时保存页面关闭GG。

② 同时,及时响应的数据驱动也是 localstoragesessionstorage 无法达到的

判空方法

//懒得写箭头还要设置名称
function validatenull(val) {
  if (typeof val == 'boolean') {
    return false;
  }
  if (val instanceof Array) {
    if (val.length == 0) return true;
  } else if (val instanceof Object) {
    if (JSON.stringify(val) === '{}') return true;
  } else {
    if (val == 'null' || val == null || val == 'undefined' || val == undefined || val == '') return true;
    return false;
  }
  return false;
}

①存储

/**
 * 存储local/session Storage
 *  name : 对应名称
 *  content: 内容
 *  type: 主要是 seesion ,不然就默认本地存储,好吧其实是不为空
 *  datetime: 虽然这里可能遇到ios的无敌问题,但是我不考虑,如果考虑就用moment.js
 */
export const setStore = (params) => {
    let {
        name,
        content,
        type,
        datetime
    } = params;
    let obj = {
        dataType: typeof(content),
        content: content,
        type: type,
        datetime: new Date().getTime()
    };
    if (type) window.sessionStorage.setItem(name, JSON.stringify(obj));
    else window.localStorage.setItem(name, JSON.stringify(obj));
};

②获取某个

/**
 * 获取local/session Storage
 */
export const getStore = (params) => {
  let {
    name,
    type
  } = params;
  let obj = {},
    content;
  obj = window.localStorage.getItem(name);
  if (validatenull(obj)) obj = window.sessionStorage.getItem(name);
  if (validatenull(obj)) return;
  obj = JSON.parse(obj);
  if (obj.dataType == 'string') {
    content = obj.content;
  } else if (obj.dataType == 'number') {
    content = Number(obj.content);
  } else if (obj.dataType == 'boolean') {
    content = eval(obj.content);
  } else if (obj.dataType == 'object') {
    content = obj.content;
  }
  return content;
};

③删除某个

/**
 * 删除local/session Storage
 * 默认可以不写type,删除全部,当然也可以选择,随自己意思吧
 */
export const removeStore = params => {
  let {
    name,
    type
  } = params;
  if (type) {
    if('session'===type){
      window.sessionStorage.removeItem(name);
    }else{
      window.localStorage.removeItem(name);
    }
  } else {
    window.localStorage.removeItem(name);
    window.sessionStorage.removeItem(name);
  }
};

④获取全部

/**
 * 获取全部local/session Storage
 */
export const getAllStore = (params) => {
  let list = [];
  let {
    type
  } = params;
  for (let i = 1; i <= window.sessionStorage.length; i++) {
    if (type) {
      list.push({
        name: window.sessionStorage.key(i),
        content: getStore({
          name: window.sessionStorage.key(i),
          type: 'session'
        })
      })
    } else {
      list.push(getStore({
        name: window.localStorage.key(i),
        content: getStore({
          name: window.localStorage.key(i),
        })
      }))
    }
  }
​
  return list;
};

⑤清空全部

/**
 * 清空全部local/session Storage
 */
export const clearStore = (params) => {
  let {
    type
  } = params;
  if (type) {
    window.sessionStorage.clear();
    return;
  }
  window.localStorage.clear()
};

顺便掺和路由:

这里怎么说呢。标签与路由分离了,标签就滑来滑去就没有意义了(不这样我怎么掺和进来),所以就掺进来。

如何进行绑定?

既然要与路由掺和,就要选定路由改变的时候去掺和,如果存在,就给它(这个路由)特别展示出来,不存在就给他新增一个(标签)出来。这样才能算的上掺和

①对router-plugin改造

之前路由定义的内容,不是很适配接下来的掺和,所以需要略微改动。

主要是修改前置导航守卫,来适配标签

//  src/router/router-plugin.js
// 1、移除了前置导航守卫
// 2、修正了校验路由方法  validPath,不再使用foreach,改用some遍历
// 3、新增 setTitle 方法,用于设置浏览器头标题
​
let RouterPlugin = function () {
    this.$router = null   
}
​
RouterPlugin.install = function (router) {
    this.$router = router
​
    this.$router.$avueRouter = {
        //正则处理路由
        validPath: function (list, path) {
            let result = false;
            list.some(ele => {
                if (new RegExp("^" + ele + ".*", "g").test(path)) {
                    result = true
                    return true
                }
            });
            return result;
        },
    }
​
    // 设置标题
    setTitle: function(title) {
        title = title ? `${title}` : '兰楹花';
        document.title = title;
    },
​
}
​
​
export default RouterPlugin;

② 对标签进行路由绑定

在每次路由变更的时候,对当前路由进行判定,若存在则展示点亮对应标签,否则,新增标签。

import website from "@/config/website";
import router from '@/router'
import store from '@/store'
​
import NProgress from 'nprogress'
​
NProgress.configure({showSpinner: false});
​
router.beforeEach((to, from, next) => {
    NProgress.start()
    if (router.$avueRouter.validPath(website.whiteList, to.path)) {
        const value = to.query.src ? to.query.src : to.path;
        const label = to.query.name ? to.query.name : to.name;
        store.commit('ADD_TAG', {
            label: label,
            value: value,
            params: to.params,
            query: to.query
        });
        next()
    } else {
        store.commit('ADD_TAG', {
            label: "主页",
            value: "/base/hi",
            params: to.params,
            query: to.query
        });
        next('/base/hi')
    }
})
​
router.afterEach(() => {
    NProgress.done();
    let title = store.getters.tag;
    title = title == undefined ? null : title
    router.$avueRouter.setTitle(title);
});

③对组件tag进行改造

引入vuex,对会话/本地存储中的标签数据提取并展示出来

<template> 
    ...
  <div ref="tag" class="tag-item" v-for="item in tagList">
    <span class="tag-text">{{item.label}}</span>
<i class="el-icon-close tag-close" v-if="item.close"/>
  </div>
    ...
<template>
​
​
<script> 
  ....
 
 import {mapGetters} from 'vuex'
  
  
  computed: {
  ...mapGetters([ 'tagList'])
  },
  
  ...
 </script>

猜你喜欢

转载自blog.csdn.net/CoffeeAndIce/article/details/105942229
今日推荐