前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >【Vue.js——Bug修复】消失的 Token(蓝桥杯真题-2424)【合集】

【Vue.js——Bug修复】消失的 Token(蓝桥杯真题-2424)【合集】

作者头像
Rossy Yan
发布2025-02-11 14:22:37
发布2025-02-11 14:22:37
10800
代码可运行
举报
运行总次数:0
代码可运行

背景介绍

小蓝开发了一个登录功能,但是在登录界面中输入用户名后点击“确认”按钮并没有如预期般成功进入欢迎界面。但是从出现欢迎语来看,数据已经发生了改变,到底是怎么回事呢?请帮助小蓝排查代码,让登录功能回归正常吧!

准备步骤

目录结构如下:

代码语言:javascript
代码运行次数:0
复制
├── components
│   ├── login.js
│   └── panel.js
├── css
│   └── style.css
├── index.html
├── lib
│   ├── vue.min.js
│   └── vuex.min.js
└── store
    ├── BaseModule.js
    ├── UserModule.js
    └── index.js 

其中:

  • index.html 是主页面。
  • components 是为示例组件文件夹。
  • lib 是存放项目相关依赖的文件夹。
  • store 是 Vuex 状态管理文件夹。
  • css 是存放项目样式的文件夹。

注意:打开环境后发现缺少项目代码,请复制下述命令至命令行进行下载。

