Vue学习笔记
1、Vue简介
Vue(读音 /vjuː/,类似于 view)是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库(如:vue-router:跳转,vue-resource:通信,vuex:管理)或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。

Vue.js 中文文档:https://cn.vuejs.org/v2/guide/
- MVVM
MVVM 源自于经典的 MVC(Model-View-Controller)模式。MVVM 的核心是 ViewModel 层,负责转换 Model 中的数据对象来让数据变得更容易管理和使用,其作用如下:
- 该层向上与视图层进行双向数据绑定
- 向下与Model层通过接口请求进行数据交互

Model-ViewModel-View-Controller
上图描述了 MVVM 一个基本结构,是不是发现比 MVC 架构中多了一个 ViewModel,没错,就是这个ViewModel,他是 MVVM 相对于 MVC 改进的核心思想。在开发过程中,由于需求的变更或添加,项目的复杂度越来越高,代码量越来越大,此时我们会发现 MVC 维护起来有些吃力,首先被人吐槽的最多的就是 MVC 的简写变成了 Massive-View-Controller(意为沉重的Controller)
由于 Controller 主要用来处理各种逻辑和数据转化,复杂业务逻辑界面的 Controller 非常庞大,维护困难,所以有人想到把 Controller 的数据和逻辑处理部分从中抽离出来,用一个专门的对象去管理,这个对象就是ViewModel,是 Model 和 Controller 之间的一座桥梁。当人们去尝试这种方式时,发现 Controller 中的代码变得非常少,变得易于测试和维护,只需要 Controller 和 ViewModel 做数据绑定即可,这也就催生了 MVVM 的热潮。
- 为什么要使用 MVVM
MVVM 模式和 MVC 模式一样,主要目的是分离视图(View)和模型(Model),有几大好处:
- 低耦合:视图(View)可以独立于 Model 变化和修改,一个 ViewModel 可以绑定到不同的 View 上,当View 变化的时候 Model 可以不变,当 Model 变化的时候 View 也可以不变。
- 可复用:你可以把一些视图逻辑放在一个 ViewModel 里面,让很多 View 重用这段视图逻辑。
- 独立开发:开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计。
- 可测试:界面素来是比较难于测试的,而现在测试可以针对 ViewModel 来写。
- MVVM 的实现者
- Model:模型层,在这里表示 JavaScript 对象
- View:视图层,在这里表示 DOM(HTML 操作的元素)
- ViewModel:连接视图和数据的中间件,Vue.js 就是 MVVM 中的 ViewModel 层的实现者
在 MVVM 架构中,是不允许数据和视图直接通信的,只能通过 ViewModel 来通信,而 ViewModel 就是定义了一个 Observer 观察者:
- ViewModel 能够观察到数据的变化,并对视图对应的内容进行更新
- ViewModel 能够监听到视图的控化,并能够通知数据发生改变
至此,我们就明白了,Vue.js 就是一个 MVVM 的实现者,他的核心就是实现了 DOM 监听与数据绑定。
- 为什么要使用 Vue.js
- 轻量级,体积小是一个重要指标。Vue.js 压缩后有只有 20多kb (Angular 压缩后56kb+,React 压缩后44kb+)
- 移动优先,更适合移动端,比如移动端的 Touch 事件易上手,学习曲线平稳,文档齐全
- 吸取了 Angular(模块化)和 React(虚拟DOM)的长处,并拥有自己独特的功能,如:计算属性
- 开源,社区活跃度高
- ......
2、快速上手
尝试 Vue.js 最简单的方法是使用 Hello World 例子。你可以在浏览器新标签页中打开它,跟着例子学习一些基础用法。或者你也可以创建一个 .html 文件,然后通过如下方式引入 Vue:
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
或者:
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
2.1、基本语法
- 声明式渲染
Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统:
<!DOCTYPE html>
<!-- <html lang="en"> -->
<head>
<meta charset="UTF-8">
<title>helloVue</title>
</head>
<body>
<!--view层 模板-->
<div id="app">
{{ message }}
</div>
<!--导入VUE-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
/*model: 数据*/
data: {
message: 'Hello Vue!'
}
})
</script>
</body>
</html>
我们已经成功创建了第一个 Vue 应用,看起来这跟渲染一个字符串模板非常类似,但是 Vue 在背后做了大量工作。现在数据和 DOM 已经被建立了关联,所有东西都是响应式的。我们要怎么确认呢?打开你的浏览器的 JavaScript 控制台(就在这个页面打开),并修改 vm.message 的值,你将看到上例相应地更新。

