最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - listening on a window property change - Stack Overflow

programmeradmin1浏览0评论

I am trying to listen inside a vue ponent to a window property change, I am not sure this is possible.
The use is for a loader, baiscally I have a file which has an interceptor which alters the "loading" property on the window object (window.loading = true when request initiated, window.loading = false when request plete (or error)) (I have issues accessing my store inside the interceptor). The vue ponent looks like this:

<template> 
    <v-progress-linear   //this is the loader element
            height="20"
            v-show="loading"
    >
    </v-progress-linear>
    ...
    puted: { 
    loading(){
    return window.loading}
    }

I also tried this as a solution:

created () {
    window.addEventListener('loading', this.handleLoading);
  },
  destroyed () {
    window.removeEventListener('loading', this.handleLoading);
  },
  methods: {
    handleLoading(val){
      console.log(val)
    this.loading =  val
}
  },

The question is how can I listen on my window.loading

EDIT

Here is the file which contains the interceptor code, note this does not have access to the vue instance.

import axios from 'axios';
import { Utils } from 'em-mon-vue';

import {UsersApi} from "./usersApi";
import {PartnersApi} from "./partnersApi";
import {TrialsApi} from "./trialsApi";

export function apiFactory($security) {
    const $http = axios.create({
        baseURL: process.env.VUE_APP_API_URL
    });
    $http.interceptors.request.use(function (config) {
        window.loading = true
        const token = $security.loginFrame.getToken();

        if (token) {
            config.headers.Authorization = `Bearer ${token}`;
        }

        return config;

    }, function (error) {
        window.loading = true
        Utils.EventBus.$emit('toastMessageHandler', {message: error.message, type: 'error'});
        window.loading = false
        return Promise.reject(error);
    }
);

    $http.interceptors.response.use(function (response) {
        window.loading = false
        return response;

    }, function (error) {
        if (error.response && error.response.status === 401) {

            Utils.EventBus.$emit('authErr', error);
        } else if (error.response && error.response.status === 403) {
            alert('You are not authorized to access this application. If you believe you are seeing this message in error, please contact [email protected].');
        }

        else if (error.response && error.response.status !== 409){
            Utils.EventBus.$emit('toastMessageHandler', {message: error.message, type: 'error'});
        }
        else if (error.response && error.response.status === 500){
            Utils.EventBus.$emit('toastMessageHandler', {message: 'There was a problem with this operation - please contact [email protected].', type: 'error'});
        }
        window.loading = false
        return Promise.reject({error});
    });

    const $api = {
        users: new UsersApi($http),
        partners: new PartnersApi($http),
        trials: new TrialsApi($http)
    };

    return $api;
}

// register $api as vue plugin
export function apiPluginFactory($api) {
    return {
        install(vue) {
            vue.prototype.$api = $api;
        },
    };
}

Here is the file which has factory function which creates the store:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

import {usersStoreFactory} from "./users/module";

// global
import {InitActions} from './actions';
import mutations from './mutations'
import getters from "./getters";

export function storeFactory($api, $config) {

    // global
    const actions  = InitActions($api);

    const store = new Vuex.Store({
        modules: {
            users: usersStoreFactory($api, $config),
        },
        state: {
            partners: null,
            // loading: window.loading
        },

        actions,
        mutations,
        getters
    });

    return store;
}

I am trying to listen inside a vue ponent to a window property change, I am not sure this is possible.
The use is for a loader, baiscally I have a file which has an interceptor which alters the "loading" property on the window object (window.loading = true when request initiated, window.loading = false when request plete (or error)) (I have issues accessing my store inside the interceptor). The vue ponent looks like this:

<template> 
    <v-progress-linear   //this is the loader element
            height="20"
            v-show="loading"
    >
    </v-progress-linear>
    ...
    puted: { 
    loading(){
    return window.loading}
    }

I also tried this as a solution:

created () {
    window.addEventListener('loading', this.handleLoading);
  },
  destroyed () {
    window.removeEventListener('loading', this.handleLoading);
  },
  methods: {
    handleLoading(val){
      console.log(val)
    this.loading =  val
}
  },

