转载修改自:https://blog.csdn.net/weixin_42505098/article/details/82820174

在写 Vue.js 时候遇到了一个问题,我在 Index 组件中嵌套了 Login 组件,并且希望在登录成功后,让右侧的「登录」直接变成「用户名」+「注销」。

一开始也是想着用 sessionStorage 或者 localStorage,但是在 Login 组件中执行 sessionStorage.setItem() 后发现导航里的登录按钮并没有发生改变。刷新后才发生变化,于是就找到了上面的文章,这里记录补充一下。

这个方法 sessionStorage 和 localStorage 均适用,下面用 sessionStorage 做演示,如果需要可以自己把所有的 sessionStorage 改成 localStorage

怎么监听

main.js 中加入:

Vue.prototype.resetSetItem = function (key, newVal) {
    // 创建一个StorageEvent事件
    var newStorageEvent = document.createEvent('StorageEvent');
    const storage = {
        setItem: function (k, val) {
            sessionStorage.setItem(k, val);
            // 初始化创建的事件
            newStorageEvent.initStorageEvent('setItem', false, false, k, null, val, null, null);
            // 派发对象
            window.dispatchEvent(newStorageEvent)
        }
    }
    return storage.setItem(key, newVal);
}

其实原作者这里加了一个 if (key === 'watchStorage') 的判断,当且仅当 key 为 watchStorage 时才执行,我给去掉了因为我觉得没必要,本身这个方法已经限制了你必须使用 this.resetSetItem() 才能触发,如果不需要监听就直接用原来的 setItem() 就行吧我觉得(

如何触发

比方说,在我的例子中,我在登录界面输入账号密码,POST 发送给后端然后后端返回了登录成功的结果时,执行 this.resetSetItem(key, value); 代码,例如在 Login.vue 里加入:

this.$axios.post(后端API, {
    XXX: YYY
})
.then(res=> {
    if (判断是否登录成功) {
        sessionStorage.clear();
        this.resetSetItem('login_status',true);
        this.resetSetItem('username',res.data['username']);
        ...
    } else if(登录失败) {
        ...
    }
})
.catch(function (error) {
    console.log(error);
});

如何监听

上述例子中,我的登录按钮在 Index.vue 组件里,因此我们可以在 Index.vue 里这么写:

export default {
    name: Index,
    data() {
        return {
            ...
            login_status: sessionStorage['login_status'],
            username: sessionStorage['username'],
            ...
        };
    },
    created() {
        window.addEventListener('setItem', ()=> {
            this.login_status = sessionStorage.getItem('login_status');
            this.username = sessionStorage.getItem('username');
            this.activeIndex = 1;
        })
    }
}

记得给登录和注册按钮套上 v-if:

<el-menu-item v-if=login_status style=float: right>注销</el-menu-item>
<el-menu-item v-if=login_status style=float: right>{{username}}</el-menu-item>
<el-menu-item v-else index=login style=float: right>登录</el-menu-item>

效果