第十一章 前端开发环境搭建

一、前端开发环境
  1. Visual Studio Code
  2. Node JS
  3. Webpack:npm install webpack -g
  4. vue-cli:npm install vue-cli -g
  5. 淘宝镜像:npm install -g cnpm --registry=https://registry.npm.taobao.org
  6. Yarn:npm i yarn -g -verbose
二、创建项目
vue init webpack icupo-web
npm install
三、安装Element UI
npm install element-ui

按照官网的引入方式在main.js中引入:

import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
...
Vue.use(ElementUI)
四、安装scss
# 注意安装的版本
npm install [email protected]
npm install [email protected]

配置build/webpack.base.conf.js,注意这个不要添加

      {
        test: /\.scss$/,
        loaders: ['style', 'css', 'sass']
      }
五、安装axios与js-cookie

对axios的封装有几个好处:

  • 统一Url配置
  • 统一Api请求
  • request拦截器,加入请求头
  • response拦截器,统一错误处理,页面重定向
  • 结合vuex做全局的loading动画,或错误处理
  • 将axios封装成vue插件

5.1 安装axios和js-cookie

npm install axios
npm install js-cookie

5.2 定义全局常量文件src/utils/global.js,并挂载到Vue,通过this.global调用常量的值。

// 后台管理系统服务器地址
export const baseUrl = 'http://localhost:8001'

// 系统数据备份还原服务器地址
export const backupBaseUrl = 'http://localhost:8002'

export default {
  baseUrl,
  backupBaseUrl
}

在main.js中挂载

import global from '@/utils/global'
...
Vue.prototype.global = global

5.3 配置axios,src/http/config.js,一些默认的配置项

import { baseUrl } from '@/utils/global'

export default {
    method: 'get',
    baseUrl: baseUrl,
    Headers: {
        'Content-Type': 'application/json;charset=UTF-8'
    },
    data: {},
    timeout: 300000,
    withCredentials: true,
    responseType: 'json'
}

5.4 axios的请求与响应的处理,src/http/axios.js

  • 导入配置文件的信息到axios对象
  • 发送请求的时候携带token,如果token不存在,则重定向到登录页面
  • 统一处理响应
import axios from 'axios'
import config from './config'
import Cookies from 'js-cookie'
import router from '../router'

export default function $axios(options) {
    return new Promise((resolve, reject) => {
        const instance = axios.create({
            baseURL: config.baseUrl,
            headers: config.headers,
            timeout: config.timeout,
            withCredentials: config.withCredentials
        })
        // request 请求拦截器
        instance.interceptors.request.use(
            config => {
                let token = Cookies.get('token')
                if (token) {
                    config.headers.Authorization = 'Bearer ' + token
                } else {
                    router.push('/login')
                }
                return config
            },
            error => {
                return Promise.reject(error)
            }
        )
        // response 响应拦截器
        instance.interceptors.response.use(
            response => {
                return response.data
            },
            err => {
                if (err && err.response) {
                    switch (err.response.status) {
                        case 400:
                            err.message = '请求错误'
                            break
                        case 401:
                            err.message = '未授权,请登录'
                            break
                        case 403:
                            err.message = '拒绝访问'
                            break
                        case 404:
                            err.message = `请求地址出错: ${err.response.config.url}`
                            break
                        case 408:
                            err.message = '请求超时'
                            break
                        case 500:
                            err.message = '服务器内部错误'
                            break
                        case 501:
                            err.message = '服务未实现'
                            break
                        case 502:
                            err.message = '网关错误'
                            break
                        case 503:
                            err.message = '服务不可用'
                            break
                        case 504:
                            err.message = '网关超时'
                            break
                        case 505:
                            err.message = 'HTTP版本不受支持'
                            break
                        default:
                    }
                }
                console.error(err)
                return Promise.reject(err)
            }
        )
        // 请求处理
        instance(options).then(res => {
            resolve(res)
            return false
        }).catch(error => {
            reject(error)
        })
    })
}

5.5 挂载api,可以通过 "this.$api.模块.方法" 的方式调用API。

  • src/http/index.js
// 导入所有接口
import api from './api'

const install = Vue => {
  if (install.installed) {
    return
  }

  install.installed = true

  Object.defineProperties(Vue.prototype, {
    $api: {
      get () {
        return api
      }
    }
  })
}

export default install

  • src/http/api.js
/* 
 * 接口统一集成模块
 */
import * as login from './modules/login'
import * as user from './modules/user'
import * as dept from './modules/dept'
import * as role from './modules/role'
import * as menu from './modules/menu'
import * as dict from './modules/dict'
import * as config from './modules/config'
import * as log from './modules/log'
import * as loginlog from './modules/loginlog'


// 默认全部导出
export default {
    login,
    user,
    dept,
    role,
    menu,
    dict,
    config,
    log,
    loginlog
}
  • main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import global from './utils/global'
import api from './http'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'

Vue.config.productionTip = false

Vue.use(api)
Vue.use(ElementUI)

Vue.prototype.global = global

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: ''
})

