68

前言

自总结完了上篇前端工程化的思想,并在vue全家桶的项目加以实践,趁热给大家总结一篇如何更有效率与质量地开发vue项目,以及其中踩过的一个个坑。。。

基于vue-cli的自定义模板(Custom Templates)

小伙伴们的vue项目应该都是用vue-cli初始化出来的,但是vue-cli只是满足了基础配置和功能,如果你有额外的配置需求或者要迎合团队的业务配置,每新建个项目都得重新安装额外配置,比如说vuex,sass,封装axios,以及相关的文件夹。为了解决上述问题,vue-cli出了一个自定义模板功能,你fork官方的模板下来然后进行修改,然后用 vue-cli 来调用。具体调用的场景有以下两种

  • 直接拉取git源:
    当你修改了模板并上传了repo上,可执行以下命令行来初始化

    vue init username/repo my-project
  • 拉取本地的模板:
    当你clone了官方模板在本地修改,可执行以下命令行来初始化

        vue init ~/fs/path/to-custom-template my-project

还可以编写meta.*(js,json)来选择安装哪些配置~

如果大家懒得去编写vuex,sass的配置,封装axios的话,可以来通过我配置完的脚手架来初始化完项目~

        vue init duosanglee/vuejs-custom-template

这个模板在repo
ps:我的这个模板的代码风格是基于standard的

引入sass全局变量,mixin,function等

首先我们考虑下以下场景:当使用rem开发移动端的时候,你定义了一个方法pxToRem的方法来实现px对rem的转换,然后在工程里为每个.vue文件@import 'public.scss',得import很多很多很多次,万一public.scss路径变了的话。。。哭都来不及。
这时候sass-resources-loader就来拯救我们了,他可以省去重复性的引入,还支持LESS,POSTCSS等
具体用法如下:

  • npm install -D sass-resources-loader

  • 首先得找到项目里的build文件夹,找到util.js
    添加一下代码

    function resolveResouce(name) {
        return path.resolve(__dirname, '../src/style/' + name);
    }
    function generateSassResourceLoader() {
        var loaders = [
     cssLoader, 
     // 'postcss-loader',
     'sass-loader',
     {
         loader: 'sass-resources-loader',
         options: {
           // it need a absolute path
           resources: [resolveResouce('common.scss')]
         }
     }
        ];
        if (options.extract) {
     return ExtractTextPlugin.extract({
       use: loaders,
       fallback: 'vue-style-loader'
     })
        } else {
     return ['vue-style-loader'].concat(loaders)
        }
    }
  • 然后还是在当前文件里找到

    return {
      css: generateLoaders(),
      postcss: generateLoaders(),
      less: generateLoaders('less'),
      sass: generateLoaders('sass', { indentedSyntax: true }),
      scss: generateLoaders('sass'),
      stylus: generateLoaders('stylus'),
      styl: generateLoaders('stylus')
    }

    替换成

    return {
      css: generateLoaders(),
      postcss: generateLoaders(),
      less: generateLoaders('less'),
      sass: generateSassResourceLoader(),
      scss: generateSassResourceLoader(),
      stylus: generateLoaders('stylus'),
      styl: generateLoaders('stylus')
    }

这样就可以在项目里使用sass全局变量,mixin,function了~~

在线 Mock 平台 easy-mock

现在讲都是前后端分离,前后端并行开发来提高开发效率,通过一个api文档来协作,所以一个好的mock工具对于提高效率也至关重要~
这里极力推荐easy-mock工具,支持团队协作编辑,生成模拟数据的在线 mock 服务,还支持导入swagger文档等功能,界面如下
clipboard.png

定义全局变量

在项目会有需要使用全局变量的需求,来处理一些频繁的操作,大家都应该会绑定到window对象上,但是这种方式不适合服务端渲染,因为服务端没有 window 对象, 是 undefined, 当试图去访问属性时会报错.我总结了两个靠谱的方法

  1. 代理到Vue的原型对象
    由于所有的组件都会从 Vue 的原型对象上继承它们的方法, 因此我们只要

    Object.defineProperty(Vue.prototype, '$xxx', { value: xxx });
    

    就可以在所有组件/实例中通过 this.$xxx: 的方式访问插件了~而不需要定义全局变量或者手动的引入了~
    至于为什么要用Object.defineProperty这个方法,是因为通过Object.defineProperty绑定的属性是只读的,以防一起开发项目的协(zhu)作(dui)者(you)去重写或者覆盖该方法的值。

  2. vuex大法
    vuex的出现就是vue为了集中式存储管理应用的所有组件的状态,所以说全局变量和方法都可以放到vuex当中~具体用法就不加阐述了,大家可仔细阅读vuex文档

组件设计

