Vue.js第5课-Vue项目预热

一、项目环境准备

在开发之前,我们需要安装 Node.jsGit,然后注册一个 GitHub 账号用来存放我们的项目,通过 Git 管理我们的项目。以上的安装和注册操作略过,可以参考我的 如何在GitHub上协作开发项目 这篇文章。

安装成功后,使用 -v 命令检查是否安装成功:

登录 GitHub,我们创建一个仓库 Vue-Travel:

此时,在 GitHub 中就有了一个 Vue-Travel 的仓库。

接下来我们将本地的代码和线上的代码通过 Git 做一个关联,这样一旦本地代码丢失了,可以通过线上代码恢复,而且线上会记录我们对代码的每一步操作。下面我们通过 SSH 将线上代码克隆到本地:

然后在 Vue-Travel 目录中创建一个 Vue.js 项目,我们打开 Vue.js 官网看一下 Vue CLI 的安装步骤:先通过 “npm install --global vue-cli” 全局安装 vue-cli,然后通过 “vue init webpack xxx” 初始化项目,根据提示一步一步完成项目的构建。

补充:在上边的执行步骤中,有些是一选项的形式进行选择的,他会提示你 “Use arrow keys”,这种情况,在 Window 下,先输入序号,然后回车就可以了。构建成功后,根据命令提示,运行项目:

此时打开我们的项目目录,可以看到多出了很多文件,接下来我们就把这个项目 push 到 GitHub 上:

通过下面命令提交到 GitHub 仓库中:

git add .
git commit -m "update"
git push

去 GitHub 上打开该仓库,可以看到项目文件已经 push 上来了。

二、项目代码结构介绍

package.json

里面有很多的依赖包,表示在开发这个项目的时候用到的第三方依赖。

LICENSE

开源协议说明。

index.html

项目首页默认的模板文件。

.postcssrc.js

postcss 的默认配置项。

.gitignore

在把代码上传到线上的时候希望忽略一些文件,比如 node_modules 等目录文件。

.eslintrc.js

对代码进行检测,里面配置了一些对对代码的规范。

.eslintignore

在里面添加的目录文件是不会受到 eslint 这个检测工具检测的,这些文件如果写的不标准,也不会进行代码不标准提示。

.editorconfig

他帮助我们配置了一下编辑器里一些语法。

.babelrc

我们的项目写的代码是 Vue 的单文件组件的写法,所以他需要通过 babel 这种语法解析器做一些语法上的转换,最终转换为浏览器能够编译执行的代码。

static 目录

放一些静态资源,一些静态的图片或者模拟的一些 json 数据。

node_modules 目录

放的是这个项目依赖的一些第三方的包。

src 目录

src 目录放的是整个项目的源代码。main.js 是整个项目的入口文件;App.vue 是项目最原始的那个根组件;router 目录下的 index.js 放这个项目的所有路由;components 里放的是项目里要用的小组件;assets 放的是项目里用到的一些图片类的资源。

config 目录

config 目录放的是一些项目的配置文件,基础的配置信息放在 index.js 中,开发环境的配置信息放在 dev.env.js 中,线上环境的配置信息放在 prod.env 中。

build 目录

build 目录放的是项目打包的 webpack 的一些配置内容:

  • webpack.base.conf:基础的 webpack 配置项。
  • webpack.dev.conf:开发环境中的 webpack 配置项。
  • webpack.prod.conf:线上环境中的 webpack 配置项。

三、单文件组件与 Vue 中的路由

打开项目中 src 目录下的 main.js 文件,他是整个项目的入口,可以看到它挂载了一个 Vue 的根实例,并把它挂载到了 app 元素上:

main.js

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'

Vue.config.productionTip = false

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

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>vue-travel</title>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

我们打开 index.html 文件,在这个 html 上有一个 div,它的 id 等于 app,所以 main.js 里这个挂载点指的就是 index.html 上面 id 是 app 的元素。main.js 中有一个 “components: { App }”,这是一种 ES6 的写法,它相当于 “components: { App : App }”,意思是我在项目里用了一个局部组件,名字叫做 app,在外层的 Vue 实例里,我给这个组件的名字也叫 App。template 里面直接把 App 这个组件渲染出来。还有一个 router,我们后面再说。

main.js 中 App 这个组件是从哪来的呢?往上看,是从 App 目录中导入进来的,我们打开 App.vue:

App.vue

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <router-view/>
  </div>
</template>

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

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

首先可以看到它是由三部分组成的,第一部分由一个 template 模板标签所包裹,第二部分由一个 script 标签所包裹,第三部分由一个 style 标签所包裹。当一个文件以 vue 为后缀的时候,我们把这种文件叫做一个单文件组件,实际上他里面放的就是 Vue 组件。这个组件就是我们启动项目时看到的那个页面,可以修改一些内容做个测试,例如把样式和 img 标签删掉。

App.vue

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

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

<style>
</style>

然后看此时的页面效果,发现 logo 和一些样式没有了,但是还留有一些内容,这些内容在哪呢?接下来就该讲 router 路由了。