5.6 一些api的案例

import axios from '../axios'

/* 
 * 系统配置模块
 */

// 保存
export const save = (data) => {
    return axios({
        url: '/config/save',
        method: 'post',
        data
    })
}
// 删除
export const batchDelete = (data) => {
    return axios({
        url: '/config/delete',
        method: 'post',
        data
    })
}
// 分页查询
export const findPage = (data) => {
    return axios({
        url: '/config/findPage',
        method: 'post',
        data
    })
}
import axios from '../axios'

/* 
 * 机构管理模块
 */

// 保存
export const save = (data) => {
    return axios({
        url: '/dept/save',
        method: 'post',
        data
    })
}
// 删除
export const batchDelete = (data) => {
    return axios({
        url: '/dept/delete',
        method: 'post',
        data
    })
}
// 查询机构树
export const findDeptTree = () => {
    return axios({
        url: '/dept/findTree',
        method: 'get'
    })
}
import axios from '../axios'

/* 
 * 字典管理模块
 */

// 保存
export const save = (data) => {
    return axios({
        url: '/dict/save',
        method: 'post',
        data
    })
}
// 删除
export const batchDelete = (data) => {
    return axios({
        url: '/dict/delete',
        method: 'post',
        data
    })
}
// 分页查询
export const findPage = (data) => {
    return axios({
        url: '/dict/findPage',
        method: 'post',
        data
    })
}
import axios from '../axios'

/* 
 * 操作日志模块
 */

// 删除
export const batchDelete = (data) => {
    return axios({
        url: '/log/delete',
        method: 'post',
        data
    })
}
// 分页查询
export const findPage = (data) => {
    return axios({
        url: '/log/findPage',
        method: 'post',
        data
    })
}
import axios from '../axios'

/* 
 * 系统登录模块
 */

// 登录
export const login = data => {
    return axios({
        url: 'login',
        method: 'post',
        data
    })
}

// 登出
export const logout = () => {
    return axios({
        url: 'logout',
        method: 'get'
    })
}
import axios from '../axios'

/* 
 * 操作日志模块
 */

// 删除
export const batchDelete = (data) => {
    return axios({
        url: '/loginlog/delete',
        method: 'post',
        data
    })
}
// 分页查询
export const findPage = (data) => {
    return axios({
        url: '/loginlog/findPage',
        method: 'post',
        data
    })
}
import axios from '../axios'

/* 
 * 菜单管理模块
 */

 // 保存
export const save = (data) => {
    return axios({
        url: '/menu/save',
        method: 'post',
        data
    })
}
// 删除
export const batchDelete = (data) => {
    return axios({
        url: '/menu/delete',
        method: 'post',
        data
    })
}
// 查找导航菜单树
export const findNavTree = (params) => {
    return axios({
        url: '/menu/findNavTree',
        method: 'get',
        params
    })
}
// 查找导航菜单树
export const findMenuTree = () => {
    return axios({
        url: '/menu/findMenuTree',
        method: 'get'
    })
}
import axios from '../axios'

/* 
 * 角色管理模块
 */

// 保存
export const save = (data) => {
    return axios({
        url: '/role/save',
        method: 'post',
        data
    })
}
// 删除
export const batchDelete = (data) => {
    return axios({
        url: '/role/delete',
        method: 'post',
        data
    })
}
// 分页查询
export const findPage = (data) => {
    return axios({
        url: '/role/findPage',
        method: 'post',
        data
    })
}
// 查询全部
export const findAll = () => {
    return axios({
        url: '/role/findAll',
        method: 'get'
    })
}
// 查询角色菜单集合
export const findRoleMenus = (params) => {
    return axios({
        url: '/role/findRoleMenus',
        method: 'get',
        params
    })
}
// 保存角色菜单集合
export const saveRoleMenus = (data) => {
    return axios({
        url: '/role/saveRoleMenus',
        method: 'post',
        data
    })
}
import axios from '../axios'

/* 
 * 用户管理模块
 */

// 保存
export const save = (data) => {
    return axios({
        url: '/user/save',
        method: 'post',
        data
    })
}
// 删除
export const batchDelete = (data) => {
    return axios({
        url: '/user/delete',
        method: 'post',
        data
    })
}
// 分页查询
export const findPage = (data) => {
    return axios({
        url: '/user/findPage',
        method: 'post',
        data
    })
}
// 导出Excel用户信息
export const exportUserExcelFile = (data) => {
    return axios({
        url: '/user/exportUserExcelFile',
        method: 'post',
        data
    })
}
// 查找用户的菜单权限标识集合
export const findPermissions = (params) => {
    return axios({
        url: '/user/findPermissions',
        method: 'get',
        params
    })
}
// 根据用户名查找
export const findByName = (params) => {
    return axios({
        url: '/user/findByName',
        method: 'get',
        params
    })
}
// 更新用户密码
export const updatePassword = (params) => {
    return axios({
        url: '/user/updatePassword',
        method: 'get',
        params
    })
}

3.4 登录逻辑