代码语言:javascript
代码运行次数:0
复制
cd /home/project
wget https://labfile.oss.aliyuncs.com/courses/18164/dist_03.zip
unzip dist_03.zip
mv dist/* ./
rm -rf dist*

在浏览器中预览 index.html 页面效果如下:

此时输入用户名后回车/点击确定,数据发生改变,但还是停留在登录页,无法正确显示登录成功界面。


目标效果

找到 index.html 中的 TODO 部分,仔细阅读 store 文件夹下的相关代码并结合 Vuex 相关知识,排查代码中存在的问题,修改后使得登录界面输入 admin 时,点击确认按钮/回车可以正确显示如下界面:


要求规定

  • 请按照给出的步骤操作,切勿修改默认提供的文件名称、文件夹路径等。
  • 满足需求后,保持 Web 服务处于可以正常访问状态,点击「提交检测」系统会自动检测。

判分标准

  • 本题完全实现题目目标得满分,否则得 0 分。

通关代码✔️

代码语言:javascript
代码运行次数:0
复制
<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="./lib/vue.min.js"></script>
    <script src="./lib/vuex.min.js"></script>
    <script src="./store/BaseModule.js"></script>
    <script src="./store/UserModule.js"></script>
    <script src="./store/index.js"></script>
    <link rel="stylesheet" href="./css/style.css">
</head>

<body>
    <div id="app">
        <div class="wrapper" style="width: 900px;">

            <!-- 2. 登录成功后的欢迎界面 -->
            <Panel v-if="token" :username="username">
                {{welcome}}
            </Panel>

            <!-- 1. 登录界面 -->
            <Login v-else @confirm="login">
                {{welcome}}
            </Login>

        </div>
    </div>

    <script src="./components/login.js"></script>
    <script src="./components/panel.js"></script>
    <script>
        // 修改下面错误代码

        var app = new Vue({
            el: '#app',
            data() { },
            computed: {
                welcome() {
                    // 使用 window.$store 访问 getters
                    return window.$store.getters['base/welcome'];
                },
                username() {
                    // 加上命名空间前缀访问 user 模块的 getters
                    return window.$store.getters['user/username'];
                },
                token() {
                    // 加上命名空间前缀访问 user 模块的 getters
                    return window.$store.getters['user/token'];
                }
            },
            methods: {
                // 回车/点击确认的回调事件
                login(username) {
                    if (username) {
                        // 加上命名空间前缀提交 user 模块的 mutations
                        window.$store.commit('user/login', { username, token: 'sxgWKnLADfS8hUxbiMWyb' });
                        // 提交 base 模块的 mutations
                        window.$store.commit('base/say', '登录成功,欢迎你回来!');
                    }
                }
            }
        })
    </script>
</body>

</html>

代码解析📑

一、HTML 部分

1. HTML 头部

代码语言:javascript
代码运行次数:0
复制
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="./lib/vue.min.js"></script>
    <script src="./lib/vuex.min.js"></script>
    <script src="./store/BaseModule.js"></script>
    <script src="./store/UserModule.js"></script>
    <script src="./store/index.js"></script>
    <link rel="stylesheet" href="./css/style.css">
</head>
  • 元信息
    • <meta charset="UTF-8">:设置页面的字符编码为 UTF - 8,确保页面能正确显示各种字符。
    • <meta http-equiv="X-UA-Compatible" content="IE=edge">:指定页面在 Internet Explorer 中以最新的渲染模式显示。
    • <meta name="viewport" content="width=device-width, initial-scale=1.0">:设置页面的视口,使页面在不同设备上能自适应显示。
  • 脚本引入
    • ./lib/vue.min.js:引入 Vue.js 库,用于构建响应式的用户界面。
    • ./lib/vuex.min.js:引入 Vuex 库,用于管理应用的状态。
    • ./store/BaseModule.js./store/UserModule.js./store/index.js:引入 Vuex 模块和存储配置文件。
  • 样式引入
    • ./css/style.css:引入外部样式文件,用于美化页面。

2. HTML 主体

代码语言:javascript
代码运行次数:0
复制
<body>
    <div id="app">
        <div class="wrapper" style="width: 900px;">

            <!-- 2. 登录成功后的欢迎界面 -->
            <Panel v-if="token" :username="username">
                {{welcome}}
            </Panel>

            <!-- 1. 登录界面 -->
            <Login v-else @confirm="login">
                {{welcome}}
            </Login>

        </div>
    </div>

    <script src="./components/login.js"></script>
    <script src="./components/panel.js"></script>
    <!-- 定义 Vue 实例的脚本代码 -->
</body>
  • Vue 挂载点
    • <div id="app">:是 Vue 实例的挂载点,Vue 会接管该元素及其子元素的渲染和交互。
  • 组件渲染
    • <Panel> 组件:使用 v-if="token" 指令,当 token 存在时渲染该组件,用于显示登录成功后的欢迎界面,并通过 :username="username" 传递 username 数据。
    • <Login> 组件:使用 v-else 指令,当 token 不存在时渲染该组件,用于显示登录界面,并通过 @confirm="login" 监听 confirm 事件,触发 login 方法。
  • 组件引入
    • ./components/login.js./components/panel.js:引入登录和欢迎界面的组件脚本。

3. Vue 实例

代码语言:javascript
代码运行次数:0
复制
var app = new Vue({
    el: '#app',
    data() { },
    computed: {
        welcome() {
            return window.$store.getters['base/welcome'];
        },
        username() {
            return window.$store.getters['user/username'];
        },
        token() {
            return window.$store.getters['user/token'];
        }
    },
    methods: {
        // 回车/点击确认的回调事件
        login(username) {
            if (username) {
                window.$store.commit('user/login', { username, token: 'sxgWKnLADfS8hUxbiMWyb' });
                window.$store.commit('base/say', '登录成功,欢迎你回来!');
            }
        }
    }
})
  • el 属性:指定 Vue 实例的挂载点为 #app
  • data 选项:这里为空,因为数据主要通过 Vuex 进行管理。
  • computed 选项: welcome:通过 window.store.getters['base/welcome'] 获取 BaseModule 中的 welcome 状态。username:通过 window.store.getters['user/username'] 获取 UserModule 中的 username 状态。token:通过 window.
  • methods 选项
    • login 方法:当用户在登录界面输入用户名并触发 confirm 事件时调用。如果用户名存在,则通过 window.$store.commit 提交两个 mutations
      • user/login:更新 UserModule 中的 usernametoken 状态。
      • base/say:更新 BaseModule 中的 welcome 状态,显示登录成功的欢迎信息。

4. 关键知识点

Vuex 模块和命名空间

  • 模块:将 Vuex 存储分割成多个模块,如 BaseModuleUserModule,便于管理不同功能的状态。
  • 命名空间UserModule 开启了命名空间(namespaced: true),在访问其 getters 和提交 mutations 时需要加上命名空间前缀,如 user/

Vue 指令

  • v-ifv-else:用于条件渲染,根据 token 的存在与否决定显示登录界面还是欢迎界面。
  • @ 语法:用于监听组件的自定义事件,如 @confirm="login" 监听 Login 组件的 confirm 事件。

Vuex 的 gettersmutations

  • getters:用于获取 Vuex 状态,类似于计算属性,可避免直接访问状态。
  • mutations:用于修改 Vuex 状态,是唯一可以修改状态的方式,通过 commit 方法触发。

二、Components 部分

Login 组件

代码语言:javascript
代码运行次数:0
复制
const LoginTemplate = `
<div class="wrapper login-wrapper" style="width: 539px;">
    <div class="newsletter">
        <div>
            <h2> <slot /> </h2>
            <p>(例如: admin)</p>
        </div>
        <form>
            <div class="c-input-group">
                <label for="newsletter" class="c-label sr-only"></label>
                <input v-model="name" type="text" class="c-input" id="newsletter" placeholder="请输入用户名">
            </div>
            <button @click="login" class="c-button">确认</button>
        </form>
    </div>
</div>
`;
Vue.component('Login', {
    name: 'Login',
    template: LoginTemplate,
    props: {},
    data() {
        return {
            name: '',
        };
    },
    watch: {},
    mounted() {},
    methods: {
        login(e) {
            this.$emit('confirm', this.name);
            e.preventDefault();
        },
    },
});
  • 模板 (LoginTemplate):定义了登录界面的 HTML 结构,包含一个输入框用于输入用户名和一个确认按钮。
  • 组件选项
    • data:定义了一个局部变量 name,用于存储用户输入的用户名。
    • methods:定义了 login 方法,当用户点击确认按钮时触发。该方法通过 $emit 触发一个自定义事件 confirm,并将用户输入的用户名作为参数传递出去,同时调用 e.preventDefault() 阻止表单的默认提交行为。

Panel 组件

代码语言:javascript
代码运行次数:0
复制
const PanelTemplate = `
<blockquote v-show="username" class="c-quote">
    <div class="c-quote__content">
        <p> <slot /> </p>
    </div>
    <cite class="c-quote__cite">
        <img src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoKCgoKCgsMDAsPEA4QDxYUExMUFiIYGhgaGCIzICUgICUgMy03LCksNy1RQDg4QFFeT0pPXnFlZXGPiI+7u/sBCgoKCgoKCwwMCw8QDhAPFhQTExQWIhgaGBoYIjMgJSAgJSAzLTcsKSw3LVFAODhAUV5PSk9ecWVlcY+Ij7u7+//CABEIACgAKAMBIgACEQEDEQH/xAAxAAACAgIDAAAAAAAAAAAAAAAABQIEAwYBBwgBAAMBAAAAAAAAAAAAAAAAAAECAwD/2gAMAwEAAhADEAAAAOubFVlZafO2E2sG4gPnWbh1IamzcVxlhnDpMQnskgQUwHP/xAArEAACAQMCAwYHAAAAAAAAAAABAgMABBEFIQYSMRMUMkFRkRAiQkNxgdH/2gAIAQEAAT8AWKkgJ8qu4rqCJ5kfCggYxnb1rR7p7m5W2l3Z/AcVHpzDqtJqcAXJiOfTNQappxKh2ZMjzX+VE9jLGw7WF1Zd1LDcHau52sWu2iGSPs7e07eWRsDLydPYEYqG0UgHb4KjP4aW2lZlT5AW82dVH7JO1a/drf6jJNEwaLlVU/CirbXNas41jgv5VRei5zVvo5m6yhai4Xt2XLXlPw9Zq/IJ5ifXkwvvT8Px/ROak0SRPuire7K0l8ceKjdsRXenCk8+1TXRK75Ff//EAB0RAAICAQUAAAAAAAAAAAAAAAABAgMTERIhQVH/2gAIAQIBAT8AyIdvJlHbFdmWJvrfhKKNEJI//8QAGBEAAwEBAAAAAAAAAAAAAAAAABESECD/2gAIAQMBAT8ARJOvj//Z" alt="">
        <div>
            <p><span>用户名:</span><strong id="username"> {{username}} </strong></p>
        </div>
    </cite>
</blockquote>
`;
Vue.component('Panel', {
    name: 'Panel',
    template: PanelTemplate,
    props: ['username'],
    data: {},
    watch: {},
    mounted() {},
    methods: {},
});
  • 模板 (PanelTemplate):定义了登录成功界面的 HTML 结构,包含一个引用块和用户头像、用户名信息。
  • 组件选项
    • props:接收一个 username 属性,用于显示登录用户的用户名。
    • v-show 指令:根据 username 是否存在来决定是否显示该组件。

三、 Vuex 状态管理

BaseModule

代码语言:javascript
代码运行次数:0
复制
const BaseModule = {
    state: () => ({
        welcome: '请输入用户名登录系统',
    }),
    getters: {
        welcome(state) {
            return state.welcome;
        },
    },
    mutations: {
        say(state, content) {
            state.welcome = content;
        },
    },
    actions: {},
};
  • state:定义了一个状态 welcome,初始值为 '请输入用户名登录系统'
  • getters:定义了一个 welcome getter,用于获取 welcome 状态的值。
  • mutations:定义了一个 say mutation,用于修改 welcome 状态的值。

UserModule

代码语言:javascript
代码运行次数:0
复制
const UserModule = {
    namespaced: true,
    state: () => ({
        username: '',
        token: null,
    }),
    getters: {
        username(state) {
            return state.username;
        },
        token(state) {
            return state.token;
        },
    },
    mutations: {
        login(state, { username, token }) {
            state.username = username;
            state.token = token;
        },
    },
};
  • namespaced:设置为 true,表示该模块使用命名空间,避免命名冲突。
  • state:定义了两个状态 usernametoken,初始值分别为 ''null
  • getters:定义了两个 getter,分别用于获取 usernametoken 状态的值。
  • mutations:定义了一个 login mutation,用于更新 usernametoken 状态的值。

存储实例创建

代码语言:javascript
代码运行次数:0
复制
const store = new Vuex.Store({
    modules: {
        base: BaseModule,
        user: UserModule,
    },
});
window.$store = store;
  • 创建一个 Vuex 存储实例 store,并将 BaseModuleUserModule 作为模块注册到存储中。
  • 将存储实例赋值给 window.$store,以便在全局范围内访问。

四、工作流程▶️

1. 页面初始化
  • Vuex 存储初始化
    • 代码中定义了 BaseModuleUserModule 两个 Vuex 模块,并创建了一个 Vuex 存储实例 store
    • BaseModule 存储了欢迎信息,初始状态下 welcome 的值为 '请输入用户名登录系统'
    • UserModule 存储了用户相关信息,包括 username(初始为空字符串)和 token(初始为 null),并且该模块开启了命名空间(namespaced: true)。
    • 最后将存储实例赋值给 window.$store,以便在全局范围内可以访问和操作这个存储实例。
代码语言:javascript
代码运行次数:0
复制
const BaseModule = {
    state: () => ({
        welcome: '请输入用户名登录系统'
    }),
    // ...
};
const UserModule = {
    namespaced: true,
    state: () => ({
        username: '',
        token: null
    }),
    // ...
};
const store = new Vuex.Store({
    modules: {
        base: BaseModule,
        user: UserModule
    }
});
window.$store = store;
  • Vue 组件注册
    • 注册了 LoginPanel 两个 Vue 组件。
    • Login 组件用于显示登录界面,包含一个输入框让用户输入用户名和一个确认按钮。
    • Panel 组件用于显示登录成功后的欢迎界面,接收 username 作为属性来显示登录用户的用户名。
代码语言:javascript
代码运行次数:0
复制
Vue.component('Login', {
    // ...
});
Vue.component('Panel', {
    // ...
});
2. 显示登录界面
  • 在 HTML 部分,通过 Vue 实例的 computed 属性获取 token 的值,根据 token 是否存在来决定显示哪个组件。
  • 由于初始状态下 tokennull,所以会显示 Login 组件,也就是登录界面。
代码语言:javascript
代码运行次数:0
复制
<div id="app">
    <div class="wrapper" style="width: 900px;">
        <!-- 登录成功后的欢迎界面 -->
        <Panel v-if="token" :username="username">
            {{welcome}}
        </Panel>
        <!-- 登录界面 -->
        <Login v-else @confirm="login">
            {{welcome}}
        </Login>
    </div>
</div>
3. 用户输入用户名并提交
  • Login 组件中,用户在输入框输入用户名,输入框使用 v-model 指令绑定到组件的 name 数据属性上,实现双向数据绑定。
  • 当用户点击确认按钮时,会触发 login 方法。
代码语言:javascript
代码运行次数:0
复制
const LoginTemplate = `
    <!-- ... -->
    <input v-model="name" type="text" class="c-input" id="newsletter" placeholder="请输入用户名">
    <!-- ... -->
    <button @click="login" class="c-button">确认</button>
    <!-- ... -->
`;
Vue.component('Login', {
    // ...
    data() {
        return {
            name: ''
        };
    },
    methods: {
        login(e) {
            this.$emit('confirm', this.name);
            e.preventDefault();
        }
    }
});
  • login 方法通过 $emit 触发一个自定义事件 confirm,并将用户输入的用户名作为参数传递出去,同时调用 e.preventDefault() 阻止表单的默认提交行为。
4. 处理登录事件
  • 在 Vue 实例中,监听 Login 组件的 confirm 事件,当事件触发时调用 login 方法。
  • login 方法中,首先检查用户名是否存在,如果存在则进行以下操作:
    • 通过 window.$store.commit 提交 user/login mutation 到 UserModule,更新 usernametoken 状态。这里模拟生成了一个固定的 token'sxgWKnLADfS8hUxbiMWyb'
    • 提交 base/say mutation 到 BaseModule,更新欢迎信息为 '登录成功,欢迎你回来!'
代码语言:javascript
代码运行次数:0
复制
var app = new Vue({
    // ...
    methods: {
        login(username) {
            if (username) {
                window.$store.commit('user/login', { username, token: 'sxgWKnLADfS8hUxbiMWyb' });
                window.$store.commit('base/say', '登录成功,欢迎你回来!');
            }
        }
    }
});
5. 显示登录成功界面
  • 由于 token 已经被更新为一个有效的值,根据 HTML 中 v-ifv-else 指令的判断,会隐藏 Login 组件,显示 Panel 组件。
  • Panel 组件接收 username 属性,显示登录用户的用户名,同时显示更新后的欢迎信息。
代码语言:javascript
代码运行次数:0
复制
<Panel v-if="token" :username="username">
    {{welcome}}
</Panel>

整个登录功能的工作流程是从页面初始化开始,用户在登录界面输入用户名并提交,触发登录事件,更新 Vuex 状态,最后根据状态的变化显示相应的界面。


测试结果👍

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-02-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景介绍
  • 准备步骤
  • 目标效果
  • 要求规定
  • 判分标准
  • 通关代码✔️
  • 代码解析📑
    • 一、HTML 部分
    • 二、Components 部分
    • 三、 Vuex 状态管理
    • 四、工作流程▶️
      • 1. 页面初始化
      • 2. 显示登录界面
      • 3. 用户输入用户名并提交
      • 4. 处理登录事件
      • 5. 显示登录成功界面
  • 测试结果👍
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档