一些vue实用小技巧总结

3,668 阅读4分钟

每天不断的coding,缺少业务总结,感觉得自己的成长缓慢,就是现在,静下心来总结一下一些常用的vue 使用小技巧吧

1. hookEvent在可视化图表中用于监听生命周期

常规处理是在 beforeDestroy 生命周期增加销毁监听的事件,但是还可以通过 hook 监听生命周期函数。 在Vue组件中,可以用过$on, $once去监听生命周期钩子函数,如监听组件的updated钩子函数可以写成 this.$on('hook:updated', () => {})

<template>
  <div class="echarts"></div>
</template>
<script>
export default {
  mounted() {
    this.chart = echarts.init(this.$el)
    // 监听窗口缩放事件,调用相关方法:
    window.addEventListener('resize', this.$_handleResizeChart)
    // 通过hook监听组件销毁钩子函数,并取消监听事件
    this.$once('hook:beforeDestroy', () => {
      window.removeEventListener('resize', this.$_handleResizeChart)
    })
  },
  updated() {},
  created() {},
  methods: {
    $_handleResizeChart() {
      this.chart.resize()
    }
  }
}
</script>

2. 点击列表数据进入其详情页面的传参问题

在商品列表页面点击进入某个商品的详情界面,需要传一个商品ID。vue 的路由传参有两种方式:query传参 和 params动态路由传参,两者之间用法区别:

  1. query通过path切换路由;params通过name切换路由
// query通过path切换路由
<router-link :to="{path: 'Detail', query: { id: 1 }}">前往Detail页面</router-link>

// params通过name切换路由
<router-link :to="{name: 'Detail', params: { id: 1 }}">前往Detail页面</router-link>
  1. query通过this.$route.query接收参数;params通过this.$route.params接收参数
// query通过this.$route.query接收参数
created () {
    const id = this.$route.query.id;
}

// params通过this.$route.params来接收参数
created () {
    const id = this.$route.params.id;
}
  1. 传参url展示不一样
query传参的url展现方式:/detail?id=1&user=123&identity=1

params动态路由的url方式:/detail/123

需要注意的是 params 动态路由传参一定要在路由中定义参数,然后在路由跳转时候必须加上参数。例如:

// 定义的路由中,只定义一个id参数
{
    path: 'detail/:id',
    name: 'Detail',
    components: Detail
}

// 穿了参数 id 和 token; id是在路由中已经定义的参数,而token没有定义
<router-link :to="{name: 'Detail', params: { id: 1, token: '123456' }}">前往Detail页面</router-link>

// 在详情页接收
created () {
    // 以下都可以正常获取到, 但是页面刷新后,id依然可以获取,而token此时就不存在了
    const id = this.$route.params.id;
    const token = this.$route.params.token;
}

3. 小项目中可以用 Vue.observable 代替 Vuex 做状态管理

Vuex 适用于大型项目的开发,我们可以用 Vue.observable 来替代 Vuex,打造一个简单的 Vuex 状态管理,其实本质上核心思想都是对观察者模式的实现。

// 创建文件 store.js 

import Vue from 'vue'
export const store = Vue.observable({
  userInfo: {},
  roleIds: []
})
// 定义 mutations, 提供修改属性的功能:
export const mutations = {
  setUserInfo(userInfo) {
    store.userInfo = userInfo
  },
  setRoleIds(roleIds) {
    store.roleIds = roleIds
  }
}
// 在组件中引用 store.js 文件

<template>
  <div>
    {{ userInfo.name }}
  </div>
</template>
<script>
import { store, mutations } from '../store'
export default {
  computed: {
    userInfo() {
      return store.userInfo
    }
  },
  created() {
    mutations.setUserInfo({
      name: '子君'
    })
  }
}
</script>

4. axios 的应用和封装

在src 目录下我们新建 request 文件夹,新建 http.js 和 api.js 文件,用 http.js 来封装我们的axios。 通过node 环境变量来匹配默认的接口 URL 前缀。axios.defaults.baseURL设置axios的默认请求地址,设置请求头相关信息:

import axios from 'axios';
import router from '../router';
import {MessageBox, Message} from 'element-ui';
import store from '@/store/index';       // 引入Vuex状态管理
// 环境选择
if (process.env.NODE_ENV == 'development') {    
    axios.defaults.baseURL = 'https://www.development.com';
} else if (process.env.NODE_ENV == 'production') {    
    axios.defaults.baseURL = 'https://www.production.com';
}
// 设置请求超时时间:
axios.defaults.timeout = 10000;
// post 请求头设置:
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';

请求拦截 —— 在登录完成之后,将用户的token通过localStorage或者cookie存在本地,然后用户每次在进入页面的时候(即在main.js中),会首先从本地存储中读取token,如果token存在说明用户已经登陆过,则更新vuex中的token状态。然后,在每次请求接口的时候,都会在请求的header中携带token,后台人员就可以根据你携带的token来判断你的登录是否过期,如果没有携带,则说明没有登录过。

axios.interceptors.request.use(    
    config => {        
        const token = store.state.token;        
        token && (config.headers.Authorization = token);       // token 塞入请求头 
        return config;    
    },    
    error => {   
        Message.warning(error);
        return Promise.error(error);    
})

响应拦截 —— 就是服务器返回给我们的数据,我们在拿到之前可以对他进行一些处理。Toast()方法,是我引入的vant库中的toast轻提示组件。

axios.interceptors.response.use(    
    response => {   
        if (response.status === 200) {            
            return Promise.resolve(response);        
        } else {            
            return Promise.reject(response);        
        }    
    },    
    // 错误状态码可以自己扩展
    error => {            
        if (error.response.status) {            
            switch (error.response.status) {                
                // 401: 未登录               
                case 401:                    
                    router.replace({                        
                        path: '/login',                        
                        query: { 
                            redirect: router.currentRoute.fullPath 
                        }
                    });
                    break;

                // 403 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);
        }
    }    
});

5. 定时器的清理问题 —— 两种实现方法

  1. 常规操作就是在data 函数定义一个定时器,最后在 beforeDestroy() 里面销毁;
data() {            
    return {                              
        timer: null  // 定时器名称          
    }        
}

this.timer = (() => {
    // 某些操作
}, 1000)

// 销毁定时器
beforeDestroy() {
    clearInterval(this.timer);        
    this.timer = null;
}
  1. 通过$once这个事件侦听器器在定义完定时器之后的位置来清除定时器
const timer = setInterval(() =>{                    
    // 某些定时器操作                
}, 500);  

// 通过$once来监听定时器,在beforeDestroy钩子可以被清除。
this.$once('hook:beforeDestroy', () => {            
    clearInterval(timer);                                    
})