Инкапсуляция Axios и управление интерфейсом API в vue

JavaScript API Vue.js axios


Как показано на картинке, вы столкнулись с беспорядком в коде~~~ Я действительно хочу сказать, Что F~U~C~K! ! !

Возвращаясь к теме, мы говорим об инкапсуляции аксиом и унифицированном управлении интерфейсом API, На самом деле, основная цель — помочь нам упростить код и облегчить последующее обновление и обслуживание.

Во-первых, пакет axios

В проекте vue мы обычно используем библиотеку axios для взаимодействия с фоном для получения данных, которая представляет собой http-библиотеку на основе обещаний, которая может работать на стороне браузера и node.js. Он имеет множество отличных функций, таких как перехват запросов и ответов, отмена запросов, преобразование json, защита на стороне клиента от XSRF и т. д. Поэтому наша Youda тоже решительно отказалась от обслуживания своей официальной библиотеки vue-resource, и прямо порекомендовала нам использовать библиотеку axios. Если вы все еще не знаете об аксиомах, вы можете перейтиДокументация по аксиомам.

Установить

npm install axios; // 安装axios

представлять

Как правило, я создаю новую папку запроса в каталоге src проекта, а затем создаю в ней новый файл http.js и файл api.js. Файл http.js используется для инкапсуляции наших аксиом, а api.js используется для унифицированного управления нашим интерфейсом.

// 在http.js中引入axios
import axios from 'axios'; // 引入axios
import QS from 'qs'; // 引入qs模块,用来序列化post类型的数据,后面会提到
// vant的toast提示框组件,大家可根据自己的ui组件更改。
import { Toast } from 'vant'; 

переключение среды

Наша проектная среда может иметь среду разработки, тестовую среду и производственную среду. Мы используем переменные среды узла, чтобы соответствовать нашему префиксу URL-адреса интерфейса по умолчанию. axios.defaults.baseURL может установить адрес запроса axios по умолчанию.

// 环境的切换
if (process.env.NODE_ENV == 'development') {    
    axios.defaults.baseURL = 'https://www.baidu.com';} 
else if (process.env.NODE_ENV == 'debug') {    
    axios.defaults.baseURL = 'https://www.ceshi.com';
} 
else if (process.env.NODE_ENV == 'production') {    
    axios.defaults.baseURL = 'https://www.production.com';
}

установить время ожидания запроса

Установите время ожидания запроса по умолчанию через axios.defaults.timeout. Например, если оно превышает 10 с, пользователь будет проинформирован о том, что время ожидания текущего запроса истекло, обновите его и т. д.

axios.defaults.timeout = 10000;

настройки заголовка почтового запроса

При отправке запроса на публикацию нам нужно добавить заголовок запроса, поэтому мы можем сделать здесь настройку по умолчанию, то есть установить заголовок запроса публикации наapplication/x-www-form-urlencoded;charset=UTF-8

axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
  • запрос на перехват

Мы можем перехватить запрос перед отправкой запроса.Зачем мы его перехватываем?Что мы используем для перехвата запроса? Например, к некоторым запросам можно получить доступ только после того, как пользователь войдет в систему, или при отправке запроса нам необходимо сериализовать отправляемые данные. В это время мы можем выполнить перехват перед отправкой запроса, чтобы сделать то, что мы хотим.

запрос на перехват

// 先导入vuex,因为我们要使用到里面的状态对象
// vuex的路径根据自己的路径去写
import store from '@/store/index';

// 请求拦截器axios.interceptors.request.use(    
    config => {        
        // 每次发送请求之前判断vuex中是否存在token        
        // 如果存在,则统一在http请求的header都加上token,这样后台根据token判断你的登录情况
        // 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断 
        const token = store.state.token;        
        token && (config.headers.Authorization = token);        
        return config;    
    },    
    error => {        
        return Promise.error(error);    
})

