『前端工程』—— Vue CLI3搭建项目实战操作

11,341 阅读8分钟

最近公司来了个新项目,之前Vue项目都是用Vue CLI2搭建的,现在准备用Vue CLI3搭建,谨以此文记录实战过程,如果觉得此文对您有帮助,帮忙点个赞,谢谢。持续更新中…………

一、安装Vue CLI3

  • 首先你要卸载Vue CLI2,用命令npm uninstall vue-cli -g卸载;
  • 输入命令npm install -g @vue/cli安装Vue CLI3;
  • 安装完成后,输入命令vue --version,查看Vue CLI的版本号是否是3.0以上,是代表安装成功。

二、搭建Vue项目

  • 新建文件夹,注意文件名字最好不要用中文,按下图操作;
  • 输入命令vue create flow_manage_platform,flow_manage_platform为项目名称;
  • 按上下键选择Manually select features(手动选择功能)项,default (babel, eslint)(默认安装);
  • 按上下键和回车键选择要安装的功能;
  • 使用路由器的历史模式,回车进入下一步;
  • 选择CSS预处理语言,选择less,回车进入下一步;
  • 选择In dedicated config files,将Babel、PostCSS等配置独立在package.json文件外;
  • 是否保存安装配置,直接回车进入下一步;
  • 如果出现下图就是开始进行下载Vue项目了;
  • 如果下载很慢,是网络问题,可以让电脑连你的手机网络;

三、清洁Vue项目

通过Vue CLI搭建的Vue项目中有很多无用的文件和代码,需要对其做一次清洁。

1、初始化

  1. 下载完成后,首先打开package.json文件,将
    "scripts": {
        "serve": "vue-cli-service serve",
        "build": "vue-cli-service build"
    },
    
    改成
    "scripts": {
        "dev": "vue-cli-service serve",
        "build": "vue-cli-service build"
    },
    
    因为在Vue CLI2中使用npm run dev命令启动项目。
  2. 使用npm install安装依赖,安装成功后,执行npm run dev,执行成功后在浏览器打开 http://localhost:8080/ ,页面展示如下图所示,说明Vue项目已经搭建成功。

2、清洁public文件下的index.html文件

清洁后如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
</head>
<body>
    <div id="app"></div>
</body>
</html>

3、清洁router.js文件

清洁后如下:

import Vue from 'vue'
import Router from 'vue-router';
Vue.use(Router)

function load(component) {
    return resolve => require([`./views/${component}`], resolve);
}

export default new Router({
    mode: 'history',
    base: process.env.BASE_URL,
    routes: [
        {
            path: '/',
            name: 'home',
            component: load('home')
        },
    ]
})

4、清洁App.vue文件

清洁后如下:

<template>
  <div>
    <router-view/>
  </div>
</template>

5、清洁views文件夹

删除views文件夹中的About.vue和Home.vue文件,

新建home.vue文件.内容如下:

<template>
    <div>
        欢迎使用Vue项目
    </div>
</template>

6、清洁components文件夹

删除components文件夹中的HelloWorld.vue文件。

7、清洁assets文件夹

删除assets文件夹夹中的logo.png文。

8、清洁完毕

重新执行npm run dev,执行成功后在浏览器打开 http://localhost:8080/ ,页面展示如下图所示,说明Vue项目已经清洁成功。

四、配置Vue项目

清洁完毕后,但其还是不满足我们项目开发的要求,需要我们进一步配置。

1、新建api文件夹

在src文件夹下新建api文件夹,主要放置axios的配置文件axios.js和接口文件。

2、新建mixins文件夹

在src文件夹下新建mixins文件夹,主要放置Vue混入文件。

在minxins文件夹下,新建index.js文件,主要放置全局混入的内容,

export default {
    data() {
    	return {
    	}
    },
    created(){
        alert('全局混乱引入成功')
    },
    methods: {
    }
}

在main.js 引入全局混入,

import mixins from './mixins';
Vue.mixin(mixins);

在浏览器页面可看到弹窗全局混乱引入成功,说明引入成功,

返回minxins/index.js文件中将

created(){
    alert('全局混乱引入成功')
},

删除!

3、新建service文件夹

在src文件夹下新建service文件夹,主要放置公共方法、配置文件。

4、配置assets文件夹

  1. 在assets文件夹下新建css文件夹,主要放置样式文件;
  2. 在assets文件夹下新建images文件夹,主要放置可以编译的图片文件。

5、新建router文件夹

在src文件夹下新建router文件夹,

删除src文件夹下的router.js文件,

