【进击的Vue(三)】使用这些让你快速开发

4,188 阅读5分钟

不要让自己的底限成为你的上限

本文主要讲以下内容,会尽可能的通过简短的例子以更清晰的方式展示出来。less的安装使用,注入less全局模块;mixin分发 Vue 组件中的可复用功能;axios封装进行模块化请求接口;vue-router懒加载、路由拦截;filter过滤器,格式化文本。

  • 使用less预编译语言代替传统css
  • mixin注入使用
  • axios封装
  • vue-router懒加载、路由拦截
  • filter过滤器

bugfix:

  • 修复loadEnv.js中导出的环境参数在webpack.config.js中异常问题。
  • 🐛: 修复eslint错误提示导致配置错误的@babel/plugin-syntax-dynamic-import

Less

less是一门css扩展的预编译语言,不使用插件的情况下需要编译成传统css。它可以使用变量、常量、嵌套、混入、函数等功能,可以更有效有弹性的写出CSS。并且有些插件在编译less过程中会自动添加对应的css前缀。

安装less

npm i less less-loader style-resources-loader -D

style-resources-loader是用于WebpackCSS处理器资源加载器,它为您的样式资源(例如)注入多个导入的模块。如variables, mixinscss, sass, scss, less, stylus

src下创建文件夹less,然后创建common.less文件,这里主要放全局的less样式,比如颜色、名称等等。示例:

@info: #2d8cf0;
@success: #19be6b;
@warning: #ff9900;
@error: #ed4014;

webpack.config.js中配置

// webpack.config.js
module.exports = {
...
  module: {
    rules: [
      {
        test: /\.less$/,
        use: [
          'style-loader', 'css-loader', 'less-loader', {
            loader: 'style-resources-loader',
            options: {
              patterns: [resolve('src/less/common.less')]
            }
          }
        ]
      }
      ...
    ]
  }
};

配置完这些就可以使用less啦,其他的同理食用。

less使用

main.vue中代码如下:

<template>
  <div class="main">main
    <div class="info">info</div>
    <div class="success">success</div>
    <div class="warning">warning</div>
    <div class="error">error</div>
  </div>
</template>
...
<style lang="less" scoped>
.main {
  .info {
    color: @info;
  }
  .success {
    color: @success;
  }
  .warning {
    color: @warning;
  }
  .error {
    color: @error;
  }
}
</style>

mixin

cn.vuejs.org/v2/guide/mi…

混入(mixin)提供了一种非常灵活的方式,来分发Vue组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。

具体例子可以看axios之mixin切换页面取消接口请求

axios

在第一篇文章【进击的Vue一】搭建Vue全家桶中已经提过了axios, 在main.js中把axios挂载在了Vue对象的原型中,直接使用不够优雅,而且如果在项目中去使用,那肯定要判断多种数据状态的返回,如果都直接在this.$http中使用会显得重复累赘。

axios封装

src目录下创建utils目录,创建request.js文件。

import axios from 'axios';

/**
 * process.env.APP_BASEURL 环境中的参数,在不同的环境下自动使用对应环境参数
 * timeout: 默认超时7秒
 * 更多信息查看:https://www.npmjs.com/package/axios
 */
const request = axios.create({
  baseURL: process.env.APP_BASEURL,
  timeout: 7000
  // headers: {
  //   common: {
  //     'Authorization': 123
  //   }
  // }
});

// 请求拦截
request.interceptors.request.use(
  config => {
    // post请求时候参数格式转换
    if (config.method === 'post' || config.method === 'POST') {
      config.data = qs.stringify(config.data);
    }

    // config是发送请求时候所带的一些内容,比如数据什么的
    return config;
  },
  error => {
    Promise.reject(error);
  }
);

request.interceptors.response.use(
  response => {
    // 处理http状态码,以及处理后端接口返回的状态值
    // const { status, data } = response;
    // if (status === 200) {
    //   return data;
    // } else {
    //   window.alert(status);
    // }
    const data = response.data;
    return data;
  },
  error => {
    // 处理请求错误
    if (error.name === 'Error') {
      // window.alert(error.message);
    }
    // return error;
  }
);

export default request;

axios使用

src目录下创建文件夹api,这个文件只用来放需要请求的接口,比如我需要请求获取数据的接口/getData

修改.env.developmentAPP_BASEURL,如果不带http|httpsaxios会默认认为这个是url后面的pathname的字符

APP_BASEURL="http://dev/"
APP_TEXT="开发测试文本"
NODE_ENV="development"
import request from '@/utils/request';

/**
 * 请求接口
 * 如果想要请求非BASE_URL以外的url,比如一个新的url: https://v1.hitokoto.cn,
 * 直接在data中重新设置url即可,会把原来的url替换掉
 * @param {Object} data
 */
export const getData = data =>
  request({
    url: '/getData',
    method: 'GET',
    ...data
  });

然后在页面使用:

import { getData } from '@/api/account/index';