Давайте поговорим о токене здесь.Как правило, после завершения входа в систему токен пользователя сохраняется локально через localStorage или cookie, а затем каждый раз, когда пользователь заходит на страницу (т.е. в main.js), токен будет считываться из сначала локальное хранилище. , если токен существует, это означает, что пользователь вошел в систему, затем обновите статус токена в vuex. Затем каждый раз, когда вы запрашиваете интерфейс, токен будет переноситься в заголовке запроса, и фоновый персонал может определить, истек ли срок вашего входа в систему, в соответствии с токеном, который вы носите.Если он не переносится, это означает, что у вас есть не вошли в. В это время у некоторых друзей могут возникнуть сомнения, то есть каждый запрос несет в себе токен, так что, если страница может быть доступна без входа пользователя? Фактически, ваш внешний запрос может содержать токен, но серверная часть может отказаться от его получения!

Перехват ответа

// 响应拦截器
axios.interceptors.response.use(    
    response => {   
        // 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据     
        // 否则的话抛出错误
        if (response.status === 200) {            
            return Promise.resolve(response);        
        } else {            
            return Promise.reject(response);        
        }    
    },    
    // 服务器状态码不是2开头的的情况
    // 这里可以跟你们的后台开发人员协商好统一的错误状态码    
    // 然后根据返回的状态码进行一些操作,例如登录过期提示,错误提示等等
    // 下面列举几个常见的操作,其他需求可自行扩展
    error => {            
        if (error.response.status) {            
            switch (error.response.status) {                
                // 401: 未登录
                // 未登录则跳转登录页面,并携带当前页面的路径
                // 在登录成功后返回当前页面,这一步需要在登录页操作。                
                case 401:                    
                    router.replace({                        
                        path: '/login',                        
                        query: { 
                            redirect: router.currentRoute.fullPath 
                        }
                    });
                    break;

                // 403 token过期
                // 登录过期对用户进行提示
                // 清除本地token和清空vuex中token对象
                // 跳转登录页面                
                case 403:
                     Toast({
                        message: '登录过期,请重新登录',
                        duration: 1000,
                        forbidClick: true
                    });
                    // 清除token
                    localStorage.removeItem('token');
                    store.commit('loginSuccess', null);
                    // 跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面 
                    setTimeout(() => {                        
                        router.replace({                            
                            path: '/login',                            
                            query: { 
                                redirect: router.currentRoute.fullPath 
                            }                        
                        });                    
                    }, 1000);                    
                    break; 

                // 404请求不存在
                case 404:
                    Toast({
                        message: '网络请求不存在',
                        duration: 1500,
                        forbidClick: true
                    });
                    break;
                // 其他错误,直接抛出错误提示
                default:
                    Toast({
                        message: error.response.data.message,
                        duration: 1500,
                        forbidClick: true
                    });
            }
            return Promise.reject(error.response);
        }
    }    
});

Хорошо понятен перехватчик ответа, то есть данные, возвращаемые нам сервером, мы можем сделать над ними некоторую обработку, прежде чем мы их получим. Например, приведенная выше идея: если код состояния, возвращаемый фоном, равен 200, данные будут возвращены нормально, в противном случае некоторые необходимые нам ошибки будут сделаны в соответствии с неправильным типом кода состояния. .

Следует отметить, что описанный выше метод Toast() является компонентом всплывающей подсказки в библиотеке vant, которую я представил.Вы можете использовать один из ваших компонентов подсказки в соответствии с вашей библиотекой пользовательского интерфейса.

Инкапсулировать метод get и метод post

Наши часто используемые методы запроса ajax включают в себя методы get, post, put и другие, я думаю, что маленькие друзья не будут незнакомы. Аналогичных методов, соответствующих axios, много, если не понятно, можете почитать документацию. Но чтобы упростить наш код, нам все же придется сделать его простую инкапсуляцию. Ниже мы в основном инкапсулируем два метода: get и post.

получить метод: мы определяем функцию get. Функция get имеет два параметра. Первый параметр представляет URL-адрес, который мы хотим запросить, а второй параметр — это параметр запроса, который мы хотим передать. Функция get возвращает объект обещания, а сервер разрешения возвращает значение, когда запрос axios успешен, и отклоняет значение ошибки, когда запрос терпит неудачу. Наконец, через экспорт выбрасывается функция get.

/**
 * get方法,对应get请求
 * @param {String} url [请求的url地址]
 * @param {Object} params [请求时携带的参数]
 */
export function get(url, params){    
    return new Promise((resolve, reject) =>{        
        axios.get(url, {            
            params: params        
        }).then(res => {
            resolve(res.data);
        }).catch(err =>{
            reject(err.data)        
    })    
});}