在router文件夹中,新建index.js和routes.js文件,

index.js内容:

import Vue from 'vue';
import Router from 'vue-router';
import routes from './routes';
Vue.use(Router);

// 路由配置
const router = new Router({
   mode: 'history',
   base: process.env.BASE_URL,
   routes,
   scrollBehavior(to, from, savedPosition) {
      if (savedPosition) {
         return savedPosition;
      } else {
         return {x: 0, y: 0};
      }
   }
});

router.beforeEach((to, from, next) => {
   next();
});

router.afterEach((to, from, next) => {
   window.scrollTo(0, 0);
});

export default router;

routes.js内容:

function load(component) {
    return resolve => require([`views/${component}`], resolve);
}

const routes = [
    {
        path: '/',
        name: 'home',
        component: load('home'),
        meta: {
            title: '首页'
        }
    },
    {
        path: '*',
        redirect: {
            path: '/'
        }
    }
];
export default routes;

6、新建store文件夹

在src文件夹下新建store文件夹,放置Vuex的内容,

删除src文件夹下的store.js文件,

在store文件夹下新建module文件夹,

在module文件夹下新建demo.js文件,

const state = {
    moduleTip: '欢迎使用Vuex模块',
};

const getters = {
    moduleTip: state => state.moduleTip,
};

const mutations = {
    SET_MODULETIP(state, data) {
        state.moduleTip = data;
    },
};

const actions = {};

export default {
    state,
    getters,
    mutations,
    actions
}

在store文件夹下新建index.js文件,

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const debug = process.env.NODE_ENV !== 'production';

import demo from './module/demo';
const store = new Vuex.Store({
    strict: debug,
    state: {
        tip: '欢迎使用Vuex',
    },
    getters: {
        tip: state => state.tip,
    },
    mutations: {
        SET_TIP(state, data) {
            state.tip = data;
        },
    },
    actions: {

    },
    modules: {
        demo,
    }
});

export default store;

在minxins/index.js文件写入,

import { mapGetters } from 'vuex';
export default {
    data() {
        return {
        }
    },
    computed: {
        ...mapGetters(['tip','moduleTip'])
    },
    mounted(){
    },
    methods: {
    }
}

在views/home.vue文件写入,

<template>
    <div>
        欢迎使用Vue项目
        {{tip}}
        {{moduleTip}}
    </div>
</template>

在浏览器页面上显示:

欢迎使用Vue项目 欢迎使用Vuex 欢迎使用Vuex模块

说明全局Vuex和模块Vuex配置成功。

7、配置文件别名

在Vue CLI3中,项目的webpack配置是要在根目录下新建vue.config.js来配置。

在vue.config.js文件中配置内容如下:

const path = require('path');
function resolve(dir) {
    return path.resolve(__dirname, dir)
}
module.exports = {
    configureWebpack: {
        resolve: {
            extensions: ['.js', '.vue', '.json'],
            alias: {
                '@': resolve('src'),
                'assets': resolve('src/assets'),
                'css':resolve('src/assets/css'),
                'images':resolve('src/assets/images'),
                'views': resolve('src/views'),
                'components':resolve('src/components'),
                'api':resolve('src/api'),
                'mixins':resolve('src/mixins'),
                'store': resolve('src/store'),
                'service':resolve('src/service'),
            }
        }
    },
}

8、关闭source map

关闭source map有两个好处

  1. 减少打包编译的时间;
  2. 避免在生产环境中用F12开发者工具在Sources中看到源码。

在vue.config.js文件中配置内容如下:

module.exports = {
    productionSourceMap: false,
}

9、配置devServer项

  1. 固定端口

    有时候后端设置跨域白名单时候要固定端口,前端也要配合固定端口,port: 8036,

  2. 开启热更新

    hot: true,

  3. 固定打开浏览器

    open: 'Google Chrome',

在vue.config.js文件中配置内容如下:

module.exports = {
    devServer:{
        port: 8036,
        hot: true,
        open: 'Google Chrome'
    }
}

四、Reset CSS样式

在src/assets/css文件夹下新建base.less文件,

文件内容如下: base.less

在main.js文件写入

import 'css/base/base.less';

