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文件
![](https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2019/8/19/16caa88120150850~tplv-t2oaga2asx-jj-mark:3024:0:0:0:q75.png)
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/'
})
]
},
}