vue使用keep-alive如何实现多页签并支持强制刷新

目录
  • 使用keep-alive实现多页签并支持强制刷新
    • 需求
    • 思路
    • 已打开菜单组件
    • Home页面
  • 使用keep-alive以后刷新部分数据如何解决
    • 项目中遇到得问题

使用keep-alive实现多页签并支持强制刷新

需求

我司有一款使用Vue构建的SPA 后台管理系统,此时客户提出一个需求。

1:要求支持打开多页签

2:多页签保留状态,即切换页签的时候不重新刷新内容。

3:关闭某一页签之后,重新打开之后,需要进行刷新

4:在当前页面可以进行强制刷新功能。

如图示意(左侧箭头为多页签,右侧为强制刷新按钮,图是网图,非本公司后台管理系统页面,效果类似)

思路

1:首先编写Tags(多页签)

2:使用Keep-alive包裹 router-view。

3:利用router-view key值变化会导致内容刷新来实现页面强制刷新

已打开菜单组件

Tags(多页签)左侧箭头指出功能

<template>
    <div class="vtag" id="nTabs">
        <div class="overFlowWapper" ref="overFlowWapper">
            <div class="tagItemWapper" ref="tagItemWapper" v-bind:style="{ width:tagsList.length*110+'px',marginLeft:curGo+'px'}">
                <div class="tagItem" v-for="(item,index) in tagsList" v-bind:class="{ active: isActive(item.path) }"
                     @contextmenu="showMenu" @click="goMe(item)" :title="(myRouter[item.name]||item.title)+(item.queryName||'')">
                    <a class="leftx" v-bind:class="{canCloseNot:!item.canClose}">
                        {{(myRouter[item.name]||item.title)+(item.queryName||'')}}

                    </a>
                    <a class="rightx" v-if="item.canClose" @click.stop="delTags(index)"><span>×</span></a>
                    <vue-context-menu :contextMenuData="contextMenuData" @delAll="delAll">
                    </vue-context-menu>
                </div>
            </div>
        </div>
        <div class="tagBtn tagleft" @click="tagLeft" v-if="tagsButtonShow">
            <img src="static/img/svg/icon_narrow.svg">
        </div>
        <div class="tagBtn tagRight" @click="tagRight" v-if="tagsButtonShow">
            <img src="static/img/svg/icon_narrow.svg">
        </div>
        <div class="tagBtn tagRefresh" @click="refreshCurrent">
            <img src="static/img/svg/icon_refresh.svg">
        </div>
    </div>
</template>

