Vue2+VueRouter2+Axios+Webpack+ElementUI 构建项目实战

安装 nodejs 环境

node下载:nodejs 官方网站

在安装好了 nodejs 之后,我们在终端中输入以下两个命令:

node -v
npm -v

这里写图片描述

若能够得到如上图的版本号信息,则说明 nodejs 环境已经安装完成了。
检查本地npm版本:npm -v,如果版本太低可以通过:npm install -g npm进行升级。


全局安装vue-cil

vue-cil是vue的脚手架工具。命令如下:

npm install -g vue-cli

这个命令只需要运行一次就可以了。安装上之后,以后就不用安装了。

安装完成后,我们在终端中输入:

vue -V

这里写图片描述

如果输出如上图的版本号信息,则代表你安装正确。


全局安装webpack

若没有安装webpack,则输入以下命令行进行npm安装

npm install webpack -g

vue-cil构建项目

用 vue-cli 构建一个项目

下面,新建一个自己的vue项目:

vue init webpack vuedemo

项目名称是不是 vuedemo ,按回车,表示,是。当然,你也可以重写一个,然后回车。
Project name vuedemo ? Yes

是不是一个 vue.js 的项目。同样,我们可以填写内容,或者直接回车
Project description A Vue.js project ? Yes

作者姓名,直接回车 ,或自己输入也行
Author ? Yes

这里是问你,需要不需要安装编译器,我们选择需要安装,也就是第一个,也就是直接回车就OK了。
Vue build standalone ? Yes

问是不是需要安装 vue-router ,需要安装,这个是管理路由的。我们直接回车。
Install vue-router? Yes

是否需要使用 ESLint 来检查你的代码。需要!所以同上,我们直接回车或N。
Use ESLint to lint your code? No

是否需要安装测试功能。不要。我们输入 n 然后回车。
Set up unit tests No ?

还是关于测试的内容,我们还是输出 n 然后回车。
Setup e2e tests with Nightwatch? No

如下图:
这里写图片描述

接下来

这里写图片描述

根据图上的提示,继续

 cd vuedemo
 npm run dev

就可以启动项目了。在浏览器里面打开localhost:8080,页面如下:
这里写图片描述

这时的目录是这样的
node_modules已经存在,就不需要npm install。

这里写图片描述

没有install的话,还是需要npm install,再运行的,如:

 cd vuedemo
 npm install
 npm run dev

其中, npm install 因为需要联网,并且是去连 github ,如果你没有翻墙的话,可能速度会比较慢。我们可以使用国内淘宝提供的 npm 镜像源来进行安装,解决翻墙的问题。

安装方法

npm install -g cnpm --registry=https://registry.npm.taobao.org

更多内容,请参考 cnpm 官方网站: https://npm.taobao.org/


standard 标准风格规范说明
我们在上面安装了代码校验,并且采用了 standard 标准风格规范。
规范官方 github 仓库地址:https://github.com/feross/standard