The question is how can I listen on my window.loading

EDIT

Here is the file which contains the interceptor code, note this does not have access to the vue instance.

import axios from 'axios';
import { Utils } from 'em-mon-vue';

import {UsersApi} from "./usersApi";
import {PartnersApi} from "./partnersApi";
import {TrialsApi} from "./trialsApi";

export function apiFactory($security) {
    const $http = axios.create({
        baseURL: process.env.VUE_APP_API_URL
    });
    $http.interceptors.request.use(function (config) {
        window.loading = true
        const token = $security.loginFrame.getToken();

        if (token) {
            config.headers.Authorization = `Bearer ${token}`;
        }

        return config;

    }, function (error) {
        window.loading = true
        Utils.EventBus.$emit('toastMessageHandler', {message: error.message, type: 'error'});
        window.loading = false
        return Promise.reject(error);
    }
);

    $http.interceptors.response.use(function (response) {
        window.loading = false
        return response;

    }, function (error) {
        if (error.response && error.response.status === 401) {

            Utils.EventBus.$emit('authErr', error);
        } else if (error.response && error.response.status === 403) {
            alert('You are not authorized to access this application. If you believe you are seeing this message in error, please contact [email protected].');
        }

        else if (error.response && error.response.status !== 409){
            Utils.EventBus.$emit('toastMessageHandler', {message: error.message, type: 'error'});
        }
        else if (error.response && error.response.status === 500){
            Utils.EventBus.$emit('toastMessageHandler', {message: 'There was a problem with this operation - please contact [email protected].', type: 'error'});
        }
        window.loading = false
        return Promise.reject({error});
    });

    const $api = {
        users: new UsersApi($http),
        partners: new PartnersApi($http),
        trials: new TrialsApi($http)
    };

    return $api;
}

// register $api as vue plugin
export function apiPluginFactory($api) {
    return {
        install(vue) {
            vue.prototype.$api = $api;
        },
    };
}

Here is the file which has factory function which creates the store:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

import {usersStoreFactory} from "./users/module";

// global
import {InitActions} from './actions';
import mutations from './mutations'
import getters from "./getters";

export function storeFactory($api, $config) {

    // global
    const actions  = InitActions($api);

    const store = new Vuex.Store({
        modules: {
            users: usersStoreFactory($api, $config),
        },
        state: {
            partners: null,
            // loading: window.loading
        },

        actions,
        mutations,
        getters
    });

    return store;
}
Share Improve this question edited Jun 20, 2020 at 9:12 CommunityBot 11 silver badge asked Aug 27, 2019 at 8:36 MichaelMichael 5,0588 gold badges37 silver badges59 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 7

I really don't think municating the loading state via window.loading is a good idea. Using something like the Vuex store or a similar singleton to hold the loading state seems like a much better approach but that has been (somewhat cryptically) ruled out in the question.

However, assuming that window.loading is the only option...

Defining a getter and setter for window.loading might be one way to get that approach to work. There are several ways that might be done but in my example I've chosen to proxy through to a Vue observable to hold the value.

const loadingMonitor = Vue.observable({
  loading: false
})

Object.defineProperty(window, 'loading', {
  get () {
    return loadingMonitor.loading
  },
  
  set (loading) {
    loadingMonitor.loading = loading
  }
})

new Vue({
  el: '#app',
  
  puted: { 
    loading () {
      return window.loading
    }
  },
  
  methods: {
    toggle () {
      window.loading = !window.loading
    }
  }
})
<script src="https://unpkg./[email protected]/dist/vue.js"></script>
<div id="app">
  <p>{{ loading }}</p>
  <button @click="toggle">Toggle</button>
</div>

Note that Vue.observable was added in Vue 2.6 so if you're using an older version you'd need to use the data of a new Vue instance to achieve the same effect.

As the value is held in an observable object it can take part in the reactivity system just like everything else. That allows it to be used in a puted property as a reactive dependency.

发布评论

评论列表(0)

  1. 暂无评论