day04 vue学习

将登录系统和 To-Do List 系统结合在一起,我们可以创建一个简单的 Vue 应用,该应用具备用户登录功能,并在用户登录后展示其个人 To-Do List。用户可以添加、删除、标记任务完成状态等。我们可以使用 Pinia 来管理用户登录状态和 To-Do 列表数据。

这个应用整体分为几大模块:

  • 主文件 (App.vuemain.js)
  • 路由管理 (router/index.js)
  • 状态管理 (stores/userStore.js)
  • 页面组件 (Login.vueTodoList.vue)

1. 设置项目和安装 Pinia

在有管理员权限下的终端创建项目并测试

复制代码
npm create vite@latest day4 -- -- template vue

npm install

npm install element-plus

npm run dev

在项目目录里运行下面的命令安装 Pinia和Vue Router:

javascript 复制代码
npm install pinia
npm install pinia vue-router

2. 文件结构

假设项目结构如下:

javascript 复制代码
src
├── App.vue
├── main.js
├── router
│   └── index.js         // 配置 Vue Router
├── stores
│   └── userStore.js     // Pinia 状态管理
└── views
    ├── Login.vue        // 登录界面
    └── TodoList.vue     // To-Do List 界面

3. 主文件 main.jsApp.vue

main.js:应用启动的核心

main.js 文件是应用的入口,负责启动整个 Vue 应用并将其挂载到页面上。

javascript 复制代码
// src/main.js
import { createApp } from 'vue';
import App from './App.vue';
import { createPinia } from 'pinia';
import router from './router';

// 创建应用实例,并配置应用的核心插件
const app = createApp(App);
app.use(createPinia());  // 安装 Pinia,用于管理全局状态
app.use(router);         // 安装路由,用于页面跳转

app.mount('#app');       // 将应用挂载到页面上
  • createApp(App):创建一个 Vue 应用实例,准备将应用展示在网页上。
  • app.use(createPinia()):安装 Pinia,用于全局管理数据。
  • app.use(router):安装路由,用于页面跳转。
  • app.mount('#app') :把应用挂载到页面上,通过 HTML 中的 id="app" 来渲染整个应用。
App.vue:页面的主要框架

App.vue 是应用的根组件,它负责展示页面内容。

javascript 复制代码
<!-- src/App.vue -->
<template>
  <div id="app">
    <router-view />  <!-- 在此处展示不同页面内容 -->
  </div>
</template>

<script setup>
// 不需要添加任何逻辑,因为这里只是一个展示页面内容的容器
</script>

<style>
/* 添加基础样式 */
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

h1, h2 {
  font-weight: normal;
  color: #4caf50;
}
</style>

<router-view /> :这是路由的占位符。根据用户访问的网址,Vue Router 会决定显示 Login.vue 还是 TodoList.vue,这让应用可以在不同页面之间切换。

4.路由管理 router/index.js

router/index.js 用于设置页面之间的导航。比如用户在登录页面登录后,可以跳转到待办事项页面。

javascript 复制代码
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import Login from '../views/Login.vue';
import TodoList from '../views/TodoList.vue';

const routes = [
  { path: '/', name: 'Login', component: Login },
  { path: '/todolist', name: 'TodoList', component: TodoList },
];

const router = createRouter({
  history: createWebHistory(),
  routes,
});

export default router;
  • routes :定义了应用中的路径与组件的对应关系。/ 表示首页路径,加载 Login.vue/todolist 加载 TodoList.vue
  • createRouter:创建一个路由实例,用于管理页面间的导航。
  • export default router :将路由实例导出,供 main.js 引入和使用。

问题:

javascript 复制代码
const router = createRouter({
  history: createWebHistory(),
  routes,
});

这个是什么用法,.createWebHistory是什么?

createRouter 是 Vue Router 4.x 中的一个函数,用于创建路由实例,用来管理 Vue 应用中的页面导航。而 createWebHistory 是一种路由模式,决定了应用的 URL 是如何被管理的。

解释 createRoutercreateWebHistory

  1. createRouter:这是 Vue Router 提供的一个方法,用于创建路由器实例。创建的路由器实例能帮助应用在不同页面间导航,比如在登录页面和待办事项页面之间切换。

  2. createWebHistory :这是 Vue Router 提供的三种路由模式之一,它决定了 URL 的管理方式。createWebHistory 使用浏览器内置的 History API ,URL 变得更"干净"、更现代,不包含 # 符号。

    • 示例 URL (Web History):https://example.com/todolist
    • 与其他模式对比
      • createWebHashHistory:URL 中会带有 # 符号(哈希模式),像 https://example.com/#/todolist。这种方式适用于无需后端支持的单页面应用。
      • createMemoryHistory:所有导航都在内存中进行,常用于服务器渲染或一些测试环境。

