vue2.0学习笔记
官网:https://cn.vuejs.org/
Vue 的核心库只关注视图层,方便与第三方库或既有项目整合。
HTML + CSS + JS : 视图 : 给用户看,刷新后台给的数据
网络通信 : axios
页面跳转 : vue-router
状态管理:vuex
Vue-UI : ICE , Element UI
1 前端核心分析 1.1 VUE 概述 Vue 是一套用来动态构建用户界面的渐进式JavaScript框架
构建用户界面:把数据通过某种办法变成用户界面
渐进式:Vue可以自底向上逐层的应用,简单应用只需要一个轻量小巧的核心库,复杂应用可以引入各式各样的Vue插件
1.2 前端三要素
HTML (结构) :超文本标记语言(Hyper Text Markup Language) ,决定网页的结构和内容
CSS (表现) :层叠样式表(Cascading Style sheets) ,设定网页的表现样式
JavaScript (行为) :是一种弱类型脚本语言,其源代码不需经过编译,而是由浏览器解释运行,用于控制网页的行为
1.3 JavaScript框架
jQuery: 大家熟知的JavaScript框架,优点是简化了DOM操作,缺点是DOM操作太频繁,影响前端性能;在前端眼里使用它仅仅是为了兼容IE6、7、8;
Angular: Google收购的前端框架,由一群Java程序员开发,其特点是将后台的MVC模式搬到了前端并增加了模块化开发的理念,与微软合作,采用TypeScript语法开发;对后台程序员友好,对前端程序员不太友好;最大的缺点是版本迭代不合理(如: 1代-> 2代,除了名字,基本就是两个东西;截止发表博客时已推出了Angular6)
React: Facebook出品,一款高性能的JS前端框架;特点是提出了新概念[虚拟DOM]用于减少真实DOM操作,在内存中模拟DOM操作,有效的提升了前端渲染效率;缺点是使用复杂,因为需要额外学习一门[JSX] 语言;
Vue:一款渐进式JavaScript框架,所谓渐进式就是逐步实现新特性的意思,如实现模块化开发、路由、状态管理等新特性。其特点是综合了Angular (模块化)和React (虚拟DOM)的优点;
Axios :前端通信框架;因为Vue 的边界很明确,就是为了处理DOM,所以并不具备通信能力,此时就需要额外使用一个通信框架与服务器交互;当然也可以直接选择使用jQuery提供的AJAX通信功能;
前端三大框架:Angular、React、Vue
1.4 Vue 的特点
遵循MVVM模式
编码简洁,体积小,运行效率高,适合移动/PC端开发
它本身只关注 UI,可以引入其它第三方库开发项目
采用组件化模式,提高代码复用率、且让代码更好维护
声明式编码,让编码人员无需直接操作DOM,提高开发效率
使用虚拟DOM 和 Diff算法,尽量复用DOM节点
1.5 Vue 周边库
vue-cli:vue 脚手架
vue-resource(axios):ajax 请求
vue-router:路由
vuex:状态管理(它是 vue 的插件但是没有用 vue-xxx 的命名规则)
vue-lazyload:图片懒加载
vue-scroller:页面滑动相关
mint-ui:基于 vue 的 UI 组件库(移动端)
element-ui:基于 vue 的 UI 组件库(PC 端)
2 第一个Vue程序 2.1 什么是MVVM
MVVM (Model-View-ViewModel) 是一种软件架构设计模式,由微软WPF (用于替代WinForm,以前就是用这个技术开发桌面应用程序的)和Silverlight (类似于Java Applet,简单点说就是在浏览器上运行的WPF)的架构师Ken Cooper和Ted Peters 开发,是一种简化用户界面的事件驱动编程方式。由John Gossman (同样也是WPF和Silverlight的架构师)于2005年在他的博客上发表。
MVVM 源自于经典的MVC (ModI-View-Controller) 模式。MVVM的核心是ViewModel层,负责转换Model中的数据对象来让数据变得更容易管理和使用,其作用如下:
该层向上与视图层进行双向数据绑定
向下与Model层通过接口请求进行数据交互
2.2 为什么要使用MVVM MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大好处:
低耦合:视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的View上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
可复用:你可以把一些视图逻辑放在一个ViewModel里面,让很多View重用这段视图逻辑。
独立开发:开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计。
可测试:界面素来是比较难于测试的,而现在测试可以针对ViewModel来写。
2.3 Vue 是 MVVM 模式的实现者
Model : 模型层(数据层)。在这里表示JavaScript对象,数据可能是固定的思数据, 更多的是来自服务器, 从网络上请求下来的数据
View : 视图层,在这里表示DOM (HTML操作的元素),给用户展示各种信息
ViewModel : 视图模型层,连接视图和数据的中间件,Vue.js就是MVVM中的ViewModel层的实现者,在MVVM架构中,是不允许数据和视图直接通信的,只能通过ViewModel来通信,而ViewModel就是定义了一个Observer观察者
VM作用:
1 ViewModel 能够观察到数据的变化,并对视图对应的内容进行更新
2 ViewModel 能够监听到视图的变化,并能够通知数据发生改变
至此,我们就明白了,Vue.js 就是一个MVVM的实现者,他的核心就是实现了DOM监听与数据绑定
2.4 Vue安装方式 方式一. 直接CDN引入
可以选择引入开发环境版本 / 生产环境版本
1 2 3 4 5 // 开发环境版本, 包含了帮助的命令行警告 <script src ='https://cdn.jsdeliver.net/npm/vue/dist/vue.js' > </script > // 生产环境版本, 优化了尺寸和速度 <script src ='https://cdn.jsdeliver.net/npm/vue' > </script >
方式二. 下载和引入
1 2 3 4 5 // 开发环境https:// vuejs.org/js/ vue.js // 生产环境https:// vuejs.org/js/ vue.min.js
方式三. NPM安装
通过webpack和CLI的使用
3 Vue基本语法 模板语法:
创建Vue, options可以放什么
el
data
methods
computed
生命周期函数 …
3.1 v-bind 现在数据和DOM已经被建立了关联,所有的东西都是响应式的。我们在控制台操作对象的属性,界面可以实时更新。
我们可以使用v-bind来绑定元素属性!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > Title</title > </head > <body > <p > 狂神说Java</p > <div id ="app" > <span v-bind:title ="message" > 鼠标悬停几秒钟查看此处动态绑定的提示信息!</span > </div > </body > <script src ="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js" > </script > <script > var vm = new Vue({ el: "#app" , data: { message: "hello,vue" } }) </script > </html >
3.2 v-if v-else 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > Title</title > </head > <body > <p > 狂神说Java</p > <div id ="app" > <h1 v-if ="type==='A'" > A</h1 > <h1 v-else-if ="type==='B'" > B</h1 > <h1 v-else > C</h1 > </div > </body > <script src ="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js" > </script > <script > var vm = new Vue({ el: "#app" , data: { type: "A" } }) </script > </html >
3.3 v-for 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > Title</title > </head > <body > <p > 狂神说Java</p > <div id ="app" > <li v-for ="item in items" > 姓名:{{item.name}},年龄:{{item.age}} </li > </div > </body > <script src ="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js" > </script > <script > var vm = new Vue({ el: "#app" , data: { items: [ {name : "zhangsan" , age : 12 }, {name : "lisi" , age : 10 }, {name : "wangwu" , age : 16 } ] } }) </script > </html >
官方推荐, 使用v-for的时候, 加上一个 key属性
key的作用是为了高效的更新虚拟DOM,key要具有唯一性
3.4 v-on 事件绑定 作用: 绑定事件监听 简写: @ 写法:
没有参数的情况下, 可以不写(); 如果方法本身有一个参数, 会默认将原生事件event参数传递进去
如果传入某个参数, 同时需要event时, 可以通过$event传入时间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > Title</title > </head > <body > <p > 狂神说Java</p > <div id ="app" > <button v-on:click ="sayHi" > Click Me</button > </div > </body > <script src ="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js" > </script > <script > var vm = new Vue({ el: "#app" , data: { message: "你点我干嘛?" }, methods: { sayHi: (function (event ) { alert(this .message) }) } }) </script > </html >
3.5 插值操作 Mustache Mustache语法 (双大括号) 可以直接写变量 可以写简单的表达式
3.6 v-once 后面不需要跟任何表达式 表示元素和组件只渲染一次, 不会随着数据的改变而变化
3.7 v-html 后面往往跟一个string类型 会将string的html解析出来并渲染
3.8 v-text 与Mustache相似, 一般不用, 不灵活
3.9 v-pre 用于跳过这个元素和它子元素的编译过程, 用于显示原本的Mustache语法
3.10 v-cloak 在某些情况下, 我们浏览器可能会直接显示出未编译的Mustache标签
3.11 v-show 当条件为false的时 v-if: 指令的元素, 不会渲染到dom中 v-show: dom增加一个行内样式display: none
4 Vue双向绑定 v-model 4.1 什么是双向绑定 Vue.js是一个MVVM框架,即数据双向绑定,即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化。这也算是Vue.js的精髓之处了。
值得注意的是,我们所说的数据双向绑定,一定是对于UI控件来说的,非UI控件不会涉及到数据双向绑定。单向数据绑定是使用状态管理工具的前提。如果我们使用vuex,那么数据流也是单项的,这时就会和双向数据绑定有冲突。
4.2 为什么要实现数据的双向绑定 在Vue.js 中,如果使用vuex ,实际上数据还是单向的,之所以说是数据双向绑定,这是用的UI控件来说,对于我们处理表单,Vue.js的双向数据绑定用起来就特别舒服了。即两者并不互斥,在全局性数据流使用单项,方便跟踪;局部性数据流使用双向,简单易操作。
4.3 在表单中使用双向数据绑定 你可以用v-model指令在表单 <input>、<textarea> 及<select> 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但v-model本质上不过是语法糖。它负责监听户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
注意:v-model会忽略所有元素的value、checked、selected特性的初始值而总是将Vue实例的数据作为数据来源,你应该通过JavaScript在组件的data选项中声明。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > Title</title > </head > <body > <div id ="app" > 下拉框: <select v-model ="selected" > <option value ="" disabled > -请选择-</option > <option > A</option > <option > B</option > <option > C</option > </select > <p > value:{{selected}}</p > </div > </body > <script src ="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js" > </script > <script > var vm = new Vue({ el: "#app" , data: { selected: "" } }) </script > </html >
5 Vue组件 5.1 注册组件基本步骤
调用Vue.extend()方法 - 创建组件构造器
调用Vue.component()方法 - 注册组件
在Vue实例的作用范围内 - 使用组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <div id ="app" > //使用组件 <my-cpn > </my-cpn > </div > <script > const cpnC = Vue.extend({ template: ' <div > <h2 > 标题</h2 > <p > 模板</p > </div > ' }) Vue.component('my-cpn' , cpnC) const app = new Vue({ el: '#app' , data:{ message: '' } }) </script >
5.2 局部组件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <div id ="app" > <my-cpn > </my-cpn > </div > <script > const cpnC = Vue.extend({ template: ' <div > <h2 > 标题</h2 > <p > 模板</p > </div > ' }) const app = new Vue({ el: '#app' , data:{ message: '' }, components: { my-cpn: cpnC } }) </script >
6 Axios通信 6.1 什么是Axios 功能强大的网络请求库
Axios是一个开源的可以用在浏览器端和NodeJS 的异步通信框架,她的主要作用就是实现AJAX异步通信,其功能特点如下:
从浏览器中创建XMLHttpRequests
从node.js创建http请求
支持Promise API [JS中链式编程]
拦截请求和响应
转换请求数据和响应数据
取消请求
自动转换JSON数据
客户端支持防御XSRF (跨站请求伪造)
GitHub: https://github.com/ axios/axios 中文文档: http://www.axios-js.com/
6.2 为什么要使用Axios 由于Vue.js是一个视图层框架且作者(尤雨溪) 严格准守SoC (关注度分离原则),所以Vue.js并不包含Ajax的通信功能,为了解决通信问题,作者单独开发了一个名为vue-resource的插件,不过在进入2.0 版本以后停止了对该插件的维护并推荐了Axios 框架。少用jQuery,因为它操作Dom太频繁 !
模拟Json数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 { "name" : "weg" , "age" : "18" , "sex" : "男" , "url" :"https://www.baidu.com" , "address" : { "street" : "文苑路" , "city" : "南京" , "country" : "中国" }, "links" : [ { "name" : "bilibili" , "url" : "https://www.bilibili.com" }, { "name" : "baidu" , "url" : "https://www.baidu.com" }, { "name" : "cqh video" , "url" : "https://www.4399.com" } ] }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > Title</title > </head > <body > <div id ="vue" > <div > {{info.name}}</div > <a v-bind:href ="info.url" > 点我进入</a > </div > </body > <script src ="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js" > </script > <script src ="https://cdn.bootcdn.net/ajax/libs/axios/0.19.2/axios.min.js" > </script > <script > var vm = new Vue({ el: "#vue" , data: { items: ['Java' ,'Python' ,'Php' ] }, data ( ) { return { info:{ name: null , age: null , sex: null , url: null , address: { street: null , city: null , country: null } } } }, mounted ( ) { axios.get("../data.json" ).then(res => (this .info=res.data)) } }) </script > </html >
6.3 Vue计算属性 计算属性的重点突出在属性两个字上(属性是名词),首先它是个属性其次这个属性有计算的能力(计算是动词),这里的计算就是个函数;简单点说,它就是一个能够将计算结果缓存起来的属性(将行为转化成了静态的属性),仅此而已;可以想象为缓存!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > Title</title > </head > <body > <div id ="app" > <div > currentTime1: {{currentTime1()}}</div > <div > currentTime2: {{currentTime2}}</div > </div > </body > <script src ="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js" > </script > <script > var vm = new Vue({ el: "#app" , data: { message: "hello,world!" }, methods: { currentTime1: function ( ) { return Date .now(); } }, computed: { currentTime2: function ( ) { this .message; return Date .now(); } } }) </script > </html >
结论: 调用方法时,每次都需要进行计算,既然有计算过程则必定产生系统开销,那如果这个结果是不经常变化的呢?此时就可以考虑将这个结果缓存起来,采用计算属性可以很方便的做到这一点,计算属性的主要特性就是为了将不经常变化的计算结果进行缓存,以节约我们的系统开销;
7 内容分发 slot 在Vue.js中我们使用 元素作为承载分发内容的出口,作者称其为插槽,可以应用在组合组件的场景中;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > </head > <body > <div id ="app" > <todo > <todo-title slot ="todo-title" v-bind:name ="title" > </todo-title > <todo-items slot ="todo-items" v-for ="item in todoItems" v-bind:item ="item" > </todo-items > </todo > </div > <script src ="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js" > </script > <script > Vue.component("todo" , { template: '<div > \ <slot name ="todo-title" > </slot > \ <ul > \ <slot name ="todo-items" > </slot > \ </ul > \ <div > ' }); Vue.component("todo-title" , { props: ['name' ], template: '<div > {{name }} </div > ' }); Vue.component("todo-items" , { props: ['item' ], template: '<li > {{item }} </li > ' }); let vm = new Vue({ el: "#app" , data: { title: "图书馆系列图书" , todoItems: ['三国演义' , '红楼梦' , '西游记' , '水浒传' ] } }); </script > </body > </html >
8 自定义事件内容分发 通过以上代码不难发现,数据项在Vue的实例中,但删除操作要在组件中完成,那么组件如何才能删除Vue实例中的数据呢?此时就涉及到参数传递与事件分发了,Vue为我们提供了自定义事件的功能很好的帮助我们解决了这个问题;
使用this.$emit (‘自定义事件名’,参数)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > </head > <body > <div id ="app" > <todo > <todo-title slot ="todo-title" v-bind:name ="title" > </todo-title > <todo-items slot ="todo-items" v-for ="(item,index) in todoItems" v-bind:item ="item" v-bind:index ="index" v-on:remove ="removeItems(index)" > </todo-items > </todo > </div > <script src ="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js" > </script > <script > Vue.component("todo" , { template: '<div > \ <slot name ="todo-title" > </slot > \ <ul > \ <slot name ="todo-items" > </slot > \ </ul > \ <div > ' }); Vue.component("todo-title" , { props: ['name' ], template: '<div > {{name }} </div > ' }); Vue.component("todo-items" , { props: ['item' ,'index' ], template: '<li > {{index }} --- {{item }} <button @click ="remove" > 删除</button > </li > ', methods: { remove: function (index ) { this .$emit('remove' ,index) } } }); let vm = new Vue({ el: "#app" , data: { title: "图书馆系列图书" , todoItems: ['三国演义' , '红楼梦' , '西游记' , '水浒传' ] }, methods: { removeItems: function (index ) { console .log("删除了" +this .todoItems[index]+"OK" ); this .todoItems.splice(index,1 ); } } }); </script > </body > </html >
9 vue-cli初始化脚手架 9.1 什么是vue-cli vue-cli 官方提供的一个脚手架,用于快速生成一个 vue 的项目模板
主要功能:
统一的目录结构
本地调试
热部署
单元测试
集成打包上线
9.2 需要的环境
安装就无脑下一步就好,安装在自己的环境目录下
确认nodejs安装成功:
cmd 下输入 node -v,查看是否能够正确打印出版本号即可! cmd 下输入 npm-v,查看是否能够正确打印出版本号即可! 这个npm,就是一个软件包管理工具,就和linux下的apt软件安装差不多!
npm 是 JavaScript 世界的包管理工具,并且是 Node.js 平台的默认包管理工具。通过 npm 可以安装、共享、分发代码,管理项目依赖关系。
安装 Node.js 淘宝镜像加速器(cnpm)
这样子的话,下载会快很多~
1 2 3 4 5 6 7 npm install cnpm -g npm config set registry https://registry.npm.taobao.org npm install cnpm -g
安装的位置:C:\Users\Administrator\AppData\Roaming\npm
9.3 安装vue-cli 1 2 3 4 5 cnpm install vue-cli -g vue list
9.4 第一个 vue-cli 应用程序 创建一个Vue项目,我们随便建立一个空的文件夹在电脑上。
我这里在D盘下新建一个目录D:\Project\vue-study;
创建一个基于 webpack 模板的 vue 应用程序
1 2 3 vue init webpack myvue
一路都选择no即可;
初始化并运行
1 2 3 cd myvuenpm install npm run dev
执行完成后,目录多了很多依赖
9.5 脚手架文件结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 .文件目录 ├── node_modules ├── public │ ├── favicon.ico: 页签图标 │ └── index.html: 主页面 ├── src │ ├── assets: 存放静态资源 │ │ └── logo.png │ │── component: 存放组件 │ │ └── HelloWorld.vue │ │── App.vue: 汇总所有组件 │ └── main.js: 入口文件 ├── .gitignore: git版本管制忽略的配置 ├── babel.config.js: babel的配置文件 ├── package.json: 应用包配置文件 ├── README.md: 应用描述文件 └── package-lock.json: 包版本控制文件
src/components/School.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <template> <div class="demo"> <h2>学校名称:{{ name }}</h2> <h2>学校地址:{{ address }}</h2> <button @click="showName">点我提示学校名</button> </div> </template> <script> export default { name: "School", data() { return { name: "UESTC", address: "成都", }; }, methods: {showName() {alert(this.name);},}, }; </script> <style> .demo {background-color: orange;} </style>
src/components/Student.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <template> <div> <h2>学生姓名:{{ name }}</h2> <h2>学生年龄:{{ age }}</h2> </div> </template> <script> export default { name: "Student", data() { return { name: "cess", age: 18, }; }, }; </script>
src/App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <template> <div> <img src="./assets/logo.png" alt=""> <School></School> <Student></Student> </div> </template> <script> // 引入组件 import School from './components/School.vue' import Student from './components/Student.vue' export default { name:'App', components:{ School, Student } } </script>
src/main.js
1 2 3 4 5 6 7 8 9 10 11 import Vue from 'vue' import App from './App.vue' Vue.config.productionTip = false new Vue({ el:'#app' , render: h => h(App), })
public/index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <!DOCTYPE html > <html lang ="" > <head > <meta charset ="UTF-8" > <meta http-equiv ="X-UA-Compatible" content ="IE=edge" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <link rel ="icon" href ="<%= BASE_URL %>favicon.ico" > <title > <%= htmlWebpackPlugin.options.title %></title > </head > <body > <noscript > <strong > We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong > </noscript > <div id ="app" > </div > </body > </html >
9.6 render函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import Vue from 'vue' import App from './App.vue' Vue.config.productionTip = false new Vue({ el:'#app' , render: h => h(App), })
9.7 关于不同版本的函数 1、vue.js与vue.runtime.xxx.js的区别
vue.js 是完整版的Vue,包含:核心功能+模板解析器
vue.runtime.xxx.js 是运行版的Vue,只包含核心功能,没有模板解析器esm 就是 ES6 module
2、因为 vue.runtime.xxx.js 没有模板解析器,所以不能使用template配置项,需要使用render函数接收到的createElement函数去指定具体内容
9.8 vue.config.js配置文件 vue inspect > output.js可以查看到Vue脚手架的默认配置
使用vue.config.js可以对脚手架进行个性化定制,和package.json同级目录,详见配置参考 | Vue CLI
1 2 3 4 5 6 7 8 module .exports = { pages: { index: { entry: 'src/index/main.js' } }, lineOnSave: false }
10 Webpack WebPack 是一款模块加载器兼打包工具 ,它能把各种资源,如 JS、JSX、ES6、SASS、LESS、图片等都作为模块来处理和使用 。
1 2 npm install webpack@3.6.0 -g npm install webpack-cli -g
测试安装成功: 输入以下命令有版本号输出即为安装成功
1 2 webpack -v webpack-cli -v
10.1 什么是Webpack 本质上,webpack是一个现代JavaScript应用程序的静态模块打包器(module bundler)。当webpack处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个bundle. Webpack是当下最热门的前端资源模块化管理和打包工具,它可以将许多松散耦合的模块按照依赖和规则打包成符合生产环境部署的前端资源。还可以将按需加载的模块进行代码分离,等到实际需要时再异步加载。通过loader转换,任何形式的资源都可以当做模块,比如CommonsJS、AMD、ES6、 CSS、JSON、CoffeeScript、LESS等; 伴随着移动互联网的大潮,当今越来越多的网站已经从网页模式进化到了WebApp模式。它们运行在现代浏览器里,使用HTML5、CSS3、ES6 等新的技术来开发丰富的功能,网页已经不仅仅是完成浏览器的基本需求; WebApp通常是一个SPA (单页面应用) ,每一个视图通过异步的方式加载,这导致页面初始化和使用过程中会加载越来越多的JS代码,这给前端的开发流程和资源组织带来了巨大挑战。 前端开发和其他开发工作的主要区别,首先是前端基于多语言、多层次的编码和组织工作,其次前端产品的交付是基于浏览器的,这些资源是通过增量加载的方式运行到浏览器端,如何在开发环境组织好这些碎片化的代码和资源,并且保证他们在浏览器端快速、优雅的加载和更新,就需要一个模块化系统,这个理想中的模块化系统是前端工程师多年来一直探索的难题。
10.2 使用Webpack 1 先创建一个包 交由idea打开 会生成一个.idea文件 那么就说明该文件就交由idea负责
2 在idea中创建modules包,再创建hello.js,hello.js 暴露接口 相当于Java中的类
1 2 3 4 exports .sayHi = function ( ) { document .write("<h1>狂神说ES6</h1>>" ) }
3 创建main.js 当作是js主入口 , main.js 请求hello.js 调用sayHi()方法
1 2 var hello = require ("./hello" );hello.sayHi()
4 在主目录创建webpack-config.js , webpack-config.js 这个相当于webpack的配置文件
enrty请求main.js的文件
output是输出的位置和名字
1 2 3 4 5 6 module .exports = { entry: './modules/main.js' , output: { filename: './js/bundle.js' } }
5 在idea命令台输入webpack命令(idea要设置管理员启动)
6 完成上述操作之后会在主目录生成一个dist文件,生成的js文件夹路径为/ dist/js/bundle.js
7 在主目录创建index.html 导入bundle.js index.html
1 2 3 4 5 6 7 8 9 10 11 <html lang ="en" > <head > <meta charset ="UTF-8" > <title > Title</title > <script src ="dist/js/bundle.js" > </script > </head > <body > </body > </html >
11 vue-router路由 Vue Router是Vue.js官方的路由管理器(路径跳转)。它和Vue.js的核心深度集成,让构建单页面应用变得易如反掌。包含的功能有:
11.1 安装 基于第一个vue-cli进行测试学习;先查看node_modules中是否存在 vue-router vue-router 是一个插件包,所以我们还是需要用 npm/cnpm 来进行安装的。打开命令行工具,进入你的项目目录,输入下面命令。
1 npm install vue-router --save-dev
安装完之后去node_modules路径看看是否有vue-router信息 有的话则表明安装成功。
11.2 vue-router demo实例
将之前案例由vue-cli生成的案例用idea打开
清理不用的东西 assert下的logo图片 component定义的helloworld组件 我们用自己定义的组件
清理代码 以下为清理之后的代码 src下的App.vue 和main.js以及根目录的index.html 这三个文件的关系是 index.html 调用main.js 调用App.vue
index.html:
1 2 3 4 5 6 7 8 9 10 11 12 <!DOCTYPE html > <html > <head > <meta charset ="utf-8" > <meta name ="viewport" content ="width=device-width,initial-scale=1.0" > <title > myvue</title > </head > <body > <div id ="app" > </div > </body > </html >
main.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <template> <div id="app"> <img src="./assets/logo.png"> <h1>迪师傅</h1> <router-link to="/main">首页</router-link> <router-link to="/content">内容页</router-link> <router-link to="/kuang">Kuang</router-link> <router-view></router-view> </div> </template> <script> export default { name: 'App', components: { } } </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>
在components目录下创建一个自己的组件Content,Test,Main(这两个和Content内容一样的就不放示例代码了
Content.vue:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <template> <h1>内容</h1> </template> <script> export default { name: "Content" } </script> <style scoped> </style>
安装路由,在src目录下,新建一个文件夹 : router,专门存放路由 index.js(默认配置文件都是这个名字)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 import Vue from "vue" ;import VueRouter from "vue-router" ;import Content from "../components/Content" ;import Main from "../components/Main" ;import Kuang from "../components/Kuang" ;Vue.use(VueRouter); export default new VueRouter({ routes: [ { path: '/content' , name: 'content' , component: Content }, { path: '/main' , name: 'main' , component: Main }, { path: '/kuang' , name: 'kuang' , component: Kuang } ] })
在main.js中配置路由
main.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 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中使用路由
App.vue:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <template> <div id="app"> <img src="./assets/logo.png"> <h1>迪师傅</h1> <router-link to="/main">首页</router-link> <router-link to="/content">内容页</router-link> <router-link to="/kuang">Kuang</router-link> <router-view></router-view> </div> </template> <script> export default { name: 'App', components: { } } </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>
启动测试一下 : npm run dev
项目结构图&运行效果图
12 vue + ElementUI 根据之前创建vue-cli项目一样再来创建一个新项目
1 创建一个名为 hello-vue 的工程
1 vue init webpack hello-vue
2 安装依赖,我们需要安装 vue-router、element-ui、sass-loader 和node-sass 四个插件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 cd hello-vuenpm install vue-router --save-dev npm i element-ui -S npm install cnpm install sass-loader node-sass --save-dev npm run dev
3 Npm命令解释
npm install moduleName:安装模块到项目目录下
npm install -g moduleName:-g 的意思是将模块安装到全局,具体安装到磁盘的哪个位置,要看 npm config prefix的位置
npm install moduleName -save:–save的意思是将模块安装到项目目录下,并在package文件的dependencies节点写入依赖,-S为该命令的缩写
npm install moduleName -save-dev:–save-dev的意思是将模块安装到项目目录下,并在package文件的devDependencies节点写入依赖,-D为该命令的缩写
4 创建成功后用idea打开,并删除净东西 创建views和router文件夹用来存放视图和路由
5 在views创建Main.vue
Main.vue:
1 2 3 4 5 6 7 8 9 10 <template> <h1>首页</h1> </template> <script> export default { name: "Main" } </script> <style scoped> </style>
6 在views中创建Login.vue视图组件
Login.vue:(用的ElementUI中的代码)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 <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="dialogVisible" 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: '密码不可为空', trigger: '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>
7 创建路由
在 router 目录下创建一个名为 index.js 的 vue-router 路由配置文件
index.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import Vue from "vue" ;import Router from "vue-router" ;import Main from "../views/Main" ;import Login from "../views/Login" ;Vue.use(Router); export default new Router({ routes: [ { path: '/main' , component: Main }, { path: '/login' , component: Login } ] });
8 在main.js中配置相关
main.js是index.html调用的 所以前面注册的组件要在这里导入
一定不要忘记扫描路由配置并将其用到new Vue中
main.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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) new Vue({ el: '#app' , router, render: h => h(App), })
9 在App.vue中配置显示视图
App.vue :
1 2 3 4 5 6 7 8 9 10 11 <template> <div id="app"> <router-link to="/login">login</router-link> <router-view></router-view> </div> </template> <script> export default { name: 'App', } </script>
10 测试运行
测试:在浏览器打开 http://localhost:8080/#/login
如果出现错误: 可能是因为sass-loader的版本过高导致的编译错误,当前最高版本是8.0.2,需要退回到7.3.1 ;
去package.json文件里面的 “sass-loader”的版本更换成7.3.1,然后重新cnpm install就可以了;
13 路由嵌套 嵌套路由又称子路由,在实际应用中,通常由多层嵌套的组件组合而成。
13.1 Demo 1 创建用户信息组件,在 views/user 目录下创建一个名为 Profile.vue 的视图组件;
Profile.vue
1 2 3 4 5 6 7 8 9 10 <template> <h1>个人信息</h1> </template> <script> export default { name: "UserProfile" } </script> <style scoped> </style>
2 在用户列表组件在 views/user 目录下创建一个名为 List.vue 的视图组件;
List.vue
1 2 3 4 5 6 7 8 9 10 <template> <h1>用户列表</h1> </template> <script> export default { name: "UserList" } </script> <style scoped> </style>
3 修改首页视图,我们修改 Main.vue 视图组件,此处使用了 ElementUI 布局容器组件,代码如下:
Main.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 <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>
4 配置嵌套路由修改 router 目录下的 index.js 路由配置文件,使用children放入main中写入子模块,代码如下
index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import Vue from "vue" ;import Router from "vue-router" ;import Main from "../views/Main" ;import Login from "../views/Login" ;import UserList from "../views/user/List" ;import UserProfile from "../views/user/Profile" ;Vue.use(Router); export default new Router({ routes: [ { path: '/main' , component: Main, children: [ {path : '/user/profile' ,component : UserProfile}, {path : '/user/list' ,component : UserList} ] }, { path: '/login' , component: Login } ] });
5 路由嵌套效果图
14 参数传递 14.1 Demo 1 前端传递参数
此时我们在Main.vue中的route-link位置处 to 改为了 :to,是为了将这一属性当成对象使用,注意 router-link 中的 name 属性名称 一定要和 路由中的 name 属性名称 匹配,因为这样 Vue 才能找到对应的路由路径;
1 2 <!--name:传组件名 params:传递参数,需要绑定对象:v-bind--> <router-link v-bind:to="{name: 'UserProfile', params: {id: 1}}">个人信息</router-link>
2 修改路由配置,增加props:true属性
主要是router下的index.js中的 path 属性中增加了 :id 这样的占位符
1 2 3 4 5 6 { path: '/user/profile/:id' , name: 'UserProfile' , component: UserProfile, props:true }
3 前端显示
在要展示的组件Profile.vue中接收参数
Profile.vue:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <template> <div> 个人信息 {{ id }} </div> </template> <script> export default { props: ['id'], name: "UserProfile" } </script> <style scoped> </style>
4 运行
14.2 组件重定向 重定向的意思大家都明白,但 Vue 中的重定向是作用在路径不同但组件相同的情况下,比如: 在router下面index.js的配置
1 2 3 4 5 6 7 8 9 { path: '/main' , name: 'Main' , component: Main }, { path: '/goHome' , redirect: '/main' }
说明:这里定义了两个路径,一个是 /main ,一个是 /goHome,其中 /goHome 重定向到了 /main 路径,由此可以看出重定向不需要定义组件;
使用的话,只需要在Main.vue设置对应路径即可;
1 2 3 <el-menu-item index="1-3"> <router-link to="/goHome">回到首页</router-link> </el-menu-item>
15 路由钩子与异步请求 15.1 路由模式与 404 ==路由模式有两种==
修改路由配置,代码如下:
1 2 3 4 5 export default new Router({ mode: 'history' , routes: [ ] });
404界面:
1 创建一个NotFound.vue视图组件
1 2 3 4 5 6 7 8 9 10 11 12 <template> <div> <h1>404,你的页面走丢了</h1> </div> </template> <script> export default { name: "NotFound" } </script> <style scoped> </style>
2 修改路由配置index.js
1 2 3 4 5 import NotFound from '../views/NotFound' { path: '*' , component: NotFound }
15.2 路由钩子与异步请求 beforeRouteEnter:在进入路由前执行beforeRouteLeave:在离开路由前执行
在Profile.vue中写:
1 2 3 4 5 6 7 8 9 10 11 export default { name: "UserProfile", beforeRouteEnter: (to, from, next) => { console.log("准备进入个人信息页"); next() }, beforeRouteLeave: (to, from, next) => { console.log("准备离开个人信息页"); next(); } }
参数说明:
to:路由将要跳转的路径信息
from:路径跳转前的路径信息
next:路由的控制参数
next() 跳入下一个页面
next(’/path’) 改变路由的跳转方向,使其跳到另一个路由
next(false) 返回原来的页面
next((vm)=>{}) 仅在 beforeRouteEnter 中可用,vm 是组件实例
15.3 在钩子函数中使用异步请求 1 安装 Axios
1 cnpm install --save vue-axios
2 main.js引用 Axios
1 2 3 import axios from 'axios' import VueAxios from 'vue-axios' Vue.use(VueAxios, axios)
3 准备数据 : 只有我们的 static 目录下的文件是可以被访问到的 ,所以我们就把静态文件放入该目录下。 数据和之前用的json数据一样 需要的去上述axios例子里
4 在 beforeRouteEnter 中进行异步请求
Profile.vue:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 export default { name: "UserProfile" , beforeRouteEnter: (to, from , next ) => { console .log("进入路由之前" ) next(vm => { vm.getData() }); }, beforeRouteLeave: (to, from , next ) => { console .log("离开路由之前" ) next(); }, methods: { getData: function ( ) { this .axios({ method: 'get' , url: 'http://localhost:8080/static/mock/data.json' }).then(function (response ) { console .log(response) }) } } }
5 执行