深入浅出学 Vue 开发

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/valada/article/details/81639657

课程介绍

前端技术日新月异,每一种新的思想出现,都代表了一种技术的跃进、架构的变化,那么对于目前的前端技术而言,MVVM 的思想已经可以代表当今前端领域的前沿思想理念,Angular、React、Vue 等基于 MVVM 思想的具体实现框架,也成为了人们争相学习的一个热点。而 Vue 作为其中唯一没有大公司支持但却能与它们并驾齐驱并且隐隐有超越同类的趋势,不得不说这种增长让人感到惊奇。

本系列课程内容将会带领大家由浅入深的学习 Vue 的基础知识,了解 Vue 的源码设计和实现原理,和大家一起看一下尤雨溪先生的编程思想、架构设计以及如何进行代码实现。本系列课程内容主要分为三大部分:

  • Vue 的基础知识:在这一部分将学习 Vue 的基础语法及其源码的实现。例如,Vue 的生命周期钩子如何设计?当声明了一个 directive 时,Vue 究竟执行了什么?为什么只有通过 vue.set 函数才能为响应式对象添加响应式属性?如果我们自己要实现一个响应式的框架的话,应该如何下手、如何思考等。
  • Vue 的周边生态:在这一部分将学习 Vue 的周边生态圈,包括有哪些 UI 库可以和 Vue 配合快速构建界面、如何使用 vue-router 构建前端路由、如何使用 Vuex 进行状态管理、如何使用 Axios 进行网络请求、如何使用 Webpack、使用 vue-cli 构建出的项目里的各种配置有什么意义?
  • 项目实战:在这一部分将会通过一个有意思的自动对话系统来进行项目实战,争取通过这个小项目把学到的知识点进行一个整合。

作者介绍

刘国栋,资深软件开发工程师、慕课网认证讲师、开源爱好者,目前就职于济南某国企,并且成立了个人工作室,负责前端和移动端的工作。拥有 5 年前端、移动端开发经验,在 JS、Android、iOS 领域有独特的见解,统筹过的多个项目用户数已过千万。

课程内容

导读:为什么选择 Vue

读者朋友们好,很高兴选择这门课程来学习,作为撰写者的我,也感到非常的荣幸。

程序人生

我们选择了这个 IT 行业,自然希望能够在这里走得更远。我相信没有任何一个人会甘于平庸,大家都希望能够在自己所处的行业以及所处的领域中有所建树,希望可以实现自己的价值,以获取社会的认可。而如果要实现这个目标的话,我们将要投入更多的时间和精力,才能博得更多的机会。在成长的过程中,不可避免的会踩一些坑、走一些弯路,那么有没有办法可以避免少踩一些坑、少走一些弯路呢?万幸的是,答案是有的。

站在巨人的肩膀上,我们可以看得更远,约翰 · 雷西格发布了 jQuery 的第一个版本,从此让我们进入了 jQuery 时代;尤雨溪创造了 Vue,使我们正式迈入 Vue 的时代。这些领军者,让我们能够看得更远,让我们的工作和生活变得更加简单。我与这些领军者相去甚远,微不足道,但依然希望可以尽自己的一些能力来帮助到一些人,让大家可以少走一些弯路、少踩一些坑。怀揣着这样的一个梦想,我开设了这一门课程。

框架为什么会存在

这个世界上任何事物的存在,必然是解决了世界上的一些问题。同样的道理,框架为什么会存在呢?框架的存在也必然是解决了某一个或某一类的问题,这里引入一下 Vue 的作者尤雨溪说过的话:框架的存在是为了帮助我们应对复杂度。框架作为一个工具用来帮助我们应对一类复杂的问题,我想这就是框架的定义了。

当然框架本身一样存在着复杂度,就好像我们使用扳手去拧螺丝时,扳手就是框架,它是一个工具,这个工具本身一样有学习成本,只不过它的学习成本比较低,我们使用这个工具来去解决拧螺丝这样一个如果没有扳手会变得相当复杂的问题,这和使用前端框架去解决在工作中遇到的一个复杂项目的时候所经历的过程是一样的。

所以,很自然的就会在我们使用的框架(工具——扳手)和想要去解决的问题(复杂度——拧螺丝)之间进行抉择,我们会更趋向于使用一个简单的工具来去解决一个复杂的问题,这就是框架存在的意义了。

所以我们本能的希望框架变得越来越简单,而它能够解决的问题越来越复杂。万幸的是:这个时代正在按照我们的希望来发展

主流框架

目前讨论比较多的前端框架主要有三个:

Angular React Vue

通过它们在 GitHub 的 Star 历史和 NPM 的下载趋势图来看一下。