почтовый метод:Принцип в основном такой же, как у get, но следует отметить, что метод post должен использовать операцию сериализации переданного объекта параметра, поэтому здесь мы сериализуем наши параметры через модуль qs узла. Это очень важно, если нет операции сериализации, фон не сможет получить отправленные вами данные. Это начало статьи, которую мыimport QS from 'qs';причина. Если вы не понимаете, что означает сериализация, просто посмотрите на Baidu, там много ответов.

/** 
 * post方法,对应post请求 
 * @param {String} url [请求的url地址] 
 * @param {Object} params [请求时携带的参数] 
 */
export function post(url, params) {
    return new Promise((resolve, reject) => {
         axios.post(url, QS.stringify(params))
        .then(res => {
            resolve(res.data);
        })
        .catch(err =>{
            reject(err.data)
        })
    });
}

Вот небольшая деталь,axios.get()Методы иaxios.post()По-прежнему существуют различия в способе записи параметров при отправке данных. Разница в том, что вторым параметром get является {}, а затем значением свойства params этого объекта является объект параметра. Второй параметр post — это объект параметра. Обратите внимание на небольшую разницу между ними!



Инкапсуляция axios в основном завершена.Поговорим вкратце об унифицированном управлении api.

Аккуратный API похож на печатную плату, даже если он сложный, вся схема очень понятна. Как упоминалось выше, мы создадим новый api.js, а затем сохраним в этом файле все наши API-интерфейсы.

  • Во-первых, мы представляем наши инкапсулированные методы Get и Post в API.js

/**   
 * api接口统一管理
 */
import { get, post } from './http'

Сейчас, например, у нас есть такой интерфейс, который представляет собой почтовый запрос:

http://www.baiodu.com/api/v1/users/my_address/address_edit_before

Мы можем инкапсулировать это в api.js следующим образом:

export const apiAddress = p => post('api/v1/users/my_address/address_edit_before', p);

мы определяемapiAddressэтот метод имеет параметр p, p — это объект параметра, который мы передаем при запросе интерфейса. Тогда позвоните в нашу упакованнуюpostметод,postПервый параметр метода — это адрес нашего интерфейса, а второй параметр —apiAddressПараметр p, то есть объект параметра, передаваемый при запросе интерфейса. Наконец экспорт через экспортapiAddress.

Затем на нашей странице мы можем вызвать наш интерфейс API следующим образом:

import { apiAddress } from '@/request/api';// 导入我们的api接口
export default {        
    name: 'Address',    
    created () {
        this.onLoad();
    },
    methods: {            
        // 获取数据            
        onLoad() {
            // 调用api接口,并且提供了两个参数                
            apiAddress({                    
                type: 0,                    
                sort: 1                
            }).then(res => {
                // 获取数据成功后的其他操作
                ………………                
            })            
        }        
    }
}

Для других интерфейсов API вы можете продолжить расширение ниже в pai.js. Дружеское напоминание, пишите заметки для каждого интерфейса! ! !

Одним из преимуществ управления интерфейсом API является то, что мы централизуем API. Если позже нам потребуется изменить интерфейс, мы можем напрямую найти соответствующую модификацию в api.js вместо того, чтобы переходить на каждую страницу, чтобы найти наш интерфейс, а затем изменить его. хлопотный. Дело в том, что если количество модификаций относительно велико, спецификация будет gg. Кроме того, если мы изменим интерфейс непосредственно в нашем бизнес-коде, легко случайно переместить наш бизнес-код и вызвать ненужные проблемы.


Ну и наконец представлен готовый код пакета axios.

/**axios封装
 * 请求拦截、相应拦截、错误统一处理
 */
import axios from 'axios';import QS from 'qs';
import { Toast } from 'vant';
import store from '../store/index'

// 环境的切换
if (process.env.NODE_ENV == 'development') {    
    axios.defaults.baseURL = '/api';
} else if (process.env.NODE_ENV == 'debug') {    
    axios.defaults.baseURL = '';
} else if (process.env.NODE_ENV == 'production') {    
    axios.defaults.baseURL = 'http://api.123dailu.com/';
}

// 请求超时时间
axios.defaults.timeout = 10000;

// post请求头
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';