大家都知道组件化的思想就是分治,几乎任意类型的应用程序界面,都可以抽象为一个组件树,那我们该按照什么规则把应用抽象成组件,来应对复杂多变的业务需求呢。
我们从通信、黑箱,继承这几个角度来看看

  • 通信: vue的父子组件通信机制是props down,events up,尽量保持松耦合,一直保持单向数据流的特点,并加以强约束。需要注意的时候,尽可能减少跨组件通信,例如使用$parent,$root。

  • 继承: 当两个组件存在些许的共性,又存在足够的差异性的时候,就可以用到vue的继承---mixin,他允许你封装一块在应用的其他组件中都可以使用的函数。如果使用姿势正确,他们不会改变函数作用域外部的任何东西。而且mixin还有各种高阶用法,大家可自行查询(我也不会)。

  • 黑箱: 组件的黑箱状态既只暴露易变的接口和方法,渲染给入的数据,组件内部封装不变的逻辑。

  • 设计模式原则: 运用设计模式原则,比如单一职责原则,将组件拆分抽离成更细粒度,保证高内聚性;再如接口隔离原则,采用稳定的服务端接口,将变化模块分离,使得组件得以解耦;里氏替换原则、依赖倒置原则等等。。

目录结构

-- src
    -- assets                      # 私有资源
    -- common                      # 通用组件
    -- components                  # 业务组件
    -- api.js                      # 请求文件      
    -- config                      # 环境变量配置
        -- env.js                  # 环境变量文件
        -- http.js                 # 封装axios文件
    -- pages                       # 页面维度
        -- pageA                   # 页面A
            -- pageA.vue           # 页面A单文件
            -- pageA-components    # 页面A下的一个组件
            -- children            # 子页面
    -- router                      # 路由
        -- index.js                # 路由入口
        -- routes.js               # 路由配置信息
    -- store                       # vuex
        -- modules                 # vuex模块
        -- index.js                # vuex入口
    -- utils                       # js通用方法
    -- app.vue                     # 顶层单文件
    -- main.js                     # 入口

大家可以从目录结构中看出我整个项目分割的思维
首先我把组件分为通用组件业务组件两大类。

  1. 通用组件是与业务耦合低,是有简单状态或者无状态的,数据几乎全部依赖于输入,它只负责渲染给入的数据。比如按钮是一个组件,可能有一个参数决定了它的尺寸,一个参数决定了它是否可以点击,但是点击这个按钮之后会发生什么,就不是按钮这个组件需要知道的事情了。

  2. 业务组件是与业务耦合高,可以由多个通用组件和其他的业务组件组成,会拥有一些方法,用来修改持有的数据,对内来看,它自己持有一些数据和方法,用来决定内容的渲染,对外又是一个简单的props接受数据。可以理解为组件树的非叶子节点,通过自身数据变化,进而操纵子组件的内容。

然后config文件夹放置了环境变量文件env.js和封装http库文件http.js

env.js
clipboard.png

http.js
clipboard.png

然后我把路由里的routes.js和api.js请求文件都单独抽离了出来。

自动生成雪碧图

前端项目中自动生成雪碧图节省了我们很多的时间,我们只要把图片扔到文件夹里,webpack-spritesmith就能按照我们设定的规则自动合成css-sprite,安装配置如下:

var SpritesmithPlugin = require('webpack-spritesmith');
...
module.exports = {
  ...
  plugins: [
    new SpritesmithPlugin({
      src: {
        cwd: './src/assets/sp/',
        glob: '*.png'
      },
      target: {
        image: './src/assets/sprite/sprite.png',
        css: './src/assets/sprite/sprite.css'
      },
      apiOptions: {
        cssImageRef: './sprite.png'
      },
      spritesmithOptions: {
        algorithm: 'top-down',
        padding: 100
      }
    })
  ]
}

自动修复eslint格式错误

这个功能的建立在小伙伴的开发工具是vscode情况下~
首先在vscode扩展里面安装vscode的eslint插件,然后settings.json里添加如下配置

"eslint.validate": [
    "javascript",
    "javascriptreact",
    {
        "language": "html",
        "autoFix": true
    },
    {
        "language": "vue",
        "autoFix": true
    }
],
"eslint.autoFixOnSave": true,

然后会在save文件的时候eslint插件自动根据项目下的.eslintrc来设置代码格式~
sf不支持播放gif..具体效果大家只能自行查看

跨域

在浏览vue-cli的官方文档时候发现了vue-cli自带了API proxy,解决了在项目中后端联调的时候的跨域问题。具体安装配置如下:
首先我们找到config文件下的index.js,再找到dev对象下的proxyTable属性,然后把以下代码添加进去

proxyTable: {
  '/api': {
    target: '网站名',
    pathRewrite: {
      '^/api': ''
    }
  }
}

然后重启本地服务器,这样你发送的/api/a就会代理发送到"网站名/a"了~

开发利器emmet