Angular、React 和 Vue 的 GitHub Star 历史:

这里写图片描述

npm 的下载趋势图:

这里写图片描述

可以看到在 GitHub 上面,Vue 的数据上升最快,并且在 2018 年 6 月 28 日已经超过了 React,成为了最受欢迎的前端框架。而在 npm 中,React 的数据遥遥领先,这得益于 React 强大的社区力量,我们无法否认,React 社区作为当前最活跃的前端社区,提供出了特别多优秀的想法和理念,它们为 React 提供了强大的生态支持,同时也让我们在选择周边框架的时候需要进行更多的选择。

当然这三个框架都非常的优秀,我们不去讨论它们的优劣,我们的选择都只是基于我们的取舍:我们希望工具足够简单,而它可以解决的问题却要足够复杂。这就够了,不是吗?

Angular:Angular 期望做的事情非常多,比如说它会包含着它自己的路由,这让我们决定去使用 Angular 的时候,就必须要接受它的全部,这就使得学习成本变得更高,但同时选择变得会更少,不过有时候选择少了并非是一件坏事,它可以让我们更加专注。

React 与 Vue:React 与 Vue 一样都是专注只做界面,而其他的所有一切都会有各种配套的工具,比如说路由,或者状态管理工具,所以说使用它们的话你可能需要做更多的选择,而这种方式则使得它们本身(React、Vue)的学习曲线相对平缓。

从上面的分析可以看出,Angular 提供了一个复杂的工具,用于解决一整套复杂的问题。而 React 与 Vue 则专注于解决一个特定的问题,而把其他的问题交给了它们的生态圈来处理,这样做的同时也会让我们花更多的时间来选择合适的周边工具。

所以说这些框架各有优劣,并没有绝对的谁好谁坏之分,我们选择什么样的工具,取决于我们面对了什么样的问题。没有人会喜欢用大炮去打蚊子,也没有人会想到用苍蝇拍来打大象。我们喜欢刚刚好,追求事半功倍,如果你也是这么想的,那么至少我们的底层观念是一致的。

Vue 的特点

经过了那么多的铺垫,总算到了本次课程内容的重点:Vue,它到底有什么魅力?为什么值得我们花费时间去学习?先来看一下 Vue 到底拥有什么样的特点。

我们会从以下8个方面来对 Vue 进行分析:

  • MVVM 框架
  • 单页面应用程序
  • 轻量化与易学习
  • 渐进式与兼容性
  • 视图组件化
  • 虚拟 DOM(Virtual DOM)
  • 社区支持
  • 未来的 Vue 走向

(1)MVVM 框架

所谓 MVVM 框架就是:Model-View-ViewModel,就像下面这样:

这里写图片描述

那么这个 MVVM 框架,应该怎么去理解呢?它的第一个 View,相当于页面中的 DOM,最后一个 Model 相当于数据源,就像下面这个样子:

这里写图片描述

其中,a 标签就是 DOM,data 对象就是数据源,这两者之间永远不会直接通信,它们所有的联系都是通过 ViewModel,也就是监控者来进行的。监控者会去负责检测数据的变化,然后把数据实时展示在页面中。例如,把 text 的内容更改为 “Hello Vue” 的话,那么 a 标签中展示的内容,也会自动变为 “Hello Vue”。这样就不需要手动的操作 DOM,所有对 DOM 操作都会通过监控者来完成。如果以前写过复杂的 DOM 操作的话(如 **.parent().parent().parent()...),就会发现这种方式带来的便利。

Vue 正是使用了这种 MVVM 的框架形式,并且通过声明式渲染响应式数据绑定的方式来帮助我们完全避免了对 DOM 的操作。

(2)单页面应用程序

单页面应用程序(SPA),一般指为:一个页面就是一个应用(或子应用)。随着技术的发展,现在的前端网页早已不只局限于在浏览器上展示了,手机 App 上、微信公众号上都有了越来越多的展示机会。

那么如果把传统的多页面应用形式放入到我们的手机上面会是什么样子呢?当进行页面跳转打开一个新的页面的时候,它会变成这样:

这里写图片描述

等的花儿都谢了 有没有?

而如果使用单页面的形式来开发的话,就不会出现这样一种情况。因为我们的整个应用就只有一个页面,当我们的这一个单页被加载进来之后,就不会在进行关于页面的网络请求。Vue 配合生态圈中的 Vue-Router 就可以非常方便的开发复杂的单页应用。

(3)轻量化与易学习