// 请求拦截器
axios.interceptors.request.use(    
    config => {
        // 每次发送请求之前判断是否存在token,如果存在,则统一在http请求的header都加上token,不用每次请求都手动添加了
        // 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断
        const token = store.state.token;        
        token && (config.headers.Authorization = token);        
        return config;    
    },    
    error => {        
        return Promise.error(error);    
    })

// 响应拦截器
axios.interceptors.response.use(    
    response => {        
        if (response.status === 200) {            
            return Promise.resolve(response);        
        } else {            
            return Promise.reject(response);        
        }    
    },
    // 服务器状态码不是200的情况    
    error => {        
        if (error.response.status) {            
            switch (error.response.status) {                
                // 401: 未登录                
                // 未登录则跳转登录页面,并携带当前页面的路径                
                // 在登录成功后返回当前页面,这一步需要在登录页操作。                
                case 401:                    
                    router.replace({                        
                        path: '/login',                        
                        query: { redirect: router.currentRoute.fullPath } 
                    });
                    break;
                // 403 token过期                
                // 登录过期对用户进行提示                
                // 清除本地token和清空vuex中token对象                
                // 跳转登录页面                
                case 403:                     
                    Toast({                        
                        message: '登录过期,请重新登录',                        
                        duration: 1000,                        
                        forbidClick: true                    
                    });                    
                    // 清除token                    
                    localStorage.removeItem('token');                    
                    store.commit('loginSuccess', null);                    
                    // 跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面
                    setTimeout(() => {                        
                        router.replace({                            
                            path: '/login',                            
                            query: { 
                                redirect: router.currentRoute.fullPath 
                            }                        
                        });                    
                    }, 1000);                    
                    break; 
                // 404请求不存在                
                case 404:                    
                    Toast({                        
                        message: '网络请求不存在',                        
                        duration: 1500,                        
                        forbidClick: true                    
                    });                    
                break;                
                // 其他错误,直接抛出错误提示                
                default:                    
                    Toast({                        
                        message: error.response.data.message,                        
                        duration: 1500,                        
                        forbidClick: true                    
                    });            
            }            
            return Promise.reject(error.response);        
        }       
    }
);
/** 
 * get方法,对应get请求 
 * @param {String} url [请求的url地址] 
 * @param {Object} params [请求时携带的参数] 
 */
export function get(url, params){    
    return new Promise((resolve, reject) =>{        
        axios.get(url, {            
            params: params        
        })        
        .then(res => {            
            resolve(res.data);        
        })        
        .catch(err => {            
            reject(err.data)        
        })    
    });
}
/** 
 * post方法,对应post请求 
 * @param {String} url [请求的url地址] 
 * @param {Object} params [请求时携带的参数] 
 */
export function post(url, params) {    
    return new Promise((resolve, reject) => {         
        axios.post(url, QS.stringify(params))        
        .then(res => {            
            resolve(res.data);        
        })        
        .catch(err => {            
            reject(err.data)        
        })    
    });
}


Если вам понравилось, поставьте ❤❤(*^▽^*)


**********Великолепная разделительная линия******************Великолепная разделительная линия************* **** *Великолепная разделительная линия******************Великолепная разделительная линия****************** *Великолепная разделительная линия**** *****

2018.8.14 обновление

Пакет axios варьируется в зависимости от различных потребностей. Большое спасибо за некоторые очень уместные предложения в комментариях, я также подумал об этом и улучшил его для разных нужд. Основные изменения заключаются в следующем:

1. Оптимизировать пакет axios, удалить предыдущий get и post

2. Обработка отключения сети

3. Более модульное управление API

4. Существует несколько доменных имен интерфейса

5. API монтируется на vue.prototype, чтобы сохранить вводные шаги.


Чтобы оптимизировать пакет axios в http.js, сначала вставьте код напрямую:

/**
 * axios封装
 * 请求拦截、响应拦截、错误统一处理
 */
import axios from 'axios';
import router from '../router';
import store from '../store/index';
import { Toast } from 'vant';

/** 
 * 提示函数 
 * 禁止点击蒙层、显示一秒后关闭
 */
const tip = msg => {    
    Toast({        
        message: msg,        
        duration: 1000,        
        forbidClick: true    
    });
}

/** 
 * 跳转登录页
 * 携带当前页面路由,以期在登录页面完成登录后返回当前页面
 */
