使用vue一年多了,作了一个javaee的项目(全栈,前端使用的mvvm框架vue),三个移动端项目,其中两个钉钉子应用(钉钉的坑不少,心累),一个微信的(ing)。本身也慢慢摸索出一些项目中的最佳实践,整理了一下,作个记录一块儿交流。若是你在阅读过程当中,以为我某些地方作的不对或者有更好的方法时,欢迎交流~javascript
清晰的目录结构不只能够展示一个团队的水平,并且别人维护(接锅)的时候,也能更好的理解你的项目。这个每一个团队都有本身的标准或者风格,没有固定的格式。我通常是这么安排的(vue-cli项目),下面是src目录:css
—— src
|—— assets // 项目资源目录
|—— styles // 样式文件
|—— reset.scss // reset css,会在 /src/main.js 中被导入
|—— variables.scss // 项目中的变量,混合(mixin)等公有样式变量
|—— ...
|—— images // 图片
|—— fonts // 字体
|—— ...
|—— components // 组件目录
|—— layout // 布局相关组件
|—— Header.vue // 头部
|—— BottomMenu.vue // 底部菜单
|—— ...
|—— common // 公有组件
|—— base // 基础组件
|—— ...
|—— pages // 页面目录
|—— user // 用户相关页面
|—— Login.vue // 登陆页面
|—— Register.vue // 注册页面
|—— Info.vue // 详情页面
|—— order // 订单相关页面
|—— List.vue // 订单列表
|—— Detail.vue //订单详情
|—— ...
|—— Home.vue // 主页
|—— ...
|—— router // 路由
|—— modules // 存放各个模块的路由
|—— user.js // 用户模块
|—— order.js // 订单模块
|—— index.js // 路由主js,整合各个模块,而且还会定义一些全局钩子等其余
|—— store // 全局状态管理目录
|—— mutation-types.js // mutation types
|—— index.js // 主js,整合各个模块的
|—— actions.js // actions
|—— modules // 各个模块的states
|—— user.js
|—— order.js
|—— common // 全局工具方法
|—— data-format.js // 数据转换
|—— http.js // 网络请求
|—— ...
|—— App.vue
|—— main.js
|—— init-plugins.js // 依赖的第三方的初始化,会在main.js中引入
以上只是我我的的习惯,不过这个结构要根据具体的项目状况调整。没必要为了模块化而模块化。若是你的项目业务逻辑不复杂,整个项目也就十几个页面,能够适当的删减部分模块。html
你的项目可能须要一些这样的组件,来提高用户体验。前端
no-data-foundvue
这个存在的场景是,好比你加载数据列表或者筛选列表查询等数据操做,若是请求成功可是没有数据,这时候有必要提供一个no-data-found的组件。html5
errorjava
当你的应用出错的时候,好比网络超时加载不了数据,也能够给一个组件作提示ios
在开始咱们项目以前,咱们应该知道,有哪些方法是必要的、共有的,相似于咱们的工具方法同样。这里我罗列一些供参考:git
日期与字符串转换
github
关于日期都全部操做,建议采用
momentJs
。功能强大并且兼容性好,我深深的记得以前一个钉钉项目中日期操做不兼容iphone手机的时候,那个bug让我找了半天才找到根源。
官网传送门:http://momentjs.cn/
数字与字符串转换
你的应用应该包含一套用于提示用户的组件:
Toast
用于提示用户一些信息
Confirm
用户提示用户是否确认接下来的操做。对于一些重要的操做,好比提交表单,删除信息等操做,务必使用。
Loading
当用户在上传或者下载图片等其余资源的时候,用于提示进度信息。固然这个请求方法要可以得到到相应的进度信息才行,伪造须谨慎(手动斜眼笑)。
Spinner
加载数据时的提示,俗称“菊花图“
mint-ui:http://mint-ui.github.io/docs/#/
vux:https://doc.vux.li/zh-CN/
这里要说的是,你能够对这些方法进行二次封装,以便更方便的使用。包装后,可能就能够像下面这样使用了:
Dialog.toast('cool')
Dialog.confirm('Are you sure?',()=>{Dialog.toast('confirm')}) Dialog.spinner('loading...')
咱们知道vue的SFC(单文件组件,即以.vue结尾的文件),提供了三个基础的顶级标签:<template>
, <style>
,<script>
。我我的比较喜欢把样式也写进SFC中,由于这样针对性很强,调试某个页面样式的时候,只要打开一个文件就好了。(这么说是由于我一开始是隔离全部的css文件到assets目录下,这样虽然代码看起来漂亮了,你只要在style标签内import样式就能够了,可是调试的时候很是不方便。)
固然,前提是在你使用css预处理器的状况下:
为了系统的UI一致性(consistency),咱们的设计稿确定是一套统一的主题的。因此咱们不一样页面的边框粗细颜色,按钮背景色,字体大小颜色,一级边框二级边框…,一级标题二级标题…等等众多的样式须要保持一致。若是在每一个页面都定义一次,这可行,可是工做量和作法都是不值得提倡的。
有一些loader就是负责处理这类状况的,以sass为例,你可使用 sass-resources-loader
来完成全局变量的共享。使用方法也很简单:
- 安装
npm install sass-resources-loader --save-dev
scss: generateLoaders('sass').concat({
loader: 'sass-resources-loader',
options: {
resources: path.resolve(__dirname, '../src/assets/styles/variables.scss')
}
})
接下来就能够在任意的组件中使用这个varibles.scss里面的样式了。
有的ui框架会修改默认样式,并且不一样浏览器的样式标准也有一些不一样,因此resetcss颇有必要。国内诸如淘宝,百度等都有本身的resetcss,你能够参考这篇博客得到帮助,也能够根据这个自定义本身项目的resetcss。
https://meyerweb.com/eric/tools/css/reset/
<style scoped>
with <style>
也许你遇到过这种状况,须要修改某一个ui框架的默认样式,可是在scoped的style块中修改不成功。不得不将style块的scoped属性拿掉,或者将这个要改变的样式放进全局样式里再在main.js中导入,或者直接将样式定义在App.vue里面。这些都是可行的,可是要注意命名空间要是正确的,否则是找不到样式的。
这里提供另外一种方法。其实在vue的SFC中,是容许多个style块的。你能够像下面这样使用:
<style scoped lang="scss"> .order-detail { // put your local style here } </style>
<style> .mint-button{ // put your global style here if you want to change the lib's style } </style>
可能不少人用vue-router的时候,只是用来作路由跳转,配置路由的时候,添加一个path和component就完事了。若是这样能知足你的全部需求,那也ok。可是有一些业务场景,使用meta属性能够很是巧妙的解决问题。
这里分享一下我使用过的例子:
想要动态的显示应用/系统的标题,你会怎么作呢?
你可能会在每个页面的钩子中给document.title赋值,可是有更简单的方法,好比我定义一个下面的router:
{ name:'user-detail', path:'/user-detail', component: UserDetail, meta: { title: '用户信息' }
},
接着在App.vue里面,添加下面的代码:
watch:{
'$route':function(to, from){
document.title = to.meta.title
}
}
这样每次定义router的时候,只要填写了meta属性,系统的title就会跟着改变了。
另外,在App.vue里面watch的$route,还有不少用处,好比处理前进后退的动画等。
咱们知道vue提供了一个<keep-alive>
组件,用户缓存组件以得到更快的交互。简单介绍一下,当设置某一页面为keep-alive的时候,它的mounted只会在第一次加载的时候执行一次,后面在打开该页面的时候都不会执行。可是activated
和deactivated
两个钩子能够捕获页面进入和退出的动做。
根据不一样的业务逻辑,有些页面须要缓存有些页面不须要缓存,因此咱们也能够定义在router中:
{ name:'user-detail', path:'/user-detail', component: UserDetail, meta: { title: '用户信息', keepAlive: true }
},
而后修改主路由入口的代码(App.vue)
<template v-if="$route.meta.keepAlive">
<keep-alive>
<router-view/>
</keep-alive>
</template>
<template v-else>
<router-view/>
</template>
这样你就能够根据本身的须要,决定哪些页面须要缓存了。
关于<keep-alive>
组件的更多用法,参考:https://cn.vuejs.org/v2/api/#keep-alive
咱们知道,vue-router提供了页面的滚动行为。vue-router的滚动行为
咱们也能够在路由中配置该属性,来细粒度的控制咱们页面的滚动行为。
scrollBehavior方法,摘自官网例子 。我给注释翻译了一下。
https://github.com/vuejs/vue-router/blob/next/examples/scroll-behavior/app.js
// - 只在支持html5 history 模式的浏览器中有效
// - 默认无滚动行为
// - 返回false的话,会阻止滚动行为
const scrollBehavior = (to, from, savedPosition) => {
if (savedPosition) {
// savedPosition 只在popstate的导航中有效
// popstate:https://developer.mozilla.org/zh-CN/docs/Web/Events/popstate
return savedPosition
} else {
const position = {}
// 经过返回选择器来滚动到锚点位置
if (to.hash) {
position.selector = to.hash
}
// 检查路由元数据(meta)配置中是不是返回顶部的需求
if (to.matched.some(m => m.meta.scrollToTop)) {
// 设置滚动位置的x和y坐标:顶部
position.x = 0
position.y = 0
}
// 若是返回的位置是假值(falsy)或者是空对象,将会返回当前滚动的位置
return position
}
}
OK,今天就说这么多,还有一些,好比异常处理,vuex使用场景,一致性(consistency)等,下次有机会在写一篇,今天头有点痛,得睡觉了。
有一些实践我已经用到这个项目https://github.com/JerryYuanJ/a-vue-app-template中了,可是因为这个项目写的时间比较早,并且主要是为了熟悉vue和其余一些练习为主,那时候还不懂事,因此不少地方仍是得改的,若是你须要拿项目来练手上面的一些实践的话,这会是个不错的选择。你能够pull requeset,我会merge的~欢迎star