背景

通过bootstrap3已经完成了一个网站的静态页面,想通过vuejs + webpack的组合,让前端更酷一点,顺便也是练练手,所以接下来就是行动。

选型

在一开始,vuejs并不是首选,而是看的emberjs,这货看起来和我写后端类似,继承一个对象类,然后开始写行为方法,当然,我作为一个后端选手,还不太明白前端的概念,只是觉得亲切。后来偶然的情况,看到一篇文章说emberjs上手比较困难,而且效率不高,不管是开发上的还是运行上的,所以,我就索性把所有的前端框架都拿来对比了一下。

首先是angularjs,谷歌一直是我们开发界的翘楚,榜样,谷歌出的东西,就是无条件好,我也曾经用angular做过一个小项目,虽然那时候是用的1.x,现在好像已经到4了,但是总归变化不……大尼玛太大了,算了,已经看不懂了。

接下来是react,脸书出品,也算精品,等等,这dom上一个两个奇形怪状的是什么东西,完全是天书。

然后是vuejs,国人参与了核心开发的,嗯,看起来好像挺简单,上手挺快,效率还高,就它了。

环境

选定vuejs之后,接下来就是看官方网站上的手册,手册上写得很清楚,入门就不再赘述了,我现在要做的是怎么把我现有的静态界面弄成vuejs like的。

这个时候我看到了一个vuejs+webpack的项目模板,可以通过vue-cli来完成,安装都是通过npm,npm就不得不说,这玩意玩nodejs的都太熟悉了,所以赶紧来一波

$ npm install -g vue-cli
$ vue init webpack my-vue
$ cd my-vue
$ npm install
$ npm run dev

在初始化的时候,会有一些询问,类似于项目名、介绍、作者、是否使用eslint、是否使用测试等,我把Karma + Mocha的测试都给屏蔽掉了,我不是不爱测试,一来前端都很直接,看得到结果,二来,我一个初学者,弄得太高大全,容易迷失方向。

完成之后,项目会形成一个标准结构,

 - build
 - config
 - dist
 - node_modules
 - src
    - assets
    - components
    - router
 - static
 .babelrc
 .editorconfig
 .eslintignore
 .eslintrc.js
 .gitignore
 .postcssrc.js
 index.html
 package-lock.json
 package.json

build

这个文件夹是webpack相关内容,我们暂时别动它,它可以使我们的工作全部打包成production状态,自动替换路径、混淆、优化等

config

这个文件夹主要是环境的配置,有开发状态和生产状态,定义了不同的参数,我们也可以不动

dist

这个文件夹是运行指令

    npm run build

之后的内容存放的地方,可以将dist更名为你的项目,然后放到http-server中就可以开动了。

src

这个文件夹就很重点了,它是我们主要工作的地方,其中

  • assets文件夹是存放静态资源的,例如一些图片啊什么的
  • components文件夹是存放vue的组件的,结尾是以vue结尾
  • router文件夹里面的index.js文件用来定义路由

App.vue是整个组件的入口,main.js是执行的入口。

其他

其他文件和文件夹就不一一赘述了

页面分割

现在有了项目,我们就得分割我们的静态页面了,假设我们的静态页面有三个频道,首页、新闻页、关于页,那作为初学者,我们可以很容易的将这三个页面做成三个组件,Home.vue、News.vue、About.vue。

同时我们把这三个界面需要的公共部分都放到App.vue中。

<template>
  <div id="app">
    <nav>...</nav>
    <router-view></router-view>
    <footer>...</footer>
  </div>
</template>

<script>
export default {
  name: 'app'
}
</script>

<style>
#app {
  text-align: center;
}
</style>

可以看到template部分放入了nav和footer,而中间就是我们要换来换去的地方,当然,也可以将nav和footer都做成component,然后各个页面去引用,这个很灵活,可以去尝试。

资源加载

完成了界面分割之后,就是图片怎么加载了,第三方的js怎么引用了。

图片来说的话,只要放在assets中,当构建之后,会自动放置在static/img下,vue中的路径也会自动更换。

第三方的js来说就有意思了,有三种方式,第一种是放在assets中,然后和图片一样的引入方式,第二种是cdn的,这种直接放在index.html中,

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>my-vue-template</title>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
    <script src="//cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
  </body>
</html>

可以看到jquery就这样引入了。

第三种方式是通过npm引入,例如momentjs,

    npm install moment --save

然后在main.js中引入,

import Vue from 'vue'
import App from './App'
import router from './router'
import moment from 'moment'
import VueLazyload from 'vue-lazyload'

Vue.config.productionTip = false

Vue.use(VueLazyload)

Vue.filter('formatDate', function (value) {
  if (value) {
    return moment(String(value)).format('YYYY-MM-DD HH:mm:ss')
  }
})

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  template: '<App/>',
  components: { App }
})

这个范例引入了moment和vue-lazyload两个,并通过Vue.filter设置了一个过滤装置,能够将日期格式化成我们想要的格式。

注意:我比较喜欢直接用cdn的形式,因为这样比较节约自己服务器的资源。

路由

编译完成后,会只有一个index.html文件,其中间的组件都是动态加载的,通过路由来完成,我们在router/index.js中进行配置,

import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/components/Home'
import News from '@/components/News'
import About from '@/components/About'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home
    },
    {
      path: '/news',
      name: 'News',
      component: News
    },
    {
      path: '/about',
      name: 'About',
      component: About
    }
  ]
})

这里可以看到,我们先将组件进行import,然后在routes中添加这几个连接,有一个注意的地方是,如果我们不希望点击“/news”的时候,会解析到首页的话,那我们就要在router-link中设置一下,


    <router-link to="/" active-class="active" exact>首页</router-link>
    
    <router-link to="/news" active-class="active">新闻</router-link>

加入exact,即可表示这里的router-link只完全匹配“/”才行,而不是其子都可以。active-class表示在激活时的class,这个方便你的nav高亮显示。

一些坑

文件检查加入忽略项

  // add your custom rules here
  'rules': {
    // allow paren-less arrow functions
    'arrow-parens': 0,
    'no-undef': 0,
    'space-before-function-paren': 0,
    // allow async-await
    'generator-star-spacing': 0,
    // allow debugger during development
    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
  }

这里我们追加了no-undef和space-before-function-paren。

no-undef

这个错误提示主要是由于我们在index.html中引入了三方包(例如jquery),jquery我们并没有通过import来引入,但是我们又要在script中引用,就会报这个错误,但是这是肯定不会引起错误的,所以屏蔽掉

space-before-function-paren

这个错误提示主要来自于一种优雅的方法写法,

...

<script>
export default {
  name: 'app',
  data() {
      return {
          ...
      }
  }
}
</script>

...

data()这个写法很优雅,替代了data: function()的方式,但是由于这个错误提示,导致这个方式无法通过,必须在单词和括号之间加入空格,但是很多IDE在format的时候会自动将两个放在一起而引起,所以我们忽略掉这个提示。

下一步

现在,我们就可以通过vue来浏览静态内容了,那么下一步该干点啥了,对了,将有public api的cms和vue结合起来,后端内容由cms产出,前端直接用vue来调用内容,再显示出来,嗯,想想还有点小激动呢。