Vue 工程化最佳实践

目录结构

总览

  • api 目录用于存放 api 请求,文件名与模型名称基本一致,文件名使用小驼峰,方法名称与后端 restful 控制器一致.

  • enums 目录存放 常量,与后端的常量目录对应
  • icons 目录用于存放图标,element-ui 提供的图标实在是太少啦。所以我通常会使用 阿里的 iconfont
  • lang 目录存放多语言
  • layouts 目录存放布局
    • 上面展示的是一个后台系统,empty 为一个空布局。用于登录页面,其他页面则使用 default 布局。布局不需要过多介绍,写过 laravel blade 都很熟悉了。这里的布局需要和 vue-router 配合使用
  • mixins 类似 php 的 trait, 但是它更强大,完整贴合 vue 组件的生命周期
  • plugins 目录存放插件配置,比如 axios,vue-lazy 等 (这是从 nuxt 中学到的概念)
  • router 目录存放与 前端路由相关的配置,总体来说类似于 laravel 的 api 层
  • store 目录即 vuex 的目录,类似于前端的 model. 其文件与后端 model 相匹配,采用小驼峰命名
  • utils 目录存放辅助函数
  • views 为业务视图层,相信后端同学也很熟悉。其由 vue-router 直接调度
  • main.js 为 app 的入口,类似于后端的 index.php
  • components 目录,存放组件。通常是一些可复用的组件会单独存放在该目录

总体来说,已后端的 mvc 思想来看现代的前端项目是非常的自然的。后端的 model 对应前端的 store, 后端的 router 对应前端的 router, 后端的 controller + views 对应前端的 views.

基础规范

就目前来说 vue 项目很少用到 class, 因此 .js 文件通常都是一个 module, 所以文件名使用小驼峰的形式命名。如果有类文件,则类文件使用大驼峰的形式命名.

.vue 文件 可以使用 中划线和大驼峰两种命名方式,参考了 element/iview/nuxt 项目之后,推荐统一使用中划线命名.

所有的文件夹名称统一使用中划线命名

引入 vue 组件时文件时需要转换成大驼峰 import ‘TestTest‘ from ‘@/components/test-test‘

在 template 使用时依旧使用中划线

<test-test />

其他规范如变量命名和使用规范 使用 eslint 的 standard 即可很好的解决.

前端存在很多的事件 如 change/input/upload/sumit 等等,相应的处理推荐使用 handle + 事件名称,如 handleChange

生命周期

vue-router 解析当前用户键入的 url, 然后匹配合适的视图组件加载.

着重介绍一下 我对 views 目录下的视图组件的理解,已修改地址为例

script 部分既控制器部分,其请求数据,然后注入到 view 中,就像后端的 mvc 一样。只不过 vue 将 vc 其写入到了一个文件中。这样理解对于写过后端的同学显得更加的自然

控制器如何获取数据?

在过去的 vue 项目中,我们可能会见到这样的写法

// ... views/address/edit.vue
created () {
    axios.get(‘/addresses/1‘)
        .then((response) => {
             this.list = resposne.data
        })
}

//...

这种写法无异于后端在控制器中写 sql 语句一样,在工程化实践中不推荐这么做,后端通过 model 来获取数据会更加的优雅自然。在 vue 项目中,model 既 vuex, 因此推荐这么做

如果你对我说的东西一脸懵逼,那么你可以看一下 vuex 的文档。我现在做的就是用后端熟悉的概念,来描述前端项目的最佳实践

// ... views/address/edit.vue 控制器+视图
computed: {
    address: () => this.$store.address.itemBy[1] // 从store模型中取出我们想要数据
}
// ...
// ... store/modules/address.js  数据源
export default {
    state: {
        itemBy: {}
    },
    actions: {
        ...
    },
    mutations: {
        ...
    }
}
// ...
store 中的数据从哪里来?

数据当然是从后端的数据库中获取,我们不能让前端直接访问我们的数据库,因此我们会提供 api 让前端访问.store 中存在一个发起 api 请求的地方,既 action.

// ... store/modules/address.js  模型
export default {
    state: {
        itemBy: {}
    },
    actions: {
        async fetchItem({ commit, state }, { id }) {
             // 对axios和api进行了简单的封装,使api请求更加语义化
            cosnt { data } = await address.show(id)

            // action只能通过提交commit来修改state,具体原因请查看vuex文档 (其实我也忘了为啥 (╯﹏╰))
            commit(‘SET_ITEM‘, data)
        }
    },
    mutations: {
        SET_ITEM: (state, item) => {
            state.itemBy[item.id] = item
        }
    }
}
// ...

这样我们的模型中就有数据啦

什么时候去调用 fetchItem 去请求后端呢?

https://router.vuejs.org/zh/guide/advanced/data-fetching.html vue-router 文档的解答