缩进使用两个空格。
字符串使用单引号,用双引号只是为了避免转义单引号。
无未使用变量。这能帮助发现大量的错误。
不使用分号。这么做,没问题,真的!
行首不能是 ( ,[ 或 ` 。
这是省略分号时唯一陷阱—— standard 自动为你检查。
关键字后面放一个空格。if (condition) { … }
函数名字后面放一个空格。function name (arg) { … }
始终用 ===,不要用 ==。不过可以用 obj == null 检测 null || undefined。
始终处理 node.js 回调的 err 参数。
始终以 window 引用浏览器的全局变量。 document 和 navigator 除外。
这是为了防止使用浏览器那些命名糟糕的全局变量,比如 open, length, event 和 name。


认识项目所有文件

├── README.md                       // 项目说明文档
├── node_modules                    // 项目依赖包文件夹
├── build                           // 编译配置文件,一般不用管
│   ├── build.js
│   ├── check-versions.js
│   ├── dev-client.js
│   ├── dev-server.js
│   ├── utils.js
│   ├── vue-loader.conf.js
│   ├── webpack.base.conf.js
│   ├── webpack.dev.conf.js
│   └── webpack.prod.conf.js
├── config                          // 项目基本设置文件夹
│   ├── dev.env.js              // 开发配置文件
│   ├── index.js                    // 配置主文件
│   └── prod.env.js             // 编译配置文件
├── index.html                      // 项目入口文件
├── package-lock.json           // npm5 新增文件,优化性能
├── package.json                    // 项目依赖包配置文件
├── src                             // 我们的项目的源码编写文件
│   ├── App.vue                 // APP入口文件
│   ├── assets                      // 初始项目资源目录,回头删掉
│   │   └── logo.png
│   ├── components              // 组件目录
│   │   └── Hello.vue           // 测试组件,回头删除
│   ├── main.js                 // 主配置文件
│   └── router                      // 路由配置文件夹
│       └── index.js            // 路由配置文件
└── static                          // 资源放置目录

如上,就是我们的 vue 初始化后得到的一个项目的完整结构。其他大多数文件我们是不用管的

我们绝大多数的操作,就是在 src 这个目录下面。默认的 src 结构比较简单,我们需要重新整理。
另外 static 资源目录,我们也需要根据放置不同的资源,在这边构建不同的子文件夹。


配置 src 目录

把项目文件夹整理成如下的结构

├── App.vue                         // APP入口文件
├── api                             // 接口调用工具文件夹
│   └── index.js                    // 接口调用工具
├── components                      // 组件文件夹,目前为空
├── config                          // 项目配置文件夹
│   └── index.js                    // 项目配置文件
├── frame                           // 子路由文件夹
│   └── frame.vue                   // 默认子路由文件
├── main.js                         // 项目配置文件
├── page                                // 我们的页面组件文件夹
│   ├── content.vue             // 准备些 cnodejs 的内容页面
│   └── index.vue                   // 准备些 cnodejs 的列表页面
├── router                          // 路由配置文件夹
│   └── index.js                    // 路由配置文件
├── style                           // scss 样式存放目录
│   ├── base                        // 基础样式存放目录
│   │   ├── _base.scss          // 基础样式文件
│   │   ├── _color.scss     // 项目颜色配置变量文件
│   │   ├── _mixin.scss     // scss 混入文件
│   │   └── _reset.scss     // 浏览器初始化文件
│   ├── scss                        // 页面样式文件夹
│   │   ├── _content.scss       // 内容页面样式文件
│   │   └── _index.scss     // 列表样式文件
│   └── style.scss              // 主样式文件
└── utils                           // 常用工具文件夹
    └── index.js                    // 常用工具文件

因为我们删除了一些默认的文件,所以这个时候项目一定是报错的,先不管他,我们根据我们的需求,新建如上的项目结构。这些都是在 src 目录里面的结构。


配置 static 目录

├── css             // 放一些第三方的样式文件
├── font                // 放字体图标文件
├── image           // 放图片文件,如果是复杂项目,可以在这里面再分门别类
└── js              // 放一些第三方的JS文件,如 jquery

你可能很奇怪,我们不是把样式和 JS 都写到里面去么,为什么还要在这边放呢?

因为,如果是放在 src 目录里面,则每次打包的时候,都需要打包的。这回增加我们的打包项目的时间长度。而且,一些地方放的文件,我们一般是不会去修改的,也没必要 npm 安装,直接引用就好了。你可以根据自己的情况,对这些可以不进行打包而直接引用的文件提炼出来,放在资源目录里面直接调用,这样会大大的提高我们的项目的打包效率。


全局引用ElementUI

npm安装:

npm i element-ui -S

安装完成后,完整引入element-ui,
在 main.js 中写入以下内容:

import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';

Vue.use(ElementUI);

new Vue({
  el: '#app',
  render: h => h(App)
});

安装字体包fontawesome

npm 安装 font-awesome:

npm install font-awesome 

然后在main.js 文件中引入

 import 'font-awesome/css/font-awesome.css'

调整 App.vue 和 router 路由

调整 App.vue 文件
我们先把默认项目里面没用的东西先删除掉,把代码调整为下面的样子。

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

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

<style lang="scss">
  @import "./style/style";
</style>

入口,只有一个空的路由视窗,我们的项目的所有内容,都基于这个视窗来展现。

我们的样式,都将从 src/style/style.scss 这个文件中引用,因此,在 App.vue 这个文件中,直接引用 ./style/style 即可。

好,调整好了我们的 App.vue 文件后,因为我们使用了 scss 文件预编译,所以我们需要安装两个支持 scss 的 npm 包。

我们在项目终端内输入下面的两句命令来进行安装:

npm install sass-loader -D
npm install node-sass -D

调整 index.vue 和 content.vue 文件

昨天,我们在 page 文件夹下面建立了两个空文本文件 index.vue 和 content.vue 文件,是我们准备用来放列表和内容的。

这里,我们先去填写一点基础内容在里面。

index.vue

<template>
  <div class="index-wrap">
    <el-container>
      <el-aside><navMenu></navMenu></el-aside>
      <el-container id="el-container">
        <el-header><my-header></my-header></el-header>
        <el-main>
          <router-view></router-view>
        </el-main>
        <el-footer><my-footer></my-footer></el-footer>
      </el-container>
    </el-container>
  </div>
</template>

<script>
  import myHeader from '../components/Header'
  import myFooter from '../components/Footer'
  import navMenu from '../components/NavMenu'
  export default {
    name: "Index" ,
    components: {
      myHeader, myFooter, navMenu
    }
  }
</script>

Header.vue

<template>
    <div class="header" id="Header">
      This is my Header
    </div>
</template>

<script>
export default {
  name: "Header"
}
</script>

<style scoped>
</style>

Footer.vue

<template>
    <div class="footer" id="Footer">
      This is my Footer
    </div>
</template>

<script>
export default {
    name: "Footer"
}
</script>

NavMenu.vue

<template>
  <div class="nav-menu">
    This is my NavMenu
  </div>
</template>

<script>
export default {
  name: "NavMenu"
}
</script>

Content.vue

<template>
  <div>
      This is my Content
  </div>
</template>

ContentList.vue

<template>
  <div>
      This is my ContentList
  </div>
</template>

调整 router 路由文件

在router/index.js调整路由
可以参考官方文档《动态路由匹配》

import Vue from 'vue'
import Router from 'vue-router'
import Index from '@/page/Index'
import Content from '@/page/Content'
import ContentList from '@/page/ContentList'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Index',
      component: Index,
      children: [
        {
          path: '/Content',
          name: 'Content',
          component: Content,
        },
        {
          path: '/ContentList/:id',
          name: 'ContentList',
          component: ContentList,
        }
      ]
    }
  ]
})

配置 Axios api 接口调用文件

安装 axios 工具。执行下面的命令进行安装

npm install axios -D

还记得文中整理的系统结构吗?我们新建了一个 src/api/index.js 这个空文本文件。这里,我们给它填写上内容。

// 配置API接口地址
var root = 'https://cnodejs.org/api/v1'
// 引用axios
var axios = require('axios')
// 自定义判断元素类型JS
function toType (obj) {
  return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase()
}
// 参数过滤函数
function filterNull (o) {
  for (var key in o) {
    if (o[key] === null) {
      delete o[key]
    }
    if (toType(o[key]) === 'string') {
      o[key] = o[key].trim()
    } else if (toType(o[key]) === 'object') {
      o[key] = filterNull(o[key])
    } else if (toType(o[key]) === 'array') {
      o[key] = filterNull(o[key])
    }
  }
  return o
}
/*
  接口处理函数
  这个函数每个项目都是不一样的,我现在调整的是适用于
  https://cnodejs.org/api/v1 的接口,如果是其他接口
  需要根据接口的参数进行调整。参考说明文档地址:
  https://cnodejs.org/topic/5378720ed6e2d16149fa16bd
  主要是,不同的接口的成功标识和失败提示是不一致的。
  另外,不同的项目的处理方法也是不一致的,这里出错就是简单的alert
*/

function apiAxios (method, url, params, success, failure) {
  if (params) {
    params = filterNull(params)
  }
  axios({
    method: method,
    url: url,
    data: method === 'POST' || method === 'PUT' ? params : null,
    params: method === 'GET' || method === 'DELETE' ? params : null,
    baseURL: root,
    withCredentials: false
  })
  .then(function (res) {
    if (res.data.success === true) {
      if (success) {
        success(res.data)
      }
    } else {
      if (failure) {
        failure(res.data)
      } else {
        window.alert('error: ' + JSON.stringify(res.data))
      }
    }
  })
  .catch(function (err) {
    let res = err.response
    if (err) {
      window.alert('api error, HTTP CODE: ' + res.status)
    }
  })
}

// 返回在vue模板中的调用接口
export default {
  get: function (url, params, success, failure) {
    return apiAxios('GET', url, params, success, failure)
  },
  post: function (url, params, success, failure) {
    return apiAxios('POST', url, params, success, failure)
  },
  put: function (url, params, success, failure) {
    return apiAxios('PUT', url, params, success, failure)
  },
  delete: function (url, params, success, failure) {
    return apiAxios('DELETE', url, params, success, failure)
  }
}

我们写好这个文件之后,保存。
有关 axios 的更多内容,请参考官方 github: https://github.com/mzabriskie/axios ,中文资料自行百度。


调整 main.js 绑定 api/index.js 文件

在main.js中,加入下代码

// 引用API文件
import api from './api/index.js'
// 将API方法绑定到全局
Vue.prototype.$api = api

这样,我们就可以在项目中使用我们封装的 api 接口调用文件了。

测试一下看看能不能调通

我们来修改一下 src/page/Content.vue 文件,将代码调整为以下代码:

<template>
  <div>
      This is my Content
  </div>
</template>
<script>
export default {
  created () {
    this.$api.get('topics', null, r => {
      console.log(r)
    })
  }
}
</script>

好,这里是调用 cnodejs.org 的 topics 列表接口,并且将结果打印出来。

我们在浏览器中打开控制台,看看 console 下面有没有输出入下图一样的内容。如果有的话,就说明我们的接口配置已经成功了。

这里写图片描述

好,如果你操作正确,代码没有格式错误的话,那么现在应该得到的结果是和我一样的。如果出错或者怎么样,请仔细的检查代码,看看有没有什么问题。


将接口用 webpack 代理到本地

我们可以注意到我们的 src/api/index.js 的第一句,就是:

// 配置API接口地址
var root = 'https://cnodejs.org/api/v1'

这里,我们将接口地址写死了。

配置 webpack 将接口代理到本地

好在,vue-cli 脚手架工具,已经充分的考虑了这个问题,我们只要进行简单的设置,就可以实现我们的目的。

我们打开 config/index.js 文件,找到以下代码:

  dev: {
    env: require('./dev.env'),
    port: 8080,
    autoOpenBrowser: true,
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    proxyTable: {},
    cssSourceMap: false
  }

其中,proxyTable: {}, 这一行,就是给我们配置代理的。

根据 cnodejs.org 的接口,我们把这里调整为:

proxyTable: {
  '/api/v1/**': {
    target: 'https://cnodejs.org', // 你接口的域名
    secure: false,
    changeOrigin: false,
  }
}

OK,我们这样配置好后,就可以将接口代理到本地了。

更多接口参数配置,请参考 https://github.com/chimurai/http-proxy-middleware#options
webpack 接口配置文档 https://webpack.js.org/configuration/dev-server/#devserver-proxy

重新配置 src/api/index.js 文件

好,上面已经代理成功了,但是我们的 src/api/index.js 文件,还是直接调用的人家的地址呢,我们要调整为我们的地址,调整如下:

// 配置API接口地址
var root = '/api/v1'

值得注意的事情是,配置完成后,是不会立即生效的,我们需要重启我们的项目。
我们按 ctrl + c 停止掉之前的服务,然后重新输入命令 npm run dev 重启项目,就可以了。

这里写图片描述
没有问题,数据过来了。


编辑Content.vue文件

<template>
    <div>
      <h1>this.is content</h1>
      <ul>
        <li v-for="item in list">
          <time v-text="item.create_at"></time>
          <router-link :to="'/ContentList/' + item.id">
            {{ item.title }}
          </router-link>
        </li>
      </ul>
    </div>
</template>

<script>
  export default {
    name: "Content",
    data(){
      return {
        list: []
      }
    },
    created () {
      this.getData()
    },
    methods: {
      getData () {
        let that = this
        this.$api.get('topics', null, res => {
          that.list = res.data
        })
      }
    }
  }
</script>

<style scoped>

</style>

css样式,我就不多说了,相信大家自己能搞定

如此,我们能得到以下的content页面:

这里写图片描述


写一个公用的时间处理工具函数

编写 src/utils/index.js 文件
直接给代码如下:

export default {
  goodTime (str) {
    let now = new Date().getTime()
    let oldTime = new Date(str).getTime()
    let difference = now - oldTime
    let result = ''
    let minute = 1000 * 60
    let hour = minute * 60
    let day = hour * 24
    let month = day * 30
    let year = month * 12
    let _year = difference / year
    let _month = difference / month
    let _week = difference / (7 * day)
    let _day = difference / day
    let _hour = difference / hour
    let _min = difference / minute

    if (_year >= 1) {
      result = '发表于 ' + ~~(_year) + ' 年前'
    } else if (_month >= 1) {
      result = '发表于 ' + ~~(_month) + ' 个月前'
    } else if (_week >= 1) {
      result = '发表于 ' + ~~(_week) + ' 周前'
    } else if (_day >= 1) {
      result = '发表于 ' + ~~(_day) + ' 天前'
    } else if (_hour >= 1) {
      result = '发表于 ' + ~~(_hour) + ' 个小时前'
    } else if (_min >= 1) {
      result = '发表于 ' + ~~(_min) + ' 分钟前'
    } else {
      result = '刚刚'
    }
    return result
  }
}

在 main.js 中将我们的方法函数给绑定上。如下代码:

// 引用工具文件
import utils from './utils/index.js'
// 将工具方法绑定到全局
Vue.prototype.$utils = utils

然后,调整Content.vue代码:

<time v-text="$utils.goodTime(i.create_at)"></time>

如此,得到以下的content页面:

这里写图片描述

好,我们已经看到,时间已经搞的挺好的了。


再把内容页面渲染出来

编写内容页面ContentList.vue:

<template>
    <div>
      <h2 v-text="contentList.title"></h2>
      <p>作者:{{contentList.author.loginname}}  发表于:{{$utils.goodTime(contentList.create_at)}}</p><hr>
      <article v-html="contentList.content"></article>
      <h3>网友回复:</h3>
      <ul>
        <li v-for="item in contentList.replies">
          <p>评论者:{{item.author.loginname}}  评论于:{{$utils.goodTime(item.create_at)}}</p>
          <article v-html="item.content"></article>
        </li>
      </ul>
    </div>
</template>

<script>
  export default {
    name: "ContentList",
    data () {
      return {
        id: this.$route.params.id,
        contentList: {}
      }
    },
    created () {
      this.getData()
    },
    methods: {
      getData () {
        this.$api.get('topic/' + this.id, null, res => {
          this.contentList = res.data
        })
      }
    }
  }
</script>

<style scoped>

</style>

好,我们这边把代码写进 src/page/content.vue 文件。然后保存,我在我们先前的列表页面随便点开一篇文章,然后我们看下结果:

这里写图片描述

好,按照我们的需求已经渲染出来了。


打包项目并发布到子目录

然后运行如下代码,进行打包:

npm run build

运行结果如下:

这里写图片描述

好,我们已经打包好了。文件打包位置于项目目录里面的 dist 文件夹内。

但是,我们从上图可以看到,我们生成了一些 .map 的文件。当我们的项目变得比较大的时候,这些文件,第一个是,非常大,第二个,编译时间非常长。所以,我们要把这个文件给去掉。

去掉 map 文件

我们编辑 /config/index.js 文件,找到其中的

productionSourceMap: true,

修改为:

productionSourceMap: false,

然后我们重新运行打包命令:

npm run build

好,我们看下运行结果:

这里写图片描述

没用的 map 文件已经没有了。

好,我们可以从上图中看出,有一个 tip 。它告诉我们,打包出来的文件,必须在 http 服务中运行,否则,不会工作。


安装 http-server 启动 http 服务

我们进入 dist 文件夹,然后启动一个 http 服务,来看看可以不可以访问。

你可能不知道如何启动这样一个 http 服务,或者,你现在已经到 apache 里面去进行配置去了。不用那么麻烦,我们有 nodejs 环境,只要全局安装一个 http-server 服务就好了呀。

npm install http-server -g

安装好了之后正常我们就能够使用 http-server 命令来跑服务了。但是,这个世界不正常的时候是很多的嘛!

在终端里面输入:

http-server

这里写图片描述

看能否正常启动,还是爆 -bash: http-server: command not found 错误,这里,是说没有找到这个命令,没有关系,这是表示,我们的 nodejs 的程序执行路径,没有添加到环境变量中去。

首先,如上图所示,我们的 http-server 安装到了 /usr/local/Cellar/node/7.6.0/bin/ 这个目录下面,我们只要把这个目录,添加到环境变量即可。

请注意,你的安装路径可能和我的是不一致的,请注意调整。

我们在终端内执行下面两个命令,就可以了。

echo 'export PATH="$PATH:/usr/local/Cellar/node/7.6.0/bin/"' >> ~/.bash_profile 
. ~/.bash_profile

第一条命令是追加环境变量,第二个命令是,使我们的追加立即生效。

好,一个插曲结束。

忘记了我们要干嘛了吗?我们要把我们打包出来的东西跑起来呀!

cd dist
http-server -p 8080

如果你是严格按照我的教程来的,那么现在已经可以顺利的跑起来了。我们在浏览器中输入 http://127.0.0.1:3000 就应该可以访问了。

当然,会报错,说是接口找不到,404错误。因为我们把接口给通过代理的方式开启到了本地,但是这里我们并没有开启代理,所以就跑不起来了。很正常的。

这是因为示例的接口的问题。实际开发你还要按照我的这个做。只不过,最终代码放到真实的服务器环境去和后端接口在一个 http 服务下面的话,就不存在这个问题了。

好,我们就跑起来了。


将项目打包到子目录

刚刚,我们是将文件,打包为根目录访问的。也就是说,必须在 dist 文件夹下面启动一个服务,才能把项目跑起来。

但是我们开发的大多数项目,可能是必须跑在二级目录,甚至更深层次的目录的。怎么做呢?

我们编辑 config/index.js 文件,找到:

assetsPublicPath: '/',

把 ‘/’ 修改为你要放的子目录的路径就行了。这里,我要放到 /dist/ 目录下面。于是,我就把这里修改为

assetsPublicPath: '/dist/',

有些人,在config/index.js中,改为assetsPublicPath: ‘/dist/’,
打包后使用http-server运行项目时,浏览器就会报404错误;
但是将assetsPublicPath: ‘/dist/’改为assetsPublicPath: ‘./’,重新打包后就可以正常访问了

然后,重新运行

npm run build

进行打包。

很快,就打包好了。

还记得,我们在项目文件夹中用 npm run dev 就可以开启一个 http 服务吗?并且那里,我们还代理了接口的。

然后我们访问二级目录 /dist/ 我们就可以看到效果了。

这里写图片描述

注意,我访问的不是根目录,而是 /dist/ 这个子目录哦,这里是访问的我们打包的文件的。

├── index.html
└── static
    ├── css
    │   └── app.d41d8cd98f00b204e9800998ecf8427e.css
    └── js
        ├── app.8ffccad49e36e43a4e9b.js
        ├── manifest.7a471601ff5a8b26ee49.js
        └── vendor.057dd4249604e1e9c3b5.js

好,到这里,我们的打包工作,就讲完了。

实际开发中,你只需要把 dist 文件夹中打包好的文件,给运维他们,让他们去部署到真实的服务器环境就好了。

关于项目打包时,图片等资源的处理,
请查看本博文参考的原作者的博文 http://blog.csdn.net/fungleo/article/details/77799057

本文有参考https://blog.csdn.net/fungleo/article/details/53171052

版权声明:本文由 LuviaWu参考修改作为原创,允许转载,但转载必须保留首发链接。

猜你喜欢

转载自blog.csdn.net/luviawu/article/details/81119006