使用Vue 3.2.37和Pinia 2.0.14构建的教程
其他版本可用。
本教程展示了如何使用Vue 3和Pinia构建一个使用Basic HTTP认证的简单登录应用。
Vue 3 + Pinia应用实例
这个例子的应用相当简约,只包含2个页面来演示Vue 3和Pinia的基本认证。
/login- 带有用户名和密码字段的公共登录页面,提交时页面会向API发送一个POST请求,以验证用户的证书。/- 安全主页,显示从安全API端点获取的用户列表,使用认证用户的基本认证凭证,基本认证凭证由Base64编码的 和 ,用一个冒号隔开 。usernamepassword:
Pinia状态管理
Pinia是由Vuejs核心团队建立的一个新的状态管理库,它简化了全局状态管理,它是Vuex的继承者,需要的代码比Vuex少很多,是Vue 3的推荐状态管理库。
状态和业务逻辑在Pinia中使用商店来定义,每个商店可以包含状态、获取器和动作。状态定义了商店管理的数据,获取器返回一个从状态和/或其他获取器派生(计算)的值,而行动是用来执行业务逻辑或异步操作的方法,如API调用。它们相当于传统(选项API)Vue组件中的data,computed 和methods 。
你可以定义任意多的Pinia商店,它们可以在整个Vue应用程序中全局访问。关于Pinea的更多信息请看pinia.vuejs.org/core-concep…
Vue组合API
例子中的组件是用Vue 3附带的新的VueComposition API构建的,组件的逻辑位于一个
Hi {{authUser?.firstName}}!
You're logged in with Vue 3 + Pinia & Basic HTTP Authentication!!
Users from secure api end point:
{{user.firstName}} {{user.lastName}}
Error loading users: {{users.error}}
Vue 3 LoginView组件
路径。/src/views/LoginView.vue
登录视图包含一个用VeeValidate库构建的表单,其中包含用户名和密码字段,用于登录到Vue 3 + Pinia应用程序。
表单验证规则是由VeeValidate支持的Yup模式验证库定义的,关于Yup的更多信息请看github.com/jquense/yup…
onSubmit() 方法通过调用authStore.login() ,将用户凭证发布到API。认证成功后,用户auth ,通过login() 动作方法存储在Pinia全局状态中,并将用户重定向到主页。
Vue组件模板包含带有输入字段和验证信息的表单。表单和字段是用VeeValidate构建的。
和 ,这些组件根据字段的名称自动钩住验证规则(schema)。
当表单被提交且有效时,表单会调用onSubmit() 方法。验证规则通过validation-schema 道具绑定到表单上,验证错误通过范围内的槽v-slot="{ errors }" ,提供给表单模板。关于用Vue 3和VeeValidate进行表单验证的更多信息,请看Vue 3 + VeeValidate - 表单验证实例(Composition API)。
<script setup>
import { Form, Field } from 'vee-validate';
import * as Yup from 'yup';
import { useAuthStore } from '@/stores';
const schema = Yup.object().shape({
username: Yup.string().required('Username is required'),
password: Yup.string().required('Password is required')
});
function onSubmit(values, { setErrors }) {
const authStore = useAuthStore();
const { username, password } = values;
return authStore.login(username, password)
.catch(error => setErrors({ apiError: error }));
}
</script>
<template>
<div>
<div class="alert alert-info">
Username: test<br />
Password: test
</div>
<h2>Login</h2>
<Form @submit="onSubmit" :validation-schema="schema" v-slot="{ errors, isSubmitting }">
<div class="form-group">
<label>Username</label>
<Field name="username" type="text" class="form-control" :class="{ 'is-invalid': errors.username }" />
<div class="invalid-feedback">{{errors.username}}</div>
</div>
<div class="form-group">
<label>Password</label>
<Field name="password" type="password" class="form-control" :class="{ 'is-invalid': errors.password }" />
<div class="invalid-feedback">{{errors.password}}</div>
</div>
<div class="form-group">
<button class="btn btn-primary" :disabled="isSubmitting">
<span v-show="isSubmitting" class="spinner-border spinner-border-sm mr-1"></span>
Login
</button>
</div>
<div v-if="errors.apiError" class="alert alert-danger mt-3 mb-0">{{errors.apiError}}</div>
</Form>
</div>
</template>
Vue 3应用程序组件
App 组件是Vue 3 + Pinia应用实例的根组件,它包含只为认证用户显示的主导航栏,以及一个用于根据当前路线/路径显示每个视图内容的RouterView 组件。
Piniaauth store的user 状态属性被用来在用户登录/退出应用程序时反应性地显示/隐藏主导航栏。
authStore.logout() 方法被主导航栏中的logout链接调用,以注销用户并重定向到登录页面。
<script setup>
import { RouterLink, RouterView } from 'vue-router';
import { useAuthStore } from '@/stores';
const authStore = useAuthStore();
</script>
<template>
<div class="app-container bg-light">
<nav v-show="authStore.user" class="navbar navbar-expand navbar-dark bg-dark">
<div class="navbar-nav">
<RouterLink to="/" class="nav-item nav-link">Home</RouterLink>
<a @click="authStore.logout()" class="nav-item nav-link">Logout</a>
</div>
</nav>
<div class="container pt-4 pb-4">
<RouterView />
</div>
</div>
</template>
<style>
@import '@/assets/base.css';
</style>
Vue 3 Main.js
main.js文件通过在主索引html文件中定义的#app div元素中安装App 组件来引导Vue应用程序。
在启动Vue应用程序之前,它导入并启用假后台api。要禁用假后台,只需删除注释// setup fake backend 下面的2行。
Pinia支持被添加到Vue应用程序中,行数为app.use(createPinia()) 。
Vue路由是通过调用app.use(router) 来配置的,路由是在router.js中定义的。
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import App from './App.vue';
import { router } from './helpers';
// setup fake backend
import { fakeBackend } from './helpers';
fakeBackend();
const app = createApp(App);
app.use(createPinia());
app.use(router);
app.mount('#app');
dotenv
dotenv文件包含了Vue应用实例中使用的环境变量,API URL被用于auth store和users store中,以向API发送HTTP请求。
在dotenv文件中设置的以VITE_ 为前缀的环境变量,在Vue应用程序中可以通过import.meta.env. (例如:import.meta.env.VITE_API_URL )访问。关于在用Vite构建的Vue应用程序中使用环境变量的更多信息,请参见vitejs.dev/guide/env-a…
VITE_API_URL=http://localhost:4000
主索引Html文件
主index.html文件是由浏览器加载的初始页面,它启动了一切。Vite开发服务器通过命令npm run dev ,在开发模式下运行该应用程序。
Vite没有像传统的前端构建工具那样捆绑javascript模块,而是利用了现代浏览器的原生ES模块支持,并增加了热模块替换等额外功能来支持开发。关于Vite开发服务器功能的更多信息,见vitejs.dev/guide/featu…
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vue 3 + Pinia - Basic HTTP Authentication Example</title>
<!-- bootstrap css -->
<link href="//netdna.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
Package.json
package.json文件包含项目配置信息,包括运行npm install 时安装的软件包依赖项,以及运行npm run dev 或npm run build 时执行的脚本等。完整的文档可在docs.npmjs.com/files/packa…
{
"name": "vue-3-pinia-basic-authentication-example",
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview --port 5050",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore"
},
"dependencies": {
"pinia": "^2.0.13",
"vee-validate": "^4.5.11",
"vue": "^3.2.37",
"vue-router": "^4.0.16",
"yup": "^0.32.11"
},
"devDependencies": {
"@vitejs/plugin-vue": "^2.3.3",
"eslint": "^8.18.0",
"eslint-plugin-vue": "^8.2.0",
"vite": "^2.9.13"
}
}
Vite.js配置
Vite的配置,Vue项目使用create-vue命令创建的官方前端构建工具和开发服务器。 npm init [[email protected]](https://jasonwatmore.com/cdn-cgi/l/email-protection).
插件@vitejs/plugin-vue 提供对Vue 3单文件组件(SFC)的支持。
别名'@' 使导入语句以at符号为前缀 (@) 相对于项目的/src 文件夹。
关于Vite配置选项的更多信息,见vitejs.dev/config/。
import { fileURLToPath, URL } from 'url';
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
});