之所以称emmet为前端开发利器是因为他可以根据我们所输入的缩写来得到相应的内容,大大节省我们的开发html和css的时间,例:

  • 输入ul>li*2>span 按下扩展键

<ul>
    <li><span></span></li>
    <li><span></span></li>
</ul>
  • 输入m0-a-0-0+posa+bgc 按下扩展键

margin: 0 auto 0 0;
position: absolute;
background-color: #fff;

更多方法请看官方文档emmet

这篇文章到此就已经结束了~感谢大家能够关注此文章~如果这篇文章能帮助到大家的话,麻烦请帮我点个赞~~~

大家有啥想法可在下面评论,也可以加我QQ:757592499来讨论~

参考:

http://www.jianshu.com/p/0375...
https://hopkinson.github.io/2...
https://github.com/dwqs/blog/...
http://jeffjade.com/2017/03/1...
http://www.jianshu.com/p/95b2...
https://segmentfault.com/a/11...


阿升
555 声望19 粉丝

26

引用和评论

26 条评论
头像
安于现状i

api.js一般怎么封装的,有例子可以看看不

2017-07-29
阿升(作者)

@安于现状i 我api.js没有封装 就是抽离出来了~评论里无法塞图片,可以加757592499详聊

2017-08-10
头像
RichardChou

清晰易懂,大神,支持一下

2017-07-24
头像
Nicofh

能不能写清楚自定义模板怎么弄上去了?

2017-07-25
阿升(作者)

@Nicofh fork官方的模板https://github.com/vuejs-temp...,然后根据你自己的需求进行修改,然后可以上传到自己的仓库,通过vue init username/repo my-project 命令来初始化自己的项目,或者可以修改完可以放在本地,通过vue init ~/fs/path/to-custom-template my-project 命令来初始化项目

2017-07-25
阿升(作者)

@Nicofh 这么讲可以更好的理解嘛~能接受的嘛 我就去改文章~

2017-07-25
Nicofh

@Nicofh 可以,这样清晰多了。 username/repo是创库的地址吗?如果这样定义模板会不会和vue,vue-router同步更新的?

2017-07-25
头像
MrTreasure

点个赞

2017-07-25
头像
星河

一味的追求工具,会使项目变得更加复杂难懂,如果原生支持export和import,会节省很大力气

2017-07-25
阿升(作者)

@星河 我是懒到极致了。。

2017-07-25
头像
kunge

点个赞

2017-07-25
头像
Indra

sass-resources-loader 这段 照着设置了 报错
loader错误ERROR in ./~/css-loader?{"minimize":true,"sourceMap":true}!./~.......................
我也不想在每个页面的style里 @import 公共的scss
求这个解决方案的详细教程

2017-08-10
阿升(作者)

@Indra https://github.com/Panda-Hope... 你可以看下这个文件,我也是参考这个设置的~

2017-08-10
头像
刘伟

sass-resource-loader 按照文字的介绍步骤 走了一遍,重启项目时一直报一个错误,导致项目启动不了,
error in ./src/vendor/v-calendar/components/CalendarDay.vue

Module build failed: Error:
Something wrong with provided resources.
Make sure 'options.resources' is String or Array of Strings.

at Object.module.exports (/Users/liuwei/doing/node_modules/sass-resources-loader/lib/loader.js:73:18)

大神们 有人遇到同样的问题吗???

2017-12-21
小事儿

@刘伟 是不是resolveResouce('common.scss'), 里面的common.scss 文件没改成自己的scss文件

2018-03-23
生活就像一堵围墙

@刘伟 大哥,我也遇到了同样的问题,究竟是?

2019-04-19
头像
vicco

学习到了, sass全局变量那块很受用,正巧看到. VSCODE也一直在用.感谢分享经验.

2018-02-06
头像
莉莉安

如果是 less,有对应的类似于sass-resources-loader 的吗

2018-04-11
头像
iceage

我报错找不到cssLoader

2018-07-16
头像
Raymond

vue-cli@3中处理全局SASS/SCSS变量的方法(亲测可用):
2020年9月6日 12:01:24

# 主流的两种方法 :
  • 使用 sass-resources-loader
  • vue.config.js 中配置 sass-loader

    // vue.config.js
    
    module.exports = {
      // sass-loader
      // https://vue-loader.vuejs.org/zh/guide/pre-processors.html#sass
      css: {
        loaderOptions: {
          sass: {
            // https://webpack.docschina.org/loaders/sass-loader/#options
            // https://webpack.docschina.org/loaders/sass-loader/#additionaldata
            // https://cli.vuejs.org/guide/css.html#passing-options-to-pre-processor-loaders
            additionalData: '@import "~@/style/variables.scss";'
          }
        }
      },
    }
# 注意:
  • vue.config.js 中引入了 variables.scss 后,不要再在 main.js 中引入,否则报错SassError: An @import loop has been found:
# 参考:
2020-09-06