<script>
    import bus from './bus';
    export default {
        data() {
            return {
                contextMenuData: {
                    // the contextmenu name(@1.4.1 updated)
                    menuName: 'demo',
                    // The coordinates of the display(菜单显示的位置)
                    axis: {
                        x: null,
                        y: null
                    },
                    // Menu options (菜单选项)
                    menulists: [
                        {
                            fnHandler: 'delAll', // Binding events(绑定事件)
                            icoName: 'fa fa-home fa-fw', // icon (icon图标 )
                            btnName: '关闭所有' // The name of the menu option (菜单名称)
                        },
                    ]
                },
                tagsList: [],//tag集合
                myRouter: {},
                curGo:0,// 当前往左走的步伐,往左为正数,往右为负数
                tagsButtonShow:false,//是不是应该显示左右侧按钮
                defaultPage:{
                    path:"",
                    name: "",
                    canClose:false,
                    title:"",
                    keepAlive:true
                }
            }
        },
        methods: {
            //右键菜单的使用
            showMenu () {
                event.preventDefault();
                let x = event.clientX;
                let y = event.clientY;
                // Get the current location
                this.contextMenuData.axis = {
                    x, y
                }
            },
            delAll()
            {
                this.tagsList = [];
                this.$router.push('/');
                this.tagsList.push(this.defaultPage);
            },
            //刷新当前页
            refreshCurrent() {
                bus.$emit('keyCurName', 1);
            },
            //按钮
            tagLeft() {
                this.curGo = 0;
            },
            //按钮
            tagRight() {
                let owidth = this.$refs.overFlowWapper.offsetWidth;
                let twidth = this.$refs.tagItemWapper.offsetWidth;
                this.curGo =owidth-twidth;
            },
            //切换是不是显示左右侧按钮的状态,规则:当tagItemWapper的宽度大于overFlowWapper时,显示两侧按钮
            tagsButtonShowChange() {
                if(typeof this.$refs.overFlowWapper == "undefined") {
                    this.tagsButtonShow = false;
                    return
                }
                let owidth = this.$refs.overFlowWapper.offsetWidth;
                // let twidth = this.$refs.tagItemWapper.offsetWidth;  这里不能用这个,这里有动画会延迟
                let twidth = 10 + this.tagsList.length*110;
                if(twidth > owidth + 15) {
                    this.tagsButtonShow = true;
                }
                else {
                    this.tagsButtonShow = false;
                    //测试提出:当导航标签数量较多出现左右滚动条时,向右滚动标签后从右边依次关闭标签,当空间足够展示当前打开的所有标签时,左侧被遮挡的标签没有自动展示
                    this.curGo = 0;
                }
            },
            goMe(item)
            {
                this.$router.push(item.path);
            },
            delTags(index)
            {
                //工作看板不可以被关闭哟
                if(index == 0) {
                    return;
                }
                const delItem = this.tagsList.splice(index, 1)[0];
                const item = this.tagsList[index] ? this.tagsList[index] : this.tagsList[index - 1];
                if (item) {
                    delItem.path === this.$route.fullPath && this.$router.push(item.path);
                }else{
                    this.$router.push('/');
                }
            },
            isActive(path) {
                return path === this.$route.fullPath;
            },
            //根据路由切换Tags标签
            setTags(route)
            {
                if(this.tagsList.length < 1) {
                    if(this.defaultPage.name == "")
                    {
                        let path = this.$router.options.routes[0].redirect;
                        let children = this.$router.options.routes[1].children;
                        for(let i=0;i<children.length;i++) {
                            let copy_i = children[i];
                            if(copy_i.path == path ) {
                                this.defaultPage.name = copy_i.name;
                                this.defaultPage.path = copy_i.path;
                                this.defaultPage.title = copy_i.meta.title;
                                this.defaultPage.keepAlive = copy_i.meta.keepAlive;
                            }
                        }
                    }
                    this.tagsList.push(this.defaultPage);
                }
                let isExist = false; //是不是已经打开了这个标签
                for(let i=0;i<this.tagsList.length;i++) {
                    if(this.tagsList[i].path === route.fullPath) {
                        isExist = true;
                        break;
                    }
                }
                if(!isExist)
                {
                    if(this.tagsList.length>11) {
                        this.tagsList.splice(1,1);
                    }
                    this.tagsList.push({
                        title: (this.myRouter[route.name]||route.meta.title),
                        path: route.fullPath,
                        name: route.matched[1].name,
                        keepAlive:route.meta.keepAlive,
                        canClose:true,
                        //详情页 附加名称
                        queryName: (route.query.name?"-"+route.query.name : "")
                    })
                }
                this.changePosition(route);
            },
            //测试提出:当导航标签数量较多出现左右滚动条时,通过导航菜单打开新标签或激活被隐藏的标签时,没有自动将导航标签移动到活动标签处
            changePosition(route) {
                let currentPosition = 1;//当前位置,从1开始
                for(let i=0;i<this.tagsList.length;i++) {
                    if(this.tagsList[i].name == route.name) {
                        currentPosition = i+1;
                    }
                }
                let currentPositionRight = 110*currentPosition-10;//当前标签最右侧的位置
                //如果当前标签最右侧的位置超出了边界,那么让他拽出来
                if(this.$refs.overFlowWapper) {
                    if(currentPositionRight>this.$refs.overFlowWapper.offsetWidth) {
                        let owidth = this.$refs.overFlowWapper.offsetWidth;
                        let twidth = this.tagsList.length*110;
                        this.curGo =owidth-twidth;
                    }
                }

            },
        },
        computed: {

        },
        watch:{
            $route:{
                immediate:true,
                handler:function(newValue){
                    this.setTags(newValue);
                },
                deep:true
            },
            tagsList:{
                immediate:true,
                handler:function(newValue) {
                    bus.$emit('keepList', this.tagsList);
                    this.tagsButtonShowChange();
                },
            },
            '$store.state.myRouter':{
                immediate:true,
                handler:function(newValue){
                    let myRouter = {};
                    if(newValue != null) {
                        for(let i=0; i<newValue.length; i++) {
                            myRouter[newValue[i].url] = newValue[i].label;
                        }
                    }
                    this.myRouter = myRouter;
                },
                deep:true
            },
        },
        created(){

        },
        mounted()
        {
            //当页面分辨率发生变化时,将curGo 偏移量修改为0
            this.addResizeFunctions({
                type: "const",
                name: "tags",
                callback: ()=>{
                    this.curGo = 0;
                    this.tagsButtonShowChange();
                }
            });
        }
    }