注意我们不再和 HTML 直接交互了。一个 Vue 应用会将其挂载到一个 DOM 元素上(对于这个例子是 #app)然后对其进行完全控制。那个 HTML 是我们的入口,但其余都会发生在新创建的 Vue 实例内部。
除了文本插值,我们还可以像这样来绑定元素 attribute:
<!DOCTYPE html>
<!-- <html lang="en"> -->
<head>
<meta charset="UTF-8">
<title>helloVue</title>
</head>
<body>
<!--view层 模板-->
<div id="app">
<span v-bind:title="message">
鼠标悬停几秒钟查看此处动态绑定的提示信息!
</span>
</div>
<!--导入VUE-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
message: '页面加载于 ' + new Date().toLocaleString()
}
})
</script>
</body>
</html>
这里我们遇到了一点新东西。你看到的 v-bind attribute 被称为指令。指令带有前缀 v-,以表示它们是 Vue 提供的特殊 attribute。可能你已经猜到了,它们会在渲染的 DOM 上应用特殊的响应式行为。在这里,该指令的意思是:“将这个元素节点的 title attribute 和 Vue 实例的 message property 保持一致”。
如果你再次打开浏览器的 JavaScript 控制台,输入 vm.message = '新消息',就会再一次看到这个绑定了 title attribute 的 HTML 已经进行了更新。
- 条件v-if
控制切换一个元素显示也相当简单:
<!DOCTYPE html>
<!-- <html lang="en"> -->
<head>
<meta charset="UTF-8">
<title>helloVue</title>
</head>
<body>
<!--view层 模板-->
<div id="app">
<h1 v-if="type==='A'">A</h1>
<h1 v-else-if="type==='B'">B</h1>
<h1 v-else="type==='C'">C</h1>
</div>
<!--导入VUE-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
var vm = new Vue({
el: "#app",
data: {
type: 'B'
}
});
</script>
</body>
</html>
继续在控制台输入 vm.type = 1,你会发现页面显示由B变为了C。
- 循环v-for
还有其它很多指令,每个都有特殊的功能。例如,v-for 指令可以绑定数组的数据来渲染一个项目列表:
<!DOCTYPE html>
<!-- <html lang="en"> -->
<head>
<meta charset="UTF-8">
<title>helloVue</title>
</head>
<body>
<!--view层 模板-->
<div id="app">
<ol>
<li v-for="todo in todos">
{{ todo.text }}
</li>
</ol>
</div>
<!--导入VUE-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
todos: [
{ text: '学习 JavaScript' },
{ text: '学习 Vue' },
{ text: '整个牛项目' }
]
}
})
</script>
</body>
</html>
在控制台里,输入 vm.todos.push({ text: '新项目' }),你会发现列表最后添加了一个新项目。