什么是路由?路由就是根据网址的不同,返回不同的内容给用户,这样一个功能我们叫做路由的功能,再来看页面上留下的这些内容,其实这些内容来自于 “<router-view/>” 这个标签,可以去除掉,保存,可以看到页面上就没有内容了。router-view 显示的是当前路由地址所对应的内容,我们来看看当前路由地址是哪里,回到页面上,可以看到当前路由的地址是 localhost 下面的一个根路径,那这个根路径对应的内容是什么呢?

我们再打开 main.js 这个文件,可以看到在入口文件中引入了一个 router,然后在创建根实例的时候使用了 router,这个 router 是什么,他就是这个项目路由配置的内容,我们打开 router 目录中的 index.js 文件:

router/index.js

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    }
  ]
})

这个文件最终导出的内容就是一组配置项,当前路由做了这样的配置:当你访问根路径的时候,根路径这个路由对应的是 “HelloWorld”,“HelloWorld” 又在 components 目录下的 HelloWorld 文件中,我们打开 hello world 这个文件,和刚才讲的 App.vue 一样是三部分构成的,他也是一个单文件组件。

然后再回到 router 目录下的 index.js 文件,路由里配置了 “component: HelloWorld” 这么一项,当用户访问根路径的时候,他给用户展示的是 HelloWorld 这个组件,恰好 App.vue 中又写了 router-view,那么 router-view 里展示的是当前路由地址所对应的内容,就是在 router 目录下的 index.js 文中配置的 HelloWorld 这个组件,我们对这个组件进行一个修改:

HelloWorld.vue

<template>

</template>

<script>
export default {
  name: 'HelloWorld',
}
</script>

<style>
</style>

此时页面上就没有任何的内容了,将以上内容弄明白后我们就可以改写代码了。

现在访问根路径的时候,我们看到的是 HelloWorld 这个单文件组件,我希望展示的是首页,在 index.js 中去掉对 HelloWorld 组件的导入,把 components 目录删掉,然后在 src 下新建一个目录叫 pages,里面放我们所有网页的集合,在 pages 中新建一个目录叫 home,也就是首页的一个目录,然后在 home 目录下新建一个 Home.vue,只要是以 vue 结尾的文件,我们都可以说是 Vue 的单文件组件,在 Home.vue 中这么写:

<template>
    <div>
        home
    </div>
</template>

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

写完组件后,回到路由,我希望访问根路径的时候,展示的不是 HelloWorld 组件了,而是 Home,这样修改一下:

import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/pages/home/Home'

Vue.use(Router)

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

回到页面上,可以看到 Home 组件被显示到页面之上了。如果访问列表页,能展示出列表页的内容,这该怎么实现呢?

到路由配置里,我们增加一条配置项,访问 list 路径的时候,去显示 List 这样一个组件,步骤和创建 Home 组件的方法一样。

pages/list/List.vue

<template>
    <div>
        list
    </div>
</template>

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

router/index.js

import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/pages/home/Home'
import List from '@/pages/list/List'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home
    },
    {
      path: '/list',
      name: 'List',
      component: List
    }
  ]
})

此时访问 list 这个路径,显示的就是 List 这个组件的内容了:

四、多页应用 VS 单页应用

1、多页应用

在多页面中,每一次页面的跳转,后端都会返回一个新的 HTML 文件。优点:首先它的首屏时间快,因为我们访问一个页面的时候,服务器给我们返回一个 HTML,然后页面就会被展现出来,这个过程只经历了一个 HTTP 请求,所以页面展示的速度非常快。第二个好处是它的搜素引擎优化效果非常好,搜索引擎在做网页排名的时候,他需要知道网页的内容,根据网页的内容他才能给你网页权重来进行一个网页的排名,搜索引擎是可以识别 HTML 中的内容的,而我们每一个页面所有的内容都放在 HTML 之中,所以这种多页应用的搜索引擎排名是非常好的。

但是多页应用也有一个缺点,就是页面之间的切换有时候会比较慢,因为每次跳转页面的时候都需要发一个 HTTP 请求,假设网络比较慢,在多页跳转的时候就会有明显的卡顿情况。

2、单页应用

打开项目并运行,在浏览器中打开 Network 下的 Dom,可以看到现在访问的是首页的页面。

在首页里我们希望能有一个链接跳转到 list 这个页,打开 Home.vue,这样去修改:

<template>
    <div>
        <div class="home">home</div>
        <router-link to="/list">列表页</router-link>
    </div>
</template>

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

这里跳转不用 a 标签,而是用 Vue 提供的 router-link 标签,里面的 to 指向跳转的页面。注意 template 模板只能向外暴露一个根标签,需要把 div 和 router-link 包裹在一起。

打开页面,点击“列表页”,就进入列表页了,后退,又回到首页了。那怎么理解单页应用呢?第一次进入页面的时候,会请求一个 HTML 文件,先把他清除掉,然后进入列表页,这个时候并没有请求一个 HTML 文件,回退到首页,也是一样,没有请求一个 HTML 文件。