</script>

Home页面

<v-tags></v-tags>  <!--刚才的tags组件-->
            <div class="content">
                <keep-alive :include="myKeepList">
                    <router-view :key="key">
                    </router-view>
                </keep-alive>
            </div>
export default {
        data(){
            return {
                myKeepList: [""],
                bindKeys:{
                    addEs: "24",
                    addWorkflow: "30",
                    announceIssuerWatching: "45",
                    approvalHistory: "33",
                    approvalTask: "32",
                    bondDetail: "50",
                },
            }
        },
        components:{
            vTags
        },
        computed: {
            key() {
                return this.bindKeys[this.$route.name];
            },
            ...mapState(['routerKey','copyRight'])
        },
        watch:{
            '$route': {
                immediate: true,
                handler: function (val) {//监听路由是否变化
                    this.showFooter = (val.name =="dashboard"?false:true);
                }
            }
        },
        methods: {
        },
        created(){
            // 只有在标签页列表里的页面才使用keep-alive,即关闭标签之后就不保存到内存中了。
            bus.$on('keepList', msg => {
                let arr = [];
                for(let i=0;i<msg.length;i++) {
                    let copy_m = msg[i];
                    if(copy_m.keepAlive) {
                        arr.push(copy_m.name);
                    }
                }
                this.myKeepList = arr;
            });
            // 点击强制刷新按钮会触发这里。
            bus.$on('keyCurName', msg => {
                this.bindKeys[this.$route.name] = new Date().getTime();
            });
        },
        mounted() {
        },
    }

使用keep-alive以后刷新部分数据如何解决

项目中遇到得问题

描述如下:

上图页面使用了keep-alive,所以当从其其他页面跳转到这个页面得时候不会刷新数据,因此解决方式为

如下图所示就可以

上图中activated和created使用方法一致,在这个方法里重新获取一下数据就好了,我们得业务场景是