2.2、事件
为了让用户和你的应用进行交互,我们可以用 v-on 指令添加一个事件监听器,通过它调用在 Vue 实例中定义的方法:
<!DOCTYPE html>
<!-- <html lang="en"> -->
<head>
<meta charset="UTF-8">
<title>helloVue</title>
</head>
<body>
<!--view层 模板-->
<div id="example">
<!-- `greet` 是在下面定义的方法名 -->
<button v-on:click="sat">点我</button>
</div>
<!--导入VUE-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
var vm = new Vue({
el: "#example",
data: { message: "helloword"},
methods: { //方法必须定义在vue内的methods中
sat: function () {
alert(this.message);
}
}
})
</script>
</body>
</html>
3、双向绑定
- 什么是数据双向绑定?
Vue.js 是一个 MVVM 框架,即数据双向绑定,即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化。 这也算是 Vue.js 精髓之处了。
值得注意的是,我们所说的数据双向绑定,一定是对于 UI 控件来说的,非 UI 控件不会涉及到数据双向绑定。单向数据绑定是使用状态管理工具的前提。如果我们使用 vuex,那么数据流也是单项的,这时就会和双向数据绑定有冲突。
- 为什么要实现双向绑定?
在 Vue.js 中,如果使用 vuex,实际上数据还是单向的,之所以说是数读双向绑定,这过用的 UI控件来说,对于我们处理表中,Vue.js 双向数据绑定用起来特别舒服。即两者并不互斥,在全局性数据流使用单项,方便跟踪。同部件数据流使用双向,简单易操作。
- 如何实现数据双向绑定
你可以用 v-model 指令在表单 <input> 、 <textarea> 及 <select> 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
- 注意:
v-model 会忽略所有表单元素的 value,checked、selected 特性的初始值而总是将 Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的 data 选项中声明初始值。
- 文本演示
<!DOCTYPE html>
<!-- <html lang="en"> -->
<head>
<meta charset="UTF-8">
<title>helloVue</title>
</head>
<body>
<!--view层 模板-->
<div id="example">
输入文本 <input type="text" v-model="message">{{message}}
</div>
<!--导入VUE-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
var vm = new Vue({
el: "#example",
data: {
message: "123"
}
})
</script>
</body>
</html>
- 单选框演示
<!DOCTYPE html>
<!-- <html lang="en"> -->
<head>
<meta charset="UTF-8">
<title>helloVue</title>
</head>
<body>
<!--view层 模板-->
<div id="example">
单选框:
<input type="radio" name="sex" value="男" v-model="message">男
<input type="radio" name="sex" value="女" v-model="message">女
{{message}}
</div>
<!--导入VUE-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
var vm = new Vue({
el: "#example",
data: {
message: ""
}
})
</script>
</body>
</html>
- 下拉框演示
<!DOCTYPE html>
<!-- <html lang="en"> -->
<head>
<meta charset="UTF-8">
<title>helloVue</title>
</head>
<body>
<!--view层 模板-->
<div id="example">
<select v-model="message">
<!--提供一个预留项 disabled默认选中 value为空-->
<option disabled value="">请选择</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>{{message}}</span>
</div>
<!--导入VUE-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
var vm = new Vue({
el: "#example",
data: {
message: ""
}
})
</script>
</body>
</html>
4、组件
组件是可复用的 vue 实例,说白了就是一组可以重复使用的模板,跟 JSTL 的自定义标签、Thymeleaf 的 th:fragment 等框架有着异曲同工之妙。通常一个应用会以一棵嵌套的组件树的形式来组织:

例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。
为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册和局部注册。
在组件中无法直接取到数据,需要通过 Prop
- 通过
Vue.component全局注册
<!DOCTYPE html>
<!-- <html lang="en"> -->
<head>
<meta charset="UTF-8">
<title>helloVue</title>
</head>
<body>
<!--view层 模板-->
<div id="example">
<!--传递组件中的值 props-->
<kuangshen v-for="item in items" v-bind:qin="item"></one>
</div>
<!--导入VUE-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
//注册组件
Vue.component('kuangshen',{
/*组件中传递数据 props*/
props: ['qin'],
template: '<li>{{qin}}</li>'
});
var vm = new Vue({
el: "#example",
data: {
items: ["Java","Javascript","C++"]
}
});
</script>
</body>
</html>

