前言
之前开发vue项目,一直是自己搭建脚手架,并没有使用配套的Vue-CLI。原因是:
一、是3.0之前的CLI无明显优势,配置繁琐;
二、是觉得自己从零配置项目可控性更强。
Vue-CLI 3.0 于去年8月份就已发布,却一直没去了解。近日,有新Vue H5项目开发,就想着用Vue CLI3.0脚手架构建项目。并记录一下构建使用过程。
项目特性
- 基于
@vue/cli3
- CSS 预编译语言:less,全局样式初始化
- ajax封装,借助Axios库实现http请求
- vue-router封装;懒加载、拦截
- 页面平滑切换
- 通用化组件
- 移动端适配
- 可视化分析工具
- 项目结构拆分 等...
使用脚手架最好的参考就是官方文档,官方文档整体还是比较清晰明了的,更新也很及时。
「链接-官方文档」
CLI3.0 功能优势
Vue CLI 致力于将 Vue 生态中的工具基础标准化。它确保了各种构建工具能够基于智能的默认配置即可平稳衔接,这样你可以专注在撰写应用上,而不必花好几天去纠结配置的问题。与此同时,它也为每个工具提供了调整配置的灵活性,无需 eject。
Vue-CLI3.0旨在近一步简化Vue项目配置,“傻瓜式”配置,促进团队开发的统一和规范化。同时也完全可以是可配置的,保留足够的扩展性。
- 功能丰富,实现开箱即用,不用再考虑繁琐的配置。
- 灵活的插件化机制,增强扩展性。
- 可以通过配套的图形化界面创建、管理项目的配置。有时看着还是很直观舒服的。
- 支持直接将一个vue文件跑起来,进行快速原型开发。
- 不用过多担心配置的更新迭代造成的连带影响。
- vue团队出品,很好地维护并跟进官方的最佳实践和前沿技术。
搭建项目
项目git地址:github.com/now1then/vu…;
初始化项目
克隆项目
git clone git@github.com:now1then/vue-h5-pro.git
安装脚手架:
npm install -g @vue/cli
# OR
yarn global add @vue/cli
创建一个项目:
vue create my-project
# OR
vue ui // 通过图形化界面创建项目
- 选择preset特性(这里选择更多功能):
- 选择需要安装的(Babel、Router、Vuex、Pre-processors、Linter / Formatter):
这里先不引入TypeScript和单元测试。
- 路由是否使用history模式(Yes)
- 选择 CSS 预处理器(Less):
- 选择ESLint 配置(ESLint + Standard config)标准配置:
- 选择什么时候执行ESLint校验(Lint on save):
- 选择以什么样的形式配置以上所选的功能,单独生成配置文件 or 附加到package.json中(In dedicated config files):
- 是否将之前的设置保存为一个预设模板(y):
如果选择 y 后会让输入名称,在下次初始化项目可以使用该预设模板快速构建项目。
运行项目
了解CLI插件命令。
启动开发服务器运行项目:**npm run serve**
;
命令会启动一个开发服务器 (基于 webpack-dev-server) 并附带开箱即用的模块热重载 (Hot-Module-Replacement)。
生产环境打包:npm run build
;
图形化界面
通过 vue ui
命令以图形化界面创建和管理项目:
vue ui
运行成功后,在打开的页面中可以新建项目,也可以导入已有项目。
管理界面:
目录介绍:
**项目仪表盘:**自定义展现一些的功能小部件;
**插件:**可以查看已安装的CLI插件,还可以搜索安装插件;
**依赖:**可以查看和管理项目的运行依赖和开发依赖;
**配置:**项目的配置项配置管理,包括Vue-CLI配置和ESLint配置等。
**任务:**可以执行对应任务(对应于package.json中脚本命令),方便查看运行结果和分析检查。
图形化界面虽然对于实际开发意义不大,但简洁直观,实际体验还是不错的。具体功能最好运行亲自体验。
主流配置插件
Babel
CLI中已预设@vue/cli-plugin-babel
,它默认使用 Babel 7 + babel-loader
+ @vue/babel-preset-app,但是可以通过 babel.config.js
配置使用任何其它 Babel 预设选项或插件。
『当前仅默认配置就够用,后续实际使用时逐步增加』
默认会转换_es6.promise、_``_es6.symbol_
等常见ES6语法,对于未引入的语法,采用"显式地列出了需要的 polyfill的方式"。比如项目中使用es6.string.includes
,则设置:
presets: [
['@vue/app', {
'polyfills': [
'es6.string.includes'
]
}]
],
ESLint
@vue/cli-plugin-eslint
『当前仅适用默认配置就够用。』,具体根据个人习惯和项目规范调整即可。
比如,本人一般关闭以下设置:
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warning' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warning' : 'off',
'semi': 0, // 语句结尾分号
'camelcase': 0, //驼峰命名
'comma-dangle': 0, // 对象最后逗号
'space-before-function-paren': 0, // 函数定义前,括号前分割
},
加载mint-ui库
// 安装
npm install mint-ui
按需引入
借助 babel-plugin-component,我们可以只引入需要的组件,以达到减小项目体积的目的。
首先,安装 babel-plugin-component:
npm install babel-plugin-component -D
然后,将babel.config.js 修改为:
module.exports = {
presets: [
['@vue/app', {
'polyfills': [
'es6.string.includes'
]
}]
],
"plugins": [
["component", {
"libraryName": "mint-ui",
"style": true
}]
]
}
这样使用组件就可以按需引入了。
ajax请求封装
借助Axios库实现http请求
「链接-axios中文文档」
安装:
npm install axios;
封装要达成的目标:
- 统一维护管理接口;
- 支持接口代理转发;
- 读取环境配置,区分处理环境。
- 拦截请求和响应,处理登录超时、404等异常情况;
- 根据请求的配置匹配接口URL前缀且作支持做特殊处理。
具体详见本人另一篇文章:
「漫漫长路-Axios封装」
移动端适配
考虑浏览器兼容性和使用习惯,移动端适配还是手淘模式,采用px转rem
+ lib-flexible
实现。postcss-pxtorem
插件把配置的px转成rem;lib-flexible
库则根据页面尺寸和dpr,自动设置html的字体和meta缩放比例。
- 安装
postcss-pxtorem
插件
yarn add postcss-pxtorem -D
- postcss.config.js中增加pxtorem配置
// postcss.config.js
module.exports = {
plugins: {
"autoprefixer": {}, 用来自动处理浏览器前缀的一个插件。
"postcss-
": {
"rootValue": 37.5, // 设计稿宽度的1/10
"unitPrecision": 5, //小数位
"minPixelValue": 1, //转换的最小单位
"selectorBlackList": [], //忽略的样式, 正则
"propList": ["*"] // 需要做转化处理的属性,如`hight`、`width`、`margin`等,`*`表示全部,正则
}
}
}
根据项目实际情况灵活配置。
- 安装
lib-flexible
,并在入口文件main.js中引入
// 安装 lib-flexible
yarn add lib-flexible
// main.js中引入lib-flexible
import 'lib-flexible';
引入移动端调试工具
手机设备上调试H5非常不方便,这时可以引入一个非常好用的调试工具Eruda。
Eruda 是一个专为手机网页前端设计的调试面板,类似 DevTools 的迷你版,其主要功能包括:捕获 console 日志、检查元素状态、显示性能指标、捕获XHR请求、显示本地存储和 Cookie 信息、浏览器特性检测等等。
详情请访问-Github链接
可以通过CDN引用,当然也可以下载到项目中直接使用。
本项目配置中使用CLI环境变量配置,来设置是否加载Eruda。 实际项目使用可灵活配置。.env.development
文件设置环境变量:
VUE_APP_ERUDA=false # ture表示启用Eruda调试工具
index.html文件设置:
<!--手机调试-->
<% if (VUE_APP_ERUDA === 'true') { %>
<script src="//cdn.bootcss.com/eruda/1.5.2/eruda.min.js"></script>
<script> window.eruda.init(); </script>
<% } %>
效果:
其他CLI配置
postcss.config.js
postcss-import:
该插件主要是解决@import引入路径问题。引入本地文件、node_modules等的文件。postcss-url:
该插件主要用来处理文件,比如图片文件、字体文件等引用路径的处理。autoprefixer:
用来自动处理浏览器前缀的一个插件。
可视化分析工具
利用可视化资源分析工具插件webpack-bundle-analyzer
分析生产文件打包大小。
// vue.config.js
configureWebpack: config => {
// 生产环境打包分析体积
if (process.env.NODE_ENV === 'production' && process.env.npm_config_report) {
return {
plugins: [
new BundleAnalyzerPlugin()
]
}
}
},
终端命令:yarn build --report
当然图形化界面任务->build->分析
中也可以粗略分析打包大小。
统一设置less全局变量
参考「链接-Vue-CLI3 css自动导入」。
利用style-resources-loader
插件,给Vue单文件自动全局导入配置路径中的LESS变量和mixin函数。 这样在使用时不用每个文件都单独引入,就可以直接使用定义的Less变量。
安装style-resources-loader
;
yarn add style-resources-loader -D
vue.config.js 配置
chainWebpack: config => { // CLI内部webpack配置
const types = ['vue-modules', 'vue', 'normal-modules', 'normal']
types.forEach(type => addStyleResource(config.module.rule('less').oneOf(type)))
},
// 全局样式 变量、函数
function addStyleResource (rule) {
rule.use('style-resource')
.loader('style-resources-loader')
.options({
patterns: [
path.resolve(__dirname, 'src/styles/variables.less'),
path.resolve(__dirname, 'src/styles/mixin.less'),
],
})
}
项目其他改动:
CSS样式初始化
引入_normalize.css
_ 、_minireset.css _
+ 自定义CSS设置,初始化CSS样式,使HTML元素样式在跨浏览器上表现得的高度一致性。
下载对应文件,直接放到src/assets/styles/
路径下。
引入fastclick
移动端点击有300ms延迟,主要是为了解决双击缩放,浏览器等待300ms以判断是否是双击操作。
可以采用引入fastclick.js的方式解决移动端300ms延迟的问题。当然,fastclick.js曾经在老版本手机上解决移动端300ms的问题上做出了很大的贡献。时至今日是否还有必要使用,各方还是各持一词。
// 安装
yarn add fastclick
// main.js中引入使用
import FastClick from 'fastclick';
FastClick.attach(document.body);
项目开发
目录结构
在团队开发时,规范的目录拆分约定,有利于协调开发和项目的长期维护。
根据个人习惯及经验,项目目录构建如下图所示:
项目开发都在src目录下;
src/assets目录主要存放静态资源文件,比如字体图标、图片、直接引入的或不常变更的第三方库等。
Vue模块说明
全局公共components组件、filter过滤器、directive指令可以直接注入到全局Vue,也可以在使用时页面组件内单独按需注入。
全局组件分为:components_basics公共基础组件
,主要存放封装的与业务无关的基础组件。components_modules公共业务组件
,主要存放提取的可重用业务组件。
对于不重用的业务组件,不用提取到外部,直接存放到具体的页面目录下即可。
页面组件内按需引入模块:
<script>
import { formatDate } from '@/utils/cloud-utils';
import MainButton from '@/component_basics/MainButton';
import transferDom from '@/directives/transferDom';
export default {
name: 'demoPage',
components: { // 组件
MainButton
},
directives: { // 指令
transferDom
},
filters: { // 过滤器
formatDate
},
data() {
return {
title: '测试'
}
},
methods: {}
}
</script>
Router路由封装
- 路由懒加载
「链接-Vue Router懒加载」
把组件按组分块,结合 Vue 的异步组件和 Webpack 的代码分割功能,实现路由组件的懒加载。
...
const Hello = () => import(/* webpackChunkName: "apply" */ '@/views/hello');
const Demo = () => import(/* webpackChunkName: "demo" */ '@/views/demo');
- 路由拦截
通过自定义meta参数,设置路由信息。
利用vue-router导航卫士,路由拦截时,作一些自定义处理。比如登录权限校验、页面标题设置等。
// 部分路由信息
{
path: '/demo',
name: 'demo',
component: Demo,
meta: {
title: '演示Demo', // 标题
requireAuth: true, // 登录权限
keepAlive: false,
}
},
//路由拦截
// 路由导航守卫
router.beforeEach((to, from, next) => {
// 登录权限
if (to.meta.requireAuth) { // 判断是否校验登录权限
if (!window.userName) { // 判断是否登录,根据实际业务处理
next({
path: '/login',
query: {
redirect: to.fullPath // 未登录,跳转到登录页,登录后跳转回当前页。
}
})
return;
}
}
// 路由发生变化修改页面title
if (to.meta.title) {
document.title = to.meta.title + ' | vue-h5-pro';
} else {
document.title = 'vue-h5-pro';
}
next()
})
页面平滑切换动画
效果图:
这里实现页面前进/后退时的整屏平滑左划/右划效果。
简单记录5个历史路由,进入新页面有左划切换效果,并记录历史路由;进入历史页面有右划切换效果,并清除历史路由。
router.js
文件中拦截路由,记录历史路由信息。
// 路由拦截 router.js
router.afterEach((to, from) => {
// console.log(to, from);
if (!(from.path === '/' && from.name === null)) {
setLocalRoute(to, from)
}
});
function setLocalRoute(to, from) {
// 本地已访问页面路由,存5条
const localRoute = window.myVue.localRoute = window.myVue.localRoute || [];
const from_index = localRoute.indexOf(from.path);
const to_index = localRoute.indexOf(to.path);
if (from_index < 0) {
localRoute.unshift(from.path);
to_index >= 0 && localRoute.splice(to_index, 1)
}
if (localRoute.length > 5) {
localRoute.splice(0, 1)
}
}
main.vue
文件中根据路由跳转,动态设置过渡动画样式。
<template>
<div id="app">
<transition :name="direction">
<router-view class="page" />
</transition>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {};
},
computed: {
// 动态设置过渡样式
direction: function() {
const currentPath = this.$route.path;
const localRoute = (window.myVue && window.myVue.localRoute) || [];
// console.log(localRoute, currentPath);
const index = localRoute.indexOf(currentPath);
let tranName = '';
if (localRoute.length === 0) {
tranName = 'fade'; // 首页,渐显
} else if (index >= 0) {
tranName = 'page-back'; // 回退,右划
} else {
tranName = 'page-go'; // 进入新页面,左划
}
return tranName;
}
},
};
</script>
<style lang="less">
.page {
position: absolute;
width: 100%;
height: 100%;
transition: all 0.8s ease-in-out;
}
.page-go-enter-active {
transform: translate3d(100%, 0, 0);
}
.page-go-enter-to {
transform: translate3d(0, 0, 0);
}
.page-go-leave-active {
transform: translate3d(0, 0, 0);
}
.page-go-leave-to {
transform: translate3d(-100%, 0, 0);
}
.page-back-enter-active {
transform: translate3d(-100%, 0, 0);
}
.page-back-enter-to {
transform: translate3d(0, 0, 0);
}
.page-back-leave-active {
transform: translate3d(0, 0, 0);
}
.page-back-leave-to {
transform: translate3d(100%, 0, 0);
}
}
</style>
项目构建及开发细节后续会持续更新。具体的代码欢迎访问项目查看。
通用化组件(更新...)
此处记录封装的通用化基础组件。
通用化基础组件存放于src/component_basic/
目录下。
Tip提示组件
比如:tip提示组件,组件使用及代码详见项目。
效果图:
项目链接
Github链接:github.com/now1then/vu…;
Vue-CLI3搭建移动端H5应用-语雀:www.yuque.com/nowthen/lon…;
Vue-CLI3搭建移动端H5应用-掘金:juejin.cn/post/684490…
待完善点:
-
制定代码及命名规范
-
项目打包上传配置
-
完善通用化组件
-
引入mock平台
-
国际化语言配置
-
提取单独的PC端项目配置
-
考虑支持多页