它的原理是这样的:js 会感知到 url 变化,当 url 变化的时候,通过 js 把当前页面的内容清掉,再把下一个页面的内容挂载到页面上,所以这个时候的路由不是后端来做了,而是由前端来做,我们判断页面到底是显示哪一个组件,然后把以前的组件清除掉,再去显示新的的组件就可以了。

当使用单页应用进行页面事件的跳转的时候,每次跳转并不去加载 HTML 文件,而是通过 js 动态的把当前页面的内容删除掉,再去把新的页面上的 DOM 结构渲染出来,这种做法带来的一个好处是,当我页面之间做跳转的时候,我不需要做 HTML 文件的请求,这样就节约了很多 HTTP 请求发送的时延,使页面切换的非常快。它的缺点是首屏时间稍慢,因为他会发送一个 HTML 和 js 的请求,两个请求都回来了,首屏才会展示出来。还有一个问题,就是 SEO 比较差,SEO 只认识 HTML 中的内容,不认识 js 中的内容。

五、项目代码初始化

这个项目要做一个移动端的网页,所以首先要改一下 index.html 下的 meta 标签:

<meta name="viewport" content="width=240, user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" />

然后引入 reset.css 文件,一个重置页面的样式表,从网上下载就可以,也可以拷贝我项目中的 reset.css 文件。在 src 目录下的 assest 目录中,创建一个 style 目录,将 reset.css 文件放进去。接下来在项目中引入这个文件,打开项目的入口文件 main.js,通过 import 来引入这个文件:

import "./assets/style/reset.css";

打开页面,可以看到 reset.css 引入成功:

还需要引入一个 border.css,移动端有一个 1 像素边框的问题,就是有的手机屏幕分辨率比较高,dpr 是 2 或者 3,如果在页面上写 “border : 1px solid”, 他实际上指的是 css 像素,在 dpr 2 的设备上,他其实对应的是 2 个物理像素,为了解决这种 1 像素被显示成多像素的问题,我们需要引入一个 border.css 文件,引入方式和 reset.css 的引入方式一样。

在移动端还有一个 300ms 点击延迟的问题,他指得是在移动端开发中,某些机型上,某些浏览器上,当执行 click 的时候,这个 click 事件会延迟 300ms 后才执行,这样我们是用 click 事件用户体验就不是特别好了,要解决这个问题,我们可以引入一个 fastclick 库,通过 npm 来安装一下:

--save 的意思就是不管在开发环境中,还是打包生成线上版本的代码,都使用 fastclick。安装好之后,打开 main.js,引入 fastclick,并使用:

import fastClick from "fastclick";
// ...

fastClick.attach(document.body);

最后,我们对项目中的一些无用代码进行一个删除,进入 router 下的 index.js,将之前见得列表页 list 删除,把上面的 import 也删除掉。打开 pages 这个目录,把 list 目录全删掉。再打开 pages 中 Home.vue 这个文件,将模板里的内容都清除掉,样式也清除掉。这个时候,项目中该删的代码基本都删除了。

本地的代码改完之后,我们把它上传到远程的 Git 仓库中:

git add .
git commit -m "project init"
git push

补充:

因为我们在使用 vue-cli 搭建项目的时候,安装了 eslint,所以如果我们不去规范 vue 或 js 文件的代码,控制台中会出现很多的警告,比如首行缩进是两个空格,字符串需要用单引号包裹,标签结束后,下边必须保留一个空行(也只能留一个空行)......等等。但是我的习惯是首行缩进 4 个空格,所以我要修改一下 eslint 的配置。

先打开 .editorconfig 文件,修改 indent_size 为 4,再打开 .eslintrc.js,在 rules 中添加一行:

'indent': ['error', 4, { 'SwitchCase': 1 }]

重启一下服务,在控制台看到 App.vue 这个文件被警告了,提示应该是 4 个缩进,结果现在是 2 个缩进。这里如果你使用的是 VS Code,那推荐你安装一个 vue-format 插件,可以对 vue 文件进行一个格式化。

但是,就是因为我的这个缩进的习惯,给自己挖了一个坑,vue-cli 搭建出的项目,默认都是 2 个,所以,为了解决控制台一大堆的警告,我只能把项目文件都格式化一遍了。

还有一种警告就是字符串必须是单引号包裹,我们可以在.eslintrc.js 文件中 rules 里配置一下 quotes,把第一项改为 0,0 表示不处理,1 表示警告,2 表示错误并退出,所以即使出现了双引号,也不会警告。

"quotes": 0

因为 eslint 规范限制太过严格,之后一定还会出现另一些 eslint 警告的,一点一点的去配置,未免有些太麻烦了,对于我这个强迫症来说,没有任何警告才是最舒服的。那如果不用 eslint 该怎么做?在创建 vue 项目的时候就不安装 eslint。如果安装了 eslint,怎么关闭呢?打开 config 目录下 index.js 文件,找到 useEslint,将他改为 false 就可以了。注意,每次修改了配置文件后都需要重新启动一下项目。


长得好看的都会关注我的 o(≧v≦)o~~

推荐阅读更多精彩内容