Bootstrap可视化布局系统 (bootcss.com)
一 前端体系
- 此课程的重点
- 前端的话,页面我不会再给大家多讲了。重点难就难在,这些框架怎么使用,比如说前端化工程。
- java全栈工程师:
- 后台开发:主打
- 前端:html、css、js、jquery、bootstrap、layui、vue、react......
- 运维:项目发布;服务器如何运行一个项目?
- 前端组成,3要素
- html:结构层
- css:表现层。如改颜色、加边框、定位......
- CSS预处理器
- 业务:css不是编程语言,而是标记语言。语法不够强大,没有变量和合理的样式复用机制。
- 需求:
- 解决上面的问题。
- 作用:提供 CSS 缺失的样式层复用机制、减少冗余代码,提高样式代码的可维护性和开发效率。
- 思想(路):CSS 预处理器定义了一种新的语言,这种专门的编程语言,为 CSS 增加了一些编程的特性,将 CSS 作为目标生成文件(即程序本身并不是css言语写的,但这个程序运行的结果,它会产生一个css文件,即用程序的方式去编。类似于java程序编译打包完成,会产生一个.jar包一样。),然后开发者就只要使用这种语言进行 CSS 的编码工作。
转化成通俗易 懂的话来说就是“ 用一种专门的编程语言,进行 Web 页面样式设计,再通过(前端)编译器转化为正常的 CSS 文件,以供项目使用” 。
- 流(原):如淘宝每年都会有年中618、双11、双12是吧,而这3个购物节使用的css样式肯定不一样是吧。那怎么办呢?每到一个购物节,阿里的那些开发人员,肯定不会直接把css写死在页面中,这样写死地改来改去会非常消耗人力和时间,很麻烦。那到底怎么办呢?他们会想一些办法,跟编程一样,写一个程序让程序自动输出css。每到一个购物节,就去改程序,自动输出新的css样式即可。动态输出css(如定时输出),这就是所谓的css预处理器。
- 常用的css预处理器有哪些:
- SASS:基于 Ruby,通过服务端处理,功能强大。解析效率高。需要学习 Ruby 语言,上手难度高于 LESS。
- LESS:基于 NodeJS,通过客户端处理,使用简单。功能比 SASS 简单,解析效率也低于 SASS,但在实际开发中足够了,所以如果我们后台人员如果需要的话,建议使用 LESS。
- 总结:几乎现在专业的前端都在用LESS写,如果做为一个前端还在用css写,那你效率会很低。
- CSS预处理器
- javascript:行为层
- Native:最早,是原生JS开发。
-
原生 JS 开发,也就是让我们按照 ECMAScript(ES) 标准的开发的。
-
目前的情况:最高版本是es9,最流行的是es6,但很多浏览器还停留在es5,而且对于大多数浏览器厂商的最高版本也只是部分支持es6。对于不支持es6的浏览器(低版本)来说怎么办呢?开发时可以使用es6规范去开发,但需要用webpack打包工具把es6的代码降级成为es5,如let转var。
-
-
TypeScript微软的标准
-
业务:javascript的缺陷
-
需求:解决这些缺陷
-
流(原): 很神奇,微软的TypeScript编写的程序,运行的结果是变成一堆javascript代码。和上面的less一样,你用less编写的程序,运行的结果是不是生成css了。
-
- Native:最早,是原生JS开发。
-
常用的javascript构架:
-
jquery: 就是一个类库。
-
Angular:mvvm
- 如何理解:“将后台的 MVC 模式搬到了前端并增加了模块化开发的念”?
- mvc的3要素分别是,m(模型)、v(视图)、c(控制器)。
- 原来的前端:只有一个v(视图),即html + css + js。后面ajax出现了,使用ajax(Axios)以后,可以与后台进行通信、交互。而视图的数据(data,即m(模型))都是我们后端给它渲染过去的。
- Angular前端:在前端实现了mvc架构(模式),称为mvvm,其中m(模型)、v(视图)、vm(view model,即数据双向绑定)。
- 如何理解:“将后台的 MVC 模式搬到了前端并增加了模块化开发的念”?
-
React:虚拟化dom
-
原来的dom操作:是通过js(如document.getElementByTag/getElementById等),对dom树进行CRUD,或者在获取dom对象以后对dom对象的文档、css进行一定的调整。
-
虚拟dom:最大的特点是它利用了内存,利用内存来缓存一些dom元素,并在内存中操作dom,有效地提高了前端的渲染率。 你们都听过,vuejs的“计算属性、计算属性缓存 vs 方法 ”这2个东西是吧。以前学计算属性的时候,老师是不是跟你们讲了虚拟dom。“计算属性“是vue的特色,是vue独有的。而“计算属性“这个特色是怎么来的?就是利用虚拟dom来的。
-
-
Vue:mvvm + 虚拟化dom
-
渐进式:就是逐步实现新特性的意思,比如vuejs会慢慢去实现es6的规范、慢慢去实现模块化的规范、慢慢实现虚拟化dom、慢慢模块化、慢慢路由、慢慢状态管理等等。
-
vue集成了Angular和React的优点,即说明了vue中也有mvvm、也有虚拟化dom。
-
后端学习它并不会觉得很难,因为它是模块化开发的 。
-
-
Axios
-
前端的通信框架,只做通信(soc原则),相当于ajax、jquery ajax 。
-
-
-
前端流行的UI框架
-
Ant-Design
-
ElementUI: 主要特点是桌面端支持较多
-
iview: 主要特点是移动端支持较多
-
ice
-
Bootstrap
-
AmazeUI
-
-
javascript构建工具
-
babel: 一般更多地是用于编译TypeScript 。
-
webpack: 模块打包工具,一般会用它来打包咱们的前端程序 。
-
-
总结:前端也在发展(css框架成百上千、javascript的框架也成面上千),但发展的很乱,但始终有一些是流行的、受到行业追捧的东西。
- 前端知识,6要素
- 逻辑
- 判断:判断一下这东西该不该展示
- 循环
- 事件
- 那我们刚才跟你说的那堆javascript代码(BOM、DOM操作),它是在干嘛?是不是叫做事件呀。事件的话那就非常多了,但总的来说就两类:浏览器事件(BOM)和标签事件(DOM)。BOM事件,说得难听一点,其实也就两个window事件、document(文档)事件。DOM事件常见的:增、删、遍历、修改节点元素内容。
- 那么前端所说的事件,有没有框架来做呀?有呀,比如jquery(库)封装了大量的事件、vuejs、React......
- 视图:应该怎么画才好看
- 前端所说的视图视图说白了就是:第1点:给用户看;第2点:刷新后台,就是做这两件事情而已。
- 前端所说的视图由谁来做?html、cs、js呀。
- 其实前端最难的是css,一个像素都不能错,不然不好看。
- 基于html、css衍生出很多我们熟知的前端视图框架:bootstrap、layui、Vue-Ui即vue相关的视图组件框架库(如飞冰ice.work、Element-Ui)......
- 网络通信
- xhr:原生javascript
- ajax:jquery封装
- axios框架:vuejs
- 页面跳转:
- 路由(转发):vue自己开发的组件:vue-router,来控制页面跳转的。
- 状态管理:
- 状态管理:就是vue会把所有的东西统一管理,这就是vuex来做的。
- 逻辑
- Vue概述
- 前端3大框架:vue、AngularJS、React.js。
- vue是一个渐进式的前端框架。
- Vue 的核心库只关注视图层,这句话什么意思?其中视图层,就是html、css、js做的东西吧。而网络通信,vue用管吗?不用。使用的是axios框架,去管网络通信的部分。页面跳转,vue用得着管吗?也不用。使用的是vuejs自己开发的组件vue-router,去管页面跳转的部分。状态管理,vue用得着管吗?那也不用。使用的是,vuex来做的。也就是说vue只关注视图层的意思是,vue只跟上面的这3个(html、css、js)打交道。
Vue只关注视图层,并遵守一个原则,叫做soc原则(Separation of concerns,关注点分离原则,关注点分离 - 中文维基百科【维基百科中文版网站】 (cljtscd.com))。也就是说,它会把它的关注点分得特别散,vue只管视图层。
- webpack
- 原理:最高版本是es9,最流行的是es6,但很多浏览器还停留在es5,而且对于大多数浏览器厂商的最高版本也只是部分支持es6。对于不支持es6的浏览器(低版本)来说怎么办呢?开发时可以使用es6规范去开发,但需要用webpack打包工具把es6的代码降级成为es5,如let转var。webpack把es6的代码打包成浏览器能够认识的代码。
我们后台有没有打包工具?有,maven就是我们后台的打包工具(构建、管理、打包工具),maven就是把java源代码打包成服务器能够认识的程序。
- 原理:最高版本是es9,最流行的是es6,但很多浏览器还停留在es5,而且对于大多数浏览器厂商的最高版本也只是部分支持es6。对于不支持es6的浏览器(低版本)来说怎么办呢?开发时可以使用es6规范去开发,但需要用webpack打包工具把es6的代码降级成为es5,如let转var。webpack把es6的代码打包成浏览器能够认识的代码。
二 前端:三端统一开发
- 混合开发(Hybrid App)
- 主要目的是实现一套代码三端统一(PC、Android:.apk、IOS:.ipa)并能够调用到设备底层硬件(如:传感器、GPS、摄像头等),打包方式主要有以下两种:
- 云打包:HBuild -> HBuildX ,DCloud出品;API Cloud
- 本地打包:Cordova(前身是 PhoneGap)
- 主要目的是实现一套代码三端统一(PC、Android:.apk、IOS:.ipa)并能够调用到设备底层硬件(如:传感器、GPS、摄像头等),打包方式主要有以下两种:
- 微信小程序
- 详见微信官网,这里就是介绍一个方便微信小程序UI开发的框架:WeUI。
三 后端技术:前端所需后端技术
- Express:NodeJS 框架
- Koa:Express 简化版
- NPM:项目综合管理工具,类似于 Maven。npm install(安装)其实就相当于java maven下载依赖包,且进行包管理。
- YARN:NPM 的替代方案,类似于 Maven 和 Gradle 的关系。
四 前后端分离的演变史
- 第1阶段,2005年之前(web 1.0):后端为主的 MVC 时代,如springmvc
- 流程
-
发起请求到前端控制器( DispatcherServlet )
-
前端控制器请求 HandlerMapping 查找 Handler ,可以根据 xml 配置、注解进行查找
-
处理器映射器 HandlerMapping 向前端控制器返回 Handler
-
前端控制器调用处理器适配器去执行 Handler
-
处理器适配器去执行 Handler
-
Handler 执行完成给适配器返回 ModelAndView
-
处理器适配器向前端控制器返回 ModelAndView , ModelAndView 是 SpringMVC 框架的 一个底层对象,包括 Model 和 View
-
前端控制器请求视图解析器去进行视图解析,根据逻辑视图名解析成真正的视图( JSP )
-
视图解析器向前端控制器返回 View
-
前端控制器进行视图渲染,视图渲染将模型数据(在 ModelAndView 对象中)填充到 request 域
-
前端控制器向用户响应结果
-
注:图里面的所有东西,只有一个controller是开发者需要做的而已。
-
-
缺点
-
前后端职责纠缠不清
-
- 流程
- 第2阶段:2005年(web 2.0):基于 AJAX 带来的 SPA 时代
- 第3阶段:now现在:大前端时代,即前端为主的 MV* 时代
- MV*
-
MVC(同步通信为主):Model、View、Controller
-
MVP(异步通信为主):Model、View、Presenter
-
MVVM(异步通信为主):Model、View、ViewModel
-
- 1 ~ 1.8 ~ 3
- 分布式、微服务、大数据
- MV*
- 第4阶段:NodeJS 带来的全栈时代
- 如nodejs前后端都可以做了。
- 但nodejs永远都不可能干掉java,因为js语言有它天生的弊端。
五 MVVM模式
1 MVVM模式的组成部分
- 从上图可知道MVVM的组成部分:
- V - View
- HTML
- CSS
- Template(如jsp、Thymeleaf,通过${ooo}(#{ooo},即Template模板)获取数据)
- 双向数据绑定
- M层(数据)会通过VM层去跟V层(前端,即html、css、Template)进行双向数据绑定。
- 情况1:VM层会去监听M层(数据),如果M层(数据)发生了改变,那么V层也要发生变化。M是1,V显示为1;当M变成2,V显示为2。
- 情况2:VM层会去监听V层(前端,即html、css、Template),如果V层(前端,即html、css、Template)发生了改变,那么M层(数据)也要发生变化。
- M层(数据)会通过VM层去跟V层(前端,即html、css、Template)进行双向数据绑定。
- VM - ViewModle
- JavaScript
- Runtime:即时运行。当M变成2,V及时显示为2。
- Compiler:即时编译。当M变成2,V及时显示为2。
- ajax & json
- ajax请求java业务逻辑(数据库),java业务逻辑(数据库)返回json数据。
- M - Model
- java业务逻辑层
- 数据库
- java业务逻辑层
- V - View
- mvvm双向数据绑定的工作流程:
- 第一步:v层(view)与vm层(viewModel)进行双向数据绑定(操作虚拟dom,页面显示快、流畅;区别于js使用document来操作真实的dom元素,页面显示卡顿。)
- 第二步:vm层通过ajax访问java后台(数据库),java后台(数据库)返回json数据。
六 第一个vue程序(vue是MVVM 模式的实现者,他的核心就是实现了 DOM 监听 与 数据绑定)
- 环境准备
- 第一步:创建vue工程(文件夹)
- 第二步:使用vscode的open project(目录)打开工程
- 第三步:官网下载vue.js
- 开发版本
-
包含完整的警告和调试模式: https://vuejs.org/js/vue.js
-
删除了警告,30.96KB min + gzip : https://vuejs.org/js/vue.min.js
-
-
CDN(在线,即在线的CDN)
-
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"> </script> :min.js是压缩版的,就一行代码。
- <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>:这个是完整版的代码。
-
- 开发版本
- 注 意:如果是idea,需要安装vue插件
- 开发
- 第一步:新建demo1.html
- 第二步:导包(要用vue,就要导包),使用在线的cdn方式:<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
- 第三步:<script></script>
- 第1步:创建vue对象(VM层,监听,即双向数据绑定)
- 第(1)步:el:绑定元素,相当于document.getElementById()
- 第(2)步:data对象:键值对(M层,即数据)
- 第(3)步:method方法:方法必须定义在method中。键值对。
- 第1步:创建vue对象(VM层,监听,即双向数据绑定)
- 第四步:html标签(V层)
- 第1步:使用{{}}({{}},即Template模板),获取data对象中的数据
- 第五步:浏览器
- 第1步:演示双向数据绑定
七 基础语法
- 指令:v- 开头
- v-bind:除了使用插值表达式{{}}进行数据渲染,也可以使用 v-bind指令,它的简写的形式就是一个冒号(:)
- 手动:我们在控制台操作对象属性,界面可以实时更新!
- 自动:我们还可以使用 v-bind 来绑定元素特性 !
- 案例:
<body> <div id="app"> <!-- 如果要将模型数据绑定在html属性中, 此时title中显示的是模型数据 --> <h1 v-bind:title="message">鼠标悬停几秒钟查看此处动态绑定的提示信息!</h1> <!-- v-bind 指令的简写形式: 冒号(:) --> <h1 :title="message">我是标题</h1> </div> <script> new Vue({ el: '#app', data: { message: '页面加载于 ' + new Date().toLocaleString() } }) </script> </body>
- v-if 系列
- v-if
- v-else-if
- v-else
- 案例
<body> <div id="app"> <!-- === 三个等号在 JS 中表示绝对等于(就是数据与类型都要相等) --> <h1 v-if="type === 'A'">A</h1> <h1 v-else-if="type === 'B'">B</h1> <h1 v-else-if="type === 'C'">C</h1> <h1 v-else>who</h1> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { type: 'A' } }) </script> </body>
- v-for
<body> <div id="app"> <li v-for="item in items"> {{ item.message }} </li> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { //items数组 items: [ {message: '狂神说Java'}, {message: '狂神说前端'} ] } }); </script> </body>
- v-bind:除了使用插值表达式{{}}进行数据渲染,也可以使用 v-bind指令,它的简写的形式就是一个冒号(:)
八 事件:v-on,我们可以使用 v-on
指令 (简写为 @
) 来监听 DOM 事件,并在事件触发时执行对应的 JavaScript(方法、函数)。
<body>
<div id="app">
<!--
在这里我们使用了 v-on 绑定了 click 事件
并指定了名为 sayHi 的方法
-->
<button v-on:click="sayHi">点我</button>
<!-- v-on 指令的简写形式 @ -->
<button @click="sayHi">点我</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'Hello World'
},
// 方法必须定义在 Vue 实例的 methods 对象中
// 这里必须传递一个事件对象event
methods: {
sayHi: function (event) {
// `this` 在方法里指向当前 Vue 实例
alert(this.message);
}
}
});
</script>
</body>
九 双向数据绑定:Vue.js的精髓之处:v-model
- Vue.js的精髓之处:
- Vue.js是一个MVVM框架,即数据双向绑定。
- 即当数据发生变化的时候,视图也就发生变化。
- 而当视图发生变化的时候,数据也会跟着同步变化。
- Vue.js是一个MVVM框架,即数据双向绑定。
- 在表单中使用双向数据绑定
- 你可以用v-model指令在表单<input> 、<textarea> 及<select>元素上创建双向数据绑
定。 - 它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但v-model本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
- 案例1:<input>、<textarea>
<!DOCTYPE html> <html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-model="http://www.w3.org/1999/xhtml" xmlns:v-model.trim="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>狂神说java</title> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> </head> <body> <div id="app"> 输入的文本:<input type="text" v-model="message"> <br/> 输入的文本是:{{message}} </div> <script> new Vue({ el: '#app', data: { message: '123' } }) </script> </body> </html>
- 案例2:<redio>、<checkbox>
<!DOCTYPE html> <html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-model="http://www.w3.org/1999/xhtml" xmlns:v-model.trim="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>狂神说java</title> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> </head> <body> <div id="app"> 性别:男<input type="radio" value="男" v-model="kuangshen"> 女<input type="radio" value="女" v-model="kuangshen"> <br/> 选中的是:{{kuangshen}} </div> <script> new Vue({ el: '#app', data: { kuangshen: '女' //将Vue实例的数据作为数据来源 } }) </script> </body> </html>
- 案例3:<select>
<!DOCTYPE html> <html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-model="http://www.w3.org/1999/xhtml" xmlns:v-model.trim="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>狂神说java</title> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> </head> <body> <div id="app"> 下拉框: <select v-model="kuangshen"> <option value="" disabled>--请选择--</option> <option>A</option> <option>B</option> <option>C</option> </select> <br/> 选择中的值:{{kuangshen}} </div> <script> new Vue({ el: '#app', data: { kuangshen: 'B' } }) </script> </body> </html>
- 注意1: v-model会忽略所有表单元素的value、checked、selected 特性的初始值,而总是将Vue实例的数据作为数据来源。你应该通过JavaScript在组件的data选项中声明初始值!
- 你可以用v-model指令在表单<input> 、<textarea> 及<select>元素上创建双向数据绑
- 注意事项
- 注意1:值得注意的是,我们所说的数据双向绑定,一定是对于UI控件来说的,非UI控件不会涉及到数据双向绑定。单向数据绑定是使用状态管理工具的前提。如果我们使用vuex ,那么数据流也是单项的,这时就会和双向数据绑定有冲突。
- 注意2:在Vue.js中,如果使用vuex,实际上数据还是单向的,之所以说是数据双向绑定,这是用的UI控件来说,对于我们处理表单,Vue.js的双向数据绑定用起来就特别舒服了。即两者并不互斥,在全局性数据流使用单项,方便跟踪;局部性数据流使用双向,简单易操作。
十 组件
- 业务:通常一个应用会以一棵嵌套的组件树的形式来组织(这和我们嵌套 HTML 元素的方式类似)。
- 需求:组件可复用(html标签是复用的)。
- 思路、想:组件是可复用的 Vue 实例,说白了就是一组可以重复使用的模板,跟 html / JSTL 的自定义标签(如自定义一个标签<kuangshen></kuangshen>,然后可以复用在html页面中)、Thymeleaf 的 th:fragment 等框架有着异曲同工之妙。
- 组织结构:
- 案例1:
<!DOCTYPE html> <html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-model="http://www.w3.org/1999/xhtml" xmlns:v-model.trim="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>狂神说java</title> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> </head> <body> <div id="app"> <ul> <!-- 有点类似自定义标签 --> <kuangshen-component-li></kuangshen-component-li> </ul> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> <script> // 先注册组件 Vue.component('kuangshen-component-li', { // 名称 template: '<li>Hello li</li>' // 模板,其实就是由多个html标签组成的 }); // 再实例化 Vue var vm = new Vue({ el: '#app' }); </script> </body> </html>
-
案例2:
<!DOCTYPE html> <html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-model="http://www.w3.org/1999/xhtml" xmlns:v-model.trim="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>狂神说java</title> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> </head> <body> <div id="app"> <ul> <!--第一步:写上组件<kuangshen-component-li></kuangshen-component-li>,即代表template属性中的内容。 问题:template属性中<li>标签之间要求有数据?答:而数据从items数组来。 --> <!--第二步:v-for="item in items"循环获取items数组中的每个数据,每一项数据的别名都叫item。--> <!--第三步:使用v-bind获取for循环中的每一个数据(item),并绑定组件对象中props属性列表中的参数panshengbo。--> <kuangshen-component-li v-for="item in items" v-bind:panshengbo="item"></kuangshen-component-li> </ul> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> <script> Vue.component('kuangshen-component-li', { //第四步:问题:直接写'<li>{{panshengbo}}</li>'是获取不了数据“panshengbo”的,我们需要通过一个参数去接收,即props。 // props:['panshengbo']用于接收传输过来的数据。 // 如果你不用props,你是无法直接接收外面的数据的。 props:['panshengbo'], //第五步:template的<li>中使用{{panshengbo}}来传输过来的每个数据。 template: '<li>{{panshengbo}}</li>' }); var vm = new Vue({ el: '#app', data:{ items:["java","linux","前端"] } }); </script> </body> </html>
-
与vue的关系:
-
如下图,是xxx.vue文件的组织形式:
-
从上面的xxx.vue文件的组织方式、组件基础的知识,可以看出,xxx.vue和组件都有一个共同的标签,那就是<template>吧。到此,总算和vue粘一点边了。
-
十一 vue的生命周期(钩子函数)
-
在 Vue 的整个生命周期中,它提供了一系列的事件(开始创建、初始化数据、编译模板、挂载 DOM、渲染→更新→渲染、卸载等)。
-
可以让我们在事件触发时注册 JS 方法,可以让我们 用自己注册的 JS 方法控制整个大局。
-
在这些事件响应方法中的 this 直接指向的是 Vue 的实例。
十二 axios异步通信
-
Axios 概述
- 原因:
-
少用 jQuery,因为它操作 Dom 太频繁!
-
-
定义:
- 【官网】易用、简洁且高效的http库
-
作用:
-
Axios 是一个开源的可以用在浏览器端和 NodeJS 的异步通信框架,它的主要作用就是实现 AJAX 异步通信。
-
-
特点:
- 从浏览器中创建 XMLHttpRequests
- 从 node.js 创建 http 请求
- 支持 Promise API [ JS中链式编程 ]
- 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换 JSON 数据
- 客户端支持防御 XSRF(跨站请求伪造)
- 地址:
- GitHub:https://github.com/axios/axios
- 中文文档:http://www.axios-js.com/
- 注意事项
- idea设置为支持es6规范的(不然代码会报编译异常)
- 浏览器必须是支持es6规范的
- 原因:
- 案例1:data.json、demo7.html 只取数据
{ "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/" } ] }
<!DOCTYPE html> <html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-model="http://www.w3.org/1999/xhtml" xmlns:v-model.trim="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>狂神说Java</title> </head> <body> <div id="app"> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script type="text/javascript"> var vm = new Vue({ el:'#app', mounted() { // 第一步:钩子函数 // 第二步:axiosn发送异步请求,获取json文件的数据,并在控制台打印 axios.get('data.json').then(response => (console.log(response.data))); } }); </script> </body> </html>
- 案例2:data.json demo7.html 渲染数据
<!DOCTYPE html> <html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-model="http://www.w3.org/1999/xhtml" xmlns:v-model.trim="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>狂神说Java</title> </head> <body> <div id="app"> <div>{{info.name}}</div> <div>{{info.address.street}}</div> <!-- 数据绑定到属性 --> <a v-bind:href="info.url">听我</a> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script type="text/javascript"> var vm = new Vue({ el:'#app', data(){ // 功能相当于data属性 return{ // 这个地方只是摆格式,并没有真正的数据。 // 而且这里的格式,必须和json字符串格式一样 info:{ name:null, url:null, address:{ street:null, city:null, country:null } } } }, mounted() { // 第一步:钩子函数 // 第二步:axios发送异步请求,获取json文件的数据,并且数据取名为info // 第三步:data(){return中的info}用于接收axios返回的数据 axios.get('data.json').then(response => (this.info = response.data)); } }); </script> </body> </html>
- 注意事项
十三 计算属性
- 定义:计算(动词)+ 属性(名词)
- 需求:
- 内存中运行:虚拟Dom,速度快
-
计算属性的主要特性就是为了将不经常变化的计算结果进行缓存,以节约我们的系统开销;
- 解决方案:计算属性
- 思想路:
- 将计算出来的结果保存到一个属性中,可以想象成缓存!
- 案例
<!DOCTYPE html> <html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-model="http://www.w3.org/1999/xhtml" xmlns:v-model.trim="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>狂神说Java</title> </head> <body> <div id="app"> <div>{{message}}</div> <!-- 调用方法 --> <div>{{currentTime1()}}</div> <!-- 计算属性(区别于调用方法) --> <div>{{currentTime2}}</div> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> <script type="text/javascript"> var vm = new Vue({ el:'#app', data: { // 方案1:普通属性(注意区别于计算属性) message: 'Hello Vue' }, methods: { // 方案2:调用方法 currentTime1: function () { return Date.now(); } }, computed: {// 方案3:计算属性(注意区别于普通属性) //currentTime2 ,这是一个属性!不是方法 currentTime2: function () { this.message;// 优点:此数据被改变后,计算属性会自动重新计算 return Date.now(); } } }); //注意:methods和computed中的方法名可重名,重名后只会调用methods中的方法 </script> </body> </html>
十四 插槽slot:内容分发
- 思想路
- 正常情况下,我们会直接使用数据渲染整个页面。
- 特殊情况下,页面只会变某个部。此时可以在页面中留出两个口(这两个口就叫做插槽),方便在里面插入东西,而且是动态地可拔插,重点是复用性。如下图所示:
- 案例:比如准备制作一个待办事项组件(todo),该组件由待办标题(todo-title)和待办内容(todo-items)组成,但这三个组件又是相互独立的,该如何操作呢?
- 数据写死
<!DOCTYPE html> <html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-model="http://www.w3.org/1999/xhtml" xmlns:v-model.trim="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>狂神说Java</title> </head> <body> <div id="app"> <!-- 第四步:使用插槽 --> <todo> <todo-title></todo-title> <todo-items></todo-items> </todo> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> <script type="text/javascript"> // 第一步: 定义一个待办事项的组件 Vue.component('todo_0', { template: '<div>\ <div>待办事项</div>\ <ul>\ <li>学习狂神说Java</li>\ </ul>\ </div>' }); // 第二步: 我们需要让待办事项的标题和值实现动态绑定,怎么做呢? 我们可以留出2个插槽(标题插槽、列表插槽)! // 1、将上面的代码留出2个插槽(标题插槽、列表插槽),即 slot Vue.component('todo', { template: '<div>\ <slot></slot>\ <ul>\ <slot></slot>\ </ul>\ </div>' }); // 2、定义一个名为 todo-title 的待办标题组件 和 todo-items 的待办内容组 Vue.component('todo-title', { template: '<div>标题</div>' }); Vue.component('todo-items', { template: '<li>java lanaguage123</li>' }); var vm = new Vue({ el:'#app' }); </script> </body> </html>
-
使用自定义的数据
<!DOCTYPE html> <html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-model="http://www.w3.org/1999/xhtml" xmlns:v-model.trim="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>狂神说Java</title> </head> <body> <div id="app"> <!-- 第四步:将这些值,通过插槽插入 --> <todo> <todo-title slot="todo-title" title="秦老师系列课程"></todo-title> <todo-items slot="todo-items" v-for="(item, index) in todoItems" v-bind:item="item" v-bind:index="index"> </todo> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> <script type="text/javascript"> // 第一步: 定义一个待办事项的组件 Vue.component('todo_0', { template: '<div>\ <div>待办事项</div>\ <ul>\ <li>学习狂神说Java</li>\ </ul>\ </div>' }); // 第二步: 我们需要让待办事项的标题和值实现动态绑定,怎么做呢? 我们可以留出2个插槽(标题插槽、列表插槽)! // 1、将上面的代码留出2个插槽(标题插槽、列表插槽),即 slot Vue.component('todo', { template: '<div>\ <slot name="todo-title"></slot>\ <ul>\ <slot name="todo-items"></slot>\ </ul>\ </div>' }); // 2、定义一个名为 todo-title 的待办标题组件 和 todo-items 的待办内容组 Vue.component('todo-title', { props: ['title'], // 接收传到组件的动态数据:title属性 template: '<div>{{title}}</div>' // 使用title属性 }); //这里的index,就是数组的下标,使用for循环遍历的时候,可以循环出来! Vue.component('todo-items', { props: ['item', 'index'], // 接收传到组件中的动态:item、index属性 template: '<li>{{index + 1}}. {{item}}</li>' // 使用item、index属性 }); // 3、实例化 Vue 并初始化数据 var vm = new Vue({ el:'#app', data: { todotitle:"学生选课", todoItems: ['狂神说Java1', '狂神说运维', '狂神说前端'] } }); </script> </body> </html>
- 数据写死
十五 自定义事件内容分发
- 业务:点击“删除”按钮,把li列表中的项目删除
- 方案1:缺点组件中无法调用vue实例中的方法,只能调用本组件中定义的方法:
<!DOCTYPE html> <html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-model="http://www.w3.org/1999/xhtml" xmlns:v-model.trim="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>狂神说Java</title> </head> <body> <div id="app"> <todo> <todo-title slot="todo-title" title="秦老师系列课程"></todo-title> <todo-items slot="todo-items" v-for="item in todoItems" v-bind:item="item"> </todo> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> <script type="text/javascript"> Vue.component('todo_0', { template: '<div>\ <div>待办事项</div>\ <ul>\ <li>学习狂神说Java</li>\ </ul>\ </div>' }); Vue.component('todo', { template: '<div>\ <slot name="todo-title"></slot>\ <ul>\ <slot name="todo-items"></slot>\ </ul>\ </div>' }); Vue.component('todo-title', { props: ['title'], template: '<div>{{title}}</div>' }); Vue.component('todo-items', { props: ['item', 'index'], // 调用成功 template: '<li>{{item}}<button @click="remove">删除</button></li>', // 调用失败 //template: '<li>{{index + 1}}. {{item}}<button @click="removeItems">删除</button></li>', methods:{ remove:function(){ alert(111); } } }); var vm = new Vue({ el:'#app', data: { todotitle:"学生选课", todoItems: ['狂神说Java1', '狂神说运维', '狂神说前端'] }, methods:{ // 该方法可以被模板中自定义事件触发 removeTodoItems: function (index) { console.log("删除 " + this.todoItems[index] + " 成功"); // splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目 // 其中 index 为添加/删除项目的位置,1 表示删除的数量 this.todoItems.splice(index, 1); } } }); </script> </body> </html>
- 方案2:理一下思路:
<!DOCTYPE html> <html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-model="http://www.w3.org/1999/xhtml" xmlns:v-model.trim="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>狂神说Java</title> </head> <body> <div id="app"> <todo> <todo-title slot="todo-title" 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="removeTodoItems(index)"> <!-- v-on:用于绑定vm实例中的方法--> <!-- 自定义事件的名称:removeTodoItems。--> <!-- 参数:(index)。 --> </todo> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> <script type="text/javascript"> Vue.component('todo_0', { template: '<div>\ <div>待办事项</div>\ <ul>\ <li>学习狂神说Java</li>\ </ul>\ </div>' }); Vue.component('todo', { template: '<div>\ <slot name="todo-title"></slot>\ <ul>\ <slot name="todo-items"></slot>\ </ul>\ </div>' }); Vue.component('todo-title', { props: ['title'], template: '<div>{{title}}</div>' }); Vue.component('todo-items', { props: ['item', 'index'], template: '<li>{{index + 1}}. {{item}}<button @click="remove">删除</button></li>', methods:{ // 自定义事件内容分发。 // 使用调用此方法时,实际上调用的是vm实例中的removeTodoItems方法。 remove:function(index){ // 这里的 remove 是自定义事件的名称,需要在 HTML 中使用 v-on:remove 的方式指派 this.$emit('remove', index); } } }); var vm = new Vue({ el:'#app', data: { todotitle:"学生选课", todoItems: ['狂神说Java1', '狂神说运维', '狂神说前端'] }, methods:{ // 该方法可以被模板中自定义事件触发 removeTodoItems: function (index) { console.log("删除 " + this.todoItems[index] + " 成功"); // splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目 // 其中 index 为添加/删除项目的位置,1 表示删除的数量 this.todoItems.splice(index, 1); } } }); </script> </body> </html>
- 方案1:缺点组件中无法调用vue实例中的方法,只能调用本组件中定义的方法:
十六 第一个vue-cli项目
- 脚手架定义
- 以前,我们在搭建一个项目的时候,项目开始前会用SSM做骨架。如果把SSM做的骨架抽出来,那它便成了一个脚手架。脚手架的作用是:基于脚本手(骨架),我们可以进行快速地进行开发。就好比咱们在idea中创建 Maven 项目时可以选择创建一个骨架项目(模板项目),这个骨架项目(模板项目)就是脚手架,使得我们的开发更加的快速;如下图所示:
- 以前,我们在搭建一个项目的时候,项目开始前会用SSM做骨架。如果把SSM做的骨架抽出来,那它便成了一个脚手架。脚手架的作用是:基于脚本手(骨架),我们可以进行快速地进行开发。就好比咱们在idea中创建 Maven 项目时可以选择创建一个骨架项目(模板项目),这个骨架项目(模板项目)就是脚手架,使得我们的开发更加的快速;如下图所示:
- vue-cli定义
- vue官方提供的一个脚手架,用于快速生成一个 vue 的项目模板:
-
预先定义好 的目录结构及基础代码:
-
统一的目录结构 : 跟咱们的maven项目一样,.java类一定要写在/src/main/java这个目录下面。你的配置文件,一定是放在项目根目录的resources目录下面。
-
统一的基础代码 : 跟maven一样,如maven会自动生成程序入口类。
-
本地调试:跟maven一样。
-
热部署:跟maven一样。
-
单元测试:跟maven一样。
-
集成打包上线: 跟maven一样。
-
-
- vue官方提供的一个脚手架,用于快速生成一个 vue 的项目模板:
-
npm与maven的区别与联系
-
npm去下载那些安装的时候,npm干的就是maven干的事情呀,你可以把npm想象成maven的包管理模块。但npm跟maven也是有区别的:npm更偏向于linux系统的操作,如果以前使用linux的话,你会发现npm的很多操作命令和linux命令都差不多,包括在线安装一些东西呀等等。
-
-
vue-cli环境搭建
-
第一步:安装Node.js(自带npm,可直接用npm了。自动帮我们配置环境变更,Add to Path。)
-
node -v
-
npm -v
-
全局安装 npm install xxx的默认目录是:
-
-
第二步:安装Git(不是必须)
-
第三步: 安装node.js淘宝镜像加速器(cnpm)。我们是不是听了好多次镜像加速器这个东西啦,那个maven是不是也是这样的。maven的中央仓库本来是在国外的,用了阿里巴巴的镜像加速器,就快很多,不然你从国外的maven中央仓库下载,那得多慢呀。同理,npm下载安装的东西,也是国外的仓库地址。如果你想加快一点速度,那只能用国内的cnpm,还是阿里的东西。但cnpm它有一些问题,有些用cnpm下载安装的包,放到项目里是能用,但在打包的时候可能就会发生各种莫名其妙的错误。所以能用npm就尽量用,实在不行再用cnpm 。
-
第四步:安装vue -cl
-
# 测试是否安装成功# 查看可以基于哪些模板创建 vue 应用程序,通常我们选择 webpackvue list
- browserify
- browserify-simple
- pwa
- simple
- webpack:一般的vue项目,我们都会通过webpack来创建。因为vue是基于es6的开发,但真正网站使用时很多还是基于es5的,我们通过使用webpack把es6的语法降级(转换)成大多数浏览器都支持的es5语法。
- webpack-simple
-
-
-
创建运行,第1个vue-clie程序: 相当于java程序中的helloworld
-
第一步:管理员模式下,cmd命令输入框
- 第二步:cd进入到某个目录
- 第三步:执行命令vue init webpack myvue ,即初始化一个webpack的vue项目,效果是在该目录下自动生成一个vue - webpack项目(名字叫myvue):
- 第四步:cd myvue
- 第五步:npm install:在当前目录下,安装此webpack模板的vue项目的所有依赖环境。npm install安装哪些呢?它根据的是配置文件pack.json中要求的进行安装的。安装的目录是,项目根目录下的node_modules目录:
- 第六步:等待npm install加载安装完成,说明这个项目初始化完毕了,初始化完毕就可以直接运行了。但这只是一个基础的前端工程,就相当于java的helloword。
- 修复:npm audit fix(run 'npm audit fix' to fix them,or 'npm audit' for details)
- 第七步:npm run dev。用于启动并运行此项目,相当于我们使用命令启动tomcat并开启8080端口那样。
- 第1步:告诉我们,自动编译整个项目,编译之后才能打包,即 xx building modules xxx
- 第2步:告诉我们,自动打包整个项目,打包之后才能启动并运行, webpack-dev-server --inline --progress --config build/webpack.dev.conf.js
- 第3步:告诉我们,编译并打包完成,DONE Compiled successfully in 3221ms
- 第4步:告诉我们,访问的路径:Your application is running here: http://localhost:8080
- 第八步:访问此前端项目:Your application is running here: http://localhost:8080,前端项目的首页是vuejs的标识,而tomcat项目的首页是一个猫。
- 第九步:停止项目:ctrl + c Y,相当于tomcat的shutdown
-
- 项目详解,第1个vue-clie程序
- 第一步:使用vs code打开项目(文件夹),因为它是一个前端项目
- 第二步:查看项目的结构
- build目录:构建
- build.js ---- 这个地方就是一些构建的一些信息,最终我们会用npm命令执行它是吧。
- check-version.js ---- 检查所有东西的版本,如检查npm、node.js版本。
- webpack.base.conf.js ---- webpack基本配置。webpack是不是就是咱们打包相关的,我们运行(npm run dev)之前,就是使用它来打包的。
- webpack.dev.conf.js ----- webpack开发环境配置
- webpack.prod.conf.js ---- webpack生产环境配置
- config目录:配置目录,包括端口号等。我们初学可以使用默认的。
- dev.env.js:开发环境变量
- prod.env.js:生产环境变量
- index.js:配置变量
- node_modules目录:包含我们使用npm install下载安装的东西,即这个程序运行起来需要的所有组件。相当于咱们java里面的lib目录,只是这里下载的不是.jar包,而是一些依赖。
- src目录:放源码的地方
- assets:资源文件,比如存放 css,图片等资源。
- component:组件文件夹,用来存放 vue 的公共组件(注册于全局,在整个项目中通过关键词便可直接输出)。
- app.vue:是项目的主组件,所有页面都是在该组件下进行切换的。
- main.js:入口文件(入口程序)。是项目的入口文件,作用是初始化 vue 实例,并引入所需要的插件。
- static目录:静态资源目录,如图片、字体等。
- index.html:项目的首页入口文件,你可以添加一些 meta 信息或统计代码啥的。
- package.json:node配置文件,记载着一些命令、依赖及其版本、简要的项目描述信息
- 比如,npm run dev命令
- build目录:构建
- 附1:package.json详解
{ // 项目/模块名称,长度必须小于等于 214 个字符,不能以"."(点)或者"_"(下划线)开头,不能包含大写字母 "name": "myvue", // 项目版本 "version": "1.0.0", // 项目描述 "description": "project", // 作者 "author": "Demo_Null", // 是否私有,设置为 true 时,npm 拒绝发布 "private": true, // 执行 npm 脚本命令简写,执行前面的简写就代表执行后面的命令 "scripts": { "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", "start": "npm run dev", "unit": "jest --config test/unit/jest.conf.js --coverage", "e2e": "node test/e2e/runner.js", "test": "npm run unit && npm run e2e", "lint": "eslint --ext .js,.vue src test/unit test/e2e/specs", "build": "node build/build.js" }, // 生产环境下,项目运行所需依赖 "dependencies": { "vue": "^2.5.2", "vue-router": "^3.0.1" }, // 开发环境下,项目所需依赖 "devDependencies": { "autoprefixer": "^7.1.2", "babel-core": "^6.22.1", "babel-eslint": "^8.2.1", "babel-helper-vue-jsx-merge-props": "^2.0.3", "babel-jest": "^21.0.2", "babel-loader": "^7.1.1", "vue-style-loader": "^3.0.1", "vue-template-compiler": "^2.5.2", "webpack": "^3.6.0", "webpack-bundle-analyzer": "^2.9.0", "webpack-dev-server": "^2.9.1", "webpack-merge": "^4.1.0" }, // 项目运行的平台 "engines": { "node": ">= 6.0.0", "npm": ">= 3.0.0" }, // 供浏览器使用的版本列表 "browserslist": [ "> 1%", "last 2 versions", "not ie <= 8" ] }
- 附2:index.js 详解
'use strict' //---严格的语法 const path = require('path') //---node.js路径模块 module.exports = { dev: { // Paths assetsSubDirectory: 'static', //---配置静态目录的地方。相当于tomcat目录中的web-info目录。 assetsPublicPath: '/', proxyTable: {}, // Various Dev Server settings host: 'localhost', // can be overwritten by process.env.HOST port: 8080, //---配置端口号 autoOpenBrowser: false,//项目运行时是否自动打开浏览器 errorOverlay: true,// 浏览器错误提示 notifyOnErrors: true,// 跨平台错误提示 poll: false, // 使用文件系统获取文件改动的通知devServer.watchOptions https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- // Use Eslint Loader? // If true, your code will be linted during bundling and // linting errors and warnings will be shown in the console. useEslint: false, // If true, eslint errors and warnings will also be shown in the error overlay // in the browser. showEslintErrorsInOverlay: false, /** * Source Maps */ // https://webpack.js.org/configuration/devtool/#development devtool: 'cheap-module-eval-source-map', // 增加调试,该属性为原始源代码 // If you have problems debugging vue-files in devtools, // set this to false - it *may* help // https://vue-loader.vuejs.org/en/options.html#cachebusting cacheBusting: true, // 使缓存失效 cssSourceMap: true // 代码压缩后bug定位将非常困难,引入SourceMap记录压缩前后的位置信息记录,当产生错误时直接定位到压缩前的位置 }, //生产环境 build: { // Template for index.html index: path.resolve(__dirname, '../dist/index.html'),// 编译输入的index.html文件 // Paths assetsRoot: path.resolve(__dirname, '../dist'),// 编译输出的静态资源路径(项目打包时的文件) assetsSubDirectory: 'static',// 编译输出的二级目录 assetsPublicPath: '/',// 编译发布的根目录,可配置为资源服务器域名或CDN域名 /** * Source Maps */ productionSourceMap: true, // 是否开启cssSourceMap // https://webpack.js.org/configuration/devtool/#production devtool: '#source-map', // 增加调试,该属性为原始源代码 // Gzip off by default as many popular static hosts such as // Surge or Netlify already gzip all static assets for you. // Before setting to `true`, make sure to: // npm install --save-dev compression-webpack-plugin productionGzip: false,// 是否开启gzip productionGzipExtensions: ['js', 'css'], // 需要使用gzip压缩文件的扩展名 // Run the build command with an extra argument to // View the bundle analyzer report after build finishes: // `npm run build --report` // Set to `true` or `false` to always turn it on or off bundleAnalyzerReport: process.env.npm_config_report // 打包分析 } } //原文链接:https://blog.csdn.net/yhj198927/article/details/124044693
- 附3:build.js 详解
'use strict' //---严格模式 require('./check-versions')() //---npm和node版本检查并立即执行,请看我的check-versions配置文件解释文章 process.env.NODE_ENV = 'production' //---process是node中的global全局对象的属性,process是node中的全局变量,env设置环境变量。此设置环境为生产环境production const ora = require('ora') //---ora是一个命令行转圈圈动画插件,好看用的 const rm = require('rimraf') //---rimraf插件是用来执行UNIX命令rm和-rf的用来删除文件夹和文件,清空旧的文件 const path = require('path') //---node.js路径模块 const chalk = require('chalk') //---chalk插件,用来在命令行中输入不同颜色的文字 const webpack = require('webpack') //---引入webpack模块使用内置插件和webpack方法 const config = require('../config') //---引入config下的index.js配置文件,此配置文件我之前介绍了请自行查阅,主要配置的是一些通用的选项 const webpackConfig = require('./webpack.prod.conf') //---下面是生产模式的webpack配置文件,请看我的webpack.prod.conf解释文章 const spinner = ora('building for production...') //---开启转圈圈动画 spinner.start() //---开始执行加载动画 //---调用rm方法,第一个参数的结果就是 dist/static,表示删除这个路径下面的所有文件 rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { if (err) throw err //---如果删除的过程中出现错误,就抛出这个错误,同时程序终止 webpack(webpackConfig, (err, stats) => { //---没有错误,就执行webpack编译 //---这个回调函数是webpack编译过程中执行 spinner.stop() //---停止转圈圈动画 if (err) throw err //---如果有错误就抛出错误 process.stdout.write(stats.toString({ //---没有错误就执行下面的代码,process.stdout.write和console.log类似,输出对象 //---stats对象中保存着编译过程中的各种消息 colors: true, //---增加控制台颜色开关 modules: false, //---不增加内置模块信息 children: false, //---不增加子级信息 chunks: false, //---允许较少的输出 chunkModules: false //---不将内置模块的信息加到包信息 }) + '\n\n') if (stats.hasErrors()) { console.log(chalk.red(' Build failed with errors.\n')) process.exit(1) } //---以上就是在编译过程中,持续打印消息 //---下面是编译成功的消息 console.log(chalk.cyan(' Build complete.\n')) console.log(chalk.yellow( ' Tip: built files are meant to be served over an HTTP server.\n' + ' Opening index.html over file:// won\'t work.\n' )) }) }) // end // 注: 如果你想自己编写一个高质量的脚手架工具,建议你: // 去补习nodejs,然后补习 es6,然后再来看webpack官方文档,然后自己独立编写一个和vue-cli类似的脚手架,如果上面的东西看不懂,更要这样做 // vue-cli还有一部分内容是关于代码测试的,可以说这块内容的复杂度不亚于webpack,这些内容对nodejs要求比较熟悉,说白了就是基础弱的很难入门,但是测试这块内容也是非常有价值的,可以借助无界面的浏览器解析引擎,通过一句命令就可以把你的代码在不同的平台上运行,还能指出问题所在,所以,我会渐渐的转战nodejs去了,后续的文章将很多是关于nodejs的文章,如果感兴趣的可以关注我的文章,一起学习探讨 //原文链接:https://blog.csdn.net/song854601134/article/details/120598334
- 附4:webpack.base.conf.js 详解,我们maven里面build result是不是也干这个事情,build result可以过滤xml让xml出去呀。也就是说此文件所配置的东西就是跟打包相关的信息,是不是跟maven特别像呀。
'use strict' const path = require('path') //---引入nodejs路径模块 const utils = require('./utils') //---引入utils工具模块,具体查看我的博客关于utils的解释,utils主要用来处理css-loader和vue-style-loader的 const config = require('../config') //---引入config目录下的index.js配置文件,主要用来定义一些开发和生产环境的属性 const vueLoaderConfig = require('./vue-loader.conf') //---vue-loader.conf配置文件是用来解决各种css文件的,定义了诸如css,less,sass之类的和样式有关的loader function resolve (dir) { //---此函数是用来返回当前目录的平行目录的路径,因为有个'..' return path.join(__dirname, '..', dir) } module.exports = { context: path.resolve(__dirname, '../'), entry: { app: './src/main.js' //---入口文件是src目录下的main.js }, output: { path: config.build.assetsRoot, //---输出路径是config目录下的index.js中的build配置中的assetsRoot,也就是dist目录 filename: '[name].js', //---项目输出文件名称,这里使用默认的name也就是main。 publicPath: process.env.NODE_ENV === 'production' //---上线地址,也就是真正的文件引用路径,如果是production生产环境,其实这里都是 '/' ? config.build.assetsPublicPath : config.dev.assetsPublicPath }, resolve: { // resolve是webpack的内置选项,顾名思义,决定要做的事情,也就是说当使用 import "jquery",该如何去执行这件事 // 情就是resolve配置项要做的,import jQuery from "./additional/dist/js/jquery" 这样会很麻烦,可以起个别名简化操作 extensions: ['.js', '.vue', '.json'], // 省略扩展名,也就是说.js,.vue,.json文件导入可以省略后缀名,这会覆盖默认的配置,所以要省略扩展名在这里一定要写上 alias: { //后面的$符号指精确匹配,也就是说只能使用 import vuejs from "vue" 这样的方式导入vue.esm.js文件,不能在后面跟上 vue/vue.js 'vue$': 'vue/dist/vue.esm.js', // resolve('src') 其实在这里就是项目根目录中的src目录,使用 import somejs from "@/some.js" 就可以导入指定文件,是不是很高大上 '@': resolve('src') } }, // 以下是一些静态资源过滤规则,通过条件进行过滤 // module用来解析不同的模块 module: { rules: [ { test: /\.(js|vue)$/, // 也就是说,对.js和.vue文件在编译之前进行检测,检查有没有语法错误 loader: 'eslint-loader', // 此选项指定enforce: 'pre'选项可以确保,eslint插件能够在编译之前检测,如果不添加此项,就要把这个配置项放到末尾,确保第一个执行 enforce: 'pre', // include选项指明这些目录下的文件要被eslint-loader检测,还有一个exclude表示排除某些文件夹 include: [resolve('src'), resolve('test')], // options表示传递给eslint-loader的参数 options: { // formatter是参数的名称,eslint-friendly-formatter是eslint的一个报告总结插件,也就是说eslint的检测 报告非常难看懂,这个插件就是整理这些报告方便查阅的 formatter: require('eslint-friendly-formatter') } }, { test: /\.vue$/, // 对vue文件使用vue-loader,该loader是vue单文件组件的实现核心,专门用来解析.vue文件的 loader: 'vue-loader', // 将vueLoaderConfig当做参数传递给vue-loader,就可以解析文件中的css相关文件 options: vueLoaderConfig }, { test: /\.js$/, // 对js文件使用babel-loader转码,该插件是用来解析es6等代码 loader: 'babel-loader', // 指明src和test目录下的js文件要使用该loader include: [resolve('src'), resolve('test')] }, { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, // 对图片相关的文件使用 url-loader 插件,这个插件的作用是将一个足够小的文件生成一个64位的DataURL // 可能有些老铁还不知道 DataURL 是啥,当一个图片足够小,为了避免单独请求可以把图片的二进制代码变成64位的 // DataURL,使用src加载,也就是把图片当成一串代码,避免请求,神不神奇?? loader: 'url-loader', options: { // 限制 10000 个字节一下的图片才使用DataURL limit: 10000, // 下面这个应该是指将[name].[hash:7].[ext]对应的图片使用url-loader测试吧,这个我是真不知道干啥的,如果知道 // 的兄弟,一定要留言给我啊,拜谢 name: utils.assetsPath('img/[name].[hash:7].[ext]') // 这个函数执行结果是 /img/[name].[hash:7].[ext] // 不知道吧 name 设置成 /img/[name].[hash:7].[ext] 意欲何为,猜测应该是输出图片的路径或者是解析图片的路径 } }, { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, // 字体文件处理,和上面一样 loader: 'url-loader', options: { limit: 10000, name: utils.assetsPath('fonts/[name].[hash:7].[ext]') } } ] } //原文链接:https://blog.csdn.net/song854601134/article/details/120598344?spm=1001.2014.3001.5502
- 附5:vue项目结构是怎么样的?详解vue目录结构! (w3cschool.cn)
十七 webpack学习使用(vuejs中的写法,就是这里的模块化处理)
- 业务
- 伴随着移动互联网的大潮,当今越来越多的网站已经从网页模式进化到了WebApp模式。也就是说,已经把网站当做一个单独的应用,并运行在浏览器里面。
- javascript模块化的演进
- 第1阶段:<script>标签
- 如<script src="module1.js"><script>。这是最原始的javascript文件加载方式,它把每一个文件都看做是一个模块,那么他们的接口通常是暴露在全局作用域下,也就是定义在window对象中,不同模块的调用都是一个作用域。缺陷明显,所以需要一些规范。
- 第2阶段:CommonsJS —— export & inport & require —— 同步阻塞加载
- 服务器端的NodeJS遵循CommonsJS规范,该规范核心思想是允许模块通过require方法来同步加载所需依赖的其它模块,然后通过exports或module.export1来导出需要暴露的接口。有优点,也有缺点。
- 优点:
●服务器端模块便于重用
●NPM中已经有超过45万个可以使用的模块包
●简单易用 - 缺点:
●同步的模块加载方式不适合在浏览器环境中,同步意味着阻塞加载,浏览器资源是异步加载的。更理想的方式是,异步非阻塞的模块加载方式。
●不能非阻塞的并行加载多个模块
- 优点:
- 服务器端的NodeJS遵循CommonsJS规范,该规范核心思想是允许模块通过require方法来同步加载所需依赖的其它模块,然后通过exports或module.export1来导出需要暴露的接口。有优点,也有缺点。
- 第3阶段:AMD —— define & require —— 异步非阻塞加载
- 第4阶段:CMD —— defind & export —— 模块的加载逻辑偏重
- 第5阶段:ES6模块 —— inport(导入) & export(暴露) & module(模块) —— 编译时错误检查
- ES6规范大家知道,现在的javascript基本上都是面对ES6规范在做的。但是浏览器不在ES5规范。
EcmaScript6标准增加了JavaScript语言层面的模块体系定义。ES6模块的设计思想是尽量静态化,使编译时就能确定模块的依赖关系,以及输入和输出的变量,增加编译检查与异常抛出(解决变量冲突),增加运行时异常(提供更多的错误信息)。CommonsJS和AMD模块,都只能在运行时确定这些东西,编译时啥都没做。
- ES6规范大家知道,现在的javascript基本上都是面对ES6规范在做的。但是浏览器不在ES5规范。
- 大家期望的模块化
- 可以兼容多种模块风格,尽量可以利用已有的代码,不仅仅只是JavaScript模块化,还有CSS、图片、字体等资源也需要模块化。
- webpack模块化处理
- webpack是一款模块加载器兼打包工具,它能把各种资源,如JS、JSX、ES6、SASS、LESS、图片等都作为模块来处理和使用。
- 第1阶段:<script>标签
- 需求
- 为了支持较低版本的浏览器,es6 转 es5。
- 依赖管理
- 流原
- webpack依赖管理功能原理
- 同maven depandence。
- webpack编译打包原理
- 前端的一键打包:当webpack处理应用程序时,它会递归地构建一个依赖关系图(dependency graph,package.json中的依赖),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个bundle。“依赖关系图”这个像啥?是不是像我们的maven呀。父子依赖,对不对,一个父项目里面有子项目,子项目中依赖(dependence)了很多很多的东西。
- 同理 —— maven的一键打包命令:maven package命令一键生成jar 或 war包,不用我们手动在命令行一步一步去做了。
- webpack依赖管理功能原理
- 分类
- webpack在vue项目中的使用方式
- 自动化构建(编译打包)
- 在vue项目中有一个build目录,build目录下有一个webpack.base.conf.js文件,就是通过此文件对webpack的设置进行自动化构建(编译打包)。那么我们来看一下,怎么手动去做这件事情。。。。。。
- 手动构建(编译打包)
- 自动化构建(编译打包)
- webpack在vue项目中的使用方式
- 环境搭建
- 第一步:安装webpack
- npm install webpack -g,打包工具,全局的在哪个目录下安装都行,如果安装失败就改用cnpm去安装
- npm install webpack-cli -g,客户端,全局的在哪个目录下安装都行,如果安装失败就改用cnpm去安装
- 第二步:测试安装成功
- webpack -v
- webpack-cli -v
- 第三步:webpack版本调整
- 咱们来看pack.json里面,里面写了1个webpack版本。我们安装的webpack肯定是最新版本的webpack吧,而pack.json中写的版本往往不是最新的。因为版本不一致,所以在使用webpack进行打包时,可能会有一些东西打包不进去。这时,我们可能需要在pack.json中,调一调一某些依赖的版本,升一升版本,或者降一降版本。
- 第四步:配置webpack —— 创建webpack.config.js配置文件
- 了解:这些东西咱们不管,理解一下就好了
- entry,入口文件,指定WebPack用哪个文件作为项目的入口 —— 就只有一个,即我们的main.js。
- output,输出,指定WebPack把处理完成的文件放置到指定路径 —— 就是我们使用webpack打包完成后,会自动生成(输出)一个文件,你要把这个文件放到哪个位置。
- module,模块,用于处理各种类型的文件 —— 我们打包是不是要把一些模块打进去呀,我们的java程序也是这样的,生成.jar包的时候需要把它此java项目所有的依赖都安上去再打包。
- plugins,插件,如:热更新、代码重用等 —— plugins是一些插件,你要是放插件,它也可以实现啊。
- resolve,设置路径指向 ——
- watch,监听,用于设置文件改动后直接打包 ——
- 了解:这些东西咱们不管,理解一下就好了
- 第一步:安装webpack
- webpack的使用
- 狂神文档参考:
- 自己的详细操作步骤
-
第一步:在某个目录下创建一个文件夹webpack-study
- 第二步:使用vs code工具打开它webpack-study
- 第三步:vs code操作
- 第1步:创建 —— 一个名为modules的目录,用于放置JS模块等资源文件。
- 第2步:暴露 —— 在modules目录下创建模块文件,如hello.js, 用于编写JS模块相关代码。
// 哈哈 这个地方是给你补es6的语法啊 // 第一步:exports,暴露一个方法(此方法执行完,会在前端生成一个h1标签,文字加粗) exports.sayHi = function(){ document.write("<h1>狂神的es666</h1>") } exports.sayHi1 = function(){ document.write("<h1>狂神的es6661</h1>") } exports.sayHi2 = function(){ document.write("<h1>狂神的es6662</h1>") } exports.sayHi3 = function(){ document.write("<h1>狂神的es6663</h1>") }
- 第3步:引入(使用)—— 在modules目录下创建一个名为main.js的入口文件,用于打包时设置entry属性
// 第一步:require,引入/使用/加载(一个包)。这里的模块名是hello,不用在后面加.js。就像java中import类时,不会有.java结尾。 var hello = require("./hello"); // 第二步:调用方法 hello.sayHi(); hello.sayHi1(); hello.sayHi2(); hello.sayHi3();
- 第4步:打包编码与设置 —— 在项目目录下创建webpack.config.js配置文件,使用webpack命令打包
// 前端一直在抄袭我们 模仿我们 // module.exports把这些模块(main.js、hello.js)编译》导出》打包 module.exports = { entry:"./modules/main.js", // 程序入口main.js。相当于java springboot程序的Application.java(入口程序)的那个main()方法 output:{ filename:"./js/bundle.js" // 输出到js目录(自动生成)下的bundle.js(自动生成) } }
- 第5步:打包操作完成 —— vscode终端中输入打包命令"webpack":
- bundle.js:经过编译(es6 》es5)、打包、压缩。
- 第6步:使用index.html —— 我们编写的代码(hello.js、main.js)经过打包出来能用了(bundle.js),我们在index.html中使用一下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>狂神说Java</title> <!-- 导入编译、打包完成的bundle.js,并使用 --> </head> <body> <!-- 这就是前端的模块化开发 --> <script src="dist/js/bundle.js"></script> </body> </html>
-
- 狂神文档参考:
十八 vue-router路由(转发)
- 业务
- 在讲完webpack(exports、require)以后,大家就能够看懂vue的工程了。
- vue遵循的是soc原则,vue本身只关注视图层,而vue工程中路由(即多个页面跳转,即以后我们后端中的重定向、转发的事情将由前端来做)的功能是使用vue-router路由组件(vue自带的)来实现的。
- 需求:多个页面之间的跳转(后端的重定向、转发事情将由前端来做)
- 思想路
-
Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。这句话的意思是,我们可以直接使用vue-router,直接import即可。
-
包含的功能有:
-
嵌套的路由/视图表 —— 也就是说,从vue的角度来看,一个页面是很多很多的组件 + 很多插槽组成( 相当于html时期,一个一个div的嵌套)的。不同的页面中,只有一部分的组件的内容是变化的,此时我们可以把这一部分的组件路由到另一个组件,用另一个组件来代替它,再完成内容的渲染就行了。
-
模块化的、基于组件的路由配置 ——
-
路由参数、查询、通配符 ——
-
基于 Vue.js 过渡系统的视图过渡效果 ——
-
细粒度的导航控制 ——
-
带有自动激活的 CSS class 的链接 ——
-
HTML5 历史模式或 hash 模式,在 IE9 中自动降级 ——
-
自定义的滚动条行为 ——
-
-
-
环境搭建 & 依赖(如axios、vue-router)的安装、导入、使用
-
第一步:新建vue工程(把src目录下多余的东西都删除掉),整理后得到的基础工程:
// main.js import Vue from 'vue' // 从vue那个组件里面,给它导过来 import App from './App' // 导入app组件 Vue.config.productionTip = false new Vue({ el: '#app', components: { App }, template: '<App/>' })
// app.vue <template> <div id="app"> </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>
-
第二步:安装 —— vue-router(安装的原理,即把模块放到node_modules目录下。这相当于在java的项目中,把第三方的jar包放到lib目录下一样)
-
第1步:管理员运行cmd
-
第2步:cd到此项目根目录下
-
第3步:执行npm install vue-router --save-dev命令
-
-
第三步:详解 —— 安装后的vue-router,在“node_modules”目录下找,如下图所示:
-
从目录结构可以看出vue-router是一个标准的前端工程。
-
-
第四步:导入 —— 安装完成后,如果需要在App.vue中使用vue-router组件,那么就直接使用import关键字导入即可(相当于java中用import导入某个类),如下图所示:
-
第五步:显示声明使用 —— 上面只是把vue-router导入进来,但vue中需要显示地声明。
// main.js import Vue from 'vue' // 从vue那个组件里面,给它导过来 import App from './App' // 导入app组件 import VueRouter from 'vue-router' // 从安装的vue-router模块中导进来 // from 'vue-router'是导入进来前的名字 // import VueRouter是导入进来后使用的qkpb Vue.config.productionTip = false // 显示地声明使用vue-router,使用的名字是导入进来后的名字 Vue.use(VueRouter); new Vue({ el: '#app', components: { App }, template: '<App/>' })
-
- 自定义组件的编写、导出、导入、使用(演示使用的项目的项目结构如下图)
- 第一步:编写&导出:在components目录下存放我们自己编写的组件Content.vue:
<!-- 组件的组成部分 --> <!-- 第一部分:页面 --> <template> <div> <h1>内容页</h1> </div> </template> <!-- 第二部分:一般是vue对象的一些东西,一般使用export进行导出 --> <script> export default { name: "Content" } </script> <!-- 第三部分:页面样式 --> <style> </style>
- 第二步:导入&使用:在App.vue中使用:
<template> <div id="app"> </div> </template> <script> // 第一步:先导入 import Content from "./components/Content.vue" export default { name: 'App', components: { // 第二步:再使用 Content } } </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.vue:
- 使用vue-router实现路由(重定向、转发)
- 第一步:编写&导出:在components目录下存放我们自己编写的组件Main.vue 和 Content.vue :
<template> <div> <h1>首页</h1> </div> </template> <script> export default { name: "Main" } </script> <style> </style>
<!-- 组件的组成部分 --> <!-- 第一部分:页面 --> <template> <div> <h1>内容页</h1> </div> </template> <!-- 第二部分:一般是vue对象的一些东西,一般使用export进行导出 --> <script> export default { name: "Content" } </script> <!-- 第三部分:页面样式 --> <style> </style>
- 第二步:在src目录下创建一个router文件夹,专门用于放在关于路由的东西
- 第三步:配置路由 —— 在router文件夹下面,创建路由的主配置文件index.js,专门用于编写路由规则:
// 导入vue import Vue from 'vue' // 导入路由插件 import Router from 'vue-router' // 导入上面定义的组件 import Content from '../components/Content' import Main from '../components/Main' // 显示声明使用路由 Vue.use(Router); // 导出新配置的路由 export default new Router({ routes: [ { // 路由路径,即只要你在浏览器地址栏输入的路径是“/content”,表明就要使用些路由。 // 使用哪个路由 & 跳转到哪个组件,由name和component属性决定 path: '/content', // 路由名称 name: 'content', // 跳转到哪个组件 component: Content } , {//如何配置两个路由(假如 首页) path: '/main', name: 'main', component: Main } ] });
从上面的代码可以看出,vue-router相当于我们java的什么呀?相当于我们springmvc项目controller类中的@RquestMapping注解,RquestMapping本身的作用就是接收前端的一个请求,并指定要方法处理的一些数据,最后要求方法跳转到另一个页面。vue-router其实也是干这么一个事情。
-
第四步:起用路由 —— 在前端工程的入口程序main.js中配置:
import Vue from 'vue' import App from './App' // 第一步:导入上面创建的路由主配置文件所在的目录,并且取名为“router” import router from './router' Vue.config.productionTip = false new Vue({ el: '#app', // 第二步:使用(配置的)路由(表),vue会自动扫描里面的路由配置 router, components: { App }, template: '<App/>' })
-
第五步:演示路由功能 —— 在 App.vue 中使用路由:
<template> <div id="app"> <!-- router-link: 默认会被渲染成一个 <a> 标签,to 属性为指定链接 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>
-
第六步:验证
-
第1步:npm run dev 访问
-
第2步:点击可以跳转
-
- 第一步:编写&导出:在components目录下存放我们自己编写的组件Main.vue 和 Content.vue :
十九 vue + elementui
- 业务
- vue前端工程现在没有自己好看的页面,我们可以使用vue+elementui构建比较好看的页面。
- 需求:网站快速成型工具
- 解决方案:
- vue + elementui
- 推荐使用 npm 的方式安装,它能更好地和 webpack 打包工具配合使用。
- element-ui官网解读:组件 | Element
- element-ui的这些组件用起来和bootstrap的组件是一样的。
- 建议学习“element-ui(组件化开发,桌面化应用) + layui(弹窗)”用于代替“bootstrap(样式化开发,桌面化应用) + layui(弹窗)”。
- hellowor:vue + elementui
- 第一步:环境搭建 & 初始化项目
- 第一次创建项目
- 第1步:npm install vue-cli -g,全局安装vue脚手架
- 第二次创建项目
- 第1步:cmd管理员
- 第2步:cd来到工作空间
- 第3步:vue init webpack hello-vue,初始化一个webpack项目,项目名称是hello-vue:
- 第一次创建项目
- 第二步:安装各种插件和组件
- 第1步:准备
- 进入工程目录(cmd 管理员身份):cd hello-vue
- 第2步:安装vue-router
- npm install vue-router --save-dev
- peer vue@"^3.2.0" from vue-router@4.1.6 》npm i vue-router@3
- 第3步:安装element-ui
- npm i element-ui -s
- 第4步:安装所有的依赖
- npm install
- 第5步:安装SASS加载器
- cnpm方式
- cnpm install sass-loader node-sass --save-dev
- 这句命令安装了两个,一个是sass-loader,另一个是node-sass。
- 你们可以拆成两名命令,也可以合成一句命令,也就是说你要安装多个组件可以一句命令安装完。
- 这里使用cnpm的时候,是因为老师使用npm安装时失败了。淘宝的镜像再怎么着都比国外(npm)的快。
- 业务/需求:我们之前聊过,前端的一些东西不能用纯css来写,是不是它就用SASS呀,你要通过SASS去编辑生成啊。就是css嘛,使用SASS编辑生成css。
- Error: Cannot find module ‘diagnostics_channel,cnpm的版本过高 》npm uninstall -g cnpm 》npm install cnpm@7.1.0 -g 》cnpm install sass-loader node-sass --save-dev
- cnpm install sass-loader node-sass --save-dev
- npm方式
- peer webpack@"^5.0.0" from sass-loader@13.2.0 》npm i sass-loader@7
- node-sass pip 安装报错,提示缺少python2 (shuzhiduo.com) 》npm install node-sass@6
- cnpm方式
- 第6步:测试
- npm run dev
- 第1步:准备
- 第三步:编号开发
- 第1步:整理项目
- 第(1)步:使用vs code打开项目
- 第(2)步:删除src下默认的文件:assets/logo.png(默认的图片)、components/HelloWorld.vue(默认的组件)
- 第(3)步:整理src/App.vue
<template> <div id="app"> </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>
- 第(4)步:静态资源文件放在static吧,放在其它地方不可见啊
- 第(5)步:新建src/router目录,用于放路由
- 第(6)步:新建src/views目录,用于放置视图,也可以叫视图组件(视图也是组件的一部分,但分得细一点,视图一般用于交互的)。这里的views目录用于存放视图组件,而components目录用于存放功能性组件,这样分工是不是就更加明确了。
- 第3步:编码
- 第(1)步:在views目录下创建Main.vue视图
<template> <h1>首页</h1> </template> <script> export default { name: 'Main', } </script> <style> </style>
- 第(2)步:在views目录下创建Login.vue视图(直接去ElementUI官网中拿的,不是我自己写的)。
<template> <div> <!-- el开头的就是element的组件(这里是表单) --> <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> <!--登录按钮,绑定了click事件,调用onSubmit方法--> <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 scoped> .login-box{ border: 1px solid #DCDFE6; width: 350px; margin: 108px auto; padding: 35px 35px 15px 35px; border-radius: 5px; -webkit-border-radius:5px; -moz-border-radius:5px; box-shadow: 0 0 25px #909339; } .login-title{ text-align: center; margin: 0 auto 40px auto; color: #303133; } </style>
-
第(3)步:路由index.js(那这个登录表单想要用怎么办?是不是要配置到路由里面去呀。组件写完它是独立的吧,独立的东西就要通过路由把它们交互起来)。
//第一步:引入(导入) import Vue from 'vue' import Router from 'vue-router' // 其中名称Router可以随便取,只要后面的vue-router对即可 import Main from '../views/Main' // 导入Main组件 import Login from '../views/Login'// 导入Login组件 //第二步:显示地使用它 Vue.use(Router) //第三步:导出一个接口 export default new Router({ routes:[// 放置(配置)各种各样的路由 { path:'/main',// 请求链接 component:Main// 路由(转发)到此组件 }, { path:'/login',// 请求链接 component:Login// 路由(转发)到此组件 } ] });
-
第(4)步:main.js。路由配置到哪里去?配置到main.js里面去吧。
import Vue from 'vue' import App from './App' //第一步:要想使用路由,那就让路由去扫描相应的包(router目录)吧,这样子的话它就会把所有配置好的路由给加载进来 import router from './router' //第二步:elementui还没导入,我们是不是要把它导入进来呀。名字'element-ui'去哪里找呀?是不是去node_modules里面找呀 import Element from 'element-ui' //第三步:导入elementui对应的css。官网案例拷贝。 //说明它导入了一个css吧,是不是就需要SASS编辑器吧,这就是我们刚才导入SASS的原因。 import 'element-ui/lib/theme-chalk/index.css'; //第四步:安装路由(显示地使用路由) Vue.use(router); //第五步:安装ElementUI(显示地使用ElementUI) Vue.use(ElementUI); //第六步:配置Router和ElementUI new Vue({ el: '#app', router,// 配置router。 render: h => h(App)// 配置ElementUI。官网拷贝。 })
-
第(5)步:App.vue修改:
<template> <div id="app"> <router-link to='/login'>login</router-link> <router-link to='/main'>main</router-link> <!--剩下的就是把路由到页面展示出来就好了--> <router-view></router-view> </div> </template> <script> export default { name: 'App' } </script> <style> </style>
- 第(1)步:在views目录下创建Main.vue视图
-
第3步:测试
-
npm run dev
-
-
附:排错,SASS版本过高
-
第(1)步:来到包版本管理文件pack.json,它里面有所有组件(插件)的版本吧。在里面找到SASS loader,看到是8.0.0版本的,所以版本太高了,所以这里我们把它的版本号改成7.3.1的版本。
-
第(2)步:由于pack.json中修改了版本,所以在终端重新npm install一下。npm install才是安装它吧,你改了不重新安装没有用的。
-
- 第1步:整理项目
- 第一步:环境搭建 & 初始化项目
二十 嵌套路由
- 业务与需求
- 如上图所示,有两个请求,外面都是一样。
- 左边那个图表明,如果我请求User下面的profile,它会显示profiel的内容。
- 右边那个图表明,如果我请求User下面的posts,它会显示posts的内容。
- 但是其它页面是不变的,这里它只变局部吧。只变局部,对于vue来说真的是太轻松了,对不对。为什么会轻松呀?因为vue是component组件拔插,对不对,意思就是说把这个组件放进去就可以了。 在vue中可以通过路由去实现这样的功能。
- 如上图所示,有两个请求,外面都是一样。
- 案例演示------------------------------------------------------------------------------
- 第一步:在src/views目录下创建user目录(模拟:用户管理模块)
- 第二步:在src/views/user目录下创建Profile.vue(模拟:用户管理模块中的,个人信息页面)。
<template> <h1>个人信息Profile</h1> </template> <script> export default { name: 'UserProfile' } </script> <style> </style>
- 第三步:在src/views/user目录下创建List.vue(模拟:用户管理模块中的,用户列表页面)。
<template> <h1>用户列表List</h1> </template> <script> export default { name: 'UserList' } </script> <style> </style>
- 第四步:src/views/Main.vue修改。关键是我们想把UserProfile.vue和UserList.vue展示出来吧。是不是应该展示在Main.vue(这里增加侧边栏)里面吧。
<template> <div> <el-container> <el-aside width="200px"> <el-menu :default-openeds="['1']"> <el-submenu index="1"> <template solt="title"><i class="el-icon-caret-right"></i>用户管理</template> <el-menu-item-group> <el-menu-item index="1-1"> <!-- 通过router-link把用户个人信息放进去 --> <router-link to="/user/profile">个人信息</router-link> </el-menu-item> <el-menu-item index="1-2"> <!-- 通过router-link把用户列表放进去 --> <router-link to="/user/list">用户列表</router-link> </el-menu-item> </el-menu-item-group> </el-submenu> <el-submenu index="2"> <template solt="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-link吧。 --> <!-- 总结:一个页面中肯定有一个router-view,展示的内容是router-link指向的组件。 --> <router-view/> </el-main> </el-container> </el-container> </div> </template> <script> export default { name: "Main" } </script> <style scoped lang="scss"> .el-header { background-color: #048bd1; color: #333; line-height: 60px; } .el-aside { color: #333; } </style>
- 第五步:index.js。我们定义了3个组件,所以我们要把它导到路由组件里面去。
//第一步:引入(导入) import Vue from 'vue' import Router from 'vue-router' // 其中名称Router可以随便取,只要后面的vue-router对即可 import Main from '../views/Main' // 导入Main组件 import Login from '../views/Login'// 导入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 } ] });
- 第六步:测试
- npm run dev
- http://localhost:8080/
- 报错:<style scoped lang="scss">改成<style scoped>
二十一 参数传递及重定向
- 参数传递
- 业务
- 点击左侧导航栏的“个人信息”菜单,要求每个登录的人,展示不同的个人信息。
- 需求
- 第一步:接收前端的参数
- 第二步:请求的方式会是:localhost:8080/user/profile?userId=xxx
- 解决方案
- <router-link to>
- 案例:没有解偶:在你的组件中使用
$route
会与路由紧密耦合,这限制了组件的灵活性,因为它只能用于特定的 URL。虽然这不一定是件坏事,但我们可以通过props
配置来解除这种行为:- 传参 —— 组件,Main.vue
<template> <div> <el-container> <el-aside width="200px"> <el-menu :default-openeds="['1']"> <el-submenu index="1"> <template solt="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>--> <!-- 传参:name传递的是路由名称,params传递的是组件参数列表 --> <router-link :to="{name:'UserProfile',params:{id:1}}">个人信息</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 solt="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: #048bd1; color: #333; line-height: 60px; } .el-aside { color: #333; } </style>
-
接收参数 —— 路由,index.js
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:[ { // 其中的"/:id"用于接收参数 path:'/user/profile/:id', name:"UserProfile",//“路由名称”用于<router-link>中的to属性用于传参数 component:UserProfile }, { path:'/user/list', component:UserList } ] }, { path:'/login', component:Login } ] });
-
页面展示“传递的参数” —— Profile.vue
<template> <div> <h1>个人信息Profile</h1> <!-- 获取参数(展示) --> {{$route.params.id}} </div> </template> <script> export default { name: 'UserProfile' } </script> <style> </style>
-
测试成功
- 传参 —— 组件,Main.vue
- 案例2:解偶(官网):通过
props
配置实现参数传递- 狂神案例
- 传参 —— Main.vue不变,<router-link :to="{name:'UserProfile',params:{id:1}}">个人信息</router-link>
- 接收 —— index.js,声明使用props的方式
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/:id', name:"UserProfile", props: true, // props参数传递,解偶 component:UserProfile }, { path:'/user/list', component:UserList } ] }, { path:'/login', component:Login } ] });
- 页面展示“传递的参数” —— Profile.vue,通过组件去接收参数
<template> <div> <h1>个人信息Profile</h1> <!-- // props参数传递,解偶 --> {{id}}abc </div> </template> <script> export default { // props参数传递,解偶,使用组件的方式接收参数 props:['id'], name: 'UserProfile' } </script> <style> </style>
- 官方文档
- 我们可以将下面的代码
const User = { template: '<div>User {{ $route.params.id }}</div>' } const routes = [{ path: '/user/:id', component: User }]
-
替换成
const User = { // 请确保添加一个与路由参数完全相同的 prop 名 props: ['id'], template: '<div>User {{ id }}</div>' } const routes = [{ path: '/user/:id', component: User, props: true }]
- 我们可以将下面的代码
- 狂神案例
-
总结:
-
在正常情况下,我们应该是传递一个对象,用对象作为参数吧。现在我们学会了单个参数(userId)的传递,那么同理,传递一个(甚至多个)对象也是用同样的方法,以此类推罢了。
-
- 业务
- 重定向
- 怎么能够实现重定向呢?
- 浏览器地址栏url不变的跳转,叫做转发。浏览器地址栏url变化的跳转,叫重定向。
- 重定向的意思就是从一个path,跳转到另外一个path。
- 案例
- 第一步:index.js,修改路由配置文件
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/:id', name:"UserProfile", }, { path:'/user/list', component:UserList }, { path:'/goHome', // 重定向,第一步:redirect:'/main' redirect:'/main' } ] }, { path:'/login', component:Login } ] });
- 第二步:Main.vue,修改
<template> <div> <el-container> <el-aside width="200px"> <el-menu :default-openeds="['1']"> <el-submenu index="1"> <template solt="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 index="1-3"> <router-link to="/goHome">返回首页</router-link> </el-menu-item> </el-menu-item-group> </el-submenu> <el-submenu index="2"> <template solt="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: #048bd1; color: #333; line-height: 60px; } .el-aside { color: #333; } </style>
- 第一步:index.js,修改路由配置文件
- 怎么能够实现重定向呢?
二十二 404和路由钩子
- 业务需求1:
- 情况:在登录页面中输入什么样的用户名和密码都可以跳转到主页。
- 想要的:跳转到主页以后,应该显示当前登录人的信息。
- 案例:跳转到主页以后,应该显示当前登录人的信息。
- 传参:Login.vue
<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:'' }, 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){ // 跳转到主页以后,应该显示当前登录人的信息。 // 第一步:传参 this.$router.push("/main/"+this.form.username); }else{ this.dialogVisible = true; return false; } }) } } } </script> <style scoped> .login-box{ border: 1px solid #DCDFE6; width: 350px; margin: 108px auto; padding: 35px 35px 15px 35px; border-radius: 5px; -webkit-border-radius:5px; -moz-border-radius:5px; box-shadow: 0 0 25px #909339; } .login-title{ text-align: center; margin: 0 auto 40px auto; color: #303133; } </style>
-
接收参数:index.js
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/:name', component:Main, // 第三步:获取并展示参数 // 第3-1步:声明使用props方式接收参数 props:true, children:[ { path:'/user/profile/:id', name:"UserProfile", props: true, component:UserProfile }, { path:'/user/list', component:UserList } ] }, { path:'/login', component:Login } ] });
- 获取数据并展示:Main.vue
<template> <div> <el-container> <el-aside width="200px"> <el-menu :default-openeds="['1']"> <el-submenu index="1"> <template solt="title"><i class="el-icon-caret-right"></i>用户管理</template> <el-menu-item-group> <el-menu-item index="1-1"> <router-link :to="{name: 'UserProfile',params: {id: 1}}">个人信息</router-link> </el-menu-item> <el-menu-item index="1-2"> <router-link to="/user/list">用户列表</router-link> </el-menu-item> <el-menu-item index="1-3"> <router-link to="/goHome">返回首页</router-link> </el-menu-item> </el-menu-item-group> </el-submenu> <el-submenu index="2"> <template solt="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> <!-- 第三步:获取并展示参数 --> <!-- 第3-3步:获取并展示数据 --> <span>{{name}}</span> </el-header> <el-main> <router-view/> </el-main> </el-container> </el-container> </div> </template> <script> export default { // 第三步:获取并展示参数 // 第3-2步:使用props属性接收参数 props:['name'], name: "Main" } </script> <style scoped lang="scss"> .el-header { background-color: #048bd1; color: #333; line-height: 60px; } .el-aside { color: #333; } </style>
-
测试
- 传参:Login.vue
-
业务需求2:去掉链接中的" # "
-
解决方案 —— 路由模式与404:
-
配置过程
-
第一步:index.js路由管理器
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({ // 去掉链接中的" # ",history模式 mode:'history', routes:[ { path:'/main/:name', component:Main, props:true, children:[ { path:'/user/profile/:id', name:"UserProfile", props: true, component:UserProfile }, { path:'/user/list', component:UserList } ] }, { path:'/login', component:Login } ] });
-
第二步:测试
-
-
-
业务需求3:纯前端处理404
-
第一步:NotFound.vue,在src/views目录下创建新组件
<template> <div id="app"> <h1>大兄弟404了</h1> </div> </template> <script> export default { name: 'NotFound' } </script> <style> </style>
-
第二步:index.js,写完组件第一种事情就是把组件配置到路由上去
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' // 第一步:导入进来 import NotFound from '../views/NotFound' Vue.use(Router) export default new Router({ mode:'history', routes:[ { path:'/main/:name', component:Main, props:true, children:[ { path:'/user/profile/:id', name:"UserProfile", props: true, component:UserProfile }, { path:'/user/list', component:UserList } ] }, { path:'/login', component:Login } , { // 第二步:配置404的路由 path:'*', // 测试1:拦截除以上请求之外的任何所有请求 component:NotFound } ] });
-
第三步:测试
-
-
业务需求4:路由钩子与异步请求
-
beforeRouteEnter,就像咱们的过滤器(chain链)、拦截器一样,即进入这个路由之前要进行过滤一下。to、from、next,即从哪里来(相当于HttpRequest),到哪里去(相同于HttpResponse),往下一个走(相当于chain链)。
-
beforeRouteLeave,离开某个路由之前干什么事,即离开某个路由之前又过滤一便。
-
案例演示1:在钩子函数中使用异步请
- 第一步:安装axios和vue-axios组件(插件), npm install axios -s npm install vue-axios -s
-
第二步:main.js要导入axios、vue-axios,不然你安装的组件是无法使用的
-
import axios from 'axios';
-
import VueAxios from 'vue-axios'
-
完整代码:
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'; // 第一步:安装Axios , cnpm install axios -s // 第二步:main.js引用Axios // 第2-1步:引入 import axios from 'axios'; import VueAxios from 'vue-axios' // 第2-2步:声明使用 Vue.use(VueAxios,axios) Vue.use(router); Vue.use(ElementUI); new Vue({ el: '#app', router, render: h => h(App) })
-
-
第三步:准备数据:只有我们的static目录下的文件是可以被访问到的,所以我们就把静态文件放入该目录下。
-
//静态数据存放的位置:static/mock/data.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/" } ] }
-
-
第四步:Profile.vue:在beforeRouteEnter中进行异步请求
<template> <div> <h1>个人信息Profile</h1> {{id}}abc </div> </template> <script> export default { props:['id'], name: 'UserProfile', // 路由钩子与异步请求 // 进入这个页面之前,先执行这段代码,使用axios加载数据 beforeRouteEnter:(to,from,next)=>{ console.log("进入路由之前,使用axios加载数据"); next((vm)=>{//vm —— 可以直接获取到当前的对象实例。vm就可以调用它本身methods中定义的方法。 vm.getData(); }) //next();// 如果没有这句放,就阻塞了。 //next("/path") //跳转到指定路径 //next(false) //返回上一页 }, // 离开这个页面之前,先执行这段代码。 beforeRouteLeave:(to,from,next)=>{ console.log("离开路由之前纟xx"); next();// 如果没有这句放,就阻塞了。 }, methods:{ getData:function(){//使用axios加载数据 this.axios({//请求 method:'get',//get方式 url:'http://localhost:8080/static/mock/data.json' }).then(function(response){//response是响应的东西,响应回来的结果 console.log(response); }); } } } </script> <style> </style>
-
第五步:测试
-
直接访问data.json:localhost:8080/static/mock/data.json
-
访问主页:localhost:8080/main
-
访问个人信息页面:http://localhost:8080/user/profile/1
-
-
附1:docsify(一键)帮助文档生成工具
附2:npm命令解释