这里不推荐在 vue 原始的生命周期中去调用初始化请求,可能会带来 数据还没有获取到,template 却已经被渲染。会造成一些数据不存在的异常,推荐在 vue-router 的生命周期中去请求数据

// ... views/address/edit.vue
async beforeRouteEnter (to, from, next) {
    // 等待模型数据加载完毕,才继续进行vue组件的生命周期
    await store.dispatch(‘fetchItem‘, to.params.id) 

    next()
}
created () {
    // 不推荐在这里调用 fetchItem
}

//...

到这里你可能发现,这和你平时写的 vue 有些不一样,没有类似 this.data = response.data 这种操作。类似这种操作其实类似赋值操作,或者称为副作用,其引入了时间的概念,使数据的管理变的复杂。直观的体现就是我们可能会有这种多余的 if(data) 判断.

当然副作用是难以避免的,但是我们可以统一的管理他们。类似上面的代码就是一套我觉得还不错的方法。从 view 的角度看,数据是固有存在存在的,其不需要关心是否是否已经被加载完毕,且 store 中的不可被 view 修改,既数据只能单向流动

在 store 中统一管理数据的另外一个好处就是方便持久化

view 层如何修改数据源?

上面的描述实际上表达了一种 发布与订阅的模式,从 store 到 view 的数据流是严格单向数据流动.

view 层不允许直接修改 store 中的数据,但是 view 层却可以通过发送 action 来影响数据源.

比如初始化时的 dispatch 的 action, 各种 event 触发的 dispatch. 当数据源发生改变时,作为订阅者的 view 层会非常自然的重新渲染.

这种设计和父子组件类似,vue 中子组件不允许直接修改父组件 props 到子组件的数据,只能通过向父组件 emit event. 在 view 和 store 之间,这种设计依然合理.

这也意味着应用中所有的数据都遵循相同的生命周期,这样可以让应用变得更加可预测且容易理解。

上面的图很好的阐述了这种开发模式。引自 https://github.com/sorrycc/blog/issues/1

view 层再深入

view 层的 script 部分,除了充当了传统的 controller, 起到初始化的作用外,实际上还做了更多的事情.

先从 data 部分说起,在 view 层会有一些状态需要记录,如 菜单的展开或收起,弹窗的弹出与关闭。对于这样的状态的管理,一种做法就是将存储在 data 部分.

也有人将所有的状态 也放在 store 中的 state 维护。既 state 分为状态和数据 两种类型.

view 层的 script 更重要的部分,是其到了一个交互反馈的作用,既类似下面的代码

<template>
    <button @click="handleSubmit"/>
</template>

<script>
    export default {
        data: {},
        methods: {
            handleSubmit() {

            }
        }
    }
</script>

关于 css 部分,由于个人不了解 css, 也不清楚 css 的业界规范及在 vue 上的最佳实践,因此不做过多介绍.

总结一下

在前面的介绍中,store 和 api 目录是和数据挂钩的,当数据库定下来,这一部分也就定了下来.

views/components 和业务 (ui) 挂钩,需要等设计稿确定后,这一部分才能确定下来.

PS 设计稿的图层通常就是组件的拆分规范?
使用 vuex 存储数据的另一个好处就是可以无缝的切换到 ssr 框架 nuxt

views 和 store 之间是一种订阅和发布的模式.

两个问题

store 中的 state 应该如何组织? 对于 api 请求,我们经常会看到这样的 json 数据

// post
{
    id: 1,
    title: xxxx,
    content: xxxx,
    user: {
        id: xxx,
        nickname: xxx,
        avatar: xxx,
    },
    comments: [
        {
            id: xxx,
            user_id: xxx,
            content: xxx,
            user: {
                // ...
            }
        },
        {
            //....
        }
    ]
}

上面的数据结构复杂,嵌套深入。如果我们将他们一股脑的存在 post 的 state 中,会造成数据过于集中,冗余. comments 无法独立化更新等等问题。使得前端 scheme/orm, 数据组织的规范化变的迫切需要

但是 vue 在这方面没有很好的规范和最佳实践. react 在这方面比较不错的实践 https://github.com/paularmstrong/normalizr

如何设计良好规范的 compoents?

组件的设计在业务层非常的重要,在下一篇我会介绍一下我总结出的一些实践

vuejs

tree-ql 意在代替 dingo/api,帮助你开发高可用的 API

原文地址:https://www.cnblogs.com/mouseleo/p/10829754.html

时间: 2024-11-11 20:56:12

Vue 工程化最佳实践的相关文章

Vue.js最佳实践

Vue.js最佳实践 第一招:化繁为简的Watchers 场景还原: created(){ this.fetchPostList() }, watch: { searchInputValue(){ this.fetchPostList() } } 组件创建的时候我们获取一次列表,同时监听input框,每当发生变化的时候重新获取一次筛选后的列表这个场景很常见,有没有办法优化一下呢? 招式解析: 首先,在watchers中,可以直接使用函数的字面量名称:其次,声明immediate:true表示创建