五、引入Element-Ui组件库

  1. 安装依赖包

    执行npm i element-ui -save命令

  2. 引入样式

    在main.js中new Vue前插入以下代码

    import 'element-ui/lib/theme-chalk/index.css';
    
  3. 完整引入Element-Ui组件库(二选一)

    如果Element-Ui中的大部分组件,项目中都有使用到,建议完整引入

    在main.js中new Vue前插入以下代码

    import ElementUI from 'element-ui';
    Vue.use(ElementUI);
    
  4. 按需引入Element-Ui组件库(二选一)

    以引入Button按钮组件为例

    • 在main.js中new Vue前插入以下代码

      //注册element-ui组件
      import {
          Button,
      } from 'element-ui';
      
      const components = [
          Button,
      ];
      for (let k of components) {
          Vue.use(k);
      }
      
    • 在src/views/home.vue文件写入

      <template>
          <div>
              欢迎使用Vue项目
              {{tip}}
              {{moduleTip}}
              <el-button>饿了吗Button组件</el-button>
          </div>
      </template>
      
    • 如果在浏览器页面上出现如以下图片,则说明按需引入成功

5. 自定义主题(批量改变element组件样式)

  • 因为element的样式是用sass写的,所以要先安装sass 和 sass-loader两个插件,执行npm i sass sass-loader -D命令;

  • 在src/assets/css/base文件夹中,新建element_theme.scss 和 element_var.scss(主题样式各种变量);

  • 在main.js中写入import 'css/base/element_theme.scss';

  • 在src/views/home.vue文件写入

    <template>
        <div>
            欢迎使用Vue项目
            {{tip}}
            {{moduleTip}}
            <el-button type="primary">饿了吗Button组件</el-button>
        </div>
    </template>
    
  • 按F12打开开发者工具,审查元素可以看下图所示

  • 在element_var.scss文件中搜索#4574d0,可以看到下图所示,将其替换成$--color-primary: red !default;

  • 浏览器页面展示所下图所示,即自定义主题成功

六、安装Jquery Js库

虽然Vue是以数据操作DOM。但是在某些情况下用Jquery还是比较方便的,比如获取某元素的高度,动态变化表格的高度使其固定头部。

  • 执行命令npm i Jquery -save
  • 在vue.config.js文件中新增代码:
    const webpack = require('webpack');
    module.exports = {
        configureWebpack: {
            plugins: [
                new webpack.ProvidePlugin({
                    $:"jquery",
                    jQuery:"jquery",
                    "windows.jQuery":"jquery"
                })
            ]
        },
    }
    
  • 在main.js文件中新增代码:
    import $ from 'jquery';
    
  • 在src/views/home.vue文件中新增代码做验证:
      <template>
          <div class="p-wrap">
              欢迎使用Vue项目
              {{tip}}
              {{moduleTip}}
              <el-button type="primary">饿了吗Button组件</el-button>
          </div>
      </template>
      <script>
      export default {
          mounted(){
               $(".p-wrap").click(function(){
                  alert('Jquery安装成功')
              });
          }
      }
      </script>
    
  • 点击浏览器页面文字部分弹出“Jquery安装成功”的弹窗,说明Jquery Js库安装成功

七、关于less-loader的坑

在对应less-loader的版本为4.1.0时,安装less的版本应该为2.7.3,不然会出现

ERROR in ./src/home/index.less
(./node_modules/_css-loader@1.0.0@css-loader!./
node_modules/_less-loader@4.1.0@less-loader/dist/cjs.js!./src/home/index.less)
Module build failed (from ./node_modules/_less-loader@4.1.0@less-loader/dist/cjs.js):

报错

八、安装js-cookie 插件

  • 这个插件主要用于浏览器cookie的存储、获取、移除,最常用是存储登录成功后后端返回的token。
  • 执行命令npm i js-cookie --save
  • 在src/service文件下新建cookie.js文件,在文件中写入
    import Cookies from 'js-cookie';
    const TokenKey = 'token';
    export function getToken() {
       return Cookies.get(TokenKey);
    }
    export function setToken(token, time) {
       return Cookies.set(TokenKey, token, {
          expires: time,
          path: '/'
       });
    }
    export function removeToken() {
       return Cookies.remove(TokenKey);
    }
    