5.状态管理 stores/userStore.js

userStore.js 负责管理登录状态和用户的待办事项。它通过 Pinia 提供了统一的数据存储。

javascript 复制代码
// src/stores/userStore.js
import { defineStore } from 'pinia';

export const useUserStore = defineStore('user', {
  state: () => ({
    name: '',
    isLoggedIn: false,
    todos: [],
  }),
  actions: {
    login(userName) {
      this.name = userName;
      this.isLoggedIn = true;
    },
    logout() {
      this.name = '';
      this.isLoggedIn = false;
    },
    addTodo(task) {
      this.todos.push({ task, done: false });
    },
    toggleTodo(index) {
      this.todos[index].done = !this.todos[index].done;
    },
    deleteTodo(index) {
      this.todos.splice(index, 1);
    },
  },
});
  • state :用来存储用户状态的数据。
    • name:记录用户名。
    • isLoggedIn:记录用户是否登录。
    • todos:一个待办事项数组,每个事项包含 task(任务名称)和 done(是否完成)。
  • actions :定义了更新状态的方法。
    • login:接受用户名参数,将用户登录。
    • logout:将用户登出,清空用户名和登录状态。
    • addTodo:添加新的待办事项。
    • toggleTodo:切换任务的完成状态。
    • deleteTodo:删除待办事项。

问题:

javascript 复制代码
export const useUserStore = defineStore('user', {
  state: () => ({
    name: '',
    isLoggedIn: false,
    todos: [],
  }),
  actions: {
    login(userName) {
      this.name = userName;
      this.isLoggedIn = true;
    },
    logout() {
      this.name = '';
      this.isLoggedIn = false;
    },
    addTodo(task) {
      this.todos.push({ task, done: false });
    },
    toggleTodo(index) {
      this.todos[index].done = !this.todos[index].done;
    },
    deleteTodo(index) {
      this.todos.splice(index, 1);
    },
  },
});

这个我不理解,我几乎没学过java,但我学过c和python,你帮我类比一下,解释一下每一行的作用,帮助我触类旁通

逐行解释和类比

  1. export const useUserStore = defineStore('user', {...});

    • 作用:创建并导出一个"数据仓库"函数,用于管理用户的登录信息和待办事项。
    • 类比
      • Python :类似于定义一个类,比如 class UserStore
      • C语言:可以类比成创建一个带函数指针的结构体,用于集中管理信息和行为。
  2. state: () => ({...})

    • 作用state 是一个函数,返回一个对象用于存储数据。这里的数据是 nameisLoggedIntodos
    • 类比
      • Pythonstate 相当于类中的实例属性。
      • C语言:可以理解为结构体的成员变量,用于存储用户状态信息。
  3. name: ''

    • 作用:用户的名字,初始为空。
    • 类比
      • Python/C :相当于一个字符串变量 name = ""
  4. isLoggedIn: false

    • 作用 :用户是否已登录,初始值为 false
    • 类比
      • Python/C :一个布尔变量 isLoggedIn = False;isLoggedIn = false;
  5. todos: []

    • 作用:待办事项列表,初始为空数组。
    • 类比
      • Pythontodos = [],即一个空列表。
      • C语言:可以想象成动态分配的指针数组。

actions 部分

actions 包含对数据执行操作的方法,类似于类中的方法或 C 中的函数指针。它们可以直接修改 state 中的数据。

login(userName)

  • 作用 :将 name 更新为 userName,并设置 isLoggedIntrue
  • 类比
    • Pythondef login(self, userName): self.name = userName; self.isLoggedIn = True
    • C语言 :类似于更新结构体成员的函数 void login(UserStore* store, char* userName)

logout()

  • 作用 :清空 name 并设置 isLoggedInfalse
  • 类比
    • Pythondef logout(self): self.name = ""; self.isLoggedIn = False
    • C语言 :更新 UserStore 成员变量的值。

addTodo(task)

  • 作用 :添加一个新的待办事项,task 是待办内容,默认为未完成。
  • 类比
    • Pythonself.todos.append({"task": task, "done": False})
    • C语言:可以想象成向结构体的指针数组添加新的字符串。