我们知道网页中引入的 JS 体积越大,那么加载所需要耗费的时间就越长,反之体积越小,则越节省时间。所以我们会更倾向于使用体积更小的 JS 文件,这也是为什么在生产版本会引入 .min 的 JS 的原因。下面是我从 Vue 官网的截图:

这里写图片描述

目前 Vue 的最新稳定版本为 2.5.16,从截图中可以看到 Vue 的生产版本只有 30.90KB 的大小,几乎不会对我们的网页加载速度产生影响。同时因为 Vue 只专注于视图层,单独的 Vue 就像一个库一样,所以使我们的学习成本变得非常低。

(4)渐进式与兼容性

渐进式框架就是:我只做分内的事情,并且不会对你要求太多。

Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。

这是 Vue 官网上面的一句话,正如在上面所说的,Vue 只做界面,而把其他的一切都交给了它的周边生态来做处理,这就要求 Vue 必须要对其他的框架拥有最大程度的兼容性。

例如,一开始只想做一个静态站,那么可以只引入 Vue 来去构建界面,过了一段时间,你想在网站上加入访问网络的功能,那么你可以再引入 axios(Vue 官方推荐)或者其他的(哪怕是 jQuery)网络请求框架,而后来随着你的网站越做越大,你想要把你的网站变成一个大型的 Web 应用的时候,可以引入一些其他你需要的 JS 文件,如 Loadsh.js、Velocity.js 等。

(5)视图组件化

所谓视图组件化就是把我们的网页拆分为一个个的组件,就像下面这样:

这里写图片描述

Vue 允许通过组件来去拼装一个页面,每个组件都是一个可复用的 Vue 实例,组件里面可以包含自己的数据,视图和代码逻辑。比如说:

这里写图片描述

CSDN 的这个个人资料模块,大家都已经不陌生了吧,当我们的 Web 应用中有多个页面都使用到这个个人资料模块的时候,就可以把它封装成一个组件,这个组件拥有单独的代码逻辑、CSS 样式、数据等,在任何一个我们需要使用到它的地方,就可以通过

<component-name></component-name>Vue.component('component-name', {    ...});

这种方式来直接引入了。

(6)Virtual DOM

Virtual DOM 也就是虚拟 DOM,大家知道浏览器去处理 DOM 操作时,是存在性能问题的,这也是我们在使用 jQuery 或者原生 JavaScript 来去频繁操作 DOM 进行数据渲染的时候,我们的页面经常出现卡顿的原因。

而虚拟 DOM 则是预先通过 JavaScript 的各种运算,把最终需要生成的 DOM 计算出来,并且进行优化,在计算完成之后才会将计算出的 DOM 放到我们的 DOM 树中。由于这种操作的方式并没有进行真实的 DOM 操作,所以才会叫它虚拟 DOM。

我们在前面说过:

Vue 是通过声明式渲染响应式数据绑定的方式来帮助我们完全避免了对 DOM 的操作。

Vue 之所以可以完全避免对 DOM 的操作,就是因为 Vue 采用了虚拟 DOM 的方式,不但避免了我们对 DOM 的复杂操作,并且大大的加快了我们应用的运行速度。

(7)来自社区的支持

虽然在全球中 Vue 的社区并没有 React 社区那么的繁华,但得益于 Vue 的本土化身份(Vue 的作者为国人尤雨溪),再加上 Vue 本身的强大,所以涌现出了特别多的国内社区,如 https://www.vue-js.com/、https://vuejs.com.cn/ 等。这种情况在其他的框架身上是没有出现过的,这使得我们在学习或者使用 Vue 的时候,可以获得更多的帮助。

(8)未来 Vue 的走向

Vue 是由国人尤雨溪在 Google 工作的时候,为了方便自己的工作而开发出来的一个库,而在 Vue 被使用的过程中,突然发现越来越多的人喜欢上了它。所以尤雨溪就进入了一个边工作、边维护的状态,在这种情况下 Vue 依然迅速的发展。

而现在尤雨溪已经正式辞去了 Google 的工作,开始专职维护 Vue,同时加入进来的还有几十位优秀的开发者,他们致力于把 Vue 打造为最受欢迎的前端框架。事实证明 Vue 确实在往越来越好的方向发展了(从 Angular、React、Vue 的对比图中可以看出 Vue 的势头)。所以我觉得完全不需要担心未来 Vue 的发展,至少在没有新的颠覆性创新出来之前,Vue 都会越做越好。

本课能够帮你些什么

说了那么多,大家应该已经对 Vue 有了一个基础的了解了,那么我们看一下,这节课的主要内容。

本课将从基础语法、生态系统、项目实战这三个部分来帮助大家详细的了解 Vue 的知识,看一下下面的脑图。

enter image description here

