通过Vue-cli构建项目框架

542 阅读4分钟

Vue CLI 2


安装环境

npm && node

webpack4

npm install webpack webpack-cli -g

vue-cli

npm install -g vue-cli

vue init

yarn global add @vue/cli-init

创建vue

vue init webpack ***


? Project name ***
? Project description ***
? Author ***
? Vue build standalone
? Install vue-router? Yes
? Use ESLint to lint your code? Yes
? Pick an ESLint preset Standard
? Set up unit tests Yes
? Pick a test runner jest
? Setup e2e tests with Nightwatch? Yes
? Should we run `npm install` for you after the project has been created? (recommended) yarn

Vue CLI 3


安装环境

3.0.0 => node版本 8.0.0

3.10.0 => node版本 ^8.12.0 || >=9.7.

nvm 切换 node 版本

删除vue-cli2.0

npm uninstall -g vue-cli

安装vue-cli3.0

npm install -g @vue/cli

创建vue

vue create ***


? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, TS, Router, Vuex, Linter
? Use class-style component syntax? Yes
? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes
? Use history mode for router? (Requires proper server setup for index fallback in production) Yes
? Pick a linter / formatter config: Standard
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)Lint on save
? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In package.json
? Save this as a preset for future projects? No

Webpack


新建配置文件

vue.config.js


    const path = require('path')
    const webpack = require('webpack')
        
    const port = ****
    const title = '***'
        
    // node方法 相对路径转换成绝对路径
    function resolve (dir) {
        return path.join(__dirname, dir)
    }
        
    module.exports = {
        // (兼容性)[https://cli.vuejs.org/zh/guide/build-targets.html#应用] 
        // 上下文路径
        publicPath: process.env.NODE_ENV === 'production' ? '/production/' : '/dev/',
        
        // 开发环境 每次保存时 lint 代码
        lintOnSave: process.env.NODE_ENV !== 'production',
        
        configureWebpack: config => {
            if (process.env.NODE_ENV === 'production') {
                config.name = title
            } else {
                config.name = `dev-${title}`
            }
        },
        
        // 链式操作 webpack内部配置
        chainWebpack: (config) => {
            // 配置短路径
            config.resolve.alias
                .set('@', resolve('src'))
                
            // // 清除规则
            // config.module.rule('svg')
            //   .uses.clear()
            
            // 修改默认svg规则
            config.module.rule('svg')
                .exclude.add(resolve('src/icons'))
                
            // 添加svg-sprite-loader
            config.module.rule('icons')
                .test(/\.svg$/) // 设置正则
                .include.add(resolve('src/icons')) // 匹配路径
                .end() // add 完上下文进入数组,使用end回退
                .use('svg-sprite-loader') // 添加loader
                .loader('svg-sprite-loader') // 切换上下文loader
                .options({ symbolId: 'icon-[name]' }) // 指定选项
                .end()
        },
        
        // 代理
        devServer: {
            port: port,
            proxy: {
                '/*.json': {
                    target: 'http://127.0.0.1:5001'
                }
            }
        }
    }

svg


文件

新建icons文件夹 src/icons

新建svg文件夹 src/icons/svg 存放svg图标

新建index.js 文件 src/icons/index.js 自动引入svg

自动获取所有svg图标

src/icons/index.js

    /**
     * 图标自动引入
     * webpack 的 require.context(要查找的文件相对路径, 是否查找子目录,要匹配文件的正则)
     */
    const req = require.context('./svg', false, /\.svg$/)
     
    req.keys().map(req)

组件 Icon

icon.vue


<template>
    <svg :class="svgClass" :width="`${scale}rem`" :height="`${scale}rem`" :fill="color">
        <use :xlink:href="`#icon-${name}`"></use>
    </svg>
</template>

<script lang="ts">
    import Vue from 'vue'
    import { Prop, Component } from 'vue-property-decorator'
    @Component
    export default class Icon extends Vue {
        @Prop({
            type: String,
            required: true
        })private name!: any
        
        @Prop({
            type: String,
            default: ''
        })private svgClass!: string
        
        @Prop({
            type: Number,
            default: 1
        })private scale!: number
        
        @Prop({
            type: String,
            default: ''
        })private color!: string
    }
</script>

引入

main.ts


import Vue from 'vue'
import './icons/index'
import icon from '@/components/icon.vue'
Vue.component('icon', icon)

使用


<icon color="#36BD64" :scale="2" name="wx"></icon>
<icon name="wx"></icon>

数据请求 axios


引入axios

yarn add axios

拦截器

路径 src/utils/serviceUtil.js


import axios from 'axios'   // 引入

// 拦截发送请求
axios.interceptors.request.use(config => {
    return config
}, error => {
    return Promise.resove(error)
})