说明:
v-for="item in items":遍历 Vue 实例中定义的名为 items 的数组,并创建同等数量的组件v-bind:qin="item":将遍历的 item 项绑定到组件中 props 定义的名为 qin 属性上, =号左边的 qin 为props 定义的属性名,右边的为 item in items 中遍历的 item 项的值
- 局部注册
全局注册往往是不够理想的。比如,如果你使用一个像 webpack 这样的构建系统,全局注册所有的组件意味着即便你已经不再使用一个组件了,它仍然会被包含在你最终的构建结果中。这造成了用户下载的 JavaScript 的无谓的增加。
在这些情况下,你可以通过一个普通的 JavaScript 对象来定义组件:
var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }
然后在 components 选项中定义你想要使用的组件:
new Vue({
el: '#app',
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
})
对于 components 对象中的每个 property 来说,其 property 名就是自定义元素的名字,其 property 值就是这个组件的选项对象。
注意局部注册的组件在其子组件中不可用。例如,如果你希望 ComponentA 在 ComponentB 中可用,则你需要这样写:
var ComponentA = { /* ... */ }
var ComponentB = {
components: {
'component-a': ComponentA
},
// ...
}
5、Vue生命周期
Vue 实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载 DOM、渲染 --> 更新 --> 渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。通俗说就是 Vue 实例从创建到销毁的过程,就是生命周期。
在 Vue 的整个生命周期中,它提供了一系列的事件,可以让我们在事件触发时注册 JS 方法,可以让我们用自己注册的 JS 方法控制整个大局,在这些事件响应方法中的 this 直接指向的是 Vue 的实例。