export default {
  created() {
    ...
    // 使用方法一
    getData().then(res => {
      console.log('Promise then', res);
    }).catch(err => {
      console.log('Promise catch error', err);
    });

    // 使用方法二
    this.getReqData();
  },
  methods: {
    // async异步
    async getReqData() {
      // 重置替换掉原来的链接
      const data = await getData({
        baseURL: 'https://v1.hitokoto.cn',
        url: ''
      });
      console.log('async异步获取', data);
    }
  }
};

因为不存在http://dev/所以会是network error。下图所示

axios之mixin切换页面取消接口请求

注意:有的业务场景是在切换页面之后就取消axios的请求,防止在新的页面还出现上个(上上上个)请求的消息提示。参考大佬的mixin方式取消。

/**
 * @name cancelRequestMixin.js
 * @url https://juejin.cn/post/6844904023191977998
 * @description 切换页面之后取消接口调用
 */

import axios from 'axios';

const CancelToken = axios.CancelToken;

const cancelRequestMixin = {
  data() {
    return {
      axiosCancelToken: null, // cancelToken实例
      axiosCancel: null // cancel方法
    };
  },
  created() {
    // 初始化生成axiosCancelToken实例,注册axiosCancel方法
    this.axiosCancelToken = new CancelToken(c => {
      this.axiosCancel = c;
    });
  },
  beforeDestroy() {
    // 组件销毁阶段调用axiosCancel方法取消请求
    this.axiosCancel('取消请求');
  }
};

export default cancelRequestMixin;

vue-router路由懒加载、路由拦截

vue-router路由懒加载

当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。

🐛:更新内容

在使用import的时候可能会报eslint的错误Parsing error: Unexpected token importeslint,这个时候需要安装babel-eslint

npm i babel-eslint -D

然后在.eslintrc.js中配置:

module.exports = {
...
  parserOptions: {
+    parser: 'babel-eslint',
    ecmaVersion: 2018,
    sourceType: 'module'
  }
...
}

懒加载使用

component: () => import(/webpackChunkName:'name'/'@/views/name.vue')

router/index.js文件修改:

import Vue from 'vue';
import VueRouter from 'vue-router';
import main from '@/views/main.vue';

Vue.use(VueRouter);

const routes = [
  {
    path: '/',
    name: 'main',
    component: main
  },
  {
    path: '/auth',
    name: 'auth',
    meta: {
      // auth字段表示需要权限才能进入
      auth: true
    },
    component: () => import(/*webpackChunkName:'auth'*/'@/views/auth.vue')
  },
  {
    // 作为拦截后的展示页面
    path: '/403',
    name: '403',
    // 这里的import eslint一直报错,有人知道是为什么吗。。
    component: () => import(/*webpackChunkName:'403'*/'@/views/403.vue')
  },
  {
    // 所有不存在的路由都会跳转到404
    path: '*',
    name: '404',
    component: () => import(/*webpackChunkName:'404'*/'@/views/404.vue')
  }
];

const router = new VueRouter({
  routes
});

export default router;

路由拦截

增加3个页面auth.vue403.vue404.vue,内容自定义,用来展示路由拦截的例子。

  • auth.vue页面展示需要权限的内容
  • 403.vue提示没有权限

修改main.js

...
router.beforeEach((to, from, next) => {
  if (to.meta.auth) {
    if (!localStorage.getItem('token')) {
      router.push('/403');
    } else {
      next();
    }
  } else {
    next();
  }
});
...

这时候想要进入auth就无法进入,会直接进入403页面,需要在localStorage中添加token: value

filter

cn.vuejs.org/v2/guide/fi…

Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始支持)。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符号指示。

<!-- 在双花括号中 -->
{{ message | capitalize }}

<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId | formatId"></div>

创建filter.js文件

这是一个格式化的函数例子

// 时间格式化
const dateFormatter = (formatter, date) => {
  date = date ? new Date(date) : new Date();
  const Y = date.getFullYear() + '';
  const M = date.getMonth() + 1;
  const D = date.getDate();
  const H = date.getHours();
  const m = date.getMinutes();
  const s = date.getSeconds();
  return formatter
    .replace(/YYYY|yyyy/g, Y)
    .replace(/YY|yy/g, Y.substr(2, 2))
    .replace(/MM/g, (M < 10 ? '0' : '') + M)
    .replace(/DD/g, (D < 10 ? '0' : '') + D)
    .replace(/HH|hh/g, (H < 10 ? '0' : '') + H)
    .replace(/mm/g, (m < 10 ? '0' : '') + m)
    .replace(/ss/g, (s < 10 ? '0' : '') + s);
};
// 方便扩展
export { dateFormatter }

定义全局过滤器并使用

main.js修改:

...
import * as filters from './filter';

Object.keys(filters).forEach(key => {
  Vue.filter(key, filters[key]);
});
...

在代码中使用

<template>
  <div>
    <p>需要被拦截的页面</p>
    <div class="money">{{ date | dateFormatter('YYYY-MM-DD')}}</div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      date: new Date()
    }
  }
}
</script>

文章到这里就结束,vue项目搭建会上传到GitHub,需要的朋友可以自行拉取,后面的文章会以此为基础。如果有需要优化的地方或者有更好的建议可以在评论区留言(假装很多人看)。
Github仓库:github.com/heiyehk/web…
代码分支在: /tree/dev/20200624-Somefeatures