这就是我们本课将要学习的所有内容,我们会通过一个对话项目完成课程的学习,教你真正掌握 Vue 开发。扫描以下二维码查看项目。

be4e1810-8b00-11e8-9fe1-c1b3d2332fb0

通过本次课程可以学习到:

  • Vue 的基础语法
  • Vue 的实现原理
  • Vue 的周边生态
  • Webpack 模块打包器
  • vue-cli 脚手架解析
  • 如何通过 vue-cli + Webpack 来开发我们的自动聊天系统

因为本次课程涉及到了 Vue 的一些实现原理,同时也会对使用 vue-cli + Webpack 构建出来的代码进行解析,所以在学习本课程之前需要具备 JavaScript 的基础知识,如果对 Vue 已经有了一些了解或者已经使用 Vue 开发过一两个项目的话,那么我相信你会在本次课程中拥有更大的收获!

点击了解更多《深入浅出学 Vue 开发》

第01课:初探 Vue

在正式开始学习 Vue 的知识之前,我们需要先对 Vue 的整体有一个大致的了解。为了达到这个目的,首先了解以下内容:

  • Vue 对移动端和浏览器版本的支持
  • 如何初始化一个 Vue 的项目
  • Vue 的代码结构

Vue 对移动端和浏览器版本的支持

因为 Vue 本身使用了 ECMAScript 5 特性,所以 Vue 支持所有兼容 ECMAScript 5 的浏览器。我们根据下面的图示来解释一下,数据来自-caniuse.com

这里写图片描述

红色:几乎不支持

黄色:大部分支持(有很小的可能会影响使用)

绿色:几乎全部支持(不影响使用)

由上面的图示可以看出,对 IE 来说,在 IE 8 及其以下的时候,是不支持 ECMAScript 5 的,也就是说,是无法使用 Vue 的,我们看一下对 IE 8 的描述。

这里写图片描述

IE 8 几乎没有 ES 5 支持,仅支持对字符串的 Object.defineProperty、Object.getOwnPropertyDescriptor、JSON 解析和属性访问。

所以说对使用了 ECMAScript 5 特性的 Vue 来说,是没有办法在 IE 8 及以下使用的。IE 8 作为天坑的分界线,其实是一直被大家所诟病的,那么 IE 9 呢?从图示中可以看出,IE 9 的背景为黄色,也就是说大部分支持,那么不支持的部分是哪些呢?我们来看一下。

这里写图片描述

可以看到,对 IE 9 来说,它不支持严格模式,这对我们使用 Vue 的影响就已经很小了,所以说可以在 IE 9 及以上可以安全的使用 Vue。

而对于其他的浏览器和移动端来说,对 ECMAScript 5 的支持还是非常不错的,Chrome 和 Firefox 都对 ECMAScript 5 早早的提供了支持,而 iOS 6 和 Android 4.4 以上也都对 ECMAScript 5 的支持非常完善了,也就是说我们可以在这些浏览器上面放心地使用 Vue 了。

如果大家对这些数据比较感兴趣,也可以点击这里,自己来看一下,这里就不再过度赘述了。

如何初始化一个 Vue 的项目

然后我们来看一下,应该如何去初始化一个 Vue 的项目。引入 Vue 的方式主要有两种:

  • 直接通过 <script> 标签引入;
  • 通过 npm 的方式引入。

分别看一下这两种引入方式应该如何去做,然后再去把它们做一些对比。

先来看一下第一种,如何通过 <script> 标签来引入 Vue。

通过 <script> 标签引入 Vue

目前 Vue 最新的稳定版本为 2.5.16,可以直接把 Vue 编译之后的代码下载到本地,然后在本地通过 <script> 标签引入,也可以直接通过 cdn 的方式来引入 Vue。具体方法如下:

// 开发版本,包含完整的警告和调试模式。// 下载地址:https://vuejs.org/js/vue.js    <script src="vue.js"></script>     // 生产版本,删除了警告,30.90KB min+gzip。    // 下载地址:https://vuejs.org/js/vue.min.js    <script src="vue.min.js"></script>     // CDN引入方式,版本号为2.5.16。    // 你也可以直接通过 https://cdn.jsdelivr.net/npm/vue/ 这个地址来查看Vue的源码    // 如果你想要引入生产版本的话,那么只需要把最后的vue.js改为vue.min.js    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>

通过这种方式来引入 Vue,就可以在 .js 文件或者 .vue 文件(需要对 .vue 文件进行解析,比如使用 vue-loader)中直接使用 Vue 的语法了。

通过 npm 的方式引入