6、Axios异步通信
- 什么是 AXIOS
Axios 是一个开源的可以用在浏览器端和 Nodes 的异步通信框架,她的主要作用就是实现 AJAX 异步通信,其功能特点如下:
- 从浏览器中创建 XMLHttpRequests
- 从 node.js 创建 http 请求
- 支持 Promise API【JS中链式编程】拦截请求和响应
- 转换请求数据和响应数据取消请求
- 自动转换 JSON 数据
- 客户端支持防御 XSRF(跨站请求伪造)
- 为什么要使用 AXIOS
由于 Vue.js 是一个视图层框架并且作者(尤雨溪)严格准守 SoC(关注度分离原则),所以 Vue. js 并不包含AJAX 的通信功能,为了解决通信问题,作者单独开发了一个名为 vue-resource 的插件,不过在进入 2.0 版本以后停止了对该插件的维护并推荐了 Axios 框架。(建议:少用 jQuery,因为它操作 Dom 太频繁)
- 第一个 AXIOS
- 准备一段 JSON 数据
{
"name":"狂神说java",
"url": "http://baidu.com",
"page": 1,
"isNonProfit": true,
"address": {
"street": "含光门",
"city":"陕西西安",
"country": "中国"
},
"links": [
{
"name": "B站",
"url": "https://www.bilibili.com/"
},
{
"name": "4399",
"url": "https://www.4399.com/"
},
{
"name": "百度",
"url": "https://www.baidu.com/"
}
]
}
- 导入在线 AXIOS CDN
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
- 编写代码
<!DOCTYPE html>
<!-- <html lang="en"> -->
<head>
<meta charset="UTF-8">
<title>helloVue</title>
</head>
<body>
<!--view层 模板-->
<div id="vue">
<p>{{info.name}}</p>
<p>{{info.links}}</p>
<a v-bind:href="info.url">点我</a>
</div>
<!--导入VUE-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
var vm = new Vue({
el: "#vue",
//data: 属性 使用钩子函数 data()是个方法
data(){
return{
// 请求的参数 必须跟JSON字符串格式一样
info: {
name: null,
url: null,
page: null,
isNonProfit: null,
address: {
street: null,
city: null,
country: null
},
links: [
{name: null,url:null}
]
}
}
},
mounted(){ //钩子函数 ES6新特性
axios.get("data.json").then(response=>(this.info=response.data));
}
});
</script>
</body>
</html>
7、计算属性
计算属性的重点突出在属性两个字上(属性是名词),首先它是个属性其次这个属性有计算的能力(计算是动词),这里的计算就是个函数,简单点说,它就是一个能够将计算结果缓存起来的属性(将行为转化成了静态的属性),仅此而已,可以想象为缓存。
<!DOCTYPE html>
<!-- <html lang="en"> -->
<head>
<meta charset="UTF-8">
<title>helloVue</title>
<style>
[v-clock]{ /* 使用v-clock解决闪烁问题 */
display: none;
}
</style>
</head>
<body>
<!--view层 模板-->
<div id="app" v-clock> <!-- 使用v-clock解决闪烁问题 -->
<p>{{currentTime1()}}</p> <!-- 调用方法 -->
<p>{{currentTime2}}</p> <!-- 调用属性 -->
</div>
<!--导入VUE-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
var vm = new Vue({
el: "#app",
data: {
message: "helloword"
},
methods: {
currentTime1: function () {
return Date.now();//返回一个时间戳
}
},
computed: { //计算属性 前提methods与computed 方法不能重名 重名之后只会调用methods的方法
currentTime2: function () {
return Date.now();//返回一个时间戳
}
}
});
</script>
</body>
</html>
- methods:定义方法,调用方法使用 currentTime1(),需要带括号
- computed:定义计算属性,调用属性使用 currentTime2,不需要带括号
调用方法时,每次都需要进行计算,既然有计算过程则必定产生系统开销,那如果这个结果是不经常变化的呢?此时就可以考虑将这个结果缓存起来,采用计算属性可以很方便的做到这一点,计算属性的主要特性就是为了将不经常变化的计算结果进行缓存,以节约我们的系统开销。
8、插槽slot
在 vue.js 中我们使用 <slot> 元素作为承载分发内容的出口,作者称其为插槽,可以应用在组合组件的场景中,插槽是组件的一种:
<!DOCTYPE html>
<!-- <html lang="en"> -->
<head>
<meta charset="UTF-8">
<title>helloVue</title>
</head>
<body>
<!--view层 模板-->
<div id="app">
<todo>
<todo-title slot="todo-title" v-bind:title="username"></todo-title>
<todo-times slot="todo-times" v-for="todoitem in todoitems" v-bind:items="todoitem"></todo-times>
</todo>
</div>
<!--导入VUE-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
/*插槽是组件的一种*/
Vue.component("todo",{
template: '<div>'+
'<slot name="todo-title"></slot>'+
'<ul>' +
'<slot name="todo-times"></slot>'+
'</ul>'+
'</div>'
})
Vue.component("todo-title",{
props: ["title"],
template: '<div>{{title}}</div>'
})
Vue.component("todo-times",{
props: ["items"],
template: '<li>{{items}}</li>'
})
var vm= new Vue({
el: "#app",
data: {
username: "秦疆",
todoitems: ["狂神说Java","狂神说前端"]
}
});
</script>
</body>
</html>
在 <slot> 使用 name 属性关联其他组件
9、自定义事件内容分发
通过上面的代码不难发现,数据项在 Vue 的实例中,但删除操作要在组件中完成,那么组件如何才能删除 Vue 实例中的数据呢?此时就涉及到参数传递与事件分发了,Vue 为我们提供了自定义事件的功能很好的帮助我们解决了这个问题,使用 this.$emit('自定义事件名',参数),操作过程如下:
<!DOCTYPE html>
<!-- <html lang="en"> -->
<head>
<meta charset="UTF-8">
<title>helloVue</title>
</head>
<body>
<!--view层 模板-->
<div id="app">
<todo>
<todo-title slot="todo-title" v-bind:title="username"></todo-title>
<!--自定义事件 v-on:remove="removeitems(index)通过自定义事件调用VUe实例中的方法" -->
<todo-times slot="todo-times" v-for="(todoitem,index) in todoitems"
v-bind:items="todoitem" v-bind:index="index" v-on:remove="removeitems(index)" v-bind:key="index"></todo-times>
</todo>
</div>
<!--导入VUE-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
/*插槽是组件的一种*/
Vue.component("todo",{
template: '<div>'+
'<slot name="todo-title"></slot>'+
'<ul>' +
'<slot name="todo-times"></slot>'+
'</ul>'+
'</div>'
})
Vue.component("todo-title",{
props: ["title"],
template: '<div>{{title}}</div>'
})
/*props获取到数组元素与数组下标*/
Vue.component("todo-times",{
props: ["items","index"],
/*绑定点击事件 方法指向组件中methods-remove*/
template: '<li>{{index}}--{{items}}<button v-on:click="remove">删除</button></li>',
methods: {
remove: function (index) {
alert(index)
/* 参数一: 自定义事件名 参数二: 数组下标 方法指向页面中的自定义事件 通过自定义事件调用VUe实例中的方法*/
this.$emit('remove',index);
}
}
})
var vm= new Vue({
el: "#app",
data: {
username: "秦疆",
todoitems: ["狂神说Java","狂神说前端","狂神说Liunx"]
},
methods: {
removeitems: function (index) {
//js中移除数组元素的方法
this.todoitems.splice(index,1);
}
}
});
</script>
</body>
</html>
for 循环不仅可以遍历出数组元素,还可以遍历出数组下标
10、Vue-cli
vue-cli 官方提供的一个脚手架,用于快速生成一个 vue 的项目模板。
预先定义好的目录结构及基础代码,就好比咱们在创建 Maven 项目时可以选择创建一个骨架项目,这个骨架项目就是脚手架,我们的开发更加的快速。
- 主要功能:
- 统一的目录结构
- 本地调试
- 热部署
- 单元测试
- 集成打包上线
10.1、安装Node.js
官网下载Node.js:http://nodejs.cn/
确认 Node.js 安装成功:
CMD 输入
node -v查看是否正确打印版本号信息即可CMD 输入
npm -v查看是否正确打印版本号信息即可,npm 就是一个软件包管理工具,就和 linux 下的 apt软件安装差不多。
检查环境变量是否存在:

安装 Node.js 淘宝境像加速器(cnpm),最好是在管理员模式下的CMD安装:
# -g就是全局安装
npm install cnpm -g
# 或使用如下解决速度慢问题
npm install --registry=https://registry.npm.taobao.org
安装完成会显示安装目录:

10.2、安装vue-cli
cnpm install vue-cli -g
# 测试是否安装成功
# 查看查看可以基于哪些模板创建vue应用程序,通常我们选择 webpack
vue list

10.3、第一个vue-cli程序
- 创建项目
- 创建一个 Vue 项目,我们随便建立一个空的文件夹在电脑上,我这里在D盘下新建一个目录
D:\WorkSpace - 创建一个基于 webpack 模板的 vue 应用程序
- Project name:项目名称,默认回车即可
- Project description:项目描述,默认回车即可Author:项目作者,默认回车即可
- Install vue-router:是否安装 vue-router,选择n不安装(后期需要再手动添加)
- Use ESLint to lint your code:是否使用 ESLint 做代码检查,选择n不安装(后期需要再手动添加)
- Set up unit tests:单元测试相关,选择n不安装(后期需要再手动添加)
- Setup e2e tests with Nightwatch:单元测试相关,选择n不安装(后期需要再手动添加)
- Should we run npm install for you after the project has been created:创建完成后直接初始化,选择n,我们手动执行并运行结果!
#这里的myvue是项目名称,可以根据自己需求取名
vue init webpack myvue #一路都选No即可
- 初始化并运行
管理员模式 CMD 进入项目目录下,我这里是D:\WorkSpace\myvue
npm install
npm run dev
编译时遇到报错,根据提示执行命令修复错误:

访问本机8080端口:

11、webpack
11.1、什么是webpack
本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
Webpack 是当下最热门的前端资源模块化管理和打包工具,它可以将许多松散耦合的模块按照依赖和规则打包成符合生产环境部署的前端资源。还可以将按需加载的模块进行代码分离,等到实际需要时再异步加载。通过 loader 转换,任何形式的资源都可以当做模块,比如 CommonsJS、AMD、ES6、Css、JSON、CoffeeScript、LESS等。
11.2、模块化的演进
- script标签
<script src = "module3.js"></script>
<script src = "module4.js"></script>
这是最原始的 JavaScript 文件加载方式,如果把每一个文件看做是一个模块,那么他们的接口通常是暴露在全局作用域下,也就是定义在 window 对象中,不同模块的调用都是一个作用域。
这种原始的加载方式暴露了一些显而易见的弊端:
- 全局作用域下容易造成变量冲突
- 文件只能按照
<script>的书写顺序进行加载开发人员必须主观-解决模块和代码库的依赖关系 - 在大型项目中各种资源难以管理,长期积累的问题导致代码库混乱不堪
- CommonsJS
服务器端的 NodeJS 遵循 CommonsJS 规范,该规范核心思想是允许模块通过 require 方法来同步加载所需依赖的其它模块,然后通过 exports 或 module.exports 来导出需要暴露的接口。
require("module");
require("../module.js");
export .doStuff = function(){};
module.exports = somevalue ;
- 优点:
服务器端模块便于重用
NPM 中已经有超过45万个可以使用的模块包简单易用
- 缺点:
同步的模块加载方式不适合在浏览器环境中,同步意味着阻塞加载,浏览器资源是异步加载的
不能非阻塞的并行加载多个模块
- 实现:
服务端的 NodeJS
Browserify,浏览器端的 CommonsJS 实现,可以使用 NPM 的模块,但是编译打包后的文件体积较大
modules-webmake,类似 Browserify,但不如 Browserify 灵活 wreq,Browserify 的前身
- AMD
Asynchronous Module Definition 规范其实主要一个主要接口 define(id ?,
dependencies?, factory); 它要在声明模块的时候指定所有的依赖 dependencies,并且还要当做形参传到 factory 中,对于依赖的模块提前执行。
- 优点:
适合在浏览器环境中异步加载模块
可以并行加载多个模块
- 缺点:
提高了开发成本,代码的阅读和书写比较困难,模块定义方式的语义不畅
不符合通用的模块化思维方式,是一种妥协的实现
- 实现
RequireJS
curl
- CMD
Commons Module Definition 规范和 AMD 很相似,尽量保持简单,并与 CommonsJS 和 NodeJS 的 Modules 规范保持了很大的兼容性。
- 优点:
依赖就近,延迟执行
可以很容易在 Nodejs 中运行
- 缺点:
依赖 SPM 打包,模块的加载逻辑偏重
- 实现:
Sea.js
coolie
- ES6 模块
EcmaScript6 标准增加了 JavaScript 语言层面的模块体系定义。ES6 模块的设计思想,是尽量静态化,使编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonsJS 和 AMD 模块,都只能在运行时确定这些东西。
import "jquery";
export funetion dostuff(){}
module "localMadule"{}
- 优点:
容易进行静态分析
面向未来的 EcmaScript 标准
- 缺点:
原生浏览器端还没有实现该标准全新的命令
新版的 NodeJS 才支持
- 实现:
Babel
11.3、安装并使用webpack
WebPack 是一款模块加载器兼打包工具,它能把各种资源,如 JS、JSX、ES6、SASS、LESS、图片等都作为模块来处理和使用。
在管理员模式下的CMD安装:
npm install webpack -g
npm install webpack-cli -g

