1.Vue.js是什么?
Vue.js是当下很火的一个JavaScript MVVM库,它是以数据驱动和组件化的思想构建的。相比于Angular.js,Vue.js提供了更加简洁、更易于理解的API,使得我们能够快速地上手并使用Vue.js。
如果你之前已经习惯了用jQuery操作DOM,学习Vue.js时请先抛开手动操作DOM的思维,因为Vue.js是数据驱动的,你无需手动操作DOM。它通过一些特殊的HTML语法,将DOM和数据绑定起来。一旦你创建了绑定,DOM将和数据保持同步,每当变更了数据,DOM也会相应地更新。
MVVM模式是什么?
下图不仅概括了MVVM模式(Model-View-ViewModel),还描述了在Vue.js中ViewModel是如何和View以及Model进行交互的。
ViewModel是Vue.js的核心,它是一个Vue实例。Vue实例是作用于某一个HTML元素上的,这个元素可以是HTML的body元素,也可以是指定了id的某个元素。
当创建了ViewModel后,双向绑定是如何达成的呢?
首先,我们将上图中的DOM Listeners和Data Bindings看作两个工具,它们是实现双向绑定的关键。
从View侧看,ViewModel中的DOM Listeners工具会帮我们监测页面上DOM元素的变化,如果有变化,则更改Model中的数据;
从Model侧看,当我们更新Model中的数据时,Data Bindings工具会帮我们更新页面中的DOM元素。
文档:https://cn.vuejs.org/v2/guide/
2.Vuex 是什么?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
状态管理模式、集中式存储管理 一听就很高大上,蛮吓人的。在我看来 vuex 就是把需要共享的变量全部存储在一个对象里面,然后将这个对象放在顶层组件中供其他组件使用。这么说吧,将vue想作是一个js文件、组件是函数,那么vuex就是一个全局变量,只是这个“全局变量”包含了一些特定的规则而已。
在vue的组件化开发中,经常会遇到需要将当前组件的状态传递给其他组件。父子组件通信时,我们通常会采用 props + emit 这种方式。但当通信双方不是父子组件甚至压根不存在相关联系,或者一个状态需要共享给多个组件时,就会非常麻烦,数据也会相当难维护,这对我们开发来讲就很不友好。vuex 这个时候就很实用,不过在使用vuex之后也带来了更多的概念和框架,需慎重!
什么是“状态管理模式”?
让我们从一个简单的 Vue 计数应用开始:
new Vue({
// state
data () {
return {
count: 0
}
},
// view
template: `
<div>{{ count }}</div>
`,
// actions
methods: {
increment () {
this.count++
}
}
})
这个状态自管理应用包含以下几个部分:
- state,驱动应用的数据源;
- view,以声明方式将 state 映射到视图;
- actions,响应在 view 上的用户输入导致的状态变化。
以下是一个表示“单向数据流”理念的极简示意:
但是,当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:
- 多个视图依赖于同一状态。
- 来自不同视图的行为需要变更同一状态。
对于问题一,传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。对于问题二,我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码。
因此,我们为什么不把组件的共享状态抽取出来,以一个全局单例模式管理呢?在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为!
另外,通过定义和隔离状态管理中的各种概念并强制遵守一定的规则,我们的代码将会变得更结构化且易维护。
这就是 Vuex 背后的基本思想,借鉴了 Flux、Redux、和 The Elm Architecture。与其他模式不同的是,Vuex 是专门为 Vue.js 设计的状态管理库,以利用 Vue.js 的细粒度数据响应机制来进行高效的状态更新。
什么情况下我应该使用 Vuex?
虽然 Vuex 可以帮助我们管理共享状态,但也附带了更多的概念和框架。这需要对短期和长期效益进行权衡。
如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex。一个简单的 store 模式就足够您所需了。但是,如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。
3.vue-router 是什么?
vue-router就是WebApp的链接路径管理系统。 vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用。vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。传统的页面应用,是用一些超链接来实现页面切换和跳转的。在vue-router单页面应用中,则是路径之间的切换,也就是组件的切换。 路由模块的本质 就是建立起url和页面之间的映射关系 。 至于我们为啥不能用a标签,这是因为用Vue做的都是单页应用,就相当于只有一个主的index.html页面,所以你写的标签是不起作用的,你必须使用vue-router来进行管理。
HTML
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<h1>Hello App!</h1>
<p>
<!-- 使用 router-link 组件来导航. -->
<!-- 通过传入 `to` 属性指定链接. -->
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
</p>
<!-- 路由出口 -->
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>
JavaScript
// 0. 如果使用模块化机制编程,导入Vue和VueRouter,要调用 Vue.use(VueRouter)
// 1. 定义 (路由) 组件。
// 可以从其他文件 import 进来
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
// 2. 定义路由
// 每个路由应该映射一个组件。 其中"component" 可以是
// 通过 Vue.extend() 创建的组件构造器,
// 或者,只是一个组件配置对象。
// 我们晚点再讨论嵌套路由。
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
// 3. 创建 router 实例,然后传 `routes` 配置
// 你还可以传别的配置参数, 不过先这么简单着吧。
const router = new VueRouter({
routes // (缩写) 相当于 routes: routes
})
// 4. 创建和挂载根实例。
// 记得要通过 router 配置参数注入路由,
// 从而让整个应用都有路由功能
const app = new Vue({
router
}).$mount('#app')
// 现在,应用已经启动了!
通过注入路由器,我们可以在任何组件内通过 this.$router
访问路由器,也可以通过 this.$route
访问当前路由:
// Home.vue
export default {
computed: {
username () {
// 我们很快就会看到 `params` 是什么
return this.$route.params.username
}
},
methods: {
goBack () {
window.history.length > 1
? this.$router.go(-1)
: this.$router.push('/')
}
}
}
该文档通篇都常使用 router
实例。留意一下 this.$router
和 router
使用起来完全一样。我们使用 this.$router
的原因是我们并不想在每个独立需要封装路由的组件中都导入路由。
文档:https://router.vuejs.org/zh/
4.ES6 是什么?
由于vue-cli生成的文件中使用的是ES6的语法,而ES6是未来的趋势,所以ES6必须一学,目前浏览器和Nodejs对ES6的支持程度不断提高,不过要在所有的浏览器中使用es6代码目前还不可行,不过babel可以帮你提前体验新的语法而不需要等待浏览器支持。babel本质上是一个js的预编译器,可以把es6程序编译成es5,从而在支持ES5的环境中运行。
特地查了一下ES6和ES2016,ES2015的区别,实际上ES6===ES2015 < ES2016,由于ECMA委员会决定将标准每年一更,因此新推出的ES6被改名为ES2015,后面的标准将实行年制命名,如ES2016,ES2017...
学习ES6/ES2015可以参考如下资源
- Learn ES2015 A detailed overview of ECMAScript 6 features. 对ES6语法的概览
- ECMAScript 6入门 阮一峰老师的ES6入门
这里首先简要介绍一些Hacker News 客户端中使用到的ES6特性:
箭头函数 => 和this
=>
是匿名函数的一种简写,即lamda表达式,格式为( 形参列表 ) => { 函数体 }
,使用箭头函数,内部函数继承了外围作用域的this值,再也不用写var that=this
这种hack代码了。直接上代码看:
// Expression bodies
var odds = evens.map(v => v + 1);
var nums = evens.map((v, i) => v + i);
// Statement bodies
nums.forEach(v => {
if (v % 5 === 0)
fives.push(v);
});
// Lexical this
var bob = {
_name: "Bob",
_friends: [],
printFriends() {
this._friends.forEach(f =>
console.log(this._name + " knows " + f));
}
};
模块定义
在ES6之前js没有一个统一的模块定义方式,流行的定义方式有AMD,CommonJS等,而ES6从语言层面对定义模块的方式进行了统一。
// lib/math.js
export function sum(x, y) {
return x + y;
}
export var pi = 3.141593;
// app.js
import * as math from "lib/math";
alert("2π = " + math.sum(math.pi, math.pi));
// otherApp.js
import {sum, pi} from "lib/math";
alert("2π = " + sum(pi, pi));
export default
(默认加载)和 export *
(整体加载)为:
// lib/mathplusplus.js
export * from "lib/math";
export var e = 2.71828182846;
export default function(x) {
return Math.exp(x);
}
// app.js
import exp, {pi, e} from "lib/mathplusplus";
alert("2π = " + exp(pi, e));
默认加载的好处是我们不需要知道模块所要加载的变量名或函数名,输出时指定任意名字,且不需要大括号。
const 和 let
const
即常量,一旦定义了即不可变。let是更好的var,由于js的设计缺陷,var变量的作用域是函数体的全部,还有变量提升等怪异特性,导致诡异的错误,极难定位bug。而let拥有块级作用域,声明的全局变量不是全局对象的属性,形如for (let x...)的循环在每次迭代时都为x创建新的绑定.能用let尽量不用var。
function f() {
{
let x;
{
// okay, block scoped name
const x = "sneaky";
// error, const
x = "foo";
}
// okay, declared with `let`
x = "bar";
// error, already declared in block
let x = "inner";
}
}
promise
语言标准实现的异步编程解决方案:
function timeout(duration = 0) {
return new Promise((resolve, reject) => {
setTimeout(resolve, duration);
})
}
var p = timeout(1000).then(() => {
return timeout(2000);
}).then(() => {
throw new Error("hmm");
}).catch(err => {
return Promise.all([timeout(100), timeout(200)]);
})
文档:http://es6.ruanyifeng.com/#docs/intro
5.webpack 是什么?
如果你已经熟悉了 webpack,随时可以跳过下面的说明。如果你没有使用过 webpack,下面是一个快速介绍:
webpack 是一个模块打包工具。它将一堆文件中的每个文件都作为一个模块,找出它们的依赖关系,将它们打包为可部署的静态资源。
一个基本的例子,想像我们有一些 CommonJS 模块,它们不能直接在浏览器中运行,所以我们需要打包成一个文件,这样就可以通过 <script>
标签加载。webpack 可以遵循 require()
调用的依赖关系,为我们完成这些工作。
但是 webpack 可以做的不止这些。通过“loader”,我们可以配置 webpack 以任何方式去转换所有类型的文件。包括以下例子:
- 转换 ES2015,CoffeeScript 或者 TypeScript 模块为普通的 ES5 CommonJS 模块;
- 可以选择在编译之前检验你的源代码;
- 将 Jade 模版转换为纯 HTML 并且嵌入 Javascript 字符串中;
- 将 Sass 文件转换为纯 CSS,然后将其转换成 JavaScript 片段,将生成的 CSS 作为
<style>
标签插入页面; - 处理 HTML 或者 CSS 中引用的图片,移动到配置的路径中,并且使用 md5 hash 重命名。
当你理解 webpack 原理后会感觉它是如此强大,它可以大大优化你的前端工作流程。它主要的缺点是配置复杂麻烦,但是使用本指南,应该可以帮助你找到 Vue.js 和 vue-loader
使用时的最常见问题的解决方案。
文档:https://webpack.docschina.org/concepts/
6.Vue Loader 是什么?
vue-loader
是一个 webpack 的 loader,可以将用下面这个格式编写的 Vue 组件转换为 JavaScript 模块:
这里有一些 vue-loader
提供的很酷的特性:
- 默认支持 ES2015;
- 允许对 Vue 组件的组成部分使用其它 webpack loader,比如对
<style>
使用 Sass 和对<template>
使用 Jade; .vue
文件中允许自定义节点,然后使用自定义的 loader 进行处理;- 把
<style>
和<template>
中的静态资源当作模块来对待,并使用 webpack loader 进行处理; - 对每个组件模拟出 CSS 作用域;
- 支持开发期组件的热重载。
简而言之,编写 Vue.js 应用程序时,组合使用 webpack 和 vue-loader
能带来一个现代,灵活并且非常强大的前端工作流程。
文档:https://vue-loader-v14.vuejs.org/zh-cn/
7.vue-cli 是什么?
vue在web前端可谓是大放异彩,尤其在国内与angular、react有三足鼎立之势。很多人想入门vue2而又苦于不知从何下手。因为vue2是以组件化开发的,最好要搭配webpack构建工具开发,而webpack很多人还不能独立配置。
而vue-cli脚手架就能很好解决这一问题。即使你对webpack还不是很了解,你也可以先搭建好项目在慢慢研究。因为cli已经全部帮我们将需要的东西配置好了,你只要写好项目的业务,在用命令行就可以达到调试或打包的功能。
简单来说就是Vue搭建的架子