toggleTodo(index)

  • 作用:切换指定任务的完成状态。
  • 类比
    • Pythonself.todos[index]["done"] = not self.todos[index]["done"]
    • C语言:可以想象成通过索引修改数组成员的布尔值。

deleteTodo(index)

  • 作用:根据索引删除待办事项。
  • 类比
    • Pythonself.todos.pop(index)
    • C语言:手动管理数组的内存,移除指定项。

6.页面组件 Login.vueTodoList.vue

Login.vue:用户登录界面

登录页面让用户输入用户名并点击"登录"按钮,完成登录后跳转到 TodoList.vue

javascript 复制代码
<!-- src/views/Login.vue -->
<template>
  <div class="login-container">
    <h1>Welcome to the App</h1>
    <input v-model="userName" placeholder="Enter your name" />
    <button @click="handleLogin">Login</button>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { useUserStore } from '../stores/userStore';
import { useRouter } from 'vue-router';

const userStore = useUserStore();
const router = useRouter();
const userName = ref('');

const handleLogin = () => {
  if (userName.value.trim()) {
    userStore.login(userName.value.trim());
    router.push({ name: 'TodoList' });
  }
};
</script>

<style scoped>
/* 样式:布局居中、按钮美化 */
</style>
  • v-model="userName" :使用 v-model 双向绑定让输入框和 userName 变量同步。
  • handleLogin :当点击"登录"按钮时,检查 userName 是否为空,如果有值,则调用 userStore.login(userName) 将用户登录,并跳转到 TodoList 页面。
TodoList.vue:待办事项界面

TodoList.vue 页面展示用户的待办事项列表,并支持添加、删除和标记完成。

javascript 复制代码
<template>
  <div class="todo-container">
    <h2>{{ userStore.name }}'s To-Do List</h2>
    <button @click="handleLogout" class="logout-btn">Logout</button>
    
    <div class="input-container">
      <input v-model="newTask" placeholder="Add a new task" @keyup.enter="addTask" />
      <button @click="addTask">Add</button>
    </div>
    
    <ul class="ul-container">
      <li v-for="(todo, index) in userStore.todos" :key="index" class="todo-item">
        <input type="checkbox" v-model="todo.done" class="checkboxs"/>
        <span :class="{ done: todo.done }">{{ todo.task }}</span>
        <button @click="removeTask(index)" class="delete-btn">Delete</button>
      </li>
    </ul>
    
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { useUserStore } from '../stores/userStore';
import { useRouter } from 'vue-router';

const userStore = useUserStore();
const router = useRouter();
const newTask = ref('');

const addTask = () => {
  if (newTask.value.trim()) {
    userStore.addTodo(newTask.value.trim());
    newTask.value = '';
  }
};

const removeTask = (index) => {
  userStore.deleteTodo(index);
};

const handleLogout = () => {
  userStore.logout();
  router.push({ name: 'Login' });
};
</script>

<style scoped>
.todo-container {
  width: 80%;
  max-width: 500px;
  margin: auto;
  text-align: center;
  margin-top: 50px;
}

.input-container {
  display: flex;
  justify-content: center;
  margin-bottom: 20px;
}

input {
  padding: 10px;
  width: 80%;
  border: 1px solid #ccc;
  border-radius: 5px;
  margin-right: 5px;
}

button {
  padding: 10px;
  background-color: #4caf50;
  color: white;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}

.logout-btn {
  background-color: #f44336;
  margin-bottom: 20px;
}

.ul-container {
  list-style: none;
  padding: 0;
  margin: 0 auto;         /* 将列表容器居中 */
  text-align: center;     /* 居中对齐文本 */
  width: 80%;             /* 设置宽度,例如 80% */
  max-width: 600px;       /* 最大宽度 */
  height: 400px;          /* 设置高度 */
  overflow-y: auto;       /* 允许垂直滚动(如果高度超出) */
  border: 1px solid #c4f1ec; /* 可选:添加边框,方便查看宽高 */
  background-color: #cdf3d4; /* 可选:背景颜色 */
}

.checkboxs{
  width: 80%;             /* 设置宽度,例如 80% */
  max-width: 20px;       /* 最大宽度 */

}



.todo-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 10px 0;
}

.todo-item input[type="checkbox"] {
  margin-right: 10px;
}

.done {
  text-decoration: line-through;
}

.delete-btn {
  background-color: #f44336;
  color: white;
  border: none;
  padding: 5px 10px;
  border-radius: 5px;
  cursor: pointer;
}
</style>
  • addTask:用来添加新任务。
  • removeTask:用来删除特定的任务。
  • handleLogout:登出后返回登录页面。