九、配置axios

  • 执行命令npm i axios -save

  • 在src/api文件夹下新建axios.js文件

  • 在axios.js配置axios

    • 创建新的axios实例,axios.create([config]),

      主要配置

      timeout指定请求超时的毫秒数(0 表示无超时时间)

      headers自定义请求头,这部分配置要和后端一致,否则后端会接收不到你的参数

      baseURL配置后端的请求地址,将自动加在 url 前面,使url可用相对地址

      import axios from 'axios';
      const service = axios.create({
          timeout: 60000,
          headers: {
              'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
              "X-Requested-With": "XMLHttpRequest",
          },
          baseURL: 'xxx',
      });
      

      上面配置,前端传给后端的数据格式为Form格式或JSON格式,例:

      //Form格式
      let data = new URLSearchParams();
      data.append("page", currentPage);
      //JSON格式
      let obj = new Object;
      obj.page=currentPage;
      

      如果后端使JAVA,一般使用Form格式

      但是要传二进制数据给后端时,要用FormData格式,例:

      let data = new FormData();
      data.append("page", currentPage);
      

      那么还要创建一个新的axios实例

      const serviceForm = axios.create({
          timeout: 60000,
          headers: {
              'Content-Type': 'multipart/form-data; charset=UTF-8',
              "X-Requested-With": "XMLHttpRequest",
          },
          baseURL: 'xxx',
      });
      
    • 配置http request 拦截器

      在请求被 then 或 catch 处理前拦截它们

      axios.interceptors.request.use(function (config) {
          // 在发送请求之前做些什么
          return config;
        }, function (error) {
          // 对请求错误做些什么
          return Promise.reject(error);
        });
      

      一般项目中都是在这里给请求头部带上token,按如下配置

      import { getToken } from 'service/cookie';
      
      //http request 拦截器 在发送请求之前做些什么
      let request = function (config) {
          const token = getToken();
          if (token) { // 判断是否存在token,如果存在的话,则每个http header都加上token
              config.headers.token = token;
          }
          return config;
      };
      

      以上config.headers.token中token是后端告知要在头部添加token的参数,后端也要配置headers允许带token的参数,否则会造成跨域。

      再写个请求错误时候拦截

      //http request 拦截器 在请求错误时做些什么
      let request_err = function (err) {
          return Promise.reject(err);
      };
      

      给每个实例使用这些request拦截器

      service.interceptors.request.use(request, request_err);
      serviceForm.interceptors.request.use(request, request_err);
      
    • 配置http response 拦截器

      在响应被 then 或 catch 处理前拦截它们。

      // 添加响应拦截器
      axios.interceptors.response.use(function (response) {
              // 对响应数据做点什么
              return response;
          }, function (error) {
              // 对响应错误做点什么
              return Promise.reject(error);
          });
      

      一般项目中都是在这里给返回数据做预处理和对报错批量处理,类似提示。

      响应成功前做拦截处理

      import { Message } from 'element-ui';
      
      let response = function (res) {
          const data = res.data;
          const message = `${data.code}--${data.msg}` || '未知错误'
          if (res.status == 200) {
              if (data.code == 200) {
                  return data;
              } else {
                  Message({
                      message: message,
                      type: 'error',
                  })
              }
          }
      };
      

      以上data.codedata.msg这些都是要和后端协商

      响应失败前拦截处理

      let response_err = function (err) {
          if (err.response) {
              const data = err.response.data;
              const message = `${data.code}--${data.msg}` || '未知错误'
              Message({
                  message: message,
                  type: 'error',
              })
          }
          return Promise.reject(err);
      };
      

      给每个实例使用这些response拦截器

      service.interceptors.response.use(response, response_err);
      serviceForm.interceptors.response.use(response, response_err);
      

      最后对外暴露axios的两个实例

      有两种方法

      一种是直接挂在window对象下,这样写可以在其它文件中直接使用service和serviceForm

      window.service = service;
      window.serviceForm = serviceForm;
      

      一种是用export导出,这样写在其它文件中使用要先import {service,serviceForm} from 'api/axios'

      export {service,serviceForm}
      
    • 在main.js文件中引入axios配置文件

      import 'api/axios'
      
    • 在src/api文件夹下新建demo.js文件,在里面实例post、get、get带参数的请求写法

      /* get请求 */
      export function get() {
          return service.get('api/get');
      }
      /* get请求带参数 */
      export function get2(data) {
      	return service.get('api/get2', {
      		params: data
          });
      }
      /* post请求带参数 */
      export function post(data) {
      	return service.post('api/post', data);
      }
      
    • 在src/views/home.vue中使用

      import * as API from 'api/demo';
      export default {
          methods: {
              get() {
                  API.get().then(res => {
                  }).catch(err => {
                  })
              },
              get2() {
                  let data =new URLSearchParams;
                  data.append('param',1)
                  API.get2(data).then(res => {
                  }).catch(err => {
                  })
              },
              post() {
                  let data =new URLSearchParams;
                  data.append('param',1)
                  API.post(data).then(res => {
                  }).catch(err => {
                  })
              }
          }
      }
      

最后

附上项目地址