vue全家桶系列之基本知识点(开箱即用vue全家桶)
vue全家桶系列之基本知识点(开箱即用vue全家桶)"scripts":{ "serve":"vue-cli-serviceserve--open" "stage":"vue-cli-servicebuild--modestaging" "build":"vue-cli-servicebuild" }配置介绍 以 VUE_APP_ 开头的变量,在代码中可以通过 process.env.VUE_APP_ 访问。 比如 VUE_APP_ENV = 'development' 通过process.env.VUE_APP_ENV 访问。 除了 VUE_APP_* 变量之外,在你的应用代码中始终可用的还有两个特殊的变量NODE_ENV 和BASE_URLgitclonehttps://github.com/sun
作者:花花小仙女
转发链接:https://mp.weixin.qq.com/s/c9uAYkWJu-zvKfELh_3V0A
前言基于 vue-cli4.0 webpack 4 vant ui sass rem 适配方案 axios 封装,构建手机端模板脚手架,开箱即用,让开发变得更简单。
先夸一下自己,收到了很多人的好评。这次好好整理一文,你们的鼓励就是我前进的动力。
github:https://github.com/sunniejs/vue-h5-template
Node 版本要求Vue CLI它需要 Node.js 8.9 或更高版本 (推荐 8.11.0 )。你可以使用 nvm 或nvm-windows 在同一台电脑中管理多个 Node 版本。
本示例 Node.js 12.14.1
启动项目gitclonehttps://github.com/sunniejs/vue-h5-template.git
cdvue-h5-template
npminstall
npmrunserve
目录
- √ Vue-cli4
- √ 配置多环境变量
- √ rem 适配方案
- √ VantUI 组件按需加载
- √ Sass 全局样式
- √ Vuex 状态管理
- √ Axios 封装及接口管理
- √ Vue-router
- √ Webpack 4 vue.config.js 基础配置
- √ 配置 proxy 跨域
- √ 配置 alias 别名
- √ 配置 打包分析
- √ 配置 externals 引入 cdn 资源
- √ 去掉 console.log
- √ splitChunks 单独打包第三方模块
- √ 添加 IE 兼容
- √ Eslint Pettier 统一开发规范
package.json 里的 scripts 配置 serve stage build,通过 --mode xxx 来执行不同环境
- 通过 npm run serve 启动本地 执行 development
- 通过 npm run stage 打包测试 执行 staging
- 通过 npm run build 打包正式 执行 production
"scripts":{
"serve":"vue-cli-serviceserve--open"
"stage":"vue-cli-servicebuild--modestaging"
"build":"vue-cli-servicebuild"
}
配置介绍
以 VUE_APP_ 开头的变量,在代码中可以通过 process.env.VUE_APP_ 访问。 比如 VUE_APP_ENV = 'development' 通过process.env.VUE_APP_ENV 访问。 除了 VUE_APP_* 变量之外,在你的应用代码中始终可用的还有两个特殊的变量NODE_ENV 和BASE_URL
在项目根目录中新建.env.*
- .env.development 本地开发环境配置
NODE_ENV='development'
#muststartwithVUE_APP_
VUE_APP_ENV='development'
- .env.staging 测试环境配置
NODE_ENV='production'
#muststartwithVUE_APP_
VUE_APP_ENV='staging'
- .env.production 正式环境配置
NODE_ENV='production'
#muststartwithVUE_APP_
VUE_APP_ENV='production'
这里我们并没有定义很多变量,只定义了基础的 VUE_APP_ENV development staging production变量我们统一在 src/config/env.*.js 里进行管理。
这里有个问题,既然这里有了根据不同环境设置变量的文件,为什么还要去 config 下新建三个对应的文件呢?修改起来方便,不需 要重启项目,符合开发习惯。
config/index.js
//根据环境引入不同配置process.env.NODE_ENV
constconfig=require('./env.' process.env.VUE_APP_ENV)
module.exports=config
配置对应环境的变量,拿本地环境文件 env.development.js 举例,用户可以根据需求修改
//本地环境配置
module.exports={
title:'vue-h5-template'
baseUrl:'http://localhost:9018' //项目地址
baseapi:'https://test.xxx.com/api' //本地api请求地址
APPID:'xxx'
APPSECRET:'xxx'
}
根据环境不同,变量就会不同了
//根据环境不同引入不同baseApi地址
import{baseApi}from'@/config'
console.log(baseApi)
✅ rem 适配方案
不用担心,项目已经配置好了 rem 适配 下免仅做介绍:
Vant 中的样式默认使用px作为单位,如果需要使用rem单位,推荐使用以下两个工具:
- postcss-pxtorem 是一款 postcss 插件,用于将单位转化为 rem
- lib-flexible 用于设置 rem 基准值
下面提供了一份基本的 postcss 配置,可以在此配置的基础上根据项目需求进行修改
//https://github.com/michael-ciniawsky/postcss-load-config
module.exports={
plugins:{
autoprefixer:{
overrideBrowserslist:['Android4.1' 'iOS7.1' 'Chrome>31' 'ff>31' 'ie>=8']
}
'postcss-pxtorem':{
rootValue:37.5
propList:['*']
}
}
}
更多详细信息:vant
新手必看,老鸟跳过
很多小伙伴会问我,适配的问题。
我们知道 1rem 等于html 根元素设定的 font-size 的 px 值。Vant UI 设置 rootValue: 37.5 你可以看到在 iPhone 6 下 看到 (1rem 等于 37.5px):
<htmldata-dpr="1"style="font-size:37.5px;"></html>
切换不同的机型,根元素可能会有不同的font-size。当你写 css px 样式时,会被程序换算成 rem 达到适配。
因为我们用了 Vant 的组件,需要按照 rootValue: 37.5 来写样式。
举个例子:设计给了你一张 750px * 1334px 图片,在 iphone6 上铺满屏幕 其他机型适配。
- 当rootValue: 70 样式 width: 750px;height: 1334px; 图片会撑满 iPhone6 屏幕,这个时候切换其他机型,图片也会跟着撑 满。
- 当rootValue: 37.5 的时候,样式 width: 375px;height: 667px; 图片会撑满 iPhone6 屏幕。
也就是 iphone 6 下 375px 宽度写 CSS。其他的你就可以根据你设计图,去写对应的样式就可以了。
当然,想要撑满屏幕你可以使用 100%,这里只是举例说明。
<imgclass="image"src="https://imgs.solui.cn/weapp/logo.png"/>
<style>/*rootValue:75*/
.image{
width:750px;
height:1334px;
}
/*rootValue:37.5*/
.image{
width:375px;
height:667px;
}</style>
✅ VantUI 组件按需加载
项目采 用 Vant 自动按需引入组件 (推荐) 下 面安装插件介绍:
babel-plugin-import 是一款 babel 插件,它会在编译过程中将import 的写法自动转换为按需引入的方式
安装插件npmibabel-plugin-import-D
在babel.config.js 设置
//对于使用babel7的用户,可以在babel.config.js中配置
constplugins=[
[
'import'
{
libraryName:'vant'
libraryDirectory:'es'
style:true
}
'vant'
]
]
module.exports={
presets:[['@vue/cli-plugin-babel/preset' {useBuiltIns:'usage' corejs:3}]]
plugins
}
使用组件
项目在 src/plugins/vant.js 下统一管理组件,用哪个引入哪个,无需在页面里重复引用
//按需全局引入vant组件
importVuefrom'vue'
import{Button List Cell Tabbar TabbarItem}from'vant'
Vue.use(Button)
Vue.use(Cell)
Vue.use(List)
Vue.use(Tabbar).use(TabbarItem)
✅ Sass 全局样式
首先 你可能会遇到 node-sass 安装不成功,别放弃多试几次!!!
目录结构,在 src/assets/css/文件夹下包含了三个文件
├──assets
│├──css
││├──index.scss#全局通用样式
││├──mixin.scss#全局mixin
││└──variables.scss#全局变量
每个页面自己对应的样式都写在自己的 .vue 文件之中
<stylelang="scss">/*globalstyles*/</style>
<stylelang="scss"scoped>/*localstyles*/</style>
vue.config.js 配置注入 sass 的 mixin variables 到全局,不需要手动引入 配置$cdn通过变量形式引入 cdn 地址
constIS_PROD=['production' 'prod'].includes(process.env.NODE_ENV)
constdefaultSettings=require('./src/config/index.js')
module.exports={
css:{
extract:IS_PROD
sourceMap:false
loaderOptions:{
scss:{
//注入`sass`的`mixin``variables`到全局 $cdn可以配置图片cdn
//详情:https://cli.vuejs.org/guide/css.html#passing-options-to-pre-processor-loaders
prependData:`
@import"assets/css/mixin.scss";
@import"assets/css/variables.scss";
$cdn:"${defaultSettings.$cdn}";
`
}
}
}
}
在 main.js 中引用全局样式(发现在上面的,prependData 里设置@import "assets/css/index.scss";并没有应用全局样式这里在 main.js 引入)
设置 js 中可以访问 $cdn .vue 文件中使用this.$cdn访问
//引入全局样式
import'@/assets/css/index.scss'
//设置js中可以访问$cdn
//引入cdn
import{$cdn}from'@/config'
Vue.prototype.$cdn=$cdn
在 css 和 js 使用
<script>console.log(this.$cdn)</script>
<stylelang="scss"scoped>.logo{
width:120px;
height:120px;
background:url($cdn '/weapp/logo.png')center/containno-repeat;
}</style>
✅ Vuex 状态管理
目录结构
├──store
│├──modules
││└──app.js
│├──index.js
│├──getters.js
main.js 引入
importVuefrom'vue'
importAppfrom'./App.vue'
importstorefrom'./store'
newVue({
el:'#app'
router
store
render:h=>h(App)
})
使用
<script>import{mapGetters}from'vuex'
exportdefault{
computed:{
...mapGetters(['userName'])
}
methods:{
//Action通过store.dispatch方法触发
doDispatch(){
this.$store.dispatch('setUserName' '真乖,赶紧关注公众号,组织都在等你~')
}
}
}</script>
✅ Vue-router
本案例采用 hash 模式,开发者根据需求修改 mode base
注意:如果你使用了 history 模式,vue.config.js 中的 publicPath 要做对应的修改
importVuefrom'vue'
importRouterfrom'vue-router'
Vue.use(Router)
exportconstrouter=[
{
path:'/'
name:'index'
component:()=>import('@/views/home/index') //路由懒加载
meta:{
title:'首页' //页面标题
keepAlive:false//keep-alive标识
}
}
]
constcreateRouter=()=>
newRouter({
//mode:'history' //如果你是history模式需要配置vue.config.jspublicPath
//base:'/app/'
scrollBehavior:()=>({y:0})
routes:router
})
exportdefaultcreateRouter()
更多:Vue Router
✅ Axios 封装及接口管理utils/request.js 封装 axios 开发者需要根据后台接口做修改。
- service.interceptors.request.use 里可以设置请求头,比如设置 token
- config.hideloading 是在 api 文件夹下的接口参数里设置,下文会讲
- service.interceptors.response.use 里可以对接口返回数据处理,比如 401 删除本地信息,重新登录
importaxiosfrom'axios'
importstorefrom'@/store'
import{Toast}from'vant'
//根据环境不同引入不同api地址
import{baseApi}from'@/config'
//createanaxiosinstance
constservice=axios.create({
baseURL:baseApi //url=baseapiurl requesturl
withCredentials:true //sendcookieswhencross-domainrequests
timeout:5000//requesttimeout
})
//request拦截器requestinterceptor
service.interceptors.request.use(
config=>{
//不传递默认开启loading
if(!config.hideloading){
//loading
Toast.loading({
forbidClick:true
})
}
if(store.getters.token){
config.headers['X-Token']=''
}
returnconfig
}
error=>{
//dosomethingwithrequesterror
console.log(error)//fordebug
returnPromise.reject(error)
}
)
//respone拦截器
service.interceptors.response.use(
response=>{
Toast.clear()
constres=response.data
if(res.status&&res.status!==200){
//登录超时 重新登录
if(res.status===401){
store.dispatch('FedLogOut').then(()=>{
location.reload()
})
}
returnPromise.reject(res||'error')
}else{
returnPromise.resolve(res)
}
}
error=>{
Toast.clear()
console.log('err' error)//fordebug
returnPromise.reject(error)
}
)
exportdefaultservice
接口管理
在src/api 文件夹下统一管理接口
- 你可以建立多个模块对接接口 比如 home.js 里是首页的接口这里讲解user.js
- url 接口地址,请求的时候会拼接上 config 下的 baseApi
- method 请求方法
- data 请求参数 qs.stringify(params) 是对数据系列化操作
- hideloading 默认 false 设置为 true 后,不显示 loading ui 交互中有些接口不需要让用户感知
importqsfrom'qs'
//axios
importrequestfrom'@/utils/request'
//userapi
//用户信息
exportfunctiongetUserInfo(params){
returnrequest({
url:'/user/userinfo'
method:'get'
data:qs.stringify(params)
hideloading:true//隐藏loading组件
})
}
如何调用
//请求接口
import{getUserInfo}from'@/api/user.js'
constparams={user:'sunnie'}
getUserInfo(params)
.then(()=>{})
.catch(()=>{})
✅ Webpack 4 vue.config.js 基础配置
如果你的 Vue Router 模式是 hash
publicPath:'./'
如果你的 Vue Router 模式是 history 这里的 publicPath 和你的 Vue Routerbase 保持一直
publicPath:'/app/'
constIS_PROD=['production' 'prod'].includes(process.env.NODE_ENV)
module.exports={
publicPath:'./' //署应用包时的基本 URL。vue-router hash 模式使用
// publicPath:'/app/' //署应用包时的基本 URL。 vue-router history模式使用
outputDir:'dist' //生产环境构建文件的目录
assetsDir:'static' //outputDir的静态资源(js、css、img、fonts)目录
lintOnSave:false
productionSourceMap:false //如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。
devServer:{
port:9020 //端口号
open:false //启动后打开浏览器
overlay:{
//当出现编译器错误或警告时,在浏览器中显示全屏覆盖层
warnings:false
errors:true
}
//...
}
}
✅ 配置 proxy 跨域
如果你的项目需要跨域设置,你需要打开 vue.config.js proxy 注释 并且配置相应参数
注意:你还需要将 src/config/env.development.js 里的 baseApi 设置成 '/'
module.exports={
devServer:{
//....
proxy:{
//配置跨域
'/api':{
target:'https://test.xxx.com' //接口的域名
//ws:true //是否启用websockets
changOrigin:true //开启代理,在本地创建一个虚拟服务端
pathRewrite:{
'^/api':'/'
}
}
}
}
}
使用 例如: src/api/home.js
exportfunctiongetUserInfo(params){
returnrequest({
url:'/api/userinfo'
method:'get'
data:qs.stringify(params)
})
}
✅ 配置 alias 别名
constpath=require('path')
constresolve=dir=>path.join(__dirname dir)
constIS_PROD=['production' 'prod'].includes(process.env.NODE_ENV)
module.exports={
chainWebpack:config=>{
//添加别名
config.resolve.alias
.set('@' resolve('src'))
.set('assets' resolve('src/assets'))
.set('api' resolve('src/api'))
.set('views' resolve('src/views'))
.set('components' resolve('src/components'))
}
}
✅ 配置 打包分析
constBundleAnalyzerPlugin=require('webpack-bundle-analyzer').BundleAnalyzerPlugin
module.exports={
chainWebpack:config=>{
//打包分析
if(IS_PROD){
config.plugin('webpack-report').use(BundleAnalyzerPlugin [
{
analyzerMode:'static'
}
])
}
}
}
npmrunbuild
✅ 配置 externals 引入 cdn 资源
这个版本 CDN 不再引入,我测试了一下使用引入 CDN 和不使用 不使用会比使用时间少。网上不少文章测试 CDN 速度快,这个开发者可 以实际测试一下。
另外项目中使用的是公共 CDN 不稳定,域名解析也是需要时间的(如果你要使用请尽量使用同一个域名)
因为页面每次遇到<script>标签都会停下来解析执行,所以应该尽可能减少<script>标签的数量 HTTP请求存在一定的开销,100K 的文件比 5 个 20K 的文件下载的更快,所以较少脚本数量也是很有必要的
暂时还没有研究放到自己的 cdn 服务器上。
constdefaultSettings=require('./src/config/index.js')
constname=defaultSettings.title||'vuemobiletemplate'
constIS_PROD=['production' 'prod'].includes(process.env.NODE_ENV)
//externals
constexternals={
vue:'Vue'
'vue-router':'VueRouter'
vuex:'Vuex'
vant:'vant'
axios:'axios'
}
//CDN外链,会插入到index.html中
constcdn={
//开发环境
dev:{
css:[]
js:[]
}
//生产环境
build:{
css:['https://cdn.jsdelivr.net/npm/vant@2.4.7/lib/index.css']
js:[
'https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.min.js'
'https://cdn.jsdelivr.net/npm/vue-router@3.1.5/dist/vue-router.min.js'
'https://cdn.jsdelivr.net/npm/axios@0.19.2/dist/axios.min.js'
'https://cdn.jsdelivr.net/npm/vuex@3.1.2/dist/vuex.min.js'
'https://cdn.jsdelivr.net/npm/vant@2.4.7/lib/index.min.js'
]
}
}
module.exports={
configureWebpack:config=>{
config.name=name
//为生产环境修改配置...
if(IS_PROD){
//externals
config.externals=externals
}
}
chainWebpack:config=>{
/**
*添加CDN参数到htmlWebpackPlugin配置中
*/
config.plugin('html').tap(args=>{
if(IS_PROD){
args[0].cdn=cdn.build
}else{
args[0].cdn=cdn.dev
}
returnargs
})
}
}
在 public/index.html 中添加
<!--使用CDN的CSS文件-->
<%for(variin
htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.css){%>
<linkhref="<%=htmlWebpackPlugin.options.cdn.css[i]%>"rel="preload"as="style"/>
<linkhref="<%=htmlWebpackPlugin.options.cdn.css[i]%>"rel="stylesheet"/>
<%}%>
<!--使用CDN加速的JS文件,配置在vue.config.js下-->
<%for(variin
htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.js){%>
<scriptsrc="<%=htmlWebpackPlugin.options.cdn.js[i]%>"></script>
<%}%>
✅ 去掉 console.log
保留了测试环境和本地环境的 console.log
npmi-Dbabel-plugin-transform-remove-console
在 babel.config.js 中配置
//获取VUE_APP_ENV非NODE_ENV,测试环境依然console
constIS_PROD=['production' 'prod'].includes(process.env.VUE_APP_ENV)
constplugins=[
[
'import'
{
libraryName:'vant'
libraryDirectory:'es'
style:true
}
'vant'
]
]
//去除console.log
if(IS_PROD){
plugins.push('transform-remove-console')
}
module.exports={
presets:[['@vue/cli-plugin-babel/preset' {useBuiltIns:'entry'}]]
plugins
}
✅ splitChunks 单独打包第三方模块
module.exports={
chainWebpack:config=>{
config.when(IS_PROD config=>{
config
.plugin('ScriptExtHtmlWebpackPlugin')
.after('html')
.use('script-ext-html-webpack-plugin' [
{
//将runtime作为内联引入不单独存在
inline:/runtime\..*\.js$/
}
])
.end()
config.optimization.splitChunks({
chunks:'all'
cacheGroups:{
//cacheGroups下可以可以配置多个组,每个组根据test设置条件,符合test条件的模块
commons:{
name:'chunk-commons'
test:resolve('src/components')
minChunks:3 //被至少用三次以上打包分离
priority:5 //优先级
reuseExistingChunk:true//表示是否使用已有的 chunk,如果为 true 则表示如果当前的 chunk 包含的模块已经被抽取出去了,那么将不会重新生成新的。
}
node_vendors:{
name:'chunk-libs'
chunks:'initial' //只打包初始时依赖的第三方
test:/[\\/]node_modules[\\/]/
priority:10
}
vantUI:{
name:'chunk-vantUI' //单独将vantUI拆包
priority:20 //数字大权重到,满足多个cacheGroups的条件时候分到权重高的
test:/[\\/]node_modules[\\/]_?vant(.*)/
}
}
})
config.optimization.runtimeChunk('single')
})
}
}
✅ 添加 IE 兼容
之前的方式 会报 @babel/polyfill is deprecated. Please use required parts of core-js andregenerator-runtime/runtime separately
@babel/polyfill 废弃,使用 core-js 和 regenerator-runtime
npmi--savecore-jsregenerator-runtime
在 main.js 中添加
//兼容IE
//https://github.com/zloirock/core-js/blob/master/docs/2019-03-19-core-js-3-babel-and-a-look-into-the-future.md#babelpolyfill
import'core-js/stable'
import'regenerator-runtime/runtime'
配置 babel.config.js
constplugins=[]
module.exports={
presets:[['@vue/cli-plugin-babel/preset' {useBuiltIns:'usage' corejs:3}]]
plugins
}
✅ Eslint Pettier 统一开发规范
该文件 .prettierrc 里写 属于你的 pettier 规则
{
"printWidth":120
"tabWidth":2
"singleQuote":true
"trailingComma":"none"
"semi":false
"wrap_line_length":120
"wrap_attributes":"auto"
"proseWrap":"always"
"arrowParens":"avoid"
"bracketSpacing":false
"jsxBracketSameLine":true
"useTabs":false
"overrides":[{
"files":".prettierrc"
"options":{
"parser":"json"
}
}]
}
鸣谢
vue-cli4-config: https://github.com/staven630/vue-cli4-config
vue-element-admin:https://github.com/PanJiaChen/vue-element-admin
mdnice:https://mdnice.com
作者:花花小仙女
转发链接:https://mp.weixin.qq.com/s/c9uAYkWJu-zvKfELh_3V0A