1. 工程目录规划
└─src
├─services # 服务相关
│ │
│ ├─ url.js # 请求地址
│ │
│ └─ map.js # 字段属性名映射(可能不需要)
| |
│ ├─ handler.js # 数据处理
│ │
│ └─ index.js
│
├─router # 路由
│ │
│ ├─ index.js # 路由入口
│ │
│ ├─ manager.js # 管理后台模块相关路由
│ │
│ └─ user.js # 用户模块相关路由
│
├─components # 公用组件
| ├─mixins # 混合
| │ │
| │ └─ CardMinix.vue # 卡片混合
│ │
│ └─ Common1.vue # 通用组件1
│ │
│ └─ Common2.vue # 通用组件2
│
├─views # 视图(业务组件)
| ├─manager # 后台管理视图
| │ │
| │ └─ Index.vue # 首页
| │ │
| │ └─ Export.vue # 数据查询/导出
| ├─user # 用户信息视图
| │ │
| │ └─ Profile.vue # 个人简介
| │ │
| │ └─ Detail.vue # 个人详情
├─store # 状态数据
| ├─manager # 后台管理state
| │ │
| │ └─ types.js
| │ │
| │ └─ action.js
| │ │
| │ └─ mutation.js
| │ │
| │ └─ state.js
| │ │
| │ └─ index.js
| ├─user # 用户信息state
| │ │
| │ └─ types.js
| │ │
| │ └─ action.js
| │ │
| │ └─ mutation.js
| │ │
| │ └─ state.js
| │ │
| │ └─ index.js
│
├─directives # 自定义指令
│
├─filters # 自定义过滤器
│
├─plugins # 自定义插件
│
├─config # 放置一些配置文件
│
├─utils # 放置一些工具函数
│
├─asserts # 静态资源
| │
| ├─less # 放置less
| │ │
| │ ├─ common.less # 通用less
| │ │
| │ └─ reset.less # 页面初始化less
| │
| ├─fonts # 放置iconfont字体
| ├─imgs # 放置图片
├─App.vue # 入口组件
├─main.js # 启动配置
其中,
- services目录中, 特别放置了
url.js
, 主要是为了方便管理所有的url请求地址, 有时后端提供的url不合规范, 后端重命名后, 对于前端来说, 修改起来是很方便的. ( 返回的数据不变的情况下, 如果返回的数据有变化, 就可能需要增加map.js
,handler.js
) -
components
和views
要严格区分, 与业务逻辑处理相关的都放在views
目录下, 公用组件都放置在components
目录下, 因为项目是不断迭代演进的过程, 有些组件可能需要多个工程复用, 有可能需要提取成npm包的形式, 此时, 严格区分业务形组件和通用组件就显得很重要了.
2. 文件引用路径别名设置
有时候项目文件过多,可能经常出现类似 "../../../static/data/xx.json" 这样的引用,写起来很麻烦而且经常容易出错(当然代码编译器能够提示就无所谓了),为了简化路径,我们可以在 build/webpack.base.conf.js 中去配置别名
image.png
这里是通过调用 resolve 方法来达到简化路径的目的,比如可以直接用@来取代src,也可以直接写 "api/xx.js",而不用一层一层的去找
3. 递归组件
在Vue中组件可以在模板内部递归调用自己,需要给组件设置name值,需要注意的是:必须限定条件,不能无限递归,否则会内存溢出(Error in nextTick: "RangeError: Maximum call stack size exceeded")。
场景: 在构建目录树时, 如果用一个组件来完成, 可能会涉及到复杂的数据处理和计算, 然后再渲染成一个目录树结构.
在此场景中, 可以写一个递归函数, 根据数据生成一个目录树节点, 然后渲染出来.
当然, 也可以考虑下使用递归组件来完成这样的工作.如:
// 父组件
<items :model='model' v-for='model in data'></items>
官方文档里面写的递归组件强调了使用name属性,
// Items.vue
<template>
<li>
<div @click='toggle'>
<i v-if='isFolder' class="fa " :class="[open?'fa-folder-open':'fa-folder']"></i>
<!--isFolder判断是否存在子级改变图标-->
<i v-if='!isFolder' class="fa fa-file-text"></i> {{model.data.menuName}}
</div>
<ul v-show="open" v-if='isFolder'>
<items v-for='cel in model.childTreeNode' :model='cel'></items>
</ul>
</li>
</template>
<script type="text/javascript">
export default {
name: 'items',
props: ['model'],
components: {},
data() {
return {
open: false,
isFolder: true
}
},
computed: {
isFolder: function() {
return this.model.childTreeNode && this.model.childTreeNode.length
}
},
methods: {
toggle: function() {
if(this.isFolder) {
this.open = !this.open
}
},
}
}
</script>
4. 路由懒加载
// Vue路由文档的写法:
const app = () => import('./app.vue') // 引入组件
const router = new VueRouter({
routes: [
{ path: '/app', component: app }
]
})
// 也要以这么写
const router = new VueRouter({
routes: [
{ path: '/app', component: () => import('./app.vue')}
]
})
5. 404页面
如果输入的路由不存在应该要跳转到404页面(自定义404页面)
export default new Router({
routes: [
{
path: '/', // 项目启动页
redirect:'/login' // 重定向到下方声明的路由
},
{
path: '*', // 404 页面
component: () => import('./notFind')
},
]
})
6. 路由拦截
场景描述:
当用户使用浏览器后退时, 提示用户保存未保存的表单。
//在路由组件中:
mounted(){
},
beforeRouteLeave (to, from, next) {
if(userInput){
//出现弹窗提醒保存表单,或者自动后台为其保存
}else{
next(true);//用户离开
}
请参考vue文档全局钩子和组件钩子
7. 深度watch与watch立即触发回调
watch很多人都在用,watch中的有两个选项deep、immediate
- deep, 在选项中指定deep: true, 可以监听对象中属性的变化
- immediate, 在选项中指定immediate:true, 将立即以表达式的当前值触发回调, 也就是默认触发一次.
watch: {
obj: {
handler(val, oldVal) {
console.log('属性发生变化触发这个回调',val, oldVal);
},
deep: true // 监听这个对象中的每一个属性变化
},
step: { // 属性
//watch
handler(val, oldVal) {
console.log("默认触发一次", val, oldVal);
},
immediate: true // 默认触发一次
},
},
8. 动态组件
9. 加载远端组件
10. 组件动态传参
- v-bind
- $attr
- $listener
11. 组件通信
- provide
- inject
网友评论