点击图标选取地理位置

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Vue实现多页签组件

    直接看效果,增加了右键菜单,分别有重新加载.关闭左边.关闭右边.关闭其他功能. 也可以到我的github上看看代码(如果觉得这个组件有用的话,别忘了顺手给个小星星) 代码:https://github.com/Caijt/VuePageTab 演示:https://caijt.github.io/VuePageTab/ 我这个多页签组件里面的删除缓存的方法不是使用keep-alive组件自带的include.exculde结合的效果,而是使用暴力删除缓存的方法,这个在上个博客中也有提到,用这种方

  • vue中keep-alive的用法及问题描述

    1.keep-alive的作用以及好处 在做电商有关的项目中,当我们第一次进入列表页需要请求一下数据,当我从列表页进入详情页,详情页不缓存也需要请求下数据,然后返回列表页,这时候我们使用keep-alive来缓存组件,防止二次渲染,这样会大大的节省性能. 2.keep-alive的基本用法 在app.vue中 <!-- 缓存所有的页面 --> <keep-alive> <router-view v-if="$route.meta.keep_alive"&g

  • vue的keep-alive用法技巧

    <keep-alive>是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM <keep-alive> 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们.和 <transition> 相似,<keep-alive>是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中. 方法1 include: 字符串或正则表达式.只有匹配的组件会被缓存. exclude: 字符串或正则表达式.任何匹配的组件都不会被缓存. e

  • vue缓存的keepalive页面刷新数据的方法

    用到这个的业务场景是这样的: a页面点击新建列表按钮进入到新建的页面b,填写b页面并点击b页面确认添加按钮,把这些数据带到a页面,填充到列表(数组),可以添加多条, 点击这条的时候进入到编辑页面,确认修改之后,回退到a页面,a页面需要更新这条数据 实现这个功能的时候,由于是路由页面之间的跳转,首先想到的方案有几个:1. 用sessionStorage本地存储:2. 用路由参数带过去:3. 用兄弟组件传值 由于是添加完之后如果按回退是需要退出整个页面,如果用路由跳转,会出现回退到编辑页面了,所以这

  • vue使用keep-alive如何实现多页签并支持强制刷新

    目录 使用keep-alive实现多页签并支持强制刷新 需求 思路 已打开菜单组件 Home页面 使用keep-alive以后刷新部分数据如何解决 项目中遇到得问题 使用keep-alive实现多页签并支持强制刷新 需求 我司有一款使用Vue构建的SPA 后台管理系统,此时客户提出一个需求. 1:要求支持打开多页签 2:多页签保留状态,即切换页签的时候不重新刷新内容. 3:关闭某一页签之后,重新打开之后,需要进行刷新 4:在当前页面可以进行强制刷新功能. 如图示意(左侧箭头为多页签,右侧为强制刷

  • vue+vuex+axios实现登录、注册页权限拦截

    在GitHub上有很多写好的模板,这个项目也是基于模板做的. 现在记录一下我做的过程 1.修改config文件夹里的dev.env.js里的BASE_API,把地址改成请求后端的公共部分 BASE_API: '"http://192.168.xx.xx"', 2.接下来就是操作src文件,先在 views里写好vew组件(login.vue,regist.vue),写好到router里的index.js里配置好路径 login.vue <template> <div

  • vue中使用vue-print.js实现多页打印

    本文主要介绍了vue项目中使用print.js打印,解决多页,分页,打印预览样式修改等问题. 引入安装vue-print.js cnpm i vue-printjs --save-dev 解决打印多页只出现一页问题 由于打印插件存在问题,如果打印文件超出一页,只显示一页,所以我们需要修改print.js源文件,所以只能手动下载vue-print.js到本地,做一些修改,然后引入到项目中,不能使用npm安装 下载 print.js https://github.com/zxc19890923/pr

  • vue+iview的菜单与页签的联动方式

    vue+iview菜单与页签联动 最近在使用vue+iview开发一个后台管理类的系统,希望做一个点击左侧菜单右侧的页签与内容都能相对应的改变. 但搞了好久的路由也没有实现这个功能. 刚开始使用vue+iview不知道iview-admin可以直接拿来使用,布局之类的开箱即用,可是自己的demo已经写了好久不忍心放弃. 一.使用iview的menu和tab做布局,将这两个组件放到主页面 由于menu与tab的数据相同且样式需要进行关联,因此可以使用vuex进行状态管理,state中写入需要管理的

  • Vue实现侧边导航栏于Tab页关联的示例代码

    目录 技术栈 效果 分析 技术栈 侧边栏用 Antdtab使用element 效果 <template> <div class="main-card"> <el-row> <el-col :span="3"> <div class="menu-all"> <div class="menu-head"> <span class="menu-h

  • Vue实现点击按钮进行上下页切换

    本文实例为大家分享了Vue实现点击按钮进行上下页切换的具体代码,供大家参考,具体内容如下 案例效果: 完整代码如下: <template>   <div id="page">     <button class="btn" @click="prePage()">上一页</button>     <ul>       <li :class="selected == inde

  • vue实现tagsview多页签导航功能的示例代码

    目录 前言 一.效果图 二.实现思路 1. 新建 tags-view.js 2. 在Vuex里面引入 tags-view.js 3. 新建 tabsView 组件 4. 新建 ScrollPane 组件 5. 引入 tabsView 组件 6. 使用 keep-alive 组件,进行页签的缓存 总结 前言 基本上后台管理系统都需要有多页签的功能,但是因为一些脚手架项目基本都把这个功能给集成好了,导致在学习或者修改的时候不知道该如何下手.今天这篇文章就来聊一聊,vue-element-admin项

  • vue 使用mescroll.js框架实现下拉加载和上拉刷新功能

    以下是代码是在项目中抽取出来的,都是实现下拉刷新上拉加载的要点. 注:以下不是用vue-cli写的,用vue-cli的请绕过,抱歉~ 1.mescroll 的页面的初始化 initMescroll(){ var _this = this; this.mescroll = new MeScroll("mescroll",{ down:{ callback: _this.downCallback //下拉刷新的回调函数 }, up:{ callback: _this.upCallback,

  • Vue同一路由强制刷新页面的实现过程

    目录 1. 思路 2. 实现过程 2.1 新建一个名为refresh.vue的文件 2.2 在refresh.vue里添加 beforeRouteEnter 2.3 在路由文件里,加上refresh 的路由 2.4 当你想刷新当前页面的时候,可以调用下面这段代码 1. 思路 使用this.$router.replace(),跳到一个空白页,然后this.$router.replace()重新跳回来 使用this.$router.replace()的原因是,其实跟this.$router.push

随机推荐