vue组件最佳实践

看了老外的一篇关于组件开发的建议(强烈建议阅读英文原版),感觉不错翻译一下加深理解. 这篇文章制定一个统一的规则来开发你的vue程序,以至于达到一下目的.1.让开发者和开发团队更容易发现一些事情.2.让你更好的利用你的IDE.3.让你更加容易的使用打包工具4.让你的代码更容易碎片化以达到复用的目的. 基于模块开发 用一些功能单一的小模块来组织你的应用 Why? 对于你自己和你团队的人来说较小的模块更容易看懂 维护 复用和调试. How? 每个组件应该保持单一 独立 可复用 可测试把你很大的组件拆

Vue.js最佳实践(五招助你成为vuejs大师)

转自https://www.jb51.net/article/139448.htm 本文面向对象是有一定Vue.js编程经验的开发者.如果有人需要Vue.js入门系列的文章可以在评论区告诉我,有空就给你们写. 对大部分人来说,掌握Vue.js基本的几个API后就已经能够正常地开发前端网站.但如果你想更加高效地使用Vue来开发,成为Vue.js大师,那下面我要传授的这五招你一定得认真学习一下了. 第一招:化繁为简的Watchers 场景还原: ? 1 2 3 4 5 6 7 8 created()

vue.js+boostrap最佳实践

一.为什么要写这篇文章 最近忙里偷闲学了一下vue.js,同时也复习了一下boostrap,发现这两种东西如果同时运用到一起,可以发挥很强大的作用,boostrap优雅的样式和丰富的组件使得页面开发变得更美观和更容易,同时vue.js又是可以绑定model和view(这个相当于MVC中的,M和V之间的关系),使得对数据变换的操作变得更加的简易,简化了很多的逻辑代码. 二.学习这篇文章需要具备的知识 1.需要有vue.js的知识 2.需要有一定的HTML.CSS.JavaScript的基础知识 3

10秒钟构建你自己的”造轮子”工厂! 2019年github/npm工程化协作开发栈最佳实践

发起一个github/npm工程协作项目,门槛太高了!! 最基础的问题,你都要花很久去研究: 如何在项目中全线使用es2017代码? 答案是babel 如何统一所有协作者的代码风格? 答案是eslint + prettier 如何测试驱动开发,让项目更健壮? 答案是jest 如何持续化集成,方便更多协作者参与项目? 答案是circleci 这四样工具的配置,是每个github项目都会用上的.另外,gitignore配置.editconfig.readme.lisence...也是必不可缺的. 你

[转] iOS开发者的Weex伪最佳实践指北

[From] http://www.cocoachina.com/ios/20170601/19404.html 引子 这篇文章是笔者近期关于Weex在iOS端的一些研究和实践心得,和大家一起分享分享,也算是对学习成果的总结.文章里面提到的做法也许不是最佳实践,也许里面的方法称不算是一份标准的指南手册,所以标题就只好叫"伪最佳实践指北"了.有更好的方法欢迎大家一起留言讨论,一起学习. 由于笔者不太了解Android,所以以下的文章不会涉及到Android. 一. React Nativ

require.js 最佳实践

require.js(官网:http://www.requirejs.org/)是一个js库,相关的基础知识,前面转载了两篇博文:Javascript模块化编程(require.js), Javascript模块化工具require.js教程,RequireJS 参考文章 1. require.js的主要作用是js的工程化,规范化: 1)它是一个js脚本的加载器,它遵循AMD(Asynchronous Module Definition)规范,实现js脚本的异步加载,不阻塞页面的渲染和其后的脚本

mpvue最佳实践 , 美团出的一个小程序框架

看手机微信,看到说美团出了1个小程序框架,  mpvue 搜下来试试,看了网上的一个对比 ----------------- 以下为引用 我们对微信小程序.mpvue.WePY 这三个开发框架的主要能力和特点做了横向对比,帮助大家了解不同框架的侧重点,结合业务场景和开发习惯,确定技术方案.对于如何更好地使用 mpvue 进行小程序开发,我们总结了一些最佳实践. 使用 vue-cli 命令行工具创建项目,使用Vue 2.x 的语法规范进行开发 避免使用框架不支持的语法特性,部分 Vue.js语法在

分布式系统关注点——99%的人都能看懂的「熔断」以及最佳实践

当我们工作所在的系统处于分布式系统初期的时候,往往这时候每个服务都只部署了一个节点. 如果想学习Java工程化.高性能及分布式.深入浅出.微服务.Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家. 那么在这样的背景下,如果某个服务A需要发布一个新版本,往往会对正在运行的其它依赖服务A的程序产生影响.甚至,一旦服务A的启动预热过程耗时过长,问题会更严重,大量请求会阻塞,产