const toLogin = () => {
    router.replace({
        path: '/login',        
        query: {
            redirect: router.currentRoute.fullPath
        }
    });
}

/** 
 * 请求失败后的错误统一处理 
 * @param {Number} status 请求失败的状态码
 */
const errorHandle = (status, other) => {
    // 状态码判断
    switch (status) {
        // 401: 未登录状态,跳转登录页
        case 401:
            toLogin();
            break;
        // 403 token过期
        // 清除token并跳转登录页
        case 403:
            tip('登录过期,请重新登录');
            localStorage.removeItem('token');
            store.commit('loginSuccess', null);
            setTimeout(() => {
                toLogin();
            }, 1000);
            break;
        // 404请求不存在
        case 404:
            tip('请求的资源不存在'); 
            break;
        default:
            console.log(other);   
        }}

// 创建axios实例
var instance = axios.create({    timeout: 1000 * 12});
// 设置post请求头
instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
/** 
 * 请求拦截器 
 * 每次请求前,如果存在token则在请求头中携带token 
 */ 
instance.interceptors.request.use(    
    config => {        
        // 登录流程控制中,根据本地是否存在token判断用户的登录情况        
        // 但是即使token存在,也有可能token是过期的,所以在每次的请求头中携带token        
        // 后台根据携带的token判断用户的登录情况,并返回给我们对应的状态码        
        // 而后我们可以在响应拦截器中,根据状态码进行一些统一的操作。        
        const token = store.state.token;        
        token && (config.headers.Authorization = token);        
        return config;    
    },    
    error => Promise.error(error))

// 响应拦截器
instance.interceptors.response.use(    
    // 请求成功
    res => res.status === 200 ? Promise.resolve(res) : Promise.reject(res),    
    // 请求失败
    error => {
        const { response } = error;
        if (response) {
            // 请求已发出,但是不在2xx的范围 
            errorHandle(response.status, response.data.message);
            return Promise.reject(response);
        } else {
            // 处理断网的情况
            // eg:请求超时或断网时,更新state的network状态
            // network状态在app.vue中控制着一个全局的断网提示组件的显示隐藏
            // 关于断网组件中的刷新重新获取数据,会在断网组件中说明
            if (!window.navigator.onLine) {
               store.commit('changeNetwork', false);
            } else {
                return Promise.reject(error);
            }
        }
    });

export default instance;
Эта аксиома аналогична предыдущей со следующими изменениями:

1. Инкапсуляция предыдущих методов get и post удалена, и ее можно использовать более гибко, создав экземпляр axios, а затем экспортировав метод по умолчанию.

2. Убрано значение управления baseUrl через переменные окружения. Учитывая, что интерфейс будет иметь несколько разных доменных имен, он готов управлять доменным именем интерфейса через переменные js. Это будет подробно описано в файле api.

3. Добавлен таймаут запроса, то есть обработка статуса отключенной сети. Поговорим об идее: когда сеть отключена, отображение и скрытие компонента запроса на отключение управляется обновлением состояния сети в vuex. Подсказка об отключении обычно имеет операцию перезагрузки данных, этот шаг будет представлен в соответствующем месте позже.

4. Извлеките публичные функции, упростите код и постарайтесь обеспечить принцип единой ответственности.


Поговорим об API, учитывая требования:

1. Более модульный

2. Несколько человек более удобны для разработки, эффективно сокращая разрешение конфликтов имен.

3. Существует множество ситуаций при обработке имен доменов интерфейса.

Здесь создается новая папка API, которая содержит index.js и base.js, а также несколько интерфейсных js-файлов, разделенных по модулям. index.js — это экспорт API, base.js управляет доменным именем интерфейса, а другие js используются для управления интерфейсами каждого модуля.

Сначала поместите код index.js:

/** 
 * api接口的统一出口
 */
// 文章模块接口
import article from '@/api/article';
// 其他模块的接口……

// 导出接口
export default {    
    article,
    // ……
}

index.js — это экспорт интерфейса API, так что интерфейс API можно разделить на несколько модулей в соответствии с функциями, что способствует совместной разработке несколькими людьми.Например, один человек отвечает только за разработку одного модуля , и т.д., а также удобный интерфейс в каждом модуле.

