zoukankan      html  css  js  c++  java
  • vue项目最佳实践

    使用vue一年多了,做了一个javaee的项目(全栈,前端使用的mvvm框架vue),三个移动端项目,其中两个钉钉子应用(钉钉的坑很多,心累),一个微信的(ing)。自己也慢慢摸索出一些项目中的最佳实践,整理了一下,做个记录一起交流。如果你在阅读过程中,觉得我某些地方做的不对或者有更好的方法时,欢迎交流~

    项目结构

    清晰的目录结构不仅可以展现一个团队的水平,而且别人维护(接锅)的时候,也能更好的理解你的项目。这个每个团队都有自己的标准或者风格,没有固定的格式。我一般是这么安排的(vue-cli项目),下面是src目录:

    —— 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中引入

    以上只是我个人的习惯,不过这个结构要根据具体的项目情况调整。不必为了模块化而模块化。如果你的项目业务逻辑不复杂,整个项目也就十几个页面,可以适当的删减部分模块。

    组件

    你的项目可能需要一些这样的组件,来提升用户体验。

    • no-data-found

      这个存在的场景是,比如你加载数据列表或者筛选列表查询等数据操作,如果请求成功但是没有数据,这时候有必要提供一个no-data-found的组件。

    • error

      当你的应用出错的时候,比如网络超时加载不了数据,也可以给一个组件做提示

    方法抽取

    在开始我们项目之前,我们应该知道,有哪些方法是必要的、共有的,类似于我们的工具方法一样。这里我罗列一些供参考:

    网络请求

    • 项目可能用到几种请求?(POST,GET,PUT,DELETE…)
      对于不同的请求,我们的请求头也需要改变,是抽取成四个方法,还是在一个方法上变异?
      哪种更适合现在的业务场景?
    • 请求出错如何处理(组件内捕获?全部捕获?其他?…)
      为什么提出这个问题呢?因为这是我前不久我的leader给我提的优化方案。之前的项目都没在意过这个,后来是把axios包了一层,使用了类似jQuery的请求方式,实现了组件内捕获业务场景错误(校验失败之类的),全部捕获请求错误(404,500,400等)。

    数据转换

    • 日期格式转换
    • 日期与字符串转换

      关于日期都所有操作,建议采用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...')

    如何管理css

    该分离还是该合并

    我们知道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
    • 使用
      如果你使用的vue-cli版本是3之前的话,修改项目中/build/utils.js中的scss成如下:
    scss: generateLoaders('sass').concat({
     loader: 'sass-resources-loader',
     options: {
       resources: path.resolve(__dirname, '../src/assets/styles/variables.scss')
     }
    })

    接下来就可以在任意的组件中使用这个varibles.scss里面的样式了。

    reset.css

    有的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的meta

    可能很多人用vue-router的时候,只是用来做路由跳转,配置路由的时候,添加一个path和component就完事了。如果这样能满足你的所有需求,那也ok。但是有一些业务场景,使用meta属性可以非常巧妙的解决问题。
    这里分享一下我使用过的例子:

    title

    想要动态的显示应用/系统的标题,你会怎么做呢?
    你可能会在每一个页面的钩子中给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,还有很多用处,比如处理前进后退的动画等。

    keepAlive

    我们知道vue提供了一个<keep-alive> 组件,用户缓存组件以获得更快的交互。简单介绍一下,当设置某一页面为keep-alive的时候,它的mounted只会在第一次加载的时候执行一次,后面在打开该页面的时候都不会执行。但是activateddeactivated两个钩子可以捕获页面进入和退出的动作。
    根据不同的业务逻辑,有些页面需要缓存有些页面不需要缓存,所以我们也可以定义在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

    scrollToTop

    我们知道,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

  • 相关阅读:
    83. Remove Duplicates from Sorted List
    141. Linked List Cycle
    hdu1028 划分数
    XDU1019 阶乘因子的个数
    poj2773 容斥原理
    poj1091 容斥原理的应用
    poj1173 多重集组合数
    HDU 1465 错排问题
    poj 1496
    复习之求一个数的约束之积模一个质数
  • 原文地址:https://www.cnblogs.com/jerryyj/p/9621546.html
Copyright © 2011-2022 走看看