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

&lt;Navbar&gt;&lt;/Navbar&gt;

这是我的 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 无法挂载组件:未定义模板或渲染函数

Laravel 5.3 vue 2组件不渲染

Vue js 无法在 Laravel 5.4 中渲染组件

Laravel:vue组件不渲染

为啥不在 Vue 和 Vue Router 生产环境中渲染我的组件?

Laravel vue组件未显示[关闭]