- 使用
- 新建目录
webpackTest测试 webpack - 编写
hello.js
//暴露一个方法
exports.Hello=function () {
document.write("<h1>狂神说ES6</h1>");
}
- 编写
main.js
var hello=require("./hello");
hello.Hello();
-
创建
webpack.config.js配置文件module.exports={ /*找到程序的入口*/ entry: './modules/main.js', output: { /*生成打包后的文件*/ filename: './js/bundle.js' } };- entry:入口文件,指定 WebPack 用哪个文件作为项目的入口
- output:输出,指定 WebPack 把处理完成的文件放置到指定路径
- module:模块,用于处理各种类型的文件
- plugins:插件,如:热更新、代码重用等,resolve:设置路径指向
- watch:监听,用于设置文件改动后直接打包

- 管理员模式 cmd 下执行
webpack打包

发现多了一个 bundle.js 文件:

使用这个 bundle.js 文件:


# 使用以下命令可以实现热部署 代码一旦改变就会重新打包
webpack --watch
12、vue-route路由
12.1、什么是 vue-route
由于 vue 的 SOC 原则,所以 vue 本身并不具备页面跳转
Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。包含的功能有:
- 嵌套的路由/视图表
- 模块化的、基于组件的路由配置路由参数、查询、通配符
- 基于 Vue.js 过渡系统的视图过渡效果细粒度的导肮控制
- 带有自动激活的 CSS class 的链接
- HTML5 历史模式或 hash 模式,在 IE9 中自动降级自定义的滚动条行为
- 安装
在 vue-cli 快速上手中创建的项目下安装 vue-route
安装完成后会在 node_modules 目录下新增 vue-route 的相关依赖,相当于导入 maven 依赖
# 安装vue-route
npm install vue-router --save-dev


12.2、快速上手
- 编写模板
在 components 目录下新建 Context.vue
<template>
<h1>内容页</h1>
</template>
<script>
export default {
name: "Context"
}
</script>
<style scoped>
</style>

- 编写 route 相关
创建 route 目录编写 index.js
import Vue from 'vue'
import VueRouter from "vue-router"; //导入路由
import Context from '../components/Context' //导入相关页面
//vue中需要显示声明使用VueRouter 安装路由
Vue.use(VueRouter);
//配置导出路由
export default new VueRouter({
//数组 可以配置多个页面
routes: [
{
//路由路径 相当于Java中的@RequestMapping
path: '/content',
//路由名字
name: "context",
//跳转的组件
component: Context
}
]
})
- 在 main.js 中使用路由
import Vue from 'vue'
import App from './App'
import router from './router' //自动扫描包里面名字为index的路由配置
Vue.config.productionTip = false
new Vue({
el: '#app',
//配置路由
router,
components: { App },
template: '<App/>'
})
- 在 App.vue 中编写视图
<template>
<div id="app">
<!--相当于 <a>标签 -->
<router-link to="/content">内容页</router-link>
<!--展示视图-->
<router-view></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>
- 测试使用
#CMD命令行执行
npm run dev

12.3、重定向
重定向也是通过 routes 配置来完成,下面例子是从 /a 重定向到 /b:
const router = new VueRouter({
routes: [
{ path: '/a', redirect: '/b' }
]
})
重定向的目标也可以是一个命名的路由:
const router = new VueRouter({
routes: [
{ path: '/a', redirect: { name: 'foo' }}
]
})
12.4、404
当我们输入一些不存在的路径时会报 404,在路由中也可以实现,编写一个 404 页面:
<template>
<div>
<h1>404</h1>
<h2>页面走丢了</h2>
</div>
</template>
<script>
export default {
name: "Notfaund"
}
</script>
<style scoped>
</style>
在路由配置 index.js 中配置:
{ //404 匹配不到的路径会走以下页面
path: "*",
component: Notfaund
}
12.5、HTML5 History模式
vue-router 默认 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。URL:localhost:8080/#/Main
如果不想要很丑的 hash,我们可以用路由的 history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。
const router = new VueRouter({
mode: 'history',
routes: [...]
})

浙公网安备 33010602011771号