问题:

javascript 复制代码
    <div class="input-container">
      <input v-model="newTask" placeholder="Add a new task" @keyup.enter="addTask" />
      <button @click="addTask">Add</button>
    </div>

keyup.enter是什么?

  • @keyup.enter="addTask"
    • @keyup 监听 keyup 事件,即当用户松开一个键时触发。
    • .enter 是修饰符,仅在用户松开 Enter 键时触发事件。
    • addTask 是调用的方法名,在用户按下 Enter 键后,调用 addTask 方法。

作用

用户在输入框中输入任务内容时,按下 Enter 键 会自动调用 addTask 方法,添加任务到待办列表,而无需点击"Add"按钮。

javascript 复制代码
    <ul>
      <li v-for="(todo, index) in userStore.todos" :key="index" class="todo-item">
        <input type="checkbox" v-model="todo.done" />
        <span :class="{ done: todo.done }">{{ todo.task }}</span>
        <button @click="removeTask(index)" class="delete-btn">Delete</button>
      </li>
    </ul>

这里面每一行是什么意思?

<ul> ... </ul>

  • 作用 :创建一个无序列表,用于显示多个待办事项(<ul> 是 HTML 的标签表示无序列表)。
  • 渲染内容 :列表项将放在 <ul> 标签内显示。

<li v-for="(todo, index) in userStore.todos" :key="index" class="todo-item">

  • v-for="(todo, index) in userStore.todos" :Vue 指令,用于遍历 userStore.todos 数组。todo 是当前循环的待办项,每个待办项有 taskdone 属性,index 是当前项目的索引。
  • :key="index":每个列表项的唯一标识,有助于 Vue 更高效地跟踪和更新每一项。
  • class="todo-item" :添加一个 CSS 类名 todo-item,方便样式控制。

<input type="checkbox" v-model="todo.done" />

  • 作用:复选框,用于显示和更新每个待办事项的完成状态。
  • v-model="todo.done" :双向绑定,将待办事项的 done 状态绑定到复选框。勾选或取消勾选复选框时,todo.done 的值会自动更新。

<span :class="{ done: todo.done }">{``{ todo.task }}</span>

  • {``{ todo.task }}:显示待办事项的任务内容(文本)。
  • :class="{ done: todo.done }" :动态绑定类名。若 todo.donetrue,则 span 元素将会有 done 类,可以用 CSS 设置完成任务的样式,比如显示删除线。

<button @click="removeTask(index)" class="delete-btn">Delete</button>

  • 作用:删除按钮,每次点击删除当前待办项。
  • @click="removeTask(index)" :Vue 指令,绑定 click 事件,点击时调用 removeTask 方法并传入 index,从 userStore.todos 中移除指定的待办项。
  • class="delete-btn" :CSS 类名 delete-btn,用于样式设置,比如调整按钮的外观。

7.项目效果

  • 登录页面:用户可以在此输入用户名并点击登录。登录后会自动跳转到 To-Do List 页面。
  • To-Do List 页面:用户可以添加任务、标记完成状态、删除任务,并包含"退出登录"按钮。点击"退出登录"会返回到登录页面。

第五天任务:学习 Vue 3 中的路由管理(Vue Router),实现不同页面间的切换与用户权限管理。

相关推荐
森叶20 分钟前
Electron 主进程中使用Worker来创建不同间隔的定时器实现过程
前端·javascript·electron
jz_ddk26 分钟前
[学习] RTKLib详解:rtcm2.c、rtcm3.c、rtcm3e与rtcmn.c
c语言·学习·算法
霸王蟹29 分钟前
React 19 中的useRef得到了进一步加强。
前端·javascript·笔记·学习·react.js·ts
霸王蟹29 分钟前
React 19版本refs也支持清理函数了。
前端·javascript·笔记·react.js·前端框架·ts
繁依Fanyi34 分钟前
ColorAid —— 一个面向设计师的色盲模拟工具开发记
开发语言·前端·vue.js·编辑器·codebuddy首席试玩官
codelxy37 分钟前
vue引用cesium,解决“Not allowed to load local resource”报错
javascript·vue.js
Generalzy1 小时前
学习!FastAPI
学习·sqlite·fastapi
ha20428941941 小时前
c++学习之--- list
c语言·c++·学习·list
程序猿阿伟2 小时前
《社交应用动态表情:RN与Flutter实战解码》
javascript·flutter·react native
N_NAN_N2 小时前
程序设计语言----软考中级软件设计师(自用学习笔记)
笔记·学习