当前位置:首页 > 技术分析 > 正文内容

开箱即用 vue全家桶+vant移动端解决方案

ruisui884个月前 (02-03)技术分析14

作者:花花小仙女

转发链接:
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

启动项目

git?clone?https://github.com/sunniejs/vue-h5-template.git

cd?vue-h5-template

npm?install

npm?run?serve

目录

  • √ 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-service?serve?--open",
??"stage":?"vue-cli-service?build?--mode?staging",
??"build":?"vue-cli-service?build",
}

配置介绍

??以 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'
#?must?start?with?VUE_APP_
VUE_APP_ENV?=?'development'
  • .env.staging 测试环境配置
NODE_ENV='production'
#?must?start?with?VUE_APP_
VUE_APP_ENV?=?'staging'
  • .env.production 正式环境配置
?NODE_ENV='production'
#?must?start?with?VUE_APP_
VUE_APP_ENV?=?'production'

这里我们并没有定义很多变量,只定义了基础的 VUE_APP_ENV development staging production变量我们统一在 src/config/env.*.js 里进行管理。

这里有个问题,既然这里有了根据不同环境设置变量的文件,为什么还要去 config 下新建三个对应的文件呢?修改起来方便,不需 要重启项目,符合开发习惯。

config/index.js

//?根据环境引入不同配置?process.env.NODE_ENV
const?config?=?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 配置

下面提供了一份基本的 postcss 配置,可以在此配置的基础上根据项目需求进行修改

