VUE
1. Vue 简介
官网:https://cn.vuejs.org/v2/guide/
Vue,是一套用于构建用户界面的渐进式框架。与其他大型框架不同的是,Vue 被设计可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。
MVVM 模式的实现者
- Model:模型层,表示 JS 对象
- View:视图层,表示 DOM (HTML 操作的元素)
- ViewModel:连接视图和数据的中间件,Vue.js 就是 MVVM 中的 ViewModel 层的实现者
在 MVVM 架构中,是不允许数据和视图直接通信的,只能通过 ViewModel 来通信,而 ViewModel 就是定义了一个 Observer 观察者
- ViewModel能够观察到数据的变化,并对视图对应的内容进行更新,能够监听到视图的变化并通知数据发生变化。
Vue.js 就是 MVVM 的实现者,核心就是实现了 DOM 监听与数据绑定
为什么使用 Vue.js
- 轻量级,体积小是一个重要指标,Vue.js 压缩后只有 20 kb+ (Angular压缩 56kkb+,React 压缩 44kb+)
- 移动优先,更适合移动端,比如移动端的 Touch 事件
- 易上手,文档齐全,学习曲线平稳
- 吸取了 Angular(模块化 MVC)和 React(虚拟 DOM)的长处,并拥有自己独特的功能:计算属性等
- 开源,社区活跃度高 等等…
2. 第一个 Vue 程序
在线 CDN :
编写代码:
Vue.js 的核心实现了 MVVM 模式,扮演的角色就是 View Model 层,第一个应用程序就是展示它的数据绑定功能
-
创建一个 .html 文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> </body> </html>
-
引入在线CDN ,Vue.js
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
-
创建一个 Vue 实例
<script> var vm = new Vue({ el:"#app", //Model:数据 data:{ message:"hello vue!!!" } }); </script>
- el:"#app" :便是绑定元素(DOM) 的 id
- data:{message:“hello vue!!!”} :数据对象中有一个名为 message 的属性,并设置了初始值hello vue!!!
-
将数据绑定到页面元素
<!--view层 等于${},模板--> <div id="app"> {{message}} </div>
只需要在绑定的元素中使用双括号将 Vue 创建的名为 message 属性括起来,即可实现数据绑定功能,也就实现了 View Model 层所需效果
完整代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--view层 等于${},模板--> <div id="app"> {{message}} </div> <!--1. 导入 vue.js--> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <!--<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>--> <script> var vm = new Vue({ el:"#app", //Model:数据 data:{ message:"hello vue!!!" } }); </script> </body> </html>
-
运行测试
启动运行弹出浏览器窗口
然后按下 F12 找到控制台 console,输入 vm.message= 123 就会发现左侧显示的内容发生了变化。这个操作中,并没有操作DOM,就让页面的 内容发生了变化,这就是借助了Vue 的数据绑定功能实现的,MVVM 模式中要求 View Model 层就是使用观察者模式来实现数据的监听与绑定,以做到数据与视图的快速响应。
第一个 Vue 应用已经创建完成了,看起来跟渲染一个字符串模板非常类似,但是 Vue 背后做了大量的工作,现在数据和 DOM 已经建立了关联,所有的东西都是响应式的,我们在控制台操作对象属性界面可以实时更新
3. 基础语法指令
在此可以看到:v-bind,v-if,v-else,v-for,v-on 等被称为指令,指令带有前缀 v 表示它们是 Vue 提供的特殊特性。
3.1 v-bind,绑定元素特性
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--1. 导入 vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<!--<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>-->
</head>
<body>
<!--view层,模板-->
<div id="app">
<!--将这个元素节点 title 特性和 Vue 实例的message属性保持一致-->
<span v-bind:title="message">
鼠标停留显示动态绑定的提示信息
</span>
</div>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
//Model:数据
data:{
message: new Date().toString()
}
});
</script>
</body>
</html>
3.2 v-if,v-else 判断语句
3.2.1 v-if v-else
注意:使用 v-* 属性绑定数据是不需要 {{}} 的
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--1. 导入 vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<!--<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>-->
</head>
<body>
<!--view层,模板-->
<div id="app">
<!--直接使用 type 类型是 boolean-->
<h1 v-if="type">yes</h1>
<h1 v-else>no</h1>
</div>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
//Model:数据
data:{
type: true
}
});
</script>
</body>
</html>
3.2.2 v-else-if
=== 三个等号在 js 中表示绝对等于(数据与类型都要相等)
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--1. 导入 vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<!--<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>-->
</head>
<body>
<!--view层,模板-->
<div id="app">
<h1 v-if="type==='A'">A</h1>
<h1 v-else-if="type==='B'">B</h1>
<h1 v-else>C</h1>
</div>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
//Model:数据
data:{
type: 'A'
}
});
</script>
</body>
</html>
3.3 v-for 循环
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--1. 导入 vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<!--<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>-->
</head>
<body>
<!--view层,模板-->
<div id="app">
<!--说明
items 是数组
item 是数组元素迭代的别名,类同于 java 的数组遍历
-->
<li v-for="(item,index) in items">
{{item.message}}----下标:{{index}}
</li>
</div>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
//Model:数据
data:{
items: [
{message:'张三'},
{message:'李四'},
{message:'王五'}
]
}
});
</script>
</body>
</html>
3.4 v-on 监听事件
事件有 Vue 事件和前端页面本身的一些事件,这里 click 是 vue 事件,绑定到 Vue 中的 methods 中的方法事件。
<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--1. 导入 vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<!--<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>-->
</head>
<body>
<!--view层,模板-->
<div id="app">
<button v-on:click="hi">click</button>
</div>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
//Model:数据
data: {
message: '张三'
},
methods: {
hi: function () {
alert(this.message);
}
}
});
</script>
</body>
</html>
4. 表单双向绑定,组件
4.1 什么是双向数据绑定
Vue.js 是一个 MV VM 框架,即数据双向绑定,当数据发生变化时视图会随之发生变化,当视图发生变化时数据也会随之同步进行变化。Vue.js 精髓
注意:数据双向绑定一定是对于 UI 控件来说的,非 UI 控件不会涉及到数据双向绑定,单向数据绑定是使用状态管理工具的前提,如果使用 vue x 数据流也是单向的,就会和双向数据绑定有冲突。
实现数据双向绑定:在 Vue.js 中,如果使用 vuex,实际上数据还是单向的,之所以说数据双向绑定,这是用的 UI 控件来说,对于我们处理表单,Vue.js 的双向数据绑定用起来就特别舒服了,即两者并不排斥,在全局数据流使用单向方便跟踪;局部性数据流使用双向简单易操作。
4.2 在表单中使用双向数据绑定
可以使用 v-model 指令在表单及元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素,v-model 负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
**注意:**v-model 会忽略所有表单元素的 value,checked,selected 特性的初始值而总是将 Vue 实例的数据作为数据来源,应该通过 js 在组件的 data 选项中声明初始值。
-
单行/多行 文本
<!DOCTYPE html> <head> <meta charset="UTF-8"> <title>Title</title> <!--1. 导入 vue.js--> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <!--<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>--> </head> <body> <!--view层,模板--> <div id="app"> 单行文本:<input type="text" v-model="message"> {{message}} <br> 多行文本:<textarea name="" id="" cols="30" rows="10" v-model="message"></textarea> {{message}} </div> <script type="text/javascript"> var vm = new Vue({ el: "#app", //Model:数据 data: { message: '' } }); </script> </body> </html>
-
单选按钮
<!DOCTYPE html> <head> <meta charset="UTF-8"> <title>Title</title> <!--1. 导入 vue.js--> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <!--<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>--> </head> <body> <!--view层,模板--> <div id="app"> <input type="radio" name="sex" value="男" v-model="checked"> 男 <input type="radio" name="sex" value="女" v-model="checked"> 女 <br> {{checked}} </div> <script type="text/javascript"> var vm = new Vue({ el: "#app", //Model:数据 data: { checked: '男' } }); </script> </body> </html>
-
复选框
<!DOCTYPE html> <head> <meta charset="UTF-8"> <title>Title</title> <!--1. 导入 vue.js--> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <!--<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>--> </head> <body> <!--view层,模板--> <div id="app"> <input type="checkbox" value="游戏" v-model="checkedProject">游戏 <br> <input type="checkbox" value="唱歌" v-model="checkedProject">唱歌 <br> <input type="checkbox" value="跳舞" v-model="checkedProject">跳舞 <br> {{checkedProject}} </div> <script type="text/javascript"> var vm = new Vue({ el: "#app", //Model:数据 data: { checkedProject: [] } }); </script> </body> </html>
-
下拉列表框
<!DOCTYPE html> <head> <meta charset="UTF-8"> <title>Title</title> <!--1. 导入 vue.js--> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <!--<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>--> </head> <body> <!--view层,模板--> <div id="app"> <select v-model="checked"> <option value="" disabled>请选择</option> <option>A</option> <option>B</option> <option>C</option> <option>D</option> </select> <br> {{checked}} </div> <script type="text/javascript"> var vm = new Vue({ el: "#app", //Model:数据 data: { checked: "" } }); </script> </body> </html>
**注意:**v-model 表达式的初始值未能匹配任何选项,元素将被渲染为“未选中”状态。IOS 中会使用户无法选择第一个选项,因为这种情况下 IOS 不会触发 change 事件,因此更推荐上面这种提供一个值为空的禁用选项。
5. 组件
组件是可复用的 Vue 实例,说白就是一组可以重复使用的模板,与 jstl 的自定义标签等框架相似,通常一个应用会以一棵嵌套的组件树的形式进行组织:
真实开发中不会以下面方式,只是理解组件的形式。
使用 Vue.component() 方法注册组件:
<script type="text/javascript">
//注册组件
Vue.component("comp-name",{
template: '<li>hello</li>'
});
//实例化 vue
var vm = new Vue({
el: "#app"
});
</script>
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--1. 导入 vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<!--<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>-->
</head>
<body>
<!--view层,模板-->
<div id="app">
<comp-name v-for="item in items" v-bind:val="item"></comp-name>
</div>
<script type="text/javascript">
//注册组件
Vue.component("comp-name",{
props:['val'],
template: '<li>{{val}}</li>'
});
//实例化 vue
var vm = new Vue({
el: "#app",
data: {
items: ["张三","李四","王五"]
}
});
</script>
</body>
</html>
- Vue.component() :注册组件
- comp-name :自定义组件名字
- template :组件的模板
- props :传递参数,需要传递参数到组件时需要使用该属性,注意属性里的值不能为大写
v-for="item in items“ :遍历 Vue 实例中定义的名为 items 的数组,并创建同等数量的组件
v-bind:val=“item” :将遍历的 item 项绑定到组件中 props 定义名为 val 属性上;= 左边 val 为 props 定义的属性名,右边为 item in items 中遍历的 item 项的值。
6. Axios 异步通信
6.1 什么是 Axios
官网:http://www.axios-js.com/
Axios 是一个开源的可以在浏览器端和 Node js 的异步通信框架,主要作用就是实现 Ajax 异步通信,功能特点:
- 从浏览器中创建 XMLHttpRequests
- 从 node.js 创建 http 请求
- 支持 Promise API,js 中链式编程
- 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换 json 数据
- 客户端支持防御 XSRF(跨站请求伪造)
由于 Vue.js 是一个视图层框架并且作者严格遵守 Soc(关注度分离原则),所以 Vue.js 并不包含 Ajax 的通信功能,为了解决通信问题,作者单独开发了一个 vue-resource 的插件,不过在进入 2.0 版本以后停止了对该插件的维护并推荐了 Axios 框架,减少使用 jQuery,因为它操作 DOM 太频繁。
6.2 代码实现
-
开发中接口大部分都是采用 json 格式,现在项目中创建一个 data.json 数据文件,内容如下:
{ "name": "张三", "url": "www.baidu.com", "student": { "name": "李四", "age": "20", "sex": "男" }, "mes": [ { "name": "bilibili", "url": "www.bilibili.com" }, { "name": "百度", "url": "www.baidu.com" } ] }
-
需要引入在线的 CDN
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
-
完整 html 代码
<!DOCTYPE html> <html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-for="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>Title</title> <!--1. 导入 vue.js--> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <!--axios异步通信--> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <!--<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>--> </head> <body> <!--view层,模板--> <div id="app"> <div>姓名:{{info.name}}</div> <div>链接:<a v-bind:href="info.url">{{info.url}}</a></div> <div>学生:{{info.student.name}},{{info.student.age}},{{info.student.sex}}</div> <li v-for="item in (info.mes)"> {{item.name}} </li> </div> <script type="text/javascript"> //实例化 vue var vm = new Vue({ el: "#app", data() { return { info: { name: null, url: null, student: { name: null, age: null, sex: null }, mes: [ { name: null, url: null }, { name: null, url: null } ] } } }, mounted() { //钩子函数 axios.get('../data.json').then(response => (this.info = response.data)); } }); </script> </body> </html>
代码中使用了 v-bind 将 a:href 的属性值与 Vue 实例中的数据进行绑定
使用 axios 框架的 get 方法请求 Ajax 并自动将数据封装进了 Vue 实例的数据对象中
在 data 中的数据结构必须和 Ajax 响应回来的数据格式匹配
7. Vue 的声明周期
Vue 实例有一个完整的声明周期,也就是从开始创建初始化数据、编译模板、挂载DOM、渲染-更新-渲染、卸载等一系列过程称为 Vue 的声明周期,就是Vue 实例从创建到销毁的过程。
在 Vue 的整个声明周期中,提供了一系列事件,可以让我们在事件触发时注册 js 方法,可以让我们用自己注册的 js 方法控制整个大局,这些事情响应方法中的 this 直接指向的就是 Vue 实例。
8. 计算属性、内容分发、自定义事件
8.1 计算属性
计算属性中属性是名词,首先是个属性,其次这个属性具有计算的能力,计算指的是函数:简单说就是一个能够计算结果缓存起来的属性(将行为转化成静态的属性),可以想象成缓存。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--1. 导入 vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<!--view层,模板-->
<div id="app">
<div>当前时间时间戳:{{nowTime1()}}</div>
<div>当前时间时间戳:{{nowTime2}}</div>
</div>
<script type="text/javascript">
//实例化 vue
var vm = new Vue({
el: "#app",
data:{
message: 123
},
methods: {
nowTime1: function () {
return Date.now();
}
},
//计算属性 methods,computed 方法名不能重名,重名之后只会调用 methods 的方法
computed:{
nowTime2:function () {
this.message
return Date.now();
}
}
});
</script>
</body>
</html>
注意:methods ,computed 里的function不能重名
- methods:定义方法,调用需要加 方法名()
- computed:定义计算属性,调用属性不需要加括号
- 在方法的值发生了变化,则缓存就会刷新,上图中最后一步发生变化
调用方法时,每次都需要进行计算,既然有计算过程则必定产生系统的开销,如果这个结果是不经常变化可以考虑把这个结果缓存起来,采用计算属性可以方便做到,计算属性的主要特性就是为了将不经常变化的计算结果进行缓存,节约系统开销。
8.2 内容分发
在 Vue.js 中使用 元素作为承载分发内容的出口,称之为插槽,可以应用在组合组件中。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--1. 导入 vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<!--view层,模板-->
<div id="app">
<!--将实例化 Vue 里面的值通过插槽插入-->
<student>
<stu-title slot="stu-title" :title="title"></stu-title>
<stu-list slot="stu-list" v-for="item in stuItems" :item="item"></stu-list>
</student>
</div>
<script type="text/javascript">
Vue.component('student', {
//1. 首先定义一个组件,整体架构包括 标题,列表,并且留出插槽
template: '<div>\
<slot name="stu-title"></slot>\
<ul>\
<slot name="stu-list"></slot>\
</ul> \
<div/>'
});
//定义标题组件
Vue.component('stu-title',{
props: ['title'],
template: '<div>{{title}}</div>'
});
//定义内容组件
Vue.component('stu-list',{
props: ['item'],
template: '<li>{{item}}</li>'
});
//实例化 vue
var vm = new Vue({
el: "#app",
data: {
title: "学生姓名列表",
stuItems: ["张三","李四","王五"]
}
});
</script>
</body>
</html>
8.3 自定义事件
通过上面代码不难发现,数据项在 Vue 实例中,但删除操作要在组件中完成,那么组件如何才能删除 Vue 实例中的数据,此时涉及到参数传递与事件分发,Vue 为我们提供了自定义事件的功能很好的帮助我们解决了这个问题,使用 this.$emit(“自定义事件名”,参数)
-
在 Vue 实例中添加 methods 对象 removeItems 方法
//实例化 vue var vm = new Vue({ el: "#app", data: { title: "学生姓名列表", stuItems: ["张三","李四","王五"] }, methods:{ removeItems:function (index) { this.stuItems.splice(index,1); } } });
-
在组件 stu-list 中添加删除按钮并绑定事件
Vue.component('stu-list',{ props: ['item','index'], template: '<li>{{item}} <button @click="deleteItem">删除</button></li>', methods:{ deleteItem:function (index) { //自定义事件分发 this.$emit('remove',index) } } });
-
自定义方法绑定
<!--增加了 v-on:remove="removeItems(index)"自定义事件,该组件会调用 Vue 实例中定义的--> <stu-list slot="stu-list" v-for="(item,index) in stuItems" :item="item" :index="index" v-on:remove="removeItems(index)"></stu-list>
-
完整代码
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Title</title> <!--1. 导入 vue.js--> <script src="https://cdn.jsdelivr.net/npm/vue"></script> </head> <body> <!--view层,模板--> <div id="app"> <!--将实例化 Vue 里面的值通过插槽插入--> <student> <stu-title slot="stu-title" :title="title"></stu-title> <!--增加了 v-on:remove="removeItems(index)"自定义事件,该组件会调用 Vue 实例中定义的--> <stu-list slot="stu-list" v-for="(item,index) in stuItems" :item="item" :index="index" v-on:remove="removeItems(index)"></stu-list> </student> </div> <script type="text/javascript"> Vue.component('student', { //1. 首先定义一个组件,整体架构包括 标题,列表,并且留出插槽 template: '<div>\ <slot name="stu-title"></slot>\ <ul>\ <slot name="stu-list"></slot>\ </ul> \ <div/>' }); //定义标题组件 Vue.component('stu-title',{ props: ['title'], template: '<div>{{title}}</div>' }); //定义内容组件 Vue.component('stu-list',{ props: ['item','index'], template: '<li>{{item}} <button @click="deleteItem">删除</button></li>', methods:{ deleteItem:function (index) { //自定义事件分发 this.$emit('remove',index) } } }); //实例化 vue var vm = new Vue({ el: "#app", data: { title: "学生姓名列表", stuItems: ["张三","李四","王五"] }, methods:{ removeItems:function (index) { this.stuItems.splice(index,1); } } }); </script> </body> </html>
9. 第一个 vue-cli 项目
vue-cli 官方提供了一个脚手架,用于快速生成 vue 的项目模板,预先定义好的目录结构及基础代码,好比创建 Maven 项目时可以选择创建一个骨架项目,这个骨架项目就是脚手架,开发更加的快速。
项目的功能: 统一的目录结构,本地调试,热部署,单元调试,集成打包上线
9.1 环境安装
- 官网下载安装包
-
Node.js:http://nodejs.cn/download/
下载完成后直接下一步安装就可以了
-
Git:https://git-scm.com/doenloads
镜像:https://npm.taobao.org/mirrors/git-for-windows/
- 安装完成后确认一下 node.js 安装成功:
- 进入 cmd,node -v 查看是否能够打印出版本号
- 进入 cmd,npm -v 查看是否能够打印出版本号
npm 是随同 node.js 一起安装的包管理工具,能解决 node.js 代码部署上的很多问题,常见的使用场景:
- 允许用户从 npm 服务器下载别人编写的第三方包到本地使用
- 允许用户从 npm 服务器下载并安装别人编写的命令行程序到本地使用
- 允许用户将自己编写的包或命令行程序上传到 npm 服务器供别人使用
由于新版的 node.js 已经继承了 npm,所以之前 npm 也一并安装好了, npm -v 可以查看安装版本。
-
安装 Node.js 淘宝镜像加速器(cnpm),安装好后下载会加速
npm install cnpm -g //-g 是全局安装,推荐使用该方式,就是安装过程比较慢需要耐心等待 npm install --registry=https://registry.npm.taobao.org //这个方式也可以解决速度慢的问题,但是每次安装需要添加参数,比较繁琐
-
查看安装
C:\Users\lishisen\AppData\Roaming\npm
-
安装 vue-cli
cnpm install vue-cli -g //测试是否安装成功,查看可以基于那些模板创建 vue 应用程序,通常选择 webpack vue list
至此 vue-cli 安装完成了
9.2 创建第一个 vue-cli 应用程序
-
创建一个空文件夹, Vue 项目
-
cmd 中 cd命令 进入该文件夹
-
vue init webpack myvue,这里 myvue 是项目名称,可以根据需求起名
然后一路 no 即可,也可以选择 yes 自动安装,no 后续需要自己配置一些环境
project name:项目名称
project description:项目描述
author:项目作者
install vue-router:是否安装 vue-router,选择 n 后续需要手动添加
Use ESLint to lint your code:是否使用 ESLint 做代码检查,选择 n 后续需要手动添加
Set up unit tests:单元测试相关,选择 n 后续需要手动添加
Setupe2etests with Nighwatch:单元测试相关,选择 n 后续需要手动添加
Should we run npm install for you after the project has been created:创建完成后直接初始化,选择 n 手动执行。
-
初始化并运行
cd 进入目录 npm install //安装所需环境,时间较长,耐心等待 npm run dev //打包运行
-
弹出 npm 窗口给出运行路径
10. webpack
10.1 webpack 简介
本质上,webpack 是一个现代 js 应用程序的静态模块打包器(module bundler),当 webpack 处理应用程序时,会递归构建一个依赖关系图,其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle
webpack 是当下最热门的前端资源模块化管理和打包工具,它可以将许多松耦合的模块按照依赖和规则打包成符合生产环境部署的前端资源,还可以将按需加载的模块进行代码分离,等到实际需要时再异步加载。通过 loader 转换,任何形式的资源都可以当作模块,比如 Commons js、AMD、ES 6、CSS、JSON、Coffee Script、LESS 等。
伴随着移动互联网的大潮,当今越来越多的网站已经从网页模式进化到了 WebApp 模式。他们运行在现代的浏览器里,使用 html5 ,css3 ,ES 6 等新的技术来开发丰富的功能,网页已经不仅仅是完成浏览器的基本需求;WebApp 通常是一个 SPA(单页面应用),每一个视图通过异步的方式加载,这导致页面初始化和使用过程中会加载越来越多的 js 代码,这给前端的开发流程和资源组织带来了巨大挑战。
前端开发和其他开发工作的主要区别,首先是前端基于多语言、多层次的编码和组织工作,其次前端产品的交付时基于浏览器的,这些资源是通过增量加载的方式运行到浏览器端,如何在开发环境组织好这些碎片化的代码和资源,并且保证他们在浏览器端快速、优雅的加载和更新,就需要一个模块化系统,这个理想中的模块化系统是前端工程师多年来一直探索的难题。
10.2 模块化的演进
-
Script 标签
<script src="module1.js"></script> <script src="module2.js"></script> <script src="module3.js"></script>
这是原始的 js 文件加载方式,如果把每个文件看作是一个模块,那么他们的接口通常是暴露在全局作用域下,也就是定义在 windows 对象中,不同模块的调用都是一个作用域。
这种方式弊端:
- 全局作用域下容易造成变量冲突
- 文件只能按照
10.3 安装 webpack
webpack 是一款模块加载器兼打包工具,能够把各种资源:js,jsx,es6,sass,less,图片等都作为模块来处理和使用。
安装:
npm install webpack -g
npm install webpack-cli -g
如果安装失败可以使用 cnpm,前提有镜像的安装
-
webpack -v 显示版本号表示安装成功
-
webpack-cli -v 显示版本号表示安装成功
配置:
在项目中创建 webpack-config.js 文件
-
entry:入口文件,指定 web pack 用哪个文件作为项目的入口,相当于 java 的 psvm
-
output:输出,指定 webpack 把处理完成的文件放置到指定路径
-
module:模块,用于处理各种类型的文件
-
plugins:插件,如:热更新,代码重用等
-
resolve:设置路径指向
-
watch:监听,用于设置文件改动后直接打包
module.exports = { entry: "", output: { path: "", filename: "" }, module: { loaders: [ {test: /\.js$/, loade: ""} ] }, plugins: {}, resolve: {}, watcher: true }
10.4 使用 webpack
-
创建项目,在 D 盘创建一个文件夹使用 idea open打开
-
创建一个 modules 目录,用于放置 js 模块等资源文件
-
在 modules 下创建模块文件,hello.js,用于编写 js 模块相关代码
//暴露方法 sayHi 1 2 3 exports.sayHi1 = function () { document.write("<h1>Hello,webpack1</h1>") } exports.sayHi2 = function () { document.write("<h1>Hello,webpack2</h1>") } exports.sayHi3 = function () { document.write("<h1>Hello,webpack3</h1>") }
-
在 modules 下创建名为 main.js 的入口文件,用于打包时的 entry 属性
//require 导入一个模块,就可以调用这个模块中方法了 var hello = require("./hello"); hello.sayHi1();
-
在 webpack.config.js 配置文件中配置入口和输出
module.exports = { //程序入口,相当于 psvm entry: './modules/main.js', // 输出到 output: { filename: "./js/bundle.js" } }
-
在命令行执行
执行 webpack 命令后就会生成 output输出的文件
webpack //直接打包 webpack --watch //用于监听变化
-
在项目中创建 html 页面,index.html,导入 webpack 打包后的 js 文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script src="dist/js/bundle.js"></script> </body> </html>
-
测试运行即可
11. vue-router 路由
11.1 简介
Vue Router 是 Vue.js 的官方路由管理器,它与 Vue.js 核心深度集成,使使用 Vue.js 轻松构建单页面应用程序变得轻而易举。功能包括:
- 嵌套路线/视图映射
- 模块化,基于组件的路由器配置
- 路由参数,查询,通配符
- 查看由 Vue.js 过渡系统提供动力的过渡效果
- 细粒度的导航控制
- 与自动活动 css 类的链接
- html5 历史记录模式或哈希模式,在 IE9 中具有自动备用
- 可自定义的滚动行为
11.2 安装 vue-router
基于 vue-cli 进行测试,vue-router 是一个插件包,所以需要使用 npm/cnpm 进行安装
在命令行,cd 进入项目目录
npm install vue-router --save-dev //执行该命令进行安装
在模块化功能中使用它,必须通过 Vue.use() 明确地安装路由功能:
//导入路由插件
import VueRouter from 'vue-router'
//使用路由
Vue.use(VueRouter);
11.3 测试
-
创建 Vue-cli 项目,删除没有用的整理出来一个干净的结构
-
components 目录下存放自己编写的组件
-
创建组件 Content.vue ,Main.vue 两个自己编写的组件
Content.vue
<template> <h1>内容</h1> </template> <script> export default { name: "Content" } </script> <style scoped> </style>
Main.vue
<template> <h1>首页</h1> </template> <script> export default { name: "Main" } </script> <style scoped> </style>
-
安装好路由之后,在 src 目录下创建一个文件夹:router,用于存放路由配置文件:index.js
import Vue from 'vue' //导入路由插件 import VueRouter from 'vue-router' //导入自定义的组件 import Main from '../components/Main' import Content from "../components/Content"; //使用路由 Vue.use(VueRouter); //配置路由 export default new VueRouter({ routes: [ { //路由路径 path: '/main', //路由名称,可省略 name: 'main', //跳转到的组件 component: Main }, { path: '/content', component: Content } ] });
-
在 main.js 中配置路由
import Vue from 'vue' import App from './App' //导入上面创建的路由配置目录 import router from './router'//自动扫描里面的路由配置 //用来关闭生产模式下给出的提示 Vue.config.productionTip = false new Vue({ el: '#app', //配置路由 router, components: { App}, template: '<App/>' });
-
在 App.vue 中使用路由
<template> <div id="app"> <!-- router-link:默认会被渲染成一个 <a> 标签,to 属性为指定链接相当于 href router-view:用于渲染路由匹配的组件 --> <router-link to="/main">首页</router-link> <router-link to="/content">内容</router-link> <router-view></router-view> </div> </template> <script> export default { name: 'App' } </script> <style></style>
12. 实现 Vue 与 ElementUI 组件库结合使用
12.1 创建项目并安装所需工具
-
建立项目文件夹
vue init webpack vue-element
-
安装依赖,vue-router,element-ui,sass-loader,node-sass 四个插件
//首先进入 vue-element 目录 cd vue -element //安装 vue-router npm install vue-router --save-dev //安装 element-ui npm i element-ui -S //安装依赖 npm install //安装 sass 加速器 cnpm install sass-loader node-sass --save-dev //启动测试 npm run dev
-
npm 命令解释:
- npm install moduleName:安装模块到项目目录中
- npm install -g moduleName:-g 是将模块安装到全局,具体安装到那个磁盘那个位置要看 npm config prefix 的位置
- npm install -save moduleName:-save 意思是将模块安装到项目下,并在 package 文件的 dependencies 节点写入依赖,-S 为该命令缩写
- npm install -save-dev moduleName:-save-dev 的意思是将模块安装到项目目录下,并在 package 文件的 devDependencies 节点写入依赖,-D 为该命令缩写
12.2 编写代码
用 idea 打开项目后,将初始化一些无用的东西删掉。创建项目结构。
- assets:存放资源文件
- components:存放 Vue 功能组件
- views:存放 Vue 视图组件
- router:存放 vue-router 路由配置
-
创建首页视图,在 views 目录下创建 Main.vue 视图组件
<template> <h1>首页</h1> </template> <script> export default { name: "Main" } </script> <style scoped> </style>
-
创建首页视图,在 views 目录下创建 Login.vue 视图组件,el- 元素为 ElementUI 组件*
<template> <div> <el-form ref="loginForm" :model="form" :rules="rules" label-width="80px" class="login-box"> <h3 class="login-title">欢迎登录</h3> <el-form-item label="账号" prop="username"> <el-input type="text" placeholder="请输入账号" v-model="form.username"/> </el-form-item> <el-form-item label="密码" prop="password"> <el-input type="password" placeholder="请输入密码" v-model="form.password"/> </el-form-item> <el-form-item> <el-button type="primary" v-on:click="onsubmit('loginForm')">登录</el-button> </el-form-item> </el-form> <el-dialog title="温馨提示" :visible.sync="dialogVisiable" width="30%" :before-close="handleClose"> <span>请输入账号和密码</span> <span slot="footer" class="dialog-footer"> <el-button type="primary" @click="dialogVisible = false">确定</el-button> </span> </el-dialog> </div> </template> <script> export default { name: "Login", data(){ return{ form:{ username:'', password:'' }, //表单验证,需要在 el-form-item 元素中增加prop属性 rules:{ username:[ {required:true,message:"账号不可为空",trigger:"blur"} ], password:[ {required:true,message:"密码不可为空",tigger:"blur"} ] }, //对话框显示和隐藏 dialogVisible:false } }, methods:{ onSubmit(formName){ //为表单绑定验证功能 this.$refs[formName].validate((valid)=>{ if(valid){ //使用vue-router路由到指定界面,该方式称为编程式导航 this.$router.push('/main'); }else{ this.dialogVisible=true; return false; } }); } } } </script> <style lang="scss" scoped> .login-box{ border:1px solid #DCDFE6; width: 350px; margin:180px auto; padding: 35px 35px 15px 35px; border-radius: 5px; -webkit-border-radius: 5px; -moz-border-radius: 5px; box-shadow: 0 0 25px #909399; } .login-title{ text-align:center; margin: 0 auto 40px auto; color: #303133; } </style>
-
在 router 目录下创建 index.js ,配置路由信息
//导入vue import Vue from 'vue' import VueRouter from 'vue-router' //导入自定义的视图组件 import Main from "../views/Main"; import Login from "../views/Login"; //使用路由 Vue.use(VueRouter); //导出 export default new VueRouter({ routes: [ { path: '/main', component: Main }, { path: '/login', component: Login } ] });
-
APP.vue 中配置 router-view
<template> <div id="app"> <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>
-
main.js
import Vue from 'vue' import App from './App' import router from './router' import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' Vue.use(router); Vue.use(ElementUI); Vue.config.productionTip = false new Vue({ el: '#app', router, components: { App }, template: '<App/>' })
-
测试
如果运行出现错误,可能是因为 sass-loader 版本过高导致的编译错误,需要退回版本到 7.3.1,在 package.json 文件中找到 “sass-loader” 的版本换成 7.3.1,然后 cnpm install 就可以了
12.3 嵌套路由
嵌套路由又称子路由,即在原有的路由添加 children:[{}] 编写子路由。
-
创建用户信息组件,在 Views新建文件夹 user,然后创建 Profile.vue (个人信息)组件和 List.vue (用户列表)组件
Profile.vue
<template> <h1>个人信息</h1> </template> <script> export default { name: "UserProfile" } </script> <style scoped> </style>
List.vue
<template> <h1>用户列表</h1> </template> <script> export default { name: "UserList" } </script> <style scoped> </style>
-
修改 Main.vue 视图组件,使用 ElementUI 布局容器组件
<template> <div> <el-container> <el-aside width="200px"> <el-menu :default-openeds="['1']"> <el-submenu index="1"> <template slot="title"><i class="el-icon-caret-right"></i>用户管理</template> <el-menu-item-group> <el-menu-item index="1-1"> <!--插入的地方--> <router-link to="/user/profile">个人信息</router-link> </el-menu-item> <el-menu-item index="1-2"> <!--插入的地方--> <router-link to="/user/list">用户列表</router-link> </el-menu-item> </el-menu-item-group> </el-submenu> <el-submenu index="2"> <template slot="title"><i class="el-icon-caret-right"></i>内容管理</template> <el-menu-item-group> <el-menu-item index="2-1">分类管理</el-menu-item> <el-menu-item index="2-2">内容列表</el-menu-item> </el-menu-item-group> </el-submenu> </el-menu> </el-aside> <el-container> <el-header style="text-align: right; font-size: 12px"> <el-dropdown> <i class="el-icon-setting" style="margin-right: 15px"></i> <el-dropdown-menu slot="dropdown"> <el-dropdown-item>个人信息</el-dropdown-item> <el-dropdown-item>退出登录</el-dropdown-item> </el-dropdown-menu> </el-dropdown> </el-header> <el-main> <!--在这里展示视图--> <router-view /> </el-main> </el-container> </el-container> </div> </template> <script> export default { name: "Main" } </script> <style scoped lang="scss"> .el-header { background-color: #B3C0D1; color: #333; line-height: 60px; } .el-aside { color: #333; } </style>
-
配置路由 /router/index.js,children 为子路由
//导入vue import Vue from 'vue' import VueRouter from 'vue-router' //导入自定义的视图组件 import Main from "../views/Main"; import Login from "../views/Login"; //导入子模块 import UserProfile from '../views/user/Profile' import UserList from '../views/user/List' //使用路由 Vue.use(VueRouter); // 导出 export default new VueRouter({ routes: [ { path: '/main', component: Main, //写入子模块 children: [ { path: '/user/profile', component: UserProfile }, { path: '/user/list', component: UserList } ] }, { path: '/login', component: Login } ] });
-
运行测试
12.4 参数传递
使用上面代码进行修改
第一种取值方式
-
修改路由的配置,router/index.js
{ //id 用于接收参数 path: '/user/profile/:id', //name 用于跳转的标识 name: 'UserProfile', component: UserProfile }
-
传递参数
在 Main.vue 中 router-link 标签的to修改为 :to 绑定
<!--name 是路由中的name属性,必须配匹,params 是传递的参数--> <router-link :to="{name: 'UserProfile',params: {id:1}}">个人信息</router-link>
-
组件中显示,{{$route.params.id}}接收
<template> <!--div必须加--> <div> <h1>个人信息</h1> {{$route.params.id}} </div> </template>
-
测试
第二种取值方式,使用 props 减少耦合,推荐使用
-
修改路由配置,views/index.js 中增加 props:true 属性
{ path: '/user/profile/:id', name: 'UserProfile', component: UserProfile, props: true }
-
Main.vue 中与之前的一样
<!--name 是路由中的name属性,必须配匹,params 是传递的参数--> <router-link :to="{name: 'UserProfile',params: {id:1}}">个人信息</router-link>
-
Profile.vue 接收参数为目标组件增加 props 属性
<template> <div> <h1>个人信息</h1> {{id}} </div> </template> <script> export default { props: ['id'], name: "UserProfile" } </script> <style scoped> </style>
-
测试,运行结果同上
12.5 组件重定向
使用 redirect 属性,这里 进入 /goHome 后重定向到了 /main 路径,重定向不需要定义组件
{
path: '/goHome',
redirect: '/main'
}
访问:
<router-link to="/goHome">回到首页</router-link>
12.6 路由模式
两种:
- hash:默认,路径有 #,http://localhost:8080/#/login
- history:路径没有 #,http://localhost:8080/login
在路由配置 index.js 中修改:
export default new Router({
mode: 'history',
routes: [
]
});
12.7 404 处理
-
在 views 下建立 NotFind.vue
<template> <h1>您访问的页面找不到</h1> </template> <script> export default { name: "NotFind" } </script> <style scoped> </style>
-
在 router/index.js 中配置路由,写到最后
{ path: '/*', component: NotFind }
-
测试
12.8 路由钩子
- beforeRouteEnter :进入路由之前执行
- beforeRouteLeave : 离开路由前执行
<script>
export default {
name: "UserProfile",
beforeRouteEnter:(to,from,next)=> {
console.log("进入页面之前");
next();
},
beforeRouteLeave:(to,from,next)=> {
console.log("进入页面之后");
next();
}
}
</script>
- to:路由要跳转的路径信息
- from:路径跳转前的路径信息
- next:路由的控制参数
- next():跳入下一个页面
- next(‘/path’):改变路由的跳转方向,使其跳到另一个路由
- next(false):返回原来的页面
- next((vm)=>{}):仅在 beforeRouteEnter中可用,vm 是组件实例
12.9 钩子函数中使用异步请求
-
安装 Axios
npm install --save axios vue-axios 安装失败用 cnpm
-
在入口 main.js 引用 Axios
import axios from 'axios' import VueAxios from 'vue-axios' Vue.use(VueAxios, axios)
-
准备数据,在 static 目录下创建 mock 目录,只有static是可以被访问的,所以将静态文件放入该目录下。
{ "name": "张三", "url": "www.baidu.com", "student": { "name": "李四", "age": "20", "sex": "男" }, "mes": [ { "name": "bilibili", "url": "www.bilibili.com" }, { "name": "百度", "url": "www.baidu.com" } ] }
-
在 Profile.vue 中 beforeRouteEnter 中进行异步请求
<script> export default { name: "UserProfile", //钩子函数,相当于是过滤器 beforeRouteEnter:(to,from,next)=> { console.log("进入页面之前"); next(vm => { //进入路由之前执行 getData 方法 vm.getData() }); }, beforeRouteLeave:(to,from,next)=> { console.log("进入页面之后"); next(); }, //axios methods: { getData: function () { this.axios({ method: 'get', url: 'http://localhost:8080/static/mock/data.json', }).then(function (response) { console.log(response) }) } } } </script>
-
测试
学习参考视频,所学内容根据前面网址视频学习,讲解通俗易懂,以上内容都是看一点视频然后写一点笔记记录下来的。