当前位置: 首页 > news >正文

智能响应式网站建设南宁网站建设服务公司

智能响应式网站建设,南宁网站建设服务公司,建设网站有哪些,网页转app工具前文vuex 过于详细,现在还是应该用pinia 看一眼下图基本明白它的流程了吧 使用步骤: Pinia 使用步骤:以登录功能为例 Pinia 是 Vue.js 的新一代状态管理库,使用起来非常简单。下面我以 用户登录 功能为例,演示 Pini…

 前文vuex 过于详细,现在还是应该用pinia

看一眼下图基本明白它的流程了吧

使用步骤:

Pinia 使用步骤:以登录功能为例

Pinia 是 Vue.js 的新一代状态管理库,使用起来非常简单。下面我以 用户登录 功能为例,演示 Pinia 的基本使用步骤:

一、安装 Pinia

npm install pinia

二、创建并配置 Pinia 实例

// main.js
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'const pinia = createPinia()
const app = createApp(App)app.use(pinia)  // 注册 Pinia
app.mount('#app')

我们项目是这样创建的:

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import router from './router'
import ElementPlus from 'element-plus';
import 'element-plus/theme-chalk/index.css';
import App from './App.vue'
import Axios from 'axios'const app=createApp(App)
app.use(router)
app.use(createPinia())
app.use(ElementPlus)
app.mount('#app')

 

三、定义用户 Store(核心)

例子1:

// store/user.js
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'export const useUserStore = defineStore('user', () => {// 1. 状态:存储用户数据const user = ref(null)  // 用户信息const isLoggedIn = ref(false)  // 登录状态// 2. getters:计算属性(获取派生状态)const username = computed(() => user.value?.username || '')// 3. actions:修改状态的方法const login = async (credentials) => {try {// 模拟 API 请求const response = await fetch('/api/login', {method: 'POST',body: JSON.stringify(credentials)})const data = await response.json()// 更新状态user.value = data.userisLoggedIn.value = truereturn true  // 登录成功} catch (error) {console.error('登录失败:', error)return false}}const logout = () => {user.value = nullisLoggedIn.value = false}return {user,isLoggedIn,username,login,logout}
})

 

  1. Store 结构

    • state:用 ref 定义响应式数据(如 userisLoggedIn
    • getters:用 computed 定义计算属性(如 username
    • actions:定义修改状态的方法(如 loginlogout
  2. 响应式原理

    • 当 user 或 isLoggedIn 变化时,所有依赖它们的组件会自动更新。

Pinia 登录与登出逻辑

这段代码是 Pinia store 中处理用户认证的核心逻辑:

一、登录逻辑:login 方法

1. 整体功能

这是一个 异步方法,负责处理用户登录流程:

  • 发送登录请求到后端 API
  • 验证用户凭证
  • 保存用户信息和登录状态
  • 返回登录结果(成功 / 失败)
2. 参数与结构

const login = async (credentials) => { ... }

  • credentials:用户输入的凭证,通常是 { username, password } 对象
const login = async (credentials) => {try {// 1. 发送 POST 请求到登录 APIconst response = await fetch('/api/login', {method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify(credentials) // 将凭证转为 JSON 格式})// 2. 解析响应数据const data = await response.json()// 3. 更新状态user.value = data.user       // 保存用户信息(如 id, username, token)isLoggedIn.value = true      // 标记为已登录return true  // 返回成功标志} catch (error) {console.error('登录失败:', error)return false // 返回失败标志}
}
4. 关键细节
  1. API 请求

    • 使用 fetch 发送 POST 请求
    • 需设置 Content-Type: application/json 头
    • 用 JSON.stringify 将对象转为 JSON 字符串
  2. 错误处理

    • 使用 try/catch 捕获网络错误或解析错误
    • 可能的错误包括:网络超时、服务器错误、JSON 解析失败等
  3. 状态更新

    • user.value 存储完整用户信息(如 { id: 1, username: 'test', token: 'xxx' }
    • isLoggedIn.value 作为登录状态标志,方便其他组件快速判断

二、登出逻辑:logout 方法

1. 整体功能

清除用户信息和登录状态,实现用户退出登录。

2. 核心步骤

const logout = () => {user.value = null        // 清空用户信息isLoggedIn.value = false // 标记为未登录
}
3. 扩展应用

在实际项目中,可能还需要:

  • 清除本地存储中的 token
  • 调用后端的登出 API(如使 token 失效)
  • 跳转到登录页或首页

可以这样扩展:

const logout = async () => {try {// 调用后端登出 APIawait fetch('/api/logout', { method: 'POST' })} catch (error) {console.warn('后端登出失败,但继续清除前端状态', error)} finally {// 清除状态user.value = nullisLoggedIn.value = false// 清除本地存储localStorage.removeItem('auth_token')// 跳转到登录页(需引入路由)router.push('/login')}
}

三、这个设计的优势

  1. 职责分离

    • 登录逻辑集中在 store 中,组件只需调用 login() 方法,无需关心具体实现
  2. 响应式更新

    • 当 user 或 isLoggedIn 变化时,所有依赖它们的组件会自动更新
  3. 可测试性

    • 可以轻松模拟 API 响应,测试登录成功 / 失败的场景
  4. 扩展性

    • 可以方便地添加额外功能(如 token 刷新、登录状态持久化)

四、常见问题及解决方案

问题 1:登录成功后页面未更新

原因:可能忘记在组件中使用响应式数据
解决方案:确保在组件中正确引入 store:

const userStore = useUserStore()
const { isLoggedIn } = storeToRefs(userStore) // 使用 storeToRefs 保持响应式
问题 2:跨页面刷新后登录状态丢失

解决方案:添加持久化插件(如 pinia-plugin-persistedstate):

export const useUserStore = defineStore('user', {// ...原有代码
}, {persist: true // 自动持久化到 localStorage
})
问题 3:如何处理 token 过期?

解决方案:在请求拦截器中检测 token 状态,过期时自动刷新:

// 假设使用 axios
axios.interceptors.response.use(response => response,async error => {if (error.response.status === 401) { // token 过期const userStore = useUserStore()await userStore.refreshToken() // 刷新 tokenreturn axios.request(error.config) // 重试原请求}return Promise.reject(error)}
)

业务流程:

  1. 登录:验证凭证 → 保存用户信息 → 标记登录状态
  2. 登出:清除用户信息 → 标记未登录状态

我们遵循了 Pinia 的设计理念:将状态管理逻辑与组件分离,使代码更易维护和测试。

 这里,const user = ref(null) 在初始状态下没有用户数据,但这正是 Pinia/Vue 中管理异步数据的常见方式。

一、为什么初始值是 null

  1. 表示 “未加载” 状态
    在用户登录前或数据未从后端获取时,user 为空是合理的。此时组件可以显示 “加载中” 或 “请登录” 的提示。

  2. 避免空值错误
    使用 ref(null) 而非直接 null 是为了保持响应式。当数据加载完成后,修改 user.value 会触发所有依赖它的组件更新。

  3. 类型安全
    在 TypeScript 中,ref(null) 可以明确类型(如 ref<User | null>(null)),避免运行时类型错误。

二、数据何时被填充?

当用户登录成功后,login action 会更新 user 的值:

const login = async (credentials) => {try {const response = await fetch('/api/login')const data = await response.json()// 登录成功后,填充用户数据user.value = data.user  // <-- 这里更新了 userisLoggedIn.value = truereturn true} catch (error) {return false}
}

三、如何在组件中安全使用?

虽然初始值是 null,但可以通过 可选链操作符(?.) 或 计算属性 安全访问:

1. 直接使用可选链

<template><div v-if="userStore.user">欢迎,{{ userStore.user.username }}</div><div v-else>请先登录</div>
</template>

2. 使用计算属性提供默认值

const username = computed(() => user.value?.username || '未登录')// 在组件中使用
<p>{{ username }}</p>  // 永远不会报错,要么显示用户名,要么显示“未登录”

第二个例子:我们例子项目的定义如下:

import { defineStore } from 'pinia'
import { ref ,computed } from 'vue'
import { postReq } from '../utils/api'//用户仓库  提供数据、计算属性、方法
export const useUserStore=defineStore("user",()=>{//ref = state  //存放用户登录后的信息const userInfo=ref({id:"",token:"",isAuth:false,})const isLogin=ref(false)//computed() = getters//返回用户登录信息const getUserInfo = computed(()=>{console.log("getUserInfo:start")//pinia存储的用户信息和本地localStorageconsole.log(userInfo.value.isAuth);console.log(JSON.parse(localStorage.getItem("isAuth")));if(userInfo.value.isAuth==false&& JSON.parse(localStorage.getItem("isAuth")) ){console.log("getUserInfo:更新用户信息")setAuthenticated(JSON.parse(localStorage.getItem("user")))}console.log("getUserInfo:end")return userInfo;}) //function() = actions//设置登录状态,获取登录信息const setAuthenticated=(u)=>{console.log("setAuthenticated:start")userInfo.value=u;//同步localStorageconsole.log(u.useType)localStorage.setItem("user",JSON.stringify(u));localStorage.setItem("token",u.token);localStorage.setItem("isAuth",u.isAuth);console.log(`setAuthenticated:${userInfo.value.isAuth}`)console.log("setAuthenticated:end")}// const setLoginState(f)=>{// 	isLogin.value=f// }//刷新tokenconst refreshToken=()=>{// refreshTokenApi().then(response=>{// 	userStore.setAuthenticated({// 		token:response.data.access_token,// 		isAuth:true// 	})// })}//退出登录const logOut=()=>{console.log("logOut:start")userInfo.value.isAuth=falseuserInfo.value.token=''//LocalStorage:除非主动删除,否则会永久存储在浏览器中。localStorage.setItem("user",'');localStorage.setItem("token",'');localStorage.setItem("isAuth",false);//SessionStorage:只在当前所在窗口关闭前有效,窗口关闭后其存储数据也就会被自动清除。sessionStorage.clear()	console.log("logOut:end")}return {userInfo,getUserInfo,setAuthenticated,logOut}
})

 

这是一个基于 Pinia 的用户认证模块,包含了用户状态管理和认证流程。下面我将详细说明其中的 actions(即修改状态的方法):

一、核心 Action 功能解析

1. setAuthenticated(u)

作用:设置用户认证状态并同步到本地存储
参数u(包含用户信息的对象,如 { id, token, isAuth }

const setAuthenticated = (u) => {console.log("setAuthenticated:start")userInfo.value = u;  // 更新 Pinia 中的用户信息// 同步到 localStorage(持久化存储)localStorage.setItem("user", JSON.stringify(u));localStorage.setItem("token", u.token);localStorage.setItem("isAuth", u.isAuth);console.log(`setAuthenticated:${userInfo.value.isAuth}`)console.log("setAuthenticated:end")
}

关键逻辑

  • 将用户信息保存到 Pinia 状态
  • 同时保存到 localStorage,确保刷新页面后数据不丢失
  • 通常在登录成功后调用,例如:

    // 登录成功后
    const userData = { id: 1, token: 'xxx', isAuth: true }
    setAuthenticated(userData)
    
2. logOut()

作用:用户退出登录,清除认证状态和本地存储

const logOut = () => {console.log("logOut:start")// 清除 Pinia 中的用户认证状态userInfo.value.isAuth = falseuserInfo.value.token = ''// 清除 localStorage 中的数据localStorage.setItem("user", '');localStorage.setItem("token", '');localStorage.setItem("isAuth", false);// 清除 sessionStorage(通常用于临时数据)sessionStorage.clear()console.log("logOut:end")
}

关键逻辑

  • 将 isAuth 标记为 false,表示未登录
  • 清空 token 和用户信息
  • 清除 localStorage 和 sessionStorage 中的相关数据
  • 通常在用户点击 "退出登录" 按钮时调用
3. refreshToken()(未完成)

作用:刷新用户 token(用于保持会话,避免频繁登录)

const refreshToken = () => {// 未完成的实现// refreshTokenApi().then(response => {//   userStore.setAuthenticated({//     token: response.data.access_token,//     isAuth: true//   })// })
}

完整实现示例

const refreshToken = async () => {try {// 调用后端刷新 token 的 APIconst response = await postReq('/api/refresh-token', {token: userInfo.value.token // 发送当前 token})// 更新用户信息(主要是新的 token)setAuthenticated({...userInfo.value,token: response.data.token,isAuth: true})return true} catch (error) {console.error('刷新 token 失败:', error)// 刷新失败时可以跳转到登录页logOut()return false}
}

二、这些 Actions 的协作流程

1. 登录流程
  1. 组件调用登录 API(如 postReq('/login')
  2. 登录成功后,获取用户信息和 token
  3. 调用 setAuthenticated 保存用户信息和 token

// 组件中的登录逻辑示例
async handleLogin() {const response = await postReq('/login', this.formData)if (response.success) {setAuthenticated(response.data.user) // 保存用户信息router.push('/dashboard') // 跳转到主页}
}
2. 登出流程
  1. 组件调用 logOut() action
  2. 清除所有认证状态和存储数据
  3. 跳转到登录页

// 组件中的登出按钮
<button @click="logOut">退出登录</button>// 组件逻辑
import { useUserStore } from '@/store/user'setup() {const userStore = useUserStore()const logOut = () => {userStore.logOut()router.push('/login')}return { logOut }
}
3. 自动刷新 token

当 API 请求返回 "token 过期" 错误时,自动调用 refreshToken

// API 拦截器示例(通常在 axios 中设置)
axios.interceptors.response.use(response => response,async error => {if (error.response.status === 401) { // token 过期const userStore = useUserStore()const refreshed = await userStore.refreshToken()if (refreshed) {// 刷新成功后,重试原请求return axios(error.config)} else {// 刷新失败,跳转到登录页router.push('/login')}}return Promise.reject(error)}
)

三、代码优化

  1. 统一存储操作
    可以创建工具函数封装 localStorage 操作,避免重复代码:
// utils/storage.js
export const setStorage = (key, value) => {localStorage.setItem(key, JSON.stringify(value))
}export const getStorage = (key) => {return JSON.parse(localStorage.getItem(key))
}export const removeStorage = (key) => {localStorage.removeItem(key)
}

其他需要完善的地方:

  1. 完善 refreshToken 实现
    补充刷新 token 的具体逻辑,处理可能的错误。

  2. 添加类型定义(如果使用 TypeScript):
    为 userInfo 和相关方法添加类型,提高代码安全性。

  3. 错误处理
    在 setAuthenticated 和 logOut 中添加错误处理,确保操作安全。

流程:

  • 登录:通过 setAuthenticated 保存用户信息
  • 登出:通过 logOut 清除所有认证数据
  • token 管理:通过 refreshToken 保持会话

它们的设计遵循了 Pinia 的最佳实践:

  1. 将状态修改逻辑集中在 actions 中
  2. 通过响应式机制自动更新依赖组件
  3. 结合本地存储实现数据持久化

Pinia Getter :计算派生状态

例子代码中,getters 部分定义了一个计算属性 username,用于从用户状态中派生数据:

一、Getter 的本质:Vuex/Pinia 中的计算属性

在 Vuex/Pinia 中,getters 类似于 Vue 组件中的 computed 属性,主要用于:

  1. 简化复杂状态访问:避免在组件中重复编写复杂的状态获取逻辑
  2. 缓存计算结果:只有依赖的状态变化时才重新计算,提高性能
  3. 派生新状态:从现有状态计算出新的值(如过滤、转换格式等)

二、代码中的 Getter 分析

1. username 计算属性

const username = computed(() => user.value?.username || '')

作用

  • 安全地获取当前用户的用户名
  • 当用户未登录(user.value 为 null)时,返回空字符串 ''
  • 当用户登录后,自动返回 user.value.username 的值

关键点

  • 使用 可选链操作符(?.) 避免 user.value 为 null 时的错误
  • 使用 || '' 提供默认值,确保返回值类型始终为字符串
  • 依赖于 user 状态的变化,当 user 更新时自动重新计算

三、Getter 的使用场景

1. 在组件中直接使用

<template><div v-if="isLoggedIn">欢迎回来,{{ username }}!</div><div v-else>请先登录</div>
</template><script>
import { useUserStore } from '@/store/user'export default {setup() {const userStore = useUserStore()return {isLoggedIn: userStore.isLoggedIn,username: userStore.username  // 直接使用 getter}}
}
</script>
2. 在其他 Getter 中复用
// 在同一个 store 中定义另一个 getter
const welcomeMessage = computed(() => {if (isLoggedIn.value) {return `欢迎回来,${username.value}!`} else {return '请登录以继续'}
})

四、Getter 的优势

  1. 代码复用
    多个组件可以共享同一个 getter,避免重复编写相同的状态处理逻辑。

  2. 安全性
    通过可选链和默认值,避免在状态未初始化时出现错误。例如:

    // 错误:直接访问可能为 null 的属性
    console.log(user.value.username)  // 当 user 为 null 时会报错// 安全:通过 getter 访问
    console.log(username.value)  // 始终返回字符串('' 或实际用户名)
    
  3. 性能优化
    计算结果会被缓存,只有依赖的状态(user)变化时才会重新计算。

五、扩展:更多 Getter 示例

1. 复杂计算
// 计算用户全名(假设 user 有 firstName 和 lastName)
const fullName = computed(() => {return user.value ? `${user.value.firstName} ${user.value.lastName}` : '未登录用户'
})
2. 过滤列表
// 假设 store 中有一个 todos 数组
const completedTodos = computed(() => {return todos.value.filter(todo => todo.completed)
})

3. 带参数的 Getter

// 通过 ID 获取用户(返回一个函数)
const getUserById = computed(() => {return (id) => users.value.find(user => user.id === id)
})// 使用方式
const user = getUserById.value(123)

例子2中getter的使用:

getUserInfo 是唯一的 getter,它的设计很特别:不仅返回用户信息,还会在必要时从本地存储恢复状态。这是一个处理状态持久化的典型实现。

一、getUserInfo 的核心功能

const getUserInfo = computed(() => {console.log("getUserInfo:start")// 检查 Pinia 中的状态与 localStorage 是否不一致console.log(userInfo.value.isAuth);console.log(JSON.parse(localStorage.getItem("isAuth")));// 如果 Pinia 中未认证,但 localStorage 显示已认证if (userInfo.value.isAuth == false && JSON.parse(localStorage.getItem("isAuth"))) {console.log("getUserInfo:更新用户信息")setAuthenticated(JSON.parse(localStorage.getItem("user")))}console.log("getUserInfo:end")return userInfo;  // 返回整个 userInfo 对象
})

核心逻辑

  1. 状态同步检查
    比较 userInfo.isAuth(Pinia 中的状态)和 localStorage.isAuth(本地存储的状态)。

  2. 自动恢复状态
    如果发现 Pinia 中的状态丢失(如刷新页面后),但本地存储中仍有用户信息,则自动调用 setAuthenticated 恢复状态。

  3. 返回完整用户信息
    无论是否需要恢复,最终都返回最新的 userInfo 对象。

二、为什么需要这样设计?

1. 解决页面刷新后状态丢失的问题

Vuex/Pinia 的状态默认存储在内存中,页面刷新后会重置。而 localStorage 可以持久化保存数据。
这个 getter 的设计确保了:

  • 用户刷新页面后,首次访问 getUserInfo 时会自动恢复之前的登录状态
  • 组件可以始终获取到最新的用户信息,无需手动处理状态恢复
2. 保持状态一致性

通过在 getter 中添加同步逻辑,确保:

  • 无论何时访问 getUserInfo,得到的都是最新且一致的状态
  • 避免了在每个组件中重复编写状态恢复逻辑,实现了逻辑复用

三、潜在问题与优化建议

1. 性能问题

每次访问 getUserInfo 都会读取 localStorage,可能影响性能。
优化方案
可以添加一个标志位,只在初始化时检查一次:

const isInitialized = ref(false)const getUserInfo = computed(() => {if (!isInitialized.value) {const localAuth = JSON.parse(localStorage.getItem("isAuth"))if (!userInfo.value.isAuth && localAuth) {setAuthenticated(JSON.parse(localStorage.getItem("user")))}isInitialized.value = true}return userInfo
})
2. 类型安全问题

直接从 localStorage 解析的数据可能不符合预期格式。
优化方案
添加类型检查和默认值:

const storedUser = JSON.parse(localStorage.getItem("user") || "{}")
setAuthenticated({id: storedUser.id || "",token: storedUser.token || "",isAuth: storedUser.isAuth || false
})
3. 代码冗余问题

当前设计中,isLogin 状态与 userInfo.isAuth 重复。

这种在 getter 中添加副作用(如状态恢复)的做法并不常见,但在处理持久化状态时是一种有效的模式。如果使用 pinia-plugin-persistedstate 插件,这些逻辑可以被自动处理,代码会更简洁。

四、在组件中使用 Store

1. 登录表单组件
<!-- LoginForm.vue -->
<template><div><h2>登录</h2><input v-model="form.username" placeholder="用户名" /><input v-model="form.password" type="password" placeholder="密码" /><button @click="handleLogin">登录</button></div>
</template><script>
import { useUserStore } from '@/store/user'
import { ref } from 'vue'export default {setup() {const userStore = useUserStore()const form = ref({username: '',password: ''})const handleLogin = async () => {const success = await userStore.login(form.value)if (success) {console.log('登录成功')// 跳转到首页或其他操作} else {console.log('登录失败')}}return {form,handleLogin}}
}
</script>
2. 导航栏组件(显示登录状态)
<!-- Navbar.vue -->
<template><nav><div v-if="userStore.isLoggedIn">欢迎,{{ userStore.username }}<button @click="userStore.logout">退出</button></div><div v-else><button @click="goToLogin">登录</button></div></nav>
</template><script>
import { useUserStore } from '@/store/user'export default {setup() {const userStore = useUserStore()const goToLogin = () => {// 跳转到登录页}return {userStore,goToLogin}}
}
</script>

使用方式:

    • 通过 useUserStore() 获取 store 实例
    • 直接调用 actions 修改状态
    • 通过 store 属性获取状态或计算属性

六、扩展:添加持久化优化

如果需要在页面刷新后保留登录状态,可以添加 pinia-plugin-persistedstate

npm install pinia-plugin-persistedstate

修改 store/user.js

export const useUserStore = defineStore('user', () => {// ... 原有代码}, {// 启用持久化persist: {key: 'user-store',storage: localStorage,}
})

总结

Pinia 的使用非常直观:

  1. 定义 Store:用 defineStore 创建数据仓库
  2. 添加状态:用 ref 定义数据
  3. 添加计算属性:用 computed 定义派生数据
  4. 添加方法:用普通函数定义修改状态的逻辑
  5. 在组件中使用:通过 useStore 获取实例并调用属性和方法

相比 Vuex,Pinia 代码更简洁,类型支持更好,是 Vue 3 项目的首选状态管理方案。

下图从特定角度对比vuex 与pinia:

http://www.dinnco.com/news/63772.html

相关文章:

  • 搬家seo的方法
  • 网站的demo怎么做怎样才能被百度秒收录
  • 罗湖实惠的网站建设费用域名搜索引擎入口
  • wordpress广告位插件哪个好上海有哪些优化网站推广公司
  • 简单的网站开发百度点击快速排名
  • 做短视频的网站收益中国营销策划第一人
  • 网页设计期末作品新颖选题荥阳网站优化公司
  • 河北招投标信息服务平台高级seo招聘
  • 网站建设可以资本化吗今日头条搜索优化怎么做
  • 游戏推广怎么做引流佛山百度网站排名优化
  • 深圳西乡固戍招聘信息seo静态页源码
  • 开服表网站开发杭州关键词优化外包
  • wordpress 替换图片函数广告网站建设网站排名优化
  • 代做毕业设计找哪个网站太原seo代理商
  • 网站开发如何软文范例300字
  • 微信微网站是什么格式的重庆二级站seo整站优化排名
  • 大学生做的美食网站注册网站的免费网址
  • 淘宝类网站开发成年培训班有哪些
  • 大理悦花轩客栈在哪些网站做推广有没有免费推广平台
  • 企业网站制作深圳旺道seo软件技术
  • 东莞做网站优化简述网站建设的一般流程
  • wordpress 游戏网页淄博seo
  • 哈尔滨高端网站建设毕业设计网站
  • wordpress教程 数据库网站排名优化公司哪家好
  • 三河网站建设线上培训机构排名前十
  • 种子搜索网站怎么做的产品推广方式都有哪些
  • php做网站后台教程官方百度app下载
  • .net开发的网站 能做成app吗百度搜索关键词指数
  • 郑州做网站的专业公司优化防控措施
  • 网站建设jiq公司注册