// 拦截应答
axios.interceptors.response.use(res => {
    let data = res.data
    let code = data.code
    if(code === 0) {
        return data
    } else {
        if(code === 错误吗) {
            <!--alert/toast-->
            return Promise.reject(data)
        }
    }
    return Promise.reject(data)
}, error => {
    let response = error.response
    if(!response) {
        <!--无网络链接-->
        return Promise.reject(error)
    }
    let data = response.data
    let status = response.status
    if(status === 401){
        <!--无权限-->
    }
    if(status === 404){
        <!--找不到页面-->
    }
    if(status === 500){
        <!--系统异常-->
    }
    <!--data.msg || 系统异常-->
    return Promise.reject(error)
})

// 封装请求
/**
 * 发送 post 请求
 *
 * @param {string} url 请求 url
 * @param {Object} data 发送的数据
 * @return {Promise}
 */
export async function post(url, data = {}) {
    return axios.post(url, data)
}

/**
 * 发送 get 请求
 *
 * @param {string} url 请求 url
 * @param {Object} data 发送的数据
 * @return {Promise}
 */
export function get(url, data = {}) {
    return axios.get(url, {
        params: data
    })
}

/**
 * 发送 update 请求
 *
 * @param {string} url 请求 url
 * @param {Object} data 发送的数据
 * @return {Promise}
 */
export function put(url, data = {}) {
    return axios.put(url, data)
}

/**
 * 发送 delete 请求
 *
 * @param {string} url 请求 url
 * @param {Object} data 发送的数据
 * @return {Promise}
 */
export function del(url, data = {}) {
    return axios.delete(url, {
        params: data
    })
}

使用时引入 import { post } from '@/utils/serviceUtil.js'

在iframe中构建form表单提交 实现导出、下载请求


export default function(path, params = {}) {
    let iframe = document.createElement('iframe')
    let dom = null
    // append to body
    document.getElementsByTagName('body')[0].appendChild(iframe)
    // get iframe window
    let win = iframe.contentWindow || iframe
    // get iframe dom
    dom = win.document
    
    let html = ['<form id="iframe-form" target="_blank"',
        'action="', path, '" method="post">']
    html.push('<input type="hidden" id="param" name="param"></form>')
    let formContent = html.join('')
    dom.open()
    dom.write(formContent)
    dom.close()
    dom.getElementById('param').value = JSON.stringify(params)
    
    // Submit the form.
    dom.getElementById('iframe-form').submit()
    iframe.onload = function () {
        setTimeout(function () {
            if (iframe.parentNode) {
                iframe.parentNode.removeChild(iframe)
            }
        }, 100)
    }
}

mock数据


模拟查询结果 mockjs

yarn add mockjs --dev

搭建模拟服务器 json-server

yarn add json-server --dev

创建mock文件

1. mock数据 mock/data

/*
* mock/data/userInfo.js
*/
const mock = require('mockjs')
const Random = mock.Random

let data = {}

module.exports = data

2. db.js


const demo = require('./data/demo')

let data = {
    demoList: []
}
module.exports = Object.assign(
    data,
    demo
)

3. 重定向路由 mock/routes.js


module.exports = {
    '/demo/list.json': '/demoList'
}

4. 搭建模拟服务器 server.js


const jsonServer = require('json-server')
const server = jsonServer.create()
const port = '5001'

// 重写routes 让route能适应我们的接口规则 xxxx.json
const routes = require('./routes')
server.use(jsonServer.rewriter(routes))

const db = require('./db')
const router = jsonServer.router(db)
const middlewares = jsonServer.defaults()

server.use(jsonServer.bodyParser)
server.use(middlewares)

server.use(function (req, res, next) {
  // get 请求把?后面的内容去掉
  if (req.method === 'GET') {
    req.url = req.url.replace(/\?.*/, '')
  }
  // post转get
  if (req.method === 'POST') {
    req.method = 'GET'
    let body = req.body
    for (const key in body.hasOwnProperty) {
      const value = body[key]
      if (typeof value === 'number') {
        body[key] = value.toString()
      }
    }
  }
  next()
})

server.use('/api', router) // 模拟api接口,就是访问api的时候给制定路由规则

server.use(router)
server.listen(port, function () {
  console.log(`JSON Server is running in http://localhost:${port}`)
})

package.json 添加启动指令

"mock": "nodemon mock/server.js"

yarn mock

缓存 service worker

安装插件

yarn add sw-register-webpack-plugin

yarn add sw-precache-webpack-plugin

vue.config.js


let SwRegisterWebpackPlugin = require('sw-register-webpack-plugin')
let SwPrecacheWebpackPlugin = require('sw-precache-webpack-plugin')

module.exports = {
    configureWebpack: {
        plugins: [
            new SwRegisterWebpackPlugin({
                filePath: path.resolve(__dirname, '../src/sw-register.js')
            }),
            new SwPrecacheWebpackPlugin({
                cacheId: '***',
                filename: 'service-worker.js',
                minify: true,
                dontCacheBustUrlsMatching: false,
                staticFileGlobs: [
                    'dist/js/**/*',
                    'dist/css/**/*',
                ],
                stripPrefix: 'dist/'
            })
        ]
    },
}