login() {
  this.$api.login.login().then(function(res) {
    Cookies.set('token', res.token)
    router.push('/')
  }).catch(function(res) {
    // 其它处理
  })
}
四、国际化
  1. 安装依赖
npm install [email protected]
  1. 配置src/i18n/index.js
import Vue from 'vue'
import VueI18n from 'vue-i18n'

Vue.use(VueI18n)

// 注册i18n实例并引入语言文件,文件格式等下解析
const i18n = new VueI18n({
  locale: 'zh_cn',
  messages: {
    'zh_cn': require('@/assets/languages/zh_cn.json'),
    'en_us': require('@/assets/languages/en_us.json')
  }
})

export default i18n

{
    "common": {
        "home": "首页",
        "login": "登录",
        "logout": "退出登录",
        "doc": "文档",
        "blog": "博客",
        "projectRepo": "项目",
        "myMsg": "我的消息",
        "config": "系统配置",           
        "backup": "备份",
        "restore": "还原",
        "backupRestore": "备份还原",
        "versionName": "版本名称",             
        "exit": "退出"
    },
    "action": {
        "operation": "操作",
        "add": "新增",
        "edit": "编辑",
        "delete": "删除",
        "batchDelete": "批量删除",
        "search": "查询",
        "loading": "拼命加载中",
        "submit": "提交",
        "comfirm": "确定",
        "cancel": "取消",
        "reset": "重置"
        
    }
}
{
    "common": {
        "home": "Home",
        "login": "Login",
        "logout": "Logout",
        "doc": "Document",
        "blog": "Blog",
        "projectRepo": "Project",
        "myMsg": "My Message",
        "config": "Config",
        "backup": "Backup",  
        "restore": "Restore",  
        "backupRestore": "Backup Restore",  
        "versionName": "Version",  
        "exit": "Exit"
    },
    "action": {
        "operation": "Operation",
        "add": "Add",
        "edit": "Edit",
        "delete": "Delete",
        "batchDelete": "Batch Delete",
        "search": "Search",
        "loading": "loading",
        "submit": "Submit",
        "comfirm": "Comfirm",
        "cancel": "Cancel",
        "reset": "Reset"
    }
}
import Vue from 'vue'
import App from './App'
import router from './router'
import i18n from './i18n'
import global from './utils/global'
import api from './http'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'

Vue.config.productionTip = false

Vue.use(api)
Vue.use(ElementUI)

Vue.prototype.global = global

/* eslint-disable no-new */
new Vue({
  el: '#app',
  i18n,
  router,
  components: { App },
  template: ''
})

  1. 切换语言函数:
changeLanguage(lang) {
  lang === '' ? 'zh_cn' : lang
  this.$i18n.locale = lang
}
  1. 使用方法:
# html中使用
{{$t('common.doc')}}
# js中使用
i18n.t('message.timeout')
五、全局状态
  1. 安装
npm install [email protected]
  1. 编写配置文件,src/store/index.js
import Vue from 'vue'
import vuex from 'vuex'

Vue.use(vuex);

// 引入子模块
import app from './modules/app'
import tab from './modules/tab'
import user from './modules/user'
import menu from './modules/menu'

const store = new vuex.Store({
    modules: {
        app: app,
        tab: tab,
        user: user,
        menu: menu
    }
})

export default store
  1. app.js。是属于应用内的全局性的配置,比如主题色、导航栏收缩状态等,详见注释。
export default {
  state: {
    test: false, // 测试
    menuRouteLoaded: false // 菜单和路由是否已经加载
  },
  getters: {
    test (state) {
      return state.test
    }
  },
  mutations: {
    setTest (state, payload) {
      state.test = payload.test
    },
    menuRouteLoaded (state, menuRouteLoaded) { // 改变菜单和路由的加载状态
      state.menuRouteLoaded = menuRouteLoaded
    }
  },
  actions: {
  }
}

import Vue from 'vue'
import App from './App'
import router from './router'
import i18n from './i18n'
import store from './store'
import global from './utils/global'
import api from './http'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'

Vue.config.productionTip = false

Vue.use(api)
Vue.use(ElementUI)

Vue.prototype.global = global

/* eslint-disable no-new */
new Vue({
  el: '#app',
  i18n,
  router,
  store,
  components: { App },
  template: ''
})

  1. 通过computed计算属性引入store属性,
computed: {
  ...mapState({
    ***: state => state.app.***
  })
}
  1. 通过语句this.$store.commit('mothodName', {})来修改值
六、全站配置
  1. 样式文件src/assets/css/site.css
# 内容
* {
    margin: 0;
    padding: 0;
    user-select: none;
}

# main.js中引入
import './assets/css/site.css'
  1. 全局图片文件src/assets/img/site。
  2. App.vue





  1. vscode调整tab为2个空格
# .eslintrc.js -> rules中添加
"indent": ["error", "tab"]
七、自定义图标功能

打开阿里icon,注册 >登录>图标管理>我的项目。项目名称:el-icon-third。

你可能感兴趣的:(第十一章 前端开发环境搭建)