简体   繁体   中英

Vue 2 Mixins for global functionalities

I would like to implement a simple auth mixin for global authentication inside the application and the routing. The auth mixin has a loggedIn data which is True or False and two functions to log in and out. The whole application is based on the vue router webpack template. The problem is that the loggedIn state will not be saved. So when I go to the Login.vue and login, loggedIn will be set to true, but when I go to the Login.vue component again the checkStatus function will log loggedIn as false again.

How can I

This is my mixin:

Auth.js

export default {
  data() {
    return {
      loggedIn: false
    }
  },
  methods: {
    logIn(user,password) {
      return new Promise((resolve, reject) => {
        console.log("Logging in ", user, password);
        this.loggedIn = true;
        resolve()
      })
    },
    logOut(){
      return new Promis ((resolve, reject) => {
        console.log("Logging out");
        this.loggedIn = false;
        resolve();
      })
    }
  }
};

main.js

import Vue from 'vue'
import App from './App'
import router from './router'
import Utils from "./mixins/Utils"
import Auth from "./mixins/Auth"

// Load mixins
Vue.mixin(Auth);
Vue.mixin(Utils);

// This part redirects to login page when authentication is needed
router.beforeEach((to, from, next) => {
  if (to.matched.some(record => record.meta.requiresAuth) && this.loggedIn) {
    next({ path: '/login', query: { redirect: to.fullPath }});
  } else {
    next();
  }
});

Login.vue

<template>
  <div>
    <form class="form-signin">
      <h1 class="mb-3">Please sign in</h1>
      <label for="inputEmail" class="sr-only">Email address</label>
      <input type="email" id="inputEmail" v-model="email" class="form-control" placeholder="Email address" required autofocus>
      <label for="inputPassword" class="sr-only">Password</label>
      <input type="password" id="inputPassword" class="form-control" placeholder="Password" required v-model="password">
      <div class="checkbox mb-3">
        <label>
          <input type="checkbox" value="remember-me"> Remember me
        </label>
      </div>
      <button class="btn btn-lg btn-primary btn-block" type="submit" v-on:click="checkCredentials">Sign in</button>
    </form>
    <div class="mb-3" style="text-align: center">
      <label>
        <router-link to="/signup">Not registerd yet? Sign up!</router-link>
      </label>
    </div>
    <notifications position="bottom center" group="notifications" />
  </div>
</template>


<script>

  export default {
    name: 'Login',
    methods: {
      checkCredentials(event) {
        event.preventDefault();
        if (this.email.length <= 0 || !this.email) {
          this.notify("Enter email", "warn")
          return;
        }
        if (this.password.length <= 0 || !this.password) {
          this.notify("Enter password", "warn");
          return;
        }
        this.performLogin(this.email, this.password);
      },
      performLogin(mail, password) {
        let x = this;
        this.logIn(mail, password)
          .then(function (result) {
            x.notify("Logged in as " + mail, "success");
            if (x.loggedIn) {
              console.log("[LOG] redirecting");
              x.$router.push(x.$route.query.redirect || '/');
            }
          })
          .catch(function (error) {
            document.cookie = "Test";
            x.notify("Error loggin in (" + error + ")", "error");
          })
      },
      checkStatus() {
        this.$log.info("Checking status", this.loggedIn)
        if (this.loggedIn) {
          this.$router.push(this.$route.query.redirect || "/");
        }
      }
    },
    data() {
      return {
        email: "",
        password: ""
      }
    },
    created() {
      this.checkStatus()
    }
  }
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
  .form-signin {
    width: 100%;
    max-width: 330px;
    padding: 15px;
    margin: auto;
  }

  .form-signin .checkbox {
    font-weight: 400;
  }

  .form-signin .form-control {
    position: relative;
    box-sizing: border-box;
    height: auto;
    padding: 10px;
    font-size: 16px;
  }

  .form-signin .form-control:focus {
    z-index: 2;
  }

  .form-signin input[type="email"] {
    margin-bottom: -1px;
    border-bottom-right-radius: 0;
    border-bottom-left-radius: 0;
  }

  .form-signin input[type="password"] {
    margin-bottom: 10px;
    border-top-left-radius: 0;
    border-top-right-radius: 0;
  }
</style>

The problem is that the loggedIn state will not be saved.

Exactly, Mixins are not meant for managing the state they are supposed to be used for functions/methods that needs to be reused in your components, to maintain the state you'd need a state management system and Vue provides one, it's called Vuex .

With Vuex you could define an initial state, in your case whether the user has logged in or not, I'd recommend you to go through the Vuex Docs once

Here's a short and simple example of how it will solve your problem,

const store = new Vuex.Store({
 state: {
  loggedIn: false
 },
 mutations: {
  logInUser (state) {
  state.loggedIn = true
 }
}
})

/* Pass the store to your Vue App */
const app = new Vue({
  el: '#app',

  // this will inject the store instance to all child components.
  store,
  components: { App },
  ..........

Now this state will be available throughout your components and won't change unless you commit a change from somewhere manually.

Login.vue

 this.$store.commit('logInUser', true)

someOtherComp.vue

console.log(this.$store.state.loggedIn) // true

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM