Vue request mode

First encapsulation axios

import axios from "axios";

const const setDefaultParams = params= > {
	return params;
}

const resolve = function (response, success, error) {
  const status = response.statue || response.status
  if (String(status) === '0') {
    success(response)
  } else {
    // console.log('api error=====', response)
    if (error) {
      error(response)
    } else{}}}const reject = function (response, error) {
  console.error('API Error')
  if (error) {
    error(response)
  }
}

// create an axios instance
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
  // withCredentials: true, // send cookies when cross-domain requests
  timeout: 5000 // request timeout
});

// request interceptor
service.interceptors.request.use(
  config= > {
    // do something before request is sent

    if (store.getters.token) {
      // let each request carry token
      // ['X-Token'] is a custom headers key
      // please modify it according to the actual situation
      config.headers["X-Token"] = getToken();
    }
    return config;
  },
  error= > {
    // do something with request error
    console.log(error); // for debug
    return Promise.reject(error); });// response interceptor
service.interceptors.response.use(
  /** * If you want to get http information such as headers or status * Please return response => response */

  /** * Determine the request status by custom code * Here is just an example * You can also judge the status by HTTP Status Code */
  response= > {
    const res = response.data;

    // if the custom code is not 20000, it is judged as an error.
    if(res.code ! = =20000) {
      Message({
        message: res.message || "Error".type: "error".duration: 5 * 1000
      });

      // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
      if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
        // to re-login
        MessageBox.confirm(
          "You have been logged out, you can cancel to stay on this page, or log in again"."Confirm logout", {
            confirmButtonText: "Re-Login".cancelButtonText: "Cancel".type: "warning"
          }
        ).then(() = > {
          store.dispatch("user/resetToken").then(() = > {
            location.reload();
          });
        });
      }
      return Promise.reject(new Error(res.message || "Error"));
    } else {
      returnres; }},error= > {
    console.log("err" + error); // for debug
    Message({
      message: error.message,
      type: "error".duration: 5 * 1000
    });
    return Promise.reject(error); }); service.get =(path, params, success, error) = > {
  const paramsData = Object.assign({
  	t:new Date().getTime()
  },params)
  params = setDefaultParams(paramsData)
  const res = service({
    url: path + '? ' + qs.stringify(params),
    method: 'get'.data: params,
    transformRequest: function (obj) {
      let ret = ' '
      for (const it in obj) {
        ret += encodeURIComponent(it) + '=' + encodeURIComponent(obj[it]) + '&'
      }
      return ret
    },
    headers: {
      'Content-Type': 'application/json'
    }
  })
  res.then(
    response= > {
      resolve(response, success, error)
    },
    response= > {
      reject(response, error)
    }
  )
}

service.put = (path, params, success, error) = > {
  const paramsData = Object.assign({
  	t:new Date().getTime()
  },params)
  params = setDefaultParams(paramsData)
  const res = service({
    url: path + '? ' + qs.stringify(params),
    method: 'put'.data: params,
    transformRequest: function (obj) {
      let ret = ' '
      for (const it in obj) {
        ret += encodeURIComponent(it) + '=' + encodeURIComponent(obj[it]) + '&'
      }
      return ret
    },
    headers: {
      'Content-Type': 'application/json'
    }
  })
  res.then(
    response= > {
      resolve(response, success, error)
    },
    response= > {
      reject(response, error)
    }
  )
}

service.post = (path, params, success, error) = > {
  params = setDefaultParams(params)
  const res = service({
    url: path,
    method: 'post'.params: params
  })
  res.then(
    response= > {
      resolve(response, success, error)
    },
    response= > {
      reject(response, error)
    }
  )
}

service.postJson = (path, params, success, error) = > {
  params = setDefaultParams(params)
  const res = service({
    url: path,
    method: 'post'.data: params,
    transformRequest: function (obj) {
      return JSON.stringify(obj)
    },
    headers: {
      'Content-Type': 'application/json'
    }
  })
  res.then(
    response= > {
      resolve(response, success, error)
    },
    response= > {
      reject(response, error)
    }
  )
  return res
}

export default service;
Copy the code

API Management Interface

import request from '@/utils/request'

export function fetchArticle(id) {
  return request({
    url: '/vue-element-admin/article/detail'.method: 'get'.params: {
      id
    }
  })
}
Copy the code

Component interface calls

import { fetchArticle } from '@/api/article'

fetchArticle(id).then(response= > {
  this.postForm = response.data

  // just for test
  this.postForm.title += `   Article Id:The ${this.postForm.id}`
  this.postForm.content_short += `   Article Id:The ${this.postForm.id}`

  // set tagsview title
  this.setTagsViewTitle()

  // set page title
  this.setPageTitle()
}).catch(err= > {
  console.log(err)
})
Copy the code

In the actual development process, when a GET request is found, the Internet Explorer and Firefox get request will be cached after the first request. To solve the problem, we need to splicing time after THE URL. If we request in the current way, we need to splicing time in each request, which is not very convenient. In order to achieve global management, we change the request mode. To use it, you need to mount utils/index.js globally

import axios from './axios'

export default {
  install: (Vue) = > {
    // Bind to the prototype chain of the vue instance so that you can call this.$axios.get() directly from the component without importing the AXIos module
    Vue.prototype.$axios = axios
  }
Copy the code

Intra-component invocation

  methods: {
    getList() {
      const uid = this.storage.get('yh-user').userId
      this.$axios.get(
        '/EipCountAction/getTaskCount.do',
        { userId: uid },
        res= > {
          this.numb = res.dataContent
        }
      )
    }
  }
Copy the code

This request, do not need each interface to splice, before the request to get unified splicing time rub

  const paramsData = Object.assign({
  	t:new Date().getTime()
  },params)
  params = setDefaultParams(paramsData)
Copy the code



The new list field on the request backend cannot be updated

This.$set() ¶

this.solutionList = r.data.data.solution;
for(let i=0; i<this.solutionList.length; i++){// There is no get/set and no response
	// this.solutionList[i].is = true;
	this.$set(this.solutionList[i],'is'.false);
}
Copy the code
  1. Vue array adds a new field, change the value of the field does not change;
    • Provides solutions;
  2. Vue2.0 adds attributes to data objects and triggers view updates;
    • Elaborate onthis.$set()The correct use of;
  3. Real-time response to failure issues after adding new attributes to vUE data;
    • Data updates are neededgeter()/seter()Two methods;

Correct understanding
a t t r s and Attrs and
listeners

Data communication between Vue components is described as follows:



In fact, there are other ways to communicate with data, such as the parent component getting the child component data and events, through:

  • Get the child component instance by binding the ref property to the child component
  • Get the child component instance with this.$children

For child components to get parent component data and events, you can do this:

  • Parent component data and events are passed through props, or event passing is implemented through emit and emit and emit and on
  • Through the ref attribute, call child component methods and pass data; Parent component data and events are passed through props, or event passing is implemented through emit and emit and emit and on
  • By enclosing the parent, the parent. The parent. The data or enclosing parevent. The data for the parent component data, by enclosing parevent. _data while forming for the parent component data, by enclosing parevent. The data for the parent component data, Execute the parent component method with this.parent

For data communication and event passing between sibling components, you can use:

  • Mount global events using eventBus
  • Use parent to pass data, parent to pass data, parent to pass data, parent.$children to call sibling events

In addition, more complex, Vue component data communication can be done through Vuex. In particular, data communication between multi-level nested components. But using Vuex is a bit wasteful if you’re just passing data from one data to another without doing any intermediate processing. However, since Vue 2.4, there is an alternative:

Use v-bind=”$attrs” to pass attributes from the parent component that are not considered bound to the props feature to the child component.

Typically this method is used in conjunction with interiAttrs. They are used this way because they make communication between components across components simple and business clear without Vuex and eventBus. In fact, that’s another thing we’re going to look at today. How attrs and Attrs and Attrs and Listeners can communicate data between multiple levels of nested components.

The business scenario

As mentioned, we are going to talk about data communication between multi-level nested components. To keep things from getting too complicated (too complex for beginners to understand and learn). Let’s take nesting between three levels of components as an example. ComponentA > ComponentB > ComponentC (ComponentA > ComponentC)





In terms of three-level nested components, their relationship is relatively simple:

  • ComponentA is the parent component of ComponentB, and their relationship is the parent-child relationship
  • ComponentB component is the parent component of ComponentC component, and their relationship is also the parent-child relationship
  • ComponentA component is the ancestor component of ComponentC component, and their relationship is the ancestor and grandson relationship




For the data communication between these three components, according to our previous knowledge, it is expected that:

Props down, $emit up.





That is to say, ComponentA to ComponentB can pass to sub-components in the way of props, and ComponentB to ComponentA through ComponentB component
e m i t Send events up, and then in C o m p o n e n t A In the component The emit sends events up and into the ComponentA component
The on mode listens for sent events. A similar approach can be used for communication between ComponentB and ComponentC. But for the communication between ComponentA component and ComponentC component, need to use ComponentB component as a transfer station, when ComponentA component needs to pass the information to ComponentC component, ComponentB accepts the information of ComponentA component, The properties are then passed to the ComponentC component.

This is a solution in this sense, but if we have too many layers of nested components, the code will be cumbersome and difficult to maintain.

In addition to the above methods to complete data communication between components, there are other methods, such as Vuex global state sharing; Use eventBus to create an instance of Vue to realize the monitoring and publishing of events, so as to achieve data communication between components. But they are too wasteful, and we should find other, simpler solutions, attrs and listeners as well as attrs mentioned at the beginning of the article.

In brief, attrs is used to realize data transmission between grandparent and grandparent components, attrs realizes data transmission between grandparent and grandparent components, attrs realizes data transmission between grandparent and grandparent components, and Listeners realize event monitoring between grandparent and grandparent components. Let’s see how you can use these two features to communicate data between nested components across levels.

terms

Before understanding how attrs and Listeners and attrs and listeners accomplish component data communication, let’s take a quick look at what they are. The listeners are attrs and Listeners on the Vue website:

The interpretation of the $attrs

Contains feature bindings (except class and style) that are not recognized (and obtained) as props in the parent scope. When a component does not declare any props, this includes all parent scoped bindings (except class and style), and internal components can be passed in via v-bind=”$attrs” — useful when creating high-level components.

The interpretation of the $listeners

Contains v-ON event listeners in the parent scope (without the.native modifier). Internal components can be passed in via V-on =”$Listeners “– useful for creating higher-level components.

The official explanation is pretty clear. In fact, you can think of attrs as a set of attributes, attrs as a set of attributes, and listeners as a set of events, Both store data in the form of objects. To put it more simply, Attrs is used to transmit data between grandparent and grandparent components, attrs is used to transmit data between grandparent and grandparent components, attrs is used to transmit data between grandparent and grandparent components, attrs is used to transmit data between grandparent and grandparent components, and Listeners are used to monitor events between grandparent and grandparent components. Attrs inherits all parent component attributes (except the props, class, and style attributes) and is typically used on child elements of a child component. Attrs inherits all parent component attributes (except properties passed by props, class, and style) and is typically used on child elements of a child component. Attrs inherits all parent component attributes (except properties passed by props, class, and style) and is typically used on child elements of a child component. Listeners are an object that contains all listeners acting on the component, with the function v-ON pointing event listeners to a particular child element of the component (the child inherits events from the parent). To make it easier for you to understand these two properties, let’s go through some simple examples. Let’s start with a simple example:

<! -- ChildComponent.vue --><template>
  <div class="child-component">
    <h1>I am a {{professional}}</h1>
  </div>
</template>

<script>
export default {
  name: "ChildComponent".props: { professional: { type: String.default: "Spirit boy"}},created() {
    console.log(this.$attrs, this.$listeners);
    // Call the parent app.vue triggerTwo() method this.$Listeners. Two()}};</script>
Copy the code
<template>
  <div id="app">
    <ChildComponent :professional="professional"
                    :name="name"
                    @one.native="triggerOne"
                    @two="triggerTwo" />
  </div>
</template>

<script>
import ChildComponent from "./components/ChildComponent.vue";
export default {
  name: "app".data() {
    return { professional: Happy Boy.name: "zhbb" };
  },
  components: { ChildComponent },
  methods: {
    triggerOne() {
      console.log("one");
    },
    triggerTwo() {
      console.log("two"); ,}}};</script>
Copy the code

App.vue (props); app.vue (props); app.vue (props); app.vue (props); app.vue (props); One event is the. Native modifier (which listens for the native event of the component root element). This simple example shows how attrs and attrs and attrs and listeners can pass data around, calling and processing where needed. For example, the parent app.vue triggerTwo() method is accessed by this.Component.two () in ChildComponent. Of course, we can also access the triggerTwo() method in parent app.vue via v−on=” Listeners.two(). Of course, we can also access the triggerTwo() method in the parent component app.vue via v-on=” Listeners.two(). There are also v−on=”listeners” on the process, regardless of the level of component nesting. We’ll talk more about this later. Also, in the example above, one of the properties is props, such as professional, and another is non-props, such as name. Components compile to treat non-props properties as raw properties and add them to DOM elements (HTML tags), such as name in the example above: If we want to remove the name attribute from the HTML tag so that it is not exposed, we can use the inheritAttrs attribute to do so.

InheritAttrs uses the default value true to apply all parent component attributes (except for props specific bindings) to the root element of the child component as a normal HTML feature. If you don’t want to use inheritAttrs as the root element of the component, the class attribute does. ** inheritAttrs: true inherits all attributes except props; InheritAttrs: false inherits only the class attribute **.

If we add inheritAttrs: false to the ChildComponent ChildComponent, the name (non-props) attribute in the recompiled code is no longer exposed:

Multi-level nested component data communication

We’ve spent a lot of time explaining attrs and attrs and attrs and listeners and how they communicate data within components. Returning to our example, see how attrs and attrs and Attrs and listeners communicate data between the three-level nested components mentioned at the beginning of this article.

<! -- ComponentA.vue --><template>
  <div class="component-a">
    <ComponentB :name="name"
                :age="age"
                @on-test1="onTest1"
                @on-test2="onTest2" />
  </div>
</template>

<script>
import ComponentB from "./ComponentB";
export default {
  name: "ComponentA".components: { ComponentB },
  data() {
    return { name: "Big ZHBB".age: 23 };
  },
  methods: {
    onTest1() {
      console.log("test1 runing...");
    },
    onTest2() {
      console.log("test2 running..."); ,}}};</script>
Copy the code
<! -- ComponentB.vue --><template>
  <div class="component-b">
    <h3>Props: {{age}}</h3>
    <p>$attrs in component B: {{$attrs}}</p>
    <p>$Listeners: {{$listeners}}</p>
    <hr />
    <ComponentC v-bind="$attrs"
                v-on="$listeners" />
  </div>
</template> <script>
import ComponentC from "./ComponentC";
export default {
  name: "ComponentB".props: { age: { type: Number.default: 30}},inheritAttrs: false.components: { ComponentC },
  mounted() {
    this.$emit("test1");
    console.log("ComponentB".this.$attrs, this.$listeners); }};</script>
Copy the code
<! -- ComponentC.vue --><template>
  <div class="component-c">
    <h3>Props set in component C: {{name}}</h3>
    <p>$attrs in component C: {{$attrs}}</p>
    <p>$Listeners: {{$listeners}}</p>
  </div>
</template>
 <script>
export default {
  name: "ComponentC".props: { name: { type: String.default: "zhbb"}},inheritAttrs: false.mounted() {
    this.$emit("test2");
    console.log("ComponentC".this.$attrs, this.$listeners); }};</script>
Copy the code
<template>
  <div id="app">
    <ComponentA />
  </div>
</template>

<script>
import ComponentA from "./components/ComponentA.vue";
export default {
  name: "app".data() {},
  components: {ComponentA },
  methods: {}};</script>
Copy the code

Vue $once(‘hook:beforeDestroy’,e=>{}) using Vue how to destroy timer

1. Timer Hook optimization

Use hook automatic cleanup timer in Vue — programmatic event listener;

export default {
    mounted() {
        this.creatInterval('hello')
        this.creatInterval('world')},methods: {creatInterval(msg) {
	        let timer = setInterval(() = > {
	            console.log(msg)
	        }, 1000)
	        this.$once('hook:beforeDestroy'.function() {
	            clearInterval(timer)
	        })
	    }
	}
}
Copy the code

Vue projects use $.once(‘ hook:beforeDestory… ;

export default{
  methods: {fun1(){
      const timer = setInterval(() = >{
      	// What needs to be done
         console.log(11111);
      },1000);
      this.$once('hook:beforeDestroy'.() = >{
        clearInterval(timer);
        timer = null; })}}}Copy the code

2. Timer Hook injection

Vue@hook those things;

<v-chart
    @hook:mounted="loading = false"
    @hook:beforeUpdated="loading = true"
    @hook:updated="loading = false"
    :data="data"
/>
Copy the code

Vue hook function hookEvent, listen to the component;

Perhaps try custom methods of hook child components or even change calls to data;

<custom-select @hook:updated="$_handleSelectUpdated" />
Copy the code

The updated hook function of the component is used to monitor data changes of a third-party component. The component does not provide the change event. After a look, Vue supports listening externally to the component’s lifecycle hook functions.

<template> <! Listen to the component's updated hook function --> <! All lifecycle hooks of a component can be listened for by @hook: hook function name.<custom-select @hook:updated="$_handleSelectUpdated" />
</template>
<script>
import CustomSelect from '.. /components/custom-select'
export default {
  components: {
    CustomSelect
  },
  methods: {
    $_handleSelectUpdated() {
      console.log('Custom-select component's updated hook function is fired')}}}</script>
Copy the code

In Vue, hooks are used as events, which are called hookEvents in the Vue source code.

$on(‘hook:updated’, () => {}) {$on(‘hook:updated’, () => {})