第二种方式为通过 npm 来直接引入。对于 npm,大家如果有过前端开发经验的话,那应该已经不陌生了。npm 作为在前端被广泛使用的包管理工具,Vue 自然也是需要提供支持的,可以直接使用如下命令来安装 Vue 的最新版本。

npm install vue

两种方式的对比

Vue 的官网推荐我们在用 Vue 去构建大型项目时,使用 npm 的方式去安装,但是说的却并不是很详细,先来看一下官网的说法:

在用 Vue 构建大型应用时推荐使用 npm 安装。npm 能很好地和诸如 Webpack 或 Browserify 模块打包器配合使用,同时 Vue 也提供配套工具来开发单文件组件。

翻译一下官网的意思:之所以推荐使用 npm 的方式来安装 Vue,是因为:

  • 使用 npm 的方式可以更好的配合模块打包器(Webpack 或者 Browserify);
  • 可以更方便的使用单文件组件(.vue 文件)。

上面两点就是推荐使用 npm 方式的原因,关于模块打包器(Webpack)和单文件组件(.vue 文件),在后面的篇幅中会详细讲解,如果大家现在就想对 Webpack 或者单文件组件进行详细了解,也可以点击链接到它们的官网来详细了解。我们在这里只大概的说一下,目的是让大家更清楚的了解 Vue 引入方式的区别。

一般在使用 Vue 来构建大型项目的时候,通常会通过npm + vue-cli + webpack的方式进行项目初始化。

我们需要安装好 npm,可以点击这里下载最新的 Node 版本。

然后使用 npm install -g vue-cli 指令下载最新的 vue-cli。

然后通过vue init <template-name> <project-name>这种方式初始化我们的项目,<template-name>是模块打包器,<project-name>是项目名称;比如可以通过 vue init webpack my-project 构建一个名字叫做 my-project 的项目。

一路回车之后,就可以得到一个使用npm + vue-cli + webpack构建出的项目了,来看一下项目的结构:

├── README.md├── build├── config├── index.html├── node_modules├── package.json├── src├── static└── test

在 package.json 文件下,可以看到一个dependencies:{"vue": "版本号"},这个 vue 就是通过 npm 来引入的 Vue,在 src 文件夹下面也已经生成了 .vue 的单文件组件。

我们可以直接通过npm run dev的方式在本地运行这个项目,也可以通过 npm run build 对这个项目进行打包。

那么是不是通过npm + vue-cli + webpack方式生成的项目就不能通过<script>标签的形式引入 Vue 了呢?显示不是的。

通过 npm 引入 vue,在项目执行打包的时候,会被打包到可执行文件之中,在通过浏览器去访问项目的时候,则会访问项目所部署的服务器中的 vue 文件,而如果服务器的带宽并不高的话(特别是一些个人的服务器,经常只有 1M 的带宽),此时,我们就要尽量的避免服务器中的流量流出。

在这种情况之下,要使用<script>标签的形式在 CDN 中去引入 vue,不失为是一个好的选择,比如可以在项目的 index.html 文件中,通过<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script> 这种方式来引入 vue,从而尽量减少服务器的压力。

就像在导读中说的:我们选择什么样的工具,取决于我们面对了什么样的问题。没有任何一种工具或者方式是在任何一种情况下都完全适用的。

Vue 的代码结构

在使用 Vue 开发项目时,我们的代码一般会写到两种文件中,分别是:

  • 非单文件组件(.js 文件);
  • 单文件组件(.vue 文件)。

通过这两种文件来看一下 Vue 的代码结构是什么样子的。

非单文件组件(.js 文件)

非单文件组件就是我们正常的 js 文件,js 文件是可以直接被浏览器解析的,可以在 js 文件中,直接通过(可以直接新建一个 html 文件,通过<script>标签的形式引入 Vue,然后复制上面的代码,看一下运行的效果)以下方式直接生成一个 Vue 对象。其中,el 为 element 的简写,#app表示 ID 为 App 的 div 标签,意思为ID 为 App 的 <div> 标签中的所有 html 内容都将被 Vue 解析。而 data 对象则是在 Vue 中生成的数据集,当修改 message 的内容时,div 中展示的数据也会随之改变。

<div id="app">  {{ message }}</div>var app = new Vue({  el: '#app',  data: {    message: 'Hello Vue!'  }})

大家还记得我们在导读中说过的 MVVM 模型吗?下面的代码是View:

<div id="app">  {{ message }}</div>

下面的代码是 Model。

data: {    message: 'Hello Vue!'  }

而 Vue 框架,即 ViewModel,Vue 连接了视图和数据,当数据发生改变时,视图中展示的数据也会发生改变,这种方式在 Vue 中被称作声明式渲染