base.js:

/**
 * 接口域名的管理
 */
const base = {    
    sq: 'https://xxxx111111.com/api/v1',    
    bd: 'http://xxxxx22222.com/api'
}

export default base;

Через base.js для управления нашим доменным именем интерфейса, независимо от того, сколько их, мы можем определить интерфейс здесь. Даже если он модифицирован, это очень удобно.

Последнее — это описание модуля интерфейса, такого как приведенный выше article.js:

/**
 * article模块接口列表
 */

import base from './base'; // 导入接口域名列表
import axios from '@/utils/http'; // 导入http中创建的axios实例
import qs from 'qs'; // 根据需求是否导入qs模块

const article = {    
    // 新闻列表    
    articleList () {        
        return axios.get(`${base.sq}/topics`);    
    },    
    // 新闻详情,演示    
    articleDetail (id, params) {        
        return axios.get(`${base.sq}/topic/${id}`, {            
            params: params        
        });    
    },
    // post提交    
    login (params) {        
        return axios.post(`${base.sq}/accesstoken`, qs.stringify(params));    
    }
    // 其他接口…………
}

export default article;

1. Непосредственно вводя наш инкапсулированный экземпляр axios, затем определяя интерфейс, вызывая экземпляр axios и возвращая его, вы можете использовать axios более гибко.Например, вы можете выполнить процесс сериализации qs для данных, отправленных во время почтового запроса.

2. Конфигурация запроса более гибкая, можно сделать другую конфигурацию под определенное требование. Что касается приоритета конфигурации, документация axios очень ясна, порядок такой: вlib/defaults.jsЗначения по умолчанию для найденной библиотеки, затемdefaultsатрибут, наконец, запрошенныйconfigпараметр. Последнее будет иметь приоритет над первым.

3. Интерфейс в стиле Restful, так же можно гибко настроить адрес API-интерфейса.

Наконец, чтобы облегчить вызов API, нам нужно смонтировать его на прототипе vue. В main.js:

import Vue from 'vue'
import App from './App'
import router from './router' // 导入路由文件
import store from './store' // 导入vuex文件
import api from './api' // 导入api接口

Vue.prototype.$api = api; // 将api挂载到vue的原型上

Затем мы можем вызвать такой интерфейс на странице, например:

methods: {    
    onLoad(id) {      
        this.$api.article.articleDetail(id, {        
            api: 123      
        }).then(res=> {
            // 执行某些操作      
        })    
    }  
}

Давайте поговорим об обработке отключения сети, вот простой пример:

<template>  
    <div id="app">    
        <div v-if="!network">      
            <h3>我没网了</h3>      
            <div @click="onRefresh">刷新</div>      
        </div>    
        <router-view/>      
    </div>
</template>

<script>
    import { mapState } from 'vuex';
    export default {  
        name: 'App',  
        computed: {    
            ...mapState(['network'])  
        },  
        methods: {    
            // 通过跳转一个空页面再返回的方式来实现刷新当前页面数据的目的
            onRefresh () {      
                this.$router.replace('/refresh')    
            }  
        }
    }
</script>

Это app.vue, вот простая демонстрация отключения. Представленный в http.js, мы будем обновлять состояние сети в vue, когда сеть отключена, поэтому здесь мы судим, нужно ли загружать отключенный компонент в соответствии с состоянием сети. При отключении сети загружаются отключенные компоненты, а компоненты соответствующей страницы не загружаются. Когда мы нажимаем, чтобы обновить, мы выполняем операцию повторной выборки данных, переходя на страницу обновления и затем немедленно возвращаясь. Итак, нам нужно создать новую страницу refresh.vue и в ееbeforeRouteEnterКрюк, а затем вернуться на текущую страницу.

// refresh.vue
beforeRouteEnter (to, from, next) {
    next(vm => {            
        vm.$router.replace(from.fullPath)        
    })    
}

Это глобальная подсказка об отключении.Конечно, ее также можно использовать в соответствии с потребностями вашего собственного проекта. Благожелательный видит благожелательный, а мудрый видит мудрость.

Если есть больше потребностей или разные потребности, вы можете внести улучшения в соответствии со своими потребностями.


Если вы чувствуете, что это полезно для вас, то добавьте в закладки ❤❤!