Laravel 和 Vue:在使用渲染任何组件之前从 Store 初始化身份验证
Posted
技术标签:
【中文标题】Laravel 和 Vue:在使用渲染任何组件之前从 Store 初始化身份验证【英文标题】:Laravel & Vue: Initialise Authentication from Store before rendering any components using 【发布时间】:2020-04-10 23:18:57 【问题描述】:我目前正在使用 laravel 和 Vue 做一个项目。
我想要实现的目标 我想在渲染任何 Vue 组件以在导航栏中包含用户名之前对用户进行身份验证。
问题 我面临的问题是 Vue Navbar 组件在用户通过身份验证并且状态已在商店中更新之前被渲染。因此,导航栏不会显示用户名,因为组件没有更新。
问题 在使用组件创建“新 vue”之前,如何访问商店、提交突变(用户身份验证)?或者:如何实现组件在身份验证发生后立即更新的反应性。
或者,我尝试使用“计算”来更新状态并在 store.state.user 更新后更新用户名。这不起作用我猜是因为我仍然不完全理解的反应性,尽管我已经阅读了很多关于它的内容。
信息 以下是一些背景信息:
我使用 Laravel 设置路由(前端和后端) 我使用 layout.blade 文件并在专用 laravel 视图文件中包含 Vue 组件 使用 JWT 进行身份验证(这工作正常)这是我的 layout.blade.php
<!doctype html>
<html>
<head>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="csrf-token" content=" csrf_token() ">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Gembox</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,400italic|Material+Icons">
<link rel="stylesheet" href="https://unpkg.com/vue-material/dist/vue-material.min.css">
<link rel="stylesheet" href="https://unpkg.com/vue-material/dist/theme/default.css">
<link rel="stylesheet" href="asset(mix('/css/app.css'))">
</head>
</head>
<body>
<div id="app">
<header>
<div>
@include('includes.header')
</div>
</header>
<div class=" main-container md-elevation-4 container">
@yield('content')
</div>
<footer class=" md-elevation-4 mb-1">
@include('includes.footer')
</footer>
<script src="asset ('js/app.js')">
</script>
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/vue-material"></script>
</div>
</body>
这是我的 header.blade.php
<Navbar></Navbar>
这是我的 store.js(user.js 是在 store.js 中导入的)
import axios from "axios";
const state =
users: [],
user: null,
loggedin: false
;
const mutations =
CREATE_USER(state, payload)
axios
.post("api/register",
name: payload.name,
password: payload.password,
email: payload.email
)
.then((response) =>
localStorage.setItem("usertoken", response.data.token);
state.user = response.data.user;
state.loggedin = true;
);
,
GET_USERS(state)
axios
.get("api/user")
.then((response) => (state.users = response.data))
.catch((err) =>
console.log(err, "Problem bei der Liste der Nutzer");
);
,
LOGIN_USER(state, payload)
axios
.post("api/login",
email: payload.email,
password: payload.password
)
.then((response) =>
localStorage.setItem("usertoken", response.data.token);
state.user = response.data.user;
state.loggedin = true;
)
.catch((err) =>
console.log(err, "Konnte keine Daten abrufen");
);
,
AUTH_USER(state)
console.log(
"Not authenticated with token",
localStorage.getItem("usertoken")
);
axios
.get("api/register",
headers:
Authorization: `Bearer $localStorage.usertoken`
)
.then((response) =>
state.user = response.data.user;
state.loggedin = true;
console.log("New user has set", state.user);
)
.catch((err) =>
console.log(err, "Konnte keine Daten abrufen");
);
,
LOGOUT_USER(state)
localStorage.removeItem("usertoken");
state.user = null;
state.loggedin = false;
console.log("logged out", state.user, state.loggedin, localStorage);
;
const getters =
users: (state) =>
return state.users;
,
user: (state) =>
return state.user;
;
const actions =
newUser: ( commit , payload) =>
commit("CREATE_USER", payload);
,
listUsers: ( commit ) =>
commit("GET_USERS");
,
loginUser: ( commit , payload) =>
commit("LOGIN_USER", payload);
,
authUser: ( commit ) =>
commit("AUTH_USER");
,
logoutUser: ( commit ) =>
commit("LOGOUT_USER");
;
export default
state,
mutations,
getters,
actions
;
这是我的 app.js
/**
* First we will load all of this project's javascript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
require("./bootstrap");
window.Vue = require("vue");
/**
* Next, we will create a fresh Vue application instance and attach it to
* the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs.
*/
import Vue from "vue";
import Vuex from "vuex";
import BootstrapVue from "bootstrap-vue";
import store from "../store/store";
import VueMaterial from "vue-material";
import "bootstrap-css-only/css/bootstrap.min.css";
import "mdbvue/lib/css/mdb.min.css";
import "@fortawesome/fontawesome-free/css/all.min.css";
import "vue-material/dist/vue-material.min.css";
import "../sass/app.scss";
Vue.use(Vuex);
Vue.use(BootstrapVue);
Vue.use(VueMaterial);
Vue.component("Signup", require("./components/User/Signup.vue"));
Vue.component("Home", require("./components/Home/Home.vue"));
Vue.component("Login", require("./components/User/Login.vue"));
Vue.component("Navbar", require("./components/Navbar/Navbar.vue"));
store.dispatch("authUser").then(() =>
new Vue(
el: "#app",
store
);
);
这是我的导航栏 Vue 组件
<template>
<div>
<p> user </p>
<nav class=" navbar navbar-expand-lg navbar-dark orange lighten-1">
<a class="navbar-brand" href="#">Navbar</a>
<button
class="navbar-toggler"
type="button"
data-toggle="collapse"
data-target="#navbarSupportedContent-555"
aria-controls="navbarSupportedContent-555"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent-555">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#"
>Home
<span class="sr-only">(current)</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Features</a>
</li>
<li class="nav-item">
<a v-if="user.length > 0" class="nav-link" href="#">Logout</a>
<a v-if="user.length < 1" class="nav-link" href="/register"
>Register</a
>
</li>
</ul>
<ul class="navbar-nav ml-auto nav-flex-icons">
<li class="nav-item avatar">
<a class="nav-link p-0" href="#">
<img
src="https://mdbootstrap.com/img/Photos/Avatars/avatar-5.jpg"
class="rounded-circle z-depth-0"
/>
</a>
</li>
</ul>
</div>
</nav>
</div>
</template>
<script>
import axios from "axios";
export default
computed:
user()
return this.$store.getters.users;
console.log(this.$store.getters.users);
,
created()
console.log("Component mounted", this.$store.getters.users);
;
</script>
非常感谢您的帮助!
谢谢 约尔格
【问题讨论】:
【参考方案1】:以下是我在您的代码中看到的几个问题:
Vuex 突变是同步的,而 Vuex 动作是异步的
Ref: Vuex Documentation on actions
您的业务逻辑必须进行操作,因为它们是异步的(即 axios 调用),并且您的数据更新/操作应该进行更改
在您的“AUTH_USER”突变中,您正在进行 axios 调用,而该调用应该在您的“authUser”操作中。
\\ Your SET_USER mutation could look like below
SET_USER(state, payload)
\\ User data will be passed in 2nd param (i.e payload)
state.user = payload
\\ if we get the data in payload then set loggedin
\\ variable to true otherwise false
state.loggedin = (payload) ? true : false
\\ Your authUser vuex action could look like below, returning the promise
authUser: ( commit ) =>
return axios
.get("api/register",
headers:
Authorization: `Bearer $localStorage.usertoken`
)
.then((response) =>
commit("SET_USER",response.data.user);
)
.catch((err) =>
console.log(err, "Konnte keine Daten abrufen");
);
【讨论】:
非常感谢!!!这节省了很多麻烦和工作。只是为了做对:每当我有异步任务时,我会将承诺放入 ACTION 而不是 MUTATION,对吗? 是的,基本上你所有的业务逻辑、API 查询等都进入“动作”,最后当你完成时,你只需通过调用适当的突变来“提交”结果。这是我最近构建的示例应用程序,它可能对您的组件组织、vuex、测试等有所帮助。[git repo]github.com/techlab23/task-management-app以上是关于Laravel 和 Vue:在使用渲染任何组件之前从 Store 初始化身份验证的主要内容,如果未能解决你的问题,请参考以下文章
Laravel 6 + Vue.js 无法挂载组件:未定义模板或渲染函数