这是基于 vue-cli4 实现的开发模板,其中包含项目常用的配置及组件封装,可供快速开发使用。
技术栈:vue-cli4 + webpack4 + element-ui + echarts + axios + less + postcss-px2rem + cesium + leaflet
// 安装依赖
npm install
// 本地启动
npm run dev
// 生产打包
npm run build
具体步骤如下;
1、安装依赖
npm install px2rem-loader --save-dev
2、在 vue.config.js 进行如下配置
css: {
// css预设器配置项
loaderOptions: {
postcss: {
plugins: [
require('postcss-px2rem')({
remUnit: 100
})
]
}
}
},
3、在 main.js 设置 html 跟字体大小
function initRem() {
let cale = window.screen.availWidth > 750 ? 2 : window.screen.availWidth / 375
window.document.documentElement.style.fontSize = `${100 * cale}px`
}
window.addEventListener('resize', function() {
initRem()
})
1、设置请求拦截和响应拦截
const PRODUCT_URL = 'https://xxxx.com'
const MOCK_URL = 'http://xxxx.com'
let http = axios.create({
baseURL: process.env.NODE_ENV === 'production' ? PRODUCT_URL : MOCK_URL,
})
// 请求拦截器
http.interceptors.request.use(
(config) => {
// 设置token,Content-Type
var token = sessionStorage.getItem('token')
config.headers['token'] = token
config.headers['Content-Type'] = 'application/json;charset=UTF-8'
// 请求显示loading效果
if (config.loading === true) {
vm.$loading.show()
}
return config
},
(error) => {
vm.$loading.hide()
return Promise.reject(error)
}
)
// 响应拦截器
http.interceptors.response.use(
(res) => {
vm.$loading.hide()
// token失效,重新登录
if (res.data.code === 401) {
// 重新登录
}
return res
},
(error) => {
vm.$loading.hide()
return Promise.reject(error)
}
)
2、封装 get 和 post 请求方法
function get(url, data, lodaing) {
return new Promise((resolve, reject) => {
http
.get(url)
.then(
(response) => {
resolve(response)
},
(err) => {
reject(err)
}
)
.catch((error) => {
reject(error)
})
})
}
function post(url, data, loading) {
return new Promise((resolve, reject) => {
http
.post(url, data, { loading: loading })
.then(
(response) => {
resolve(response)
},
(err) => {
reject(err)
}
)
.catch((error) => {
reject(error)
})
})
}
export { get, post }
3、把 get,post 方法挂载到 vue 实例上。
// main.js
import { get, post } from './js/ajax'
Vue.prototype.$http = { get, post }
1、添加方法到 vue 实例的原型链上
export default {
install (Vue, options) {
Vue.prototype.util = {
method1(val) {
...
},
method2 (val) {
...
},
}
}
2、在 main.js 通过 vue.use()注册
import utils from './js/utils'
Vue.use(utils)
本文提供以下函数封装
平时很多人对 vue-router 的配置可配置了 path 和 component,实现了路由跳转即可。其实 vue-router 可做的事情还有很多,比如
Vue 项目中实现路由按需加载(路由懒加载)的 3 中方式:
// 1、Vue异步组件技术:
{
path: '/home',
name: 'Home',
component: resolve => reqire(['../views/Home.vue'], resolve)
}
// 2、es6提案的import()
{
path: '/',
name: 'home',
component: () => import('../views/Home.vue')
}
// 3、webpack提供的require.ensure()
{
path: '/home',
name: 'Home',
component: r => require.ensure([],() => r(require('../views/Home.vue')), 'home')
}
本项目采用的是第二种方式,为了后续 webpack 打包优化。
由于单页面应用只有一个 html,所有页面的 title 默认是不会改变的,但是我们可以才路由配置中加入相关属性,再在路由守卫中通过 js 改变页面的 title
router.beforeEach((to, from, next) => {
document.title = to.meta.title
})
在应用中,通常会有以下的场景,比如商城:有些页面是不需要登录即可访问的,如首页,商品详情页等,都是用户在任何情况都能看到的;但是也有是需要登录后才能访问的,如个人中心,购物车等。此时就需要对页面访问进行控制了。
此外,像一些需要记录用户信息和登录状态的项目,也是需要做登录权限校验的,以防别有用心的人通过直接访问页面的 url 打开页面。
此时。路由守卫可以帮助我们做登录校验。具体如下:
1、配置路由的 meta 对象的 auth 属性
const routes = [
{
path: '/',
name: 'home',
component: () => import('../views/Home.vue'),
meta: { title: '首页', keepAlive: false, auth: false },
},
{
path: '/mine',
name: 'mine',
component: () => import('../views/mine.vue'),
meta: { title: '我的', keepAlive: false, auth: true },
},
]
2、在路由首页进行判断。当to.meta.auth
为true
(需要登录),且不存在登录信息缓存时,需要重定向去登录页面
router.beforeEach((to, from, next) => {
document.title = to.meta.title
const userInfo = sessionStorage.getItem('userInfo') || null
if (!userInfo && to.meta.auth) {
next('/login')
} else {
next()
}
})
项目中,总有一些页面我们是希望加载一次就缓存下来的,此时就用到 keep-alive 了。keep-alive 是 Vue 提供的一个抽象组件,用来对组件进行缓存,从而节省性能,由于是一个抽象组件,所以在 v 页面渲染完毕后不会被渲染成一个 DOM 元素。
1、通过配置路由的 meta 对象的 keepAlive 属性值来区分页面是否需要缓存
const routes = [
{
path: '/',
name: 'home',
component: () => import('../views/Home.vue'),
meta: { title: '首页', keepAlive: false, auth: false },
},
{
path: '/list',
name: 'list',
component: () => import('../views/list.vue'),
meta: { title: '列表页', keepAlive: true, auth: false },
},
]
2、在 app.vue 做缓存判断
<div id="app">
<router-view v-if="!$route.meta.keepAlive"></router-view>
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
</div>
首先我们先来了解一下环境变量,一般情况下我们的项目会有三个环境,本地环境(development),测试环境(test),生产环境(production),我们可以在项目根目录下建三个配置环境变量的文件.env.development,.env.test,.env.production
环境变量文件中只包含环境变量的“键=值”对:
NODE_ENV = 'production'
VUE_APP_ENV = 'production' // 只有VUE_APP开头的环境变量可以在项目代码中直接使用
除了自定义的 VUEAPP*变量之外,还有两个可用的变量:
下面开始配置我们的环境变量
1、在项目根目录中新建.env.*
NODE_ENV='development'
VUE_APP_ENV = 'development'
NODE_ENV='production'
VUE_APP_ENV = 'staging'
NODE_ENV='production'
VUE_APP_ENV = 'production'
为了在不同环境配置更多的变量,我们在 src 文件下新建一个 config/index
// 根据环境引入不同配置 process.env.NODE_ENV
const config = require('./env.' + process.env.VUE_APP_ENV)
module.exports = config
在同级目录下新建 env.development.js,env.test.js,env.production.js,在里面配置需要的变量。
以 env.development.js 为例
module.exports = {
baseUrl: 'http://localhost:8089', // 项目地址
baseApi: 'https://www.mock.com/api', // 本地api请求地址
}
2、配置打包命令
package.json 里的 scripts 不同环境的打包命令
"scripts": {
"dev": "vue-cli-service serve",
"build": "vue-cli-service build",
"test": "vue-cli-service build --mode test",
}
vue-cli3 开始,新建的脚手架都需要我们在 vue.config.js 配置我们项目的东西。主要包括
此外,还有很多属于优化打包的配置,后面会一一道来。
module.exports = {
// 部署应用包时的基本URL,默认为'/'
publicPath: './',
// 将构建好的文件输出到哪里,本司要求
outputDir: 'dist/static',
// 放置生成的静态资源(js、css、img、fonts)的目录。
assetsDir: 'static',
// 指定生成的 index.html 的输出路径
indexPath: 'index.html',
// 是否使用包含运行时编译器的 Vue 构建版本。
runtimeCompiler: false,
// 默认情况下 babel-loader 会忽略所有 node_modules 中的文件。如果你想要通过 Babel 显式转译一个依赖,可以在这个选项中列出来。
transpileDependencies: [],
// 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。
productionSourceMap: false,
// 配置css
css: {
// 是否使用css分离插件 ExtractTextPlugin
extract: true,
sourceMap: true,
// css预设器配置项
loaderOptions: {
postcss: {
// options here will be passed to postcss-loader
plugins: [
require('postcss-px2rem')({
remUnit: 100,
}),
],
},
},
// 启用 CSS modules for all css / pre-processor files.
modules: false,
},
// 是一个函数,允许对内部的 webpack 配置进行更细粒度的修改。
chainWebpack: (config) => {
// 配置别名
config.resolve.alias
.set('@', resolve('src'))
.set('assets', resolve('src/assets'))
.set('components', resolve('src/components'))
.set('views', resolve('src/views'))
config.optimization.minimizer('terser').tap((args) => {
// 去除生产环境console
args[0].terserOptions.compress.drop_console = true
return args
})
},
// 是否为 Babel 或 TypeScript 使用 thread-loader。该选项在系统的 CPU 有多于一个内核时自动启用,仅作用于生产构建。
parallel: require('os').cpus().length > 1,
devServer: {
host: '0.0.0.0',
port: 8088, // 端口号
https: false, // https:{type:Boolean}
open: false, // 配置自动启动浏览器 open: 'Google Chrome'-默认启动谷歌
// 配置多个代理
proxy: {
'/api': {
target: 'https://www.mock.com',
ws: true, // 代理的WebSockets
changeOrigin: true, // 允许websockets跨域
pathRewrite: {
'^/api': '',
},
},
},
},
}
从这里开始,我们开始进行 webpack 优化打包。首先我们来分析一下 webpack 打包性能瓶颈,找出问题所在,然后才能对症下药。此时就用到 webpack-bundle-analyzer 了。 1、安装依赖
npm install webpack-bundle-analyzer -D
2、在 vue.config.js 配置
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
configureWebpack: (config) => {
if (process.env.NODE_ENV === 'production') {
config.plugins.push(new BundleAnalyzerPlugin())
}
}
打包后,我们可以看到这样一份依赖图
从以上的界面中,我们可以得到以下信息:
所有现代浏览器都支持 gzip 压缩,启用 gzip 压缩可大幅缩减传输资源大小,从而缩短资源下载时间,减少首次白屏时间,提升用户体验。
gzip 对基于文本格式文件的压缩效果最好(如:CSS、JavaScript 和 HTML),在压缩较大文件时往往可实现高达 70-90% 的压缩率,对已经压缩过的资源(如:图片)进行 gzip 压缩处理,效果很不好。
const CompressionPlugin = require('compression-webpack-plugin')
configureWebpack: (config) => {
if (process.env.NODE_ENV === 'production') {
config.plugins.push(
new CompressionPlugin({
// gzip压缩配置
test: /\.js$|\.html$|\.css/, // 匹配文件名
threshold: 10240, // 对超过10kb的数据进行压缩
deleteOriginalAssets: false, // 是否删除原文件
})
)
}
}
svg 优点:
通常我们项目都是使用 iconfont 阿里巴巴图标矢量库,但是操作比较麻烦,每次更新都要重新下载链接。另外我们可以使 svg-sprite-loader 实现。
1、新增 SvgIcon 组件
<template>
<svg class="svg-icon" aria-hidden="true">
<use :xlink:href="iconName" />
</svg>
</template>
<script>
export default {
name: 'SvgIcon',
props: {
iconClass: {
type: String,
required: true,
},
},
computed: {
iconName() {
return `#icon-${this.iconClass}`
},
},
}
</script>
<style scoped>
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
2、全局注册组件并导入 svg
import SvgIcon from './SvgIcon.vue'
import Vue from 'vue'
// 注册到全局
Vue.component('svg-icon', SvgIcon)
const requireAll = (requireContext) => requireContext.keys().map(requireContext)
const req = require.context('./svg', false, /\.svg$/)
requireAll(req)
3、在 main.js 中引入
import './components/icon'
4、配置 vue.config.js
module.exports = {
chainWebpack: (config) => {
const svgRule = config.module.rule('svg')
svgRule.uses.clear()
svgRule.exclude.add(/node_modules/)
svgRule
.test(/\.svg$/)
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]',
})
const imagesRule = config.module.rule('images')
imagesRule.exclude.add(resolve('src/icons'))
config.module.rule('images').test(/\.(png|jpe?g|gif|svg)(\?.*)?$/)
},
}
// 原生 XHR
if (!this.match) {
this.custom.xhr.send(data)
return
}
// 改为
if (!this.match) {
this.custom.xhr.responseType = this.responseType
this.custom.xhr.send(data)
return
}
import * as echarts from 'echarts'
Vue.prototype.$echarts = echarts
2.调用
const myChart = this.$echarts.init(document.getElementById('chart'))
myChart.setOption({ ... })
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。