而其他的一些声明也都会被写入到 Vue 对象之中,例如,如果要在 Vue 中去定义以下方法,那么则需要使用到 methods 声明,如下:

var app = new Vue({  el: '#app',  data: {    message: 'Hello Vue!'  },  methods: {      methodsName: function (event) {          ...      }  }});

同样,如果要监听 Vue 的声明周期或者计算属性的话,也同样以这种方式来声明即可,后面在讲解到这些这些内容的时候,会详细解释。

单文件组件(.vue 文件)

第二种方式,也就是通过单文件组件的方式来使用 Vue,这也是官网所推崇的一种方式。大家可以想一下,如果项目足够复杂,若通过上面的方式使用 Vue 的话,那 js 文件得多大啊,同样也非常不利于以后代码的维护,那在以前构建项目的时候遇到这种问题时,一般想到的处理方式是什么?相信大家如果使用过 jQuery 来开发过完整项目的话,都应该能够想到,那就是模块化,比如我们常用的:AMD、CMD 或者 ES6 Module 的模块化,那么在 Vue 中的这种模块化方式,我们称它为单文件组件(.vue 文件)

先来看一下单文件组件(.vue 文件)的文件结构。

<template>     // html</template><script>    // js</script><style>    // css</style>

每一个 .vue 文件都会被当成使一个“组件”,每个“组件”中都有其单独的 html、css、js,然后再把这些“组件”拼装成一个完整的项目(如果大家对这一块不了解,可以看一下导读中提到的组件化知识)。

使用这种单文件组件(.vue 文件)的优势非常明显,它使得项目组件化,因为每个模块的功能都被单独分割,所以代码耦合性变得更低,也更利于团队开发日后维护(这块会在项目实战中实地展示这种方式的优势)。

但是 .vue 文件浏览器是无法直接解析的,需要使用到一些解析工具把 .vue 文件解析成浏览器能够看懂的 html、css 和 js 文件。干这个事的工具一般为vue-loader(就好像我们去解析 .less 文件的 Koala,不同的是vue-loader并不是一个单独的应用),而我们去使用vue-loader也都会配合 Webpack 来使用,这也是为什么构建正式大型项目的时候,一般都会使用npm + vue-cli + webpack方式的原因之一。

然后再看一下,在刚才通过npm + vue-cli + webpack来生成的my-project项目,通过这个项目来大体的认识一下单文件组件(.vue 文件)

分别打开/src/App.vue/src/main.js这两个文件,为了防止过多的代码对大家造成困扰,我把这些代码进行了一些简化。

App.vue:

<template>  <div id="app">    <img src="./assets/logo.png">    <p>{{message}}</p>  </div></template><script>export default {  data: function () {    return {      message: 'Hello Vue'    }  }}</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>

main.js:

import Vue from 'vue'import App from './App'new Vue({  el: '#app',  components: { App },  template: '<App/>'})

大家可以把这两部分的代码复制到项目中,然后执行npm run dev,通过浏览器打开http://localhost:8080/#/,则可以看到一个 Vue 的图标和“Hello Vue”的一串文字。

如果可以正常运行,那么来看一下这些代码的具体含义。

main.js里面它通过 ES6 的方式引入了 Vue 和 App.vue 两个文件,然后在初始化 Vue 的时候,通过 el 指定最外层的 div 为id为app的<div>,然后指定了 App.vue 作为 Vue 的一个组件 components,并且给他指定了模板 template 为<App/>

然后在 App.vue 中,它在<template>标签中声明了 html,在<script>标签中,指定了数据 data 为{message : 'Hello Vue'},在<style>中声明了样式,这就生成了一个完整的组件,然后把这个组件通过 ES6 module 的方式注入到 main.js 的 components 中,这样的一个循环的过程,就构成了模块化方针。

从第02课开始会正式进入 Vue 的学习,我们会依照如下脑图的顺序进行。

enter image description here

在基础语法部分,会通过html+<script>的形式来引入 Vue,致力于通过最简单直接的方式能够让大家对 Vue 的常用 API 有一个足够的了解。

在周边生态部分,会通过各种实例来帮助大家去学习 Vue 的周边生态。

最后会通过npm + vue-cli + webpack的方式,以一个实战项目来让大家把本课程所学到的所有内容都整合起来。

点击了解更多《深入浅出学 Vue 开发》

第02课:基础语法(上)

从本篇开始将学习 Vue 的基础语法,在学习基础语法的时候会使用<script>标签的形式来引入 Vue,一直持续学习到vue-cli+webpack之后,才会通过npm + vue-cli + webpack的形式来带大家进行项目实战。