//?https://github.com/michael-ciniawsky/postcss-load-config
module.exports?=?{
??plugins:?{
????autoprefixer:?{
??????overrideBrowserslist:?['Android?4.1',?'iOS?7.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):

切换不同的机型,根元素可能会有不同的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%,这里只是举例说明。



? VantUI 组件按需加载

项目采 用 Vant 自动按需引入组件 (推荐) 下 面安装插件介绍:

babel-plugin-import 是一款 babel 插件,它会在编译过程中将import 的写法自动转换为按需引入的方式

安装插件

npm?i?babel-plugin-import?-D

在babel.config.js 设置

//?对于使用?babel7?的用户,可以在?babel.config.js?中配置
const?plugins?=?[
??[
????'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组件
import?Vue?from?'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 文件之中

??/*?global?styles?*/

??/*?local?styles?*/

vue.config.js 配置注入 sass 的 mixin variables 到全局,不需要手动引入 ,配置$cdn通过变量形式引入 cdn 地址

const?IS_PROD?=?['production',?'prod'].includes(process.env.NODE_ENV)
const?defaultSettings?=?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 使用


??.logo?{
????width:?120px;
????height:?120px;
????background:?url($cdn+'/weapp/logo.png')?center?/?contain?no-repeat;
??}

? Vuex 状态管理

目录结构

├──?store
│???├──?modules
│???│???└──?app.js
│???├──?index.js
│???├──?getters.js

main.js 引入

import?Vue?from?'vue'
import?App?from?'./App.vue'
import?store?from?'./store'
new?Vue({
??el:?'#app',
??router,
??store,
??render:?h?=>?h(App)
})

使用

? Vue-router

本案例采用 hash 模式,开发者根据需求修改 mode base

注意:如果你使用了 history 模式,vue.config.js 中的 publicPath 要做对应的修改

import?Vue?from?'vue'
import?Router?from?'vue-router'

Vue.use(Router)
export?const?router?=?[
??{
????path:?'/',
????name:?'index',
????component:?()?=>?import('@/views/home/index'),?//?路由懒加载
????meta:?{
??????title:?'首页',?//?页面标题
??????keepAlive:?false?//?keep-alive?标识
????}
??}
]
const?createRouter?=?()?=>
??new?Router({
????//?mode:?'history',?//?如果你是?history模式?需要配置?vue.config.js?publicPath
????//?base:?'/app/',
????scrollBehavior:?()?=>?({y:?0}),
????routes:?router
??})

export?default?createRouter()

更多:Vue Router

? Axios 封装及接口管理

utils/request.js 封装 axios ,开发者需要根据后台接口做修改。

  • service.interceptors.request.use 里可以设置请求头,比如设置 token
  • config.hideloading 是在 api 文件夹下的接口参数里设置,下文会讲
  • service.interceptors.response.use 里可以对接口返回数据处理,比如 401 删除本地信息,重新登录
import?axios?from?'axios'
import?store?from?'@/store'
import?{Toast}?from?'vant'
//?根据环境不同引入不同api地址
import?{baseApi}?from?'@/config'
//?create?an?axios?instance
const?service?=?axios.create({
??baseURL:?baseApi,?//?url?=?base?api?url?+?request?url
??withCredentials:?true,?//?send?cookies?when?cross-domain?requests
??timeout:?5000?//?request?timeout
})

//?request?拦截器?request?interceptor
service.interceptors.request.use(
??config?=>?{
????//?不传递默认开启loading
????if?(!config.hideloading)?{
??????//?loading
??????Toast.loading({
????????forbidClick:?true
??????})
????}
????if?(store.getters.token)?{
??????config.headers['X-Token']?=?''
????}
????return?config
??},
??error?=>?{
????//?do?something?with?request?error
????console.log(error)?//?for?debug
????return?Promise.reject(error)
??}
)
//?respone拦截器
service.interceptors.response.use(
??response?=>?{
????Toast.clear()
????const?res?=?response.data
????if?(res.status?&&?res.status?!==?200)?{
??????//?登录超时,重新登录
??????if?(res.status?===?401)?{
????????store.dispatch('FedLogOut').then(()?=>?{
??????????location.reload()
????????})
??????}
??????return?Promise.reject(res?||?'error')
????}?else?{
??????return?Promise.resolve(res)
????}
??},
??error?=>?{
????Toast.clear()
????console.log('err'?+?error)?//?for?debug
????return?Promise.reject(error)
??}
)
export?default?service

接口管理

在src/api 文件夹下统一管理接口

  • 你可以建立多个模块对接接口, 比如 home.js 里是首页的接口这里讲解user.js
  • url 接口地址,请求的时候会拼接上 config 下的 baseApi
  • method 请求方法
  • data 请求参数 qs.stringify(params) 是对数据系列化操作
  • hideloading 默认 false,设置为 true 后,不显示 loading ui 交互中有些接口不需要让用户感知
import?qs?from?'qs'
//?axios
import?request?from?'@/utils/request'
//user?api

//?用户信息
export?function?getUserInfo(params)?{
??return?request({
????url:?'/user/userinfo',
????method:?'get',
????data:?qs.stringify(params),
????hideloading:?true?//?隐藏?loading?组件
??})
}

如何调用

//?请求接口
import?{getUserInfo}?from?'@/api/user.js'

const?params?=?{user:?'sunnie'}
getUserInfo(params)
??.then(()?=>?{})
??.catch(()?=>?{})

? Webpack 4 vue.config.js 基础配置

如果你的 Vue Router 模式是 hash

publicPath:?'./',

如果你的 Vue Router 模式是 history 这里的 publicPath 和你的 Vue Routerbase 保持一直

publicPath:?'/app/',
const?IS_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

export?function?getUserInfo(params)?{
??return?request({
????url:?'/api/userinfo',
????method:?'get',
????data:?qs.stringify(params)
??})
}

? 配置 alias 别名

const?path?=?require('path')
const?resolve?=?dir?=>?path.join(__dirname,?dir)
const?IS_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'))
??}
}

? 配置 打包分析

const?BundleAnalyzerPlugin?=?require('webpack-bundle-analyzer').BundleAnalyzerPlugin

module.exports?=?{
??chainWebpack:?config?=>?{
????//?打包分析
????if?(IS_PROD)?{
??????config.plugin('webpack-report').use(BundleAnalyzerPlugin,?[
????????{
??????????analyzerMode:?'static'
????????}
??????])
????}
??}
}
npm?run?build

? 配置 externals 引入 cdn 资源

这个版本 CDN 不再引入,我测试了一下使用引入 CDN 和不使用,不使用会比使用时间少。网上不少文章测试 CDN 速度快,这个开发者可 以实际测试一下。

另外项目中使用的是公共 CDN 不稳定,域名解析也是需要时间的(如果你要使用请尽量使用同一个域名)

因为页面每次遇到 ????<%?}?%>

? 去掉 console.log

保留了测试环境和本地环境的 console.log

npm?i?-D?babel-plugin-transform-remove-console

在 babel.config.js 中配置

//?获取?VUE_APP_ENV?非?NODE_ENV,测试环境依然?console
const?IS_PROD?=?['production',?'prod'].includes(process.env.VUE_APP_ENV)
const?plugins?=?[
??[
????'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

npm?i?--save?core-js?regenerator-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

const?plugins?=?[]

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

扫描二维码推送至手机访问。

版权声明:本文由ruisui88发布,如需转载请注明出处。

本文链接:http://www.ruisui88.com/post/776.html

标签: vue url传参
分享给朋友:

“开箱即用 vue全家桶+vant移动端解决方案” 的相关文章

Excel VBA 收费单据打印/一步一步带你设计【收费管理系统】12

本文于2023年6月10日首发于本人同名公众号:Excel活学活用,更多文章案例请搜索关注!☆本期内容概要☆用户窗体设置:收费结算模块设置(7)单据打印大家好,我是冷水泡茶,前几期我们分享了【收费管理系统】的设计,最近一期是(Excel VBA 收费结算模块/一步一步带你设计【收费管理系统】11),...

vue 3 学习笔记 (八)——provide 和 inject 用法及原理

在父子组件传递数据时,通常使用的是 props 和 emit,父传子时,使用的是 props,如果是父组件传孙组件时,就需要先传给子组件,子组件再传给孙组件,如果多个子组件或多个孙组件使用时,就需要传很多次,会很麻烦。像这种情况,可以使用 provide 和 inject 解决这种问题,不论组件嵌套...

迁移GIT仓库并带有历史提交记录

迁移git仓库开发在很多时候,会遇到一个问题。GIT仓库的管理,特别是仓库的迁移。我需要保留已有的历史记录,而不是重新开发,重头再来。我们可以这样做:使用--mirror模式会把本地的分支都克隆。// 先用--bare克隆裸仓库 git clone git@gitee.com:xxx/testApp...

10款超牛Vim插件,爱不释手了

我是一个忠实的Vim编辑器用户,从事开发工作多年,我一直都非常喜欢使用Vim。轻量、便捷,而且,熟悉了Vim相关的快捷键之后,效率能够成倍的提升。除了这些之外,Vim像很多知名的IDE、编辑器一样,也支持插件配置,通过这些插件,可以实现更多高级、高效的操作。今天,就来给大家分享10个我特别喜欢的Vi...

三、Uni-app + vue3 页面如何跳转及传参?

Vue 项目往往需要使用 vue-router 插件,刚开始入门 Uni-app + Vue3 项目的同学,会不会想着路由使用 vue-router V4 版本不就可以了吗?不怕大家笑话,我就是这样想的,毕竟我是第一次使用 Uni-app ,由于孕期记性贼差,所以我决定写成笔记,加深记忆。uni-a...

SpringCloudalibaba+Vue开发仿社交小程序-青牛白马七香车

Spring Cloud Alibaba和Vue是当今开发领域中最为流行的技术组合之一。本文将介绍如何使用Spring Cloud Alibaba和Vue开发仿社交小程序。download: https://www.97yrbl.com/t-1632.html项目概述本项目是一个仿社交小程序,包括用...