本篇的内容主要包括以下 3 点:

  • 声明式渲染
  • 条件渲染
  • 列表渲染

声明式渲染

声明式渲染:允许采用简洁的模板语法声明式地将数据渲染进 DOM。

用第01课中使用的事例,我们创建一个 index.html 文件,通过<script>标签的形式引入 Vue,body 中的代码如下:

<div id="app">    {{ message }}  </div>  <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>  <script>    var app = new Vue({      el: '#app',      data: {        message: 'Hello Vue!'      }    })  </script>

通过在 data 字段中声明的 message 字段,然后通过{{}}双大括号的形式在id 为 app 的 div中展示出来,这样的一种方式,Vue 称它为声明式渲染,这种{{}}双大括号的形式可以称为 Mustache(这种方式最初是由 Mustache.js 提出的),并且当声明 message 发生变化的时候,渲染出的 dom 内容也会同步发生改变,可以在打开的 index.html 的控制台中,通过app.message = '改变message内容' 命令,来观察一下 DOM 内容的变化。

我们刚才说了,声明式渲染为一种方式,也就是说所有符合通过简洁的语法来声明式的将数据渲染进 DOM 的方法,都属于声明式渲染的一种。比如把上面的代码略作修改:

<div id="app">    {{ message }}    <span v-bind:title="spanTitle">我是一个span</span>    <img v-bind:src="imgSrc" v-bind:alt="imgAlt">  </div>  <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>  <script>    var app = new Vue({      el: '#app',      data: {        message: 'Hello Vue!',        spanTitle: '我是span的title',        imgAlt: '我是一个img',        imgSrc: 'https://avatar.csdn.net/6/F/4/3_u011068996.jpg'      }    })  </script>

我们新增了两个标签<span><img>,然后声明了三个数据 spanTitle、imgAlt 和 imgSrc,通过 v-bind 指令来把数据渲染到 DOM 中,其中的v-bind为 Vue 中的指令。在 Vue 中,所有带v-前缀的,都表示它们为 Vue 提供的特殊特性。

我们刷新页面,可以看到声明出来的数据都已经被渲染到 DOM 中了:

这里写图片描述

这个时候如果细心的读者,应该可以发现,当我们去刷新页面的时候,声明的 {{ message }},会在 DOM 中一闪而过。

这里写图片描述

这是因为在 Vue 尚未编译到关联实例的时候,我们的指令还无法被解析。如果有使用过 jQuery 或者原生 JS 开发项目经验的话,那么应该知道我们一般在使用 jQuery 或者原生 JS 时,一般会监听$().ready(function)或者document.addEventListener("DOMContentLoaded", function);用于处理 DOM,而在 Vue 中使用的是虚拟 DOM 的方式,把这两者的运行速度进行一个简单的对比:

<div id="app" >    {{ new Date().getTime() }}  </div><script>    document.addEventListener('DOMContentLoaded', function(event) {        console.log('DOMContentLoaded:' + new Date().getTime());    });  </script>

通过{{}}语法直接去渲染编译完成之后的时间戳,然后去监听 JS 的 DOMContentLoaded 事件,并打印出当前的时间戳。

通过对比可以发现 Vue 的编译速度是在 DOMContentLoaded 之前的,同时 Vue 提供了v-cloak指令,用来解决这种闪烁的问题。我们可以使用v-cloak配合 CSS 规则[v-cloak] { display: none }来隐藏未编译的 Mustache({{Mustache}})标签直到实例准备完毕。

<div v-cloak>  {{ message }}</div><style>    [v-cloak] {      display: none;    }</style>

条件渲染

Vue 中的条件渲染指令主要包括以下两个:

v-if v-show

通过代码来看一下:

 <div id="app">    <div v-if="isIf === 1">        isIf为1的时候展示:{{isIf}}    </div>    <div v-else-if="isIf === 2">        isIf为2的时候展示:{{isIf}}    </div>    <div v-else>            isIf不为1或者2的时候展示:{{isIf}}        </div>    <div v-show="isShow">        当isShow为true的时候展示:{{isShow}}    </div>  </div>  <script>    var app = new Vue({      el: '#app',      data: {        isIf: 1,        isShow: false      }    });  </script>

我们可以直接在控制台中通过app.isIf = 1/2/3; app.isShow = true;的方式来控制展示的效果。

那么v-ifv-show的区别在哪里?通过渲染出的 element 来看一下。

这里写图片描述

通过 DOM 结构可以看出,v-ifv-else直接控制 DOM 是否被渲染,而v-show则是通过控制 css 的方式来控制 DOM 是否展示。

v-if中,如果一开始条件为,则 Vue 什么也不会做,当条件变为的时候,Vue 才会去渲染这一部分 DOM,当条件再次变为的时候,与这一块相关的所有内容都会被从 DOM 树中删除掉。

v-show则要简单的多,它仅仅是通过控制 css 中的 display 来控制 DOM 的显示和隐藏。

列表渲染

看一下 Vue 中的列表渲染v-for指令,可以通过item in items这种特殊语法的方式指令根据对象(数组或者是 object 对象)的选项列表来进行渲染,其中 items 为数据源,item 为每一条数据的别名,通过下面的代码来看一下。

<div id="app">      <ul>          <li v-for="(item, index) in items" v-if="item.isShow" v-bind:key="index">            <p>{{index}}</p>            <p>{{item.name}}</p>            <p>¥{{item.price}}</p>          </li>      </ul>  </div>  <script>    var app = new Vue({      el: '#app',      data: {        items: [            {                name: 'android',                price: '12.00',                isShow: false            },            {                name: 'js',                price: '13.00',                isShow: true            }        ]      }    });  </script>

如代码所示,通过一个v-for指令来便利了 items 数组,并且把它的每一条数据的别名定为 item,然后通过 isShow 字段来控制<li>标签的渲染,通过两个<p>标签来展示 name、price,其中的 index 为每一条数据的索引值,v-bind:key指令为每一条列表数据的唯一 id。当元素列表进行更新的时候,Vue 会根据绑定的v-bind:key=""key 的值来去决定 DOM 的复用策略。

我们在控制台中可以通过app.items[0].isShow = true的方式,来控制第一条数据的展示;也可以通过app.items.push({name:'IOS', price: '14.00', isShow: true})的方式,来为 items 添加一条新的数据,新添加的数据会被立刻呈现到 DOM 列表中。

v-for 指令不但可以便利数组,还可以便利 object 对象,看一下 object 对象是如何去便利的。

<div id="app">        <ul>            <li v-for="(value, key, index) in dataSource" v-bind:key="index">              <p>                    {{ index }}. {{ key }}: {{ value }}              </p>            </li>        </ul>    </div>    <script>      var app = new Vue({        el: '#app',        data: {          dataSource: {              name: 'Vue',              price: '12.99',              type: 'javaScript'          }        }      });    </script>

运行上面的代码可以看到,v-for指令把 dataSource 对象的属性进行了迭代。每一条属性提供了三个参数 value、key、index,运行上面的代码来看一下效果。

在通过 v-for 去便利数组的时候,可以通过 push 方法修改数组数据的方式来让 DOM 渲染新的数据,那么在 object 中,是否也可以用同样的方式呢?我们来试一下,在控制台中通过app.dataSource.newKey = 'newKey'的方式来为 dataSource 对象添加一个新的字段。但是,新添加的字段并没有被展示出来,但是可以通过Vue.set(object, key, value)Vue.delete(object, Key)这种方法来为 dataSource 添加或删除响应式属性,比如可以在控制台中通过:Vue.set(app.dataSource, 'newKey', 'newKey') 这种方式来添加响应式属性。

这是由于 JavaScript 的限制,Vue 不能检测到对象属性的添加或删除,下面列举一下 Vue 可以检测到的变化和无法检测到的变化。

Vue 可以检测的变化

现有数据字段的变化:item[0].isShow = true;通过Vue.set(object, key, value)的方式添加的属性通过Vue.delete(object, Key)的方式删除的属性push()pop()shift()unshift()splice()sort()reverse()filter()concat()slice()

Vue 无法检测到的变化

利用索引去设置新的数据时:items[indexOfItem] = newItem;直接修改数组的长度时:items.length = newLength;直接去添加或删除对象的属性:app.dataSource.newKey = 'newKey'

点击了解更多《深入浅出学 Vue 开发》

第03课:基础语法(下)
第04课:Vue 的生命周期及源码实现
第05课:动态数据计算
第06课:Vue 中的常用 API 及源码分析
第07课:Vue 中的组件—Component(上)
第08课:Vue 中的组件—Component(下)
第09课:如何实现一个响应式框架
第10课:动画以及常用的动画库
第11课:vue-devtools 及 Vue 中常用的组件库
第12课:路由:vue-router
第13课:状态管理:Vuex
第14课:网络请求:Axios
第15课:构建项目之前:Webpack
第16课:构建项目:vue-cli
第17课:自动对话系统(上)
第18课:自动对话系统(下)

阅读全文: http://gitbook.cn/gitchat/column/5b5b38219a3b4b3ca3085030

展开阅读全文

没有更多推荐了,返回首页