Vue:
Soc:
HTML+CSS+JS:视图:给用户看刷新后台的数据
网络通信:axios
页面跳转:vue-router
状态管理:vuex
Vue-UI:ICE , Element UI
1、前端核心分析
1.1、VUE 概述
Vue (读音/vju/, 类似于view)是一套用于构建用户界面的渐进式框架,发布于2014年2月。与其它大型框架不同的是,Vue被设计为可以自底向上逐层应用。Vue的核心库只关注视图层,不仅易于上手,还便于与第三方库(如: vue-router: 跳转,vue-resource: 通信,vuex:管理)或既有项目整合
1.2、前端三要素
- HTML (结构) :超文本标记语言(Hyper Text Markup Language) ,决定网页的结构和内容
- CSS (表现) :层叠样式表(Cascading Style sheets) ,设定网页的表现样式
- JavaScript (行为) :是一种弱类型脚本语言,其源代码不需经过编译,而是由浏览器解释运行,用于控制网页的行为
1.3、js框架
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通信功能;
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来写。
View层实现的不是Model的数据,而是ViewModel的数据,由ViewModel负责与Model层交互,这样就完全解耦了View层和Model层,这个解耦是至关重要的,他是前后端分离方案实施的重要一环
2.3、Vue使用的就是MVVM
-
Model : 模型层,在这里表示JavaScript对象
-
View : 视图层,在这里表示DOM (HTML操作的元素)
-
ViewModel : 连接视图和数据的中间件,Vue.js就是MVVM中的ViewModel层的实现者在MVVM架构中,是不允许数据和视图直接通信的,只能通过ViewModel来通信,而ViewModel就是定义了一个Observer观察者
ViewModel 能够观察到数据的变化,并对视图对应的内容进行更新
ViewModel 能够监听到视图的变化,并能够通知数据发生改变
实际上就是实现了Dom元素的监听和数据绑定
2.4、创建一个vue的项目
-
直接在资源管理器新建一个对应的文件夹,然后使用idea工具打开
-
在IDEA的插件中添加Vue.js插件
-
安装成功后可以右键想木添加也 conponent,如果没有出现手动创建一个vue文件,然后就出现了
-
创建一个html文件
-
导入vue.js
<!--导入vue.js--> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
-
编写页面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--导入vue.js--> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script> <!--view模板--> <div id="app"> {{message}} </div> <script> var vm = new Vue({//vm:数据绑定 el:"#app", //Model数据 data:{ message:"hello,Vue!" } }); </script> </body> </html>
3、Vue基本语法
3.1、v-bind
带有v-的表示他们是Vue提供的特殊属性,他们会渲染DOM上应用的特殊属性。数据和DOM已经被建立了关联,所有的东西都是响应式的。我们在控制台操作对象的属性,界面可以实时更新
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--导入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<!--view模板-->
<div id="app">
<span v-bind:title="message">
鼠标悬停几秒查看此处动态绑定信息
</span>
</div>
<script>
var vm = new Vue({//vm:数据绑定
el:"#app",
//Model数据
data:{
message:"hello,Vue11!"
}
});
</script>
</body>
</html>
3.2、v-if v-else
===:类型也需要相同
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--导入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<!--view模板-->
<div id="app">
<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>D</h1>
</div>
<script>
var vm = new Vue({//vm:数据绑定
el:"#app",
data:{
type:'A'
}
});
</script>
</body>
</html>
3.3、v-for
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--导入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<!--view模板-->
<div id="app">
<li v-for="item in items">
{{item.message}}
</li>
</div>
<script>
var vm = new Vue({//vm:数据绑定
el:"#app",
data:{
items:[
{message:"java"},
{message:"mysql"},
{message:"javaee"}
]
}
});
</script>
</body>
</html>
3.4、v-on事件绑定
事件必须定义在Vue的methods中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--导入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<!--view模板-->
<div id="app">
<button v-on:click="sayHi">chick me</button>
</div>
<script>
var vm = new Vue({//vm:数据绑定
el:"#app",
data:{
message:"vue"
},
methods:{ //必须定义在Vue的methods中 v-on绑定事件
sayHi: function (){
alert(this.message);
}
}
});
</script>
</body>
</html>
4、Vue双向绑定 v-model
- 什么是双向绑定
Vue.js是一个MVVM框架,即数据双向绑定,即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化。这也算是Vue.js的精髓之处了。
值得注意的是,我们所说的数据双向绑定,一定是对于UI控件来说的,非UI控件不会涉及到数据双向绑定。单向数据绑定是使用状态管理工具的前提。如果我们使用vuex,那么数据流也是单项的,这时就会和双向数据绑定有冲突。
-
为什么要实现数据的双向绑定
在Vue.js 中,如果使用vuex ,实际上数据还是单向的,之所以说是数据双向绑定,这是用的UI控件来说,对于我们处理表单,Vue.js的双向数据绑定用起来就特别舒服了。即两者并不互斥,在全局性数据流使用单项,方便跟踪;局部性数据流使用双向,简单易操作。 -
在表单中使用双向数据绑定
你可以用v-model指令在表单 、 及 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但v-model本质上不过是语法糖。它负责监听户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
注意:v-model会忽略所有元素的value、checked、selected特性的初始值而总是将Vue实例的数据作为数据来源,你应该通过JavaScript在组件的data选项中声明。
在Vue中的双向绑定:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--导入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<!--view模板-->
<div id="app">
<!-- 文本-->
输入的文本:<input type="text" v-model="message">{{message}}<br>
<!-- 单选框-->
<input type="radio" namn="sex" value="男" v-model="radio">男
<input type="radio" namn="sex" value="女" v-model="radio">女
<p>
选中了:{{radio}}
</p>
<!-- 下拉框-->
<select v-model="select">
<option value="" disabled>请选择</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<p>
下拉框选择了:{{select}}
</p>
</div>
<script>
var vm = new Vue({//vm:数据绑定
el:"#app",
data:{
message:"",
radio:"",
select:""
}
});
</script>
</body>
</html>
5、Vue组件
组件是可复用的Vue实例,说白了就是一组可以重复使用的模板,跟JSTL的自定义标签、Thymeleaf的th:fragment
等框架有着异曲同工之妙。通常一个应用会以一棵嵌套的组件树的形式来组织:
使用props传递属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--导入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<!--view模板-->
<div id="app">
<test v-for="item in items" v-bind:aa="item" ></test>
</div>
<script>
//定义一个Vue组件component
Vue.component("test",{
props:["aa"],
template:'<li>{{aa}}</li>'
})
var vm = new Vue({//vm:数据绑定
el:"#app",
data:{
items:["java","linux","mysql"]
}
});
</script>
</body>
</html>
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文件
{ "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" } ] }
-
测试axios获取数据
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--1.导入vue.js--> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script> <!--导入axios--> <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.19.2/axios.min.js"></script> <style> <!--解决闪烁问题--> [v-clock]{ display: none; } </style> <!--view模板--> <div id="vue" v-clock> <div>{{info.name}}</div> <div>{{info.address.street}}</div> <a v-bind:href="info.url">ddd</a> </div> <script type="text/javascript"> var vm = new Vue({ el:'#vue', //data:vm的属性 //data() vm的方法 data(){ return{ //请求的返回参数必须和json字符串一样 info:{ name:null, address:{ street:null, city:null, country:null }, url:null } } }, mounted(){//钩子函数 链式编程 ES6新特性 axios.get('../data.json').then(response=>(this.info=response.data)); } }) </script> </body> </html>
6.3、计算属性
计算属性的重点突出在属性两个字上(属性是名词),首先它是个属性其次这个属性有计算的能力(计算是动词),这里的计算就是个函数;简单点说,它就是一个能够将计算结果缓存起来的属性(将行为转化成了静态的属性),仅此而已;可以想象为缓存!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--1.导入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<!--导入axios-->
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.19.2/axios.min.js"></script>
<!--view模板-->
<div id="app" v-clock>
<p>currentTime1:{{currentTime1()}}</p>
<p>currentTime2: {{curentTime2}}</p>
</div>
<script type="text/javascript">
var vm = new Vue({
el:'#app',
data() {
message:"hello,vue"
},
methods:{
currentTime1: function (){
return Date.now();//返回一个时间戳
}
},
computed:{//计算属性: methods conmputed 方法名不能重名,重名之后之回调用methods的方法
curentTime2: function (){
return Date.now();
}
}
})
</script>
</body>
</html>
结论:
调用方法时,每次都需要进行计算,既然有计算过程则必定产生系统开销,那如果这个结果是不经常变化的呢?此时就可以考虑将这个结果缓存起来,采用计算属性可以很方便的做到这一点,计算属性的主要特性就是为了将不经常变化的计算结果进行缓存,以节约我们的系统开销;
7、内容分发 slot
在Vue.js中我们使用 元素作为承载分发内容的出口,作者称其为插槽,可以应用在组合组件的场景中;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--1.导入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<!--导入axios-->
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.19.2/axios.min.js"></script>
<!--view模板-->
<div id="app" v-clock>
<todo>
<todo-title slot="todo-title" :title="title"></todo-title>
<todo-items slot="todo-items" v-for="item in todoItems" :item="item"></todo-items>
</todo>
</div>
<script type="text/javascript">
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'],
template: '<li>{{item}}</li>'
})
var vm = new Vue({
el:'#app',
data: {
title:"列表",
todoItems:['java','前端','linux']
}
})
</script>
</body>
</html>
实现效果
8、自定义事件
通过以上代码不难发现,数据项在Vue的实例中,但删除操作要在组件中完成,那么组件如何才能删除Vue实例中的数据呢?此时就涉及到参数传递与事件分发了,Vue为我们提供了自定义事件的功能很好的帮助我们解决了这个问题;
vue.component组件不能直接删除vue实例下的属性,前端可以通过methods里的自定义方法通过绑定元素删除vue的属性,组件通过this.$emit()分发调用前端的自定义方法删除vue实例的元素
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--1.导入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<!--导入axios-->
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.19.2/axios.min.js"></script>
<!--view模板-->
<div id="app" v-clock>
<todo>
<todo-title slot="todo-title" :title="title"></todo-title>
<todo-items slot="todo-items" v-for="(item,index) in todoItems"
:item="item" v-bind:index="index" v-on:remove="removeItems(index)" key="index"></todo-items>
</todo>
</div>
<script type="text/javascript">
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>',
methods:{
remove: function (index){
//alert("111")
this.$emit('remove',index);
}
}
})
var vm = new Vue({
el:'#app',
data: {
title:"列表",
todoItems:['java','前端','linux']
},
methods: {
removeItems: function (index){
console.log("删除了"+this.todoItems[index]+"OK")
this.todoItems.splice(index,1);//一次删除一个元素
}
}
})
</script>
</body>
</html>
Vue入门小结:
核心:事件驱动,组件化
优点:借鉴了AngulaJS的模块化开发和React 的虚拟Dom,虚拟Dom就是把Dom的操作放到内存中执行
常用的标签
- v-if
- v-else-if
- v-else
- v-for
- v-on 绑定事件 简写:
@
- v-model 数据双向绑定
- v-bind 给组件绑定参数 简写:
:
组件化:
- 组件组合slot插槽
- 组件内部绑定事件需要使用到
this.$emit("事件名",参数)
- 计算属性的特色,缓存计算数据
遵循SoC’ 关注度分离原则,Vue是存粹的视图框架,并不包含,比如Ajax之类的通信功能,为了解决通信问题,需要使用Axios框架异步通信
说明:
Vue的开发都是要基于NodeJS,实际开发采用vue-cli脚手架开发,vue-router路由,vuex做状态管理; Vue UIl,界面我们一般使用ElementUI(饿了么出品),或者ICE(阿里巴巴出品!)来快速搭建前端项目~~
官网:
-
https://element.eleme.cn/#/zh-CN.
-
https://ice.work/
9、第一个vue-cli项目
9.1、什么是vue-cli
vue-cli 官方提供的一个脚手架,用于快速生成一个 vue 的项目模板;
预先定义好的目录结构及基础代码,就好比咱们在创建 Maven 项目时可以选择创建一个骨架项目,这个骨架项目就是脚手架,我们的开发更加的快速;
主要功能:
- 统一的目录结构
- 本地调试
- 热部署
- 单元测试
- 集成打包上线
9.2、运行环境安装
- 需要的环境:
Node.js : http://nodejs.cn/download/
安装就无脑下一步就好,安装在自己的环境目录下
-
Git : https://git-scm.com/downloads
镜像:https://npm.taobao.org/mirrors/git-for-windows/
确认nodejs安装成功:
- cmd 下输入
node -v
,查看是否能够正确打印出版本号即可! - cmd 下输入
npm-v
,查看是否能够正确打印出版本号即可!
这个npm,就是一个软件包管理工具,就和linux下的apt软件安装差不多!
npm 是 JavaScript 软件包管理工具,并且是 Node.js 平台的默认包管理工具。通过 npm 可以安装、共享、分发代码,管理项目依赖关系。
安装 Node.js 淘宝镜像加速器(cnpm)
# -g 就是全局安装
npm install cnpm -g
# 若安装失败,则将源npm源换成淘宝镜像
# 因为npm安装插件是从国外服务器下载,受网络影响大
npm config set registry https://registry.npm.taobao.org
# 然后再执行
npm install cnpm -g
npm安装的位置:C:\Users\Administrator\AppData\Roaming\npm
安装vue-cli
#在命令台输入
cnpm install vue-cli -g
# 如果发生错会提醒修复方法
#查看是否安装成功
vue list
第一个 vue-cli 应用程序:
# 这里的 myvue 是项目名称,可以根据自己的需求起名
vue init webpack myvue
然后全部选择no
- Project name:项目名称,默认回车即可
- Project description:项目描述,默认回车即可
- Author:项目作者,默认回车即可
- Vue build (Use arrow keys):选择第一个即可
- Install vue-router:是否安装vue-router,选择n不安装(后期需要再手动添加)
- Use ESLint to lint your code:是否使用ESLint做代码检查,选择n不安装(后期需要再手动添加)
- Set up unit tests:单元测试相关,选择n不安装(后期需要再手动添加)
- Setupe2etests with Nightwatch:单元测试相关,选择n不安装(后期需要再手动添加)
- Should we run npm install for you after the,project has been created:创建完成后直接初始化,选择n,我们手动执行;运行结果
最后初始化运行:
cd myvue
npm install
npm run dev
启动之后访问:http://localhost:8080/进入
这就是 Node.js的服务,类似于后端的tomcat
Node.js它是一个服务,它可以运行一些东西。
10、Webpack
10.1、什么是Webpack
本质上, webpack是一个现代JavaScript应用程序的静态模块打包器(module bundler) 。当webpack处理应用程序时, 它会递归地构建一个依赖关系图(dependency graph) , 其中包含应用程序需要的每个模块, 然后将所有这些模块打包成一个或多个bundle.
Webpack是当下最热门的前端资源模块化管理和打包工具, 它可以将许多松散耦合的模块按照依赖和规则打包成符合生产环境部署的前端资源。还可以将按需加载的模块进行代码分离,等到实际需要时再异步加载。通过loader转换, 任何形式的资源都可以当做模块, 比如Commons JS、AMD、ES 6、CSS、JSON、Coffee Script、LESS等;
伴随着移动互联网的大潮, 当今越来越多的网站已经从网页模式进化到了WebApp模式。它们运行在现代浏览器里, 使用HTML 5、CSS 3、ES 6等新的技术来开发丰富的功能, 网页已经不仅仅是完成浏览器的基本需求; WebApp通常是一个SPA(单页面应用) , 每一个视图通过异步的方式加载,这导致页面初始化和使用过程中会加载越来越多的JS代码,这给前端的开发流程和资源组织带来了巨大挑战。
前端开发和其他开发工作的主要区别,首先是前端基于多语言、多层次的编码和组织工作,其次前端产品的交付是基于浏览器的,这些资源是通过增量加载的方式运行到浏览器端,如何在开发环境组织好这些碎片化的代码和资源,并且保证他们在浏览器端快速、优雅的加载和更新,就需要一个模块化系统,这个理想中的模块化系统是前端工程师多年来一直探索的难题。
10.2、模块化的演进
Script标签:
<script src = "module1.js"></script>
<script src = "module2.js"></script>
<script src = "module3.js"></script>
这是最原始的JavaScript文件加载方式,如果把每一个文件看做是一个模块,那么他们的接口通常是暴露在全局作用域下,也就是定义在window对象中,不同模块的调用都是一个作用域。
这种原始的加载方式暴露了一些显而易见的弊端:
-
全局作用域下容易造成变量冲突
-
文件只能按照
10.3、CommonsJS
服务器端的NodeJS遵循CommonsJS规范,该规范核心思想是允许模块通过require
方法来同步加载
所需依赖的其它模块,然后通过exports
或module.exports来导出
需要暴露的接口。
require("module");
require("../module.js");
export.doStuff = function(){};
module.exports = someValue;
优点:
-
服务器端模块便于重用
-
NPM中已经有超过45万个可以使用的模块包
-
简单易用
缺点:
- 同步的模块加载方式不适合在浏览器环境中,同步意味着阻塞加载,浏览器资源是异步加载的
- 不能非阻塞的并行加载多个模块
实现:
- 服务端的NodeJS
- Browserify,浏览器端的CommonsJS实现,可以使用NPM的模块,但是编译打包后的文件体积较大
- modules-webmake,类似Browserify,但不如Browserify灵活
- wreq,Browserify的前身
10.4、AMD
Asynchronous Module Definition规范其实主要一个主要接口define(id?,dependencies?,factory);它要在声明模块的时候指定所有的依赖dependencies,并且还要当做形参传到factory中,对于依赖的模块提前执行。
define("module",["dep1","dep2"],functian(d1,d2){
return someExportedValue;
});
require(["module","../file.js"],function(module,file){});
优点
- 适合在浏览器环境中异步加载模块
- 可以并行加载多个模块
缺点
- 提高了开发成本,代码的阅读和书写比较困难,模块定义方式的语义不畅
- 不符合通用的模块化思维方式,是一种妥协的实现
实现
- RequireJS
- curl
10.5、CMD
Commons Module Definition规范和AMD很相似,尽保持简单,并与CommonsJS和NodeJS的Modules规范保持了很大的兼容性。
define(function(require,exports,module){
var $=require("jquery");
var Spinning = require("./spinning");
exports.doSomething = ...;
module.exports=...;
});
优点:
- 依赖就近,延迟执行
- 可以很容易在NodeJS中运行
缺点
- 依赖
SPM
打包,模块的加载逻辑偏重
实现
- Sea.js
- coolie
10.6、ES6模块
EcmaScript 6标准增加了JavaScript语言层面的模块体系定义。ES 6模块的设计思想, 是尽量静态化, 使编译时就能确定模块的依赖关系, 以及输入和输出的变量。Commons JS和AMD模块,都只能在运行时确定这些东西。
import "jquery"
export function doStuff(){}
module "localModule"{}
优点
-
容易进行静态分析
-
面向未来的Ecma Script标准
缺点
-
原生浏览器端还没有实现该标准
-
全新的命令,新版的Node JS才支持
实现
- Babel
希望的模块
系统可以兼容多种模块风格, 尽量可以利用已有的代码, 不仅仅只是JavaScript模块化, 还有CSS、图片、字体等资源也需要模块化。
10.7、安装Webpack
WebPack是一款模块加载器兼打包工具
, 它能把各种资源, 如JS、JSX、ES 6、SASS、LESS、图片等都作为模块来处理和使用。
安装命令:
npm install webpack -g
npm install webpack-cli -g
测试安装成功: 输入以下命令有版本号输出即为安装成功
webpack -v
webpack-cli -v
10.8、使用webpack
-
新建一个文件夹 然后使用iidea打开
-
创建一个modules包,在创建hello.js、hello.js暴漏接口 相当于java中的类
//暴漏一个方法 exports.sayHi = function(){ document.write("<h1>hello ES6</h1>"); }
-
创建main.js把他当作js的主入口,main.js请求hello.js调用sayHi( )方法
var hello = require("./hello"); hello.sayHi();
-
在主目录创建webpack-config.js , webpack-config.js 这个相当于webpack的配置文件
enrty请求main.js的文件
output是输出的位置和名字
module.exports = { entry: './modules/main.js', output: { filename: "./js/bundel.js" } }
-
在idea命令台输入webpack命令(idea要设置管理员启动)
-
完成上述操作之后会在主目录生成一个dist文件 生成的js文件夹路径为/ dist/js/bundle.js
-
在主目录创建index.html 导入bundle.js
index.html:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--前端的模块开发--> <script src="./dist/js/bundel.js"></script> </body> </html>
文件结构:
webpack就是一个打包工具
,打包,从哪个地方选择一个入口,自动帮你把这个入口里面它所需要的所有东西全部通过它的方式打包起来,运行。
11、Vue-router路由
Vue Router是Vue.js官方的路由管理器。它和Vue.js的核心深度集成, 让构建单页面应用变得易如反掌。包含的功能有:
- 嵌套的路由/视图表
- 模块化的、基于组件的路由配置
- 路由参数、查询、通配符
- 基于Vue js过渡系统的视图过渡效果
- 细粒度的导航控制
- 带有自动激活的CSS class的链接
- HTML5 历史模式或hash模式, 在IE 9中自动降级
- 自定义的滚动行为
安装命令:
npm install vue-router --save-dev
安装完之后z在node_modules
文件夹搜索看看是否有vue-router信息 有的话则表明安装成功。
实例:
-
将之前的vue-cli生成的项目打开
-
清理不需要的东西包括assert目录下的logo和component定义的helloweld组件
-
清理调用清除掉文件的代码
index.html
<!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> <!-- built files will be auto injected --> </body> </html>
main.js
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import VueRouter from 'vue-router' Vue.config.productionTip = false Vue.use(VueRouter); /* eslint-disable no-new */ new Vue({ el: '#app', components: { App }, template: '<App/>' })
App.vue
<template> <div id="app"> <h1>vue-router</h1> </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>
不能运行可能是这里报错的先用cnpm install vue-router@3.1.3 --save-dev命令再运行,因为可能是router版本太高了
-
创建两个vue页面
Content:
<template> <h1>内容页</h1> </template> <script> export default { name: "Content" } </script> <style scoped>/*scoped:只在当前页面生效*/ </style>
Main
<template> <h1>首页</h1> </template> <script> export default { name: "Main" } </script> <style scoped> </style>
-
在main.js中配置路由
import Vue from 'vue' import App from './App' import router from './router' Vue.config.productionTip = false Vue.use(router); /* eslint-disable no-new */ new Vue({ el: '#app', //配置路由 router, components: { App }, template: '<App/>' })
-
在App.vue中使用路由
<template> <div id="app"> <h1>vue-router</h1> <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> #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>
-
测试
项目结构:
12、vue + ElementUI
-
创建一个名为 hello-vue 的工程
vue init webpack hello-vue
-
安装依赖,我们需要安装
vue-router
、element-ui
、sass-loader
和node-sass
四个插件# 进入工程目录 cd hello-vue # 安装 vue-router npm install vue-router --save-dev # 安装 element-ui npm i element-ui -S # 安装依赖 npm install # 安装 SASS 加载器 cnpm install sass-loader node-sass --save-dev # 启动测试 npm run dev
-
Npm命令解释
- npm install moduleName:安装模块到项目目录下
- npm install -g moduleName:-g 的意思是将模块安装到全局,具体安装到磁盘的哪个位置,要看 npm config prefix的位置
- npm install moduleName -save:–save的意思是将模块安装到项目目录下,并在package文件的dependencies节点写入依赖,-S为该命令的缩写
- npm install moduleName -save-dev:–save-dev的意思是将模块安装到项目目录下,并在package文件的devDependencies节点写入依赖,-D为该命令的缩写
-
创建成功后用idea打开,并删除净东西 创建views和router文件夹用来存放视图和路由
-
在views创建Main.vue
<template> <h1>首页</h1> </template> <script> export default { name: "Main" } </script> <style scoped> </style>
-
在views中创建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: '' }, // 表单验证,需要在 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; } }); }, handleClose(){ } } } </script> <style lang="scss" scoped> .login-box { border: 1px solid #DCDFE6; width: 350px; margin: 180px auto; padding: 35px 35px 15px 35px; border-radius: 5px; -webkit-border-radius: 5px; -moz-border-radius: 5px; box-shadow: 0 0 25px #909399; } .login-title { text-align: center; margin: 0 auto 40px auto; color: #303133; } </style>
-
创建路由
在 router 目录下创建一个名为 index.js 的 vue-router 路由配置文件
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 } ] });
-
在main.js中配置相关
main.js是index.html调用的 所以前面注册的组件要在这里导入
import Vue, {h} from 'vue' import App from './App' import router from "./router"; //导入elementui import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; Vue.use(router); Vue.use(ElementUI) /* eslint-disable no-new */ new Vue({ el: '#app', router, render: h => h(App) })
-
在App.vue中配置显示视图
<template> <div id="app"> <router-link to="/login">login</router-link> <router-view></router-view> </div> </template> <script> export default { name: 'App', components: { } } </script>
-
测试运行
npm run dev
实现效果:
-
可能碰到的错误
-
export default (imported as Router ) was not found in vue-router:
原因:sass-loader和npm-sass版本不匹配
解决方式:更改版本为:
"node-sass": "^6.0.1", "sass-loader": "^7.3.1",
-
"export ‘default’ (imported as ‘Router’) was not found in ‘vue-router’
原因:router版本过高
解决方式:执行cnpm install vue-router@3.1.3 --save-dev命令
-
13、嵌套路由
嵌套路由又称子路由,在实际应用中,通常由多层嵌套的组件组合而成。同样地,URL中各段动态路径也按某种结构对应嵌套的各层组件,例如:
-
修改首页视图,我们修改 Main.vue 视图组件,此处使用了 ElementUI 布局容器组件,代码如下:
-
<template> <div> <el-container> <el-aside width="200px"> <el-menu :default-openeds="['1']"> <el-submenu index="1"> <template slot="title"><i class="el-icon-caret-right"></i>用户管理</template> <el-menu-item-group> <el-menu-item index="1-1"> <!--插入的地方--> <router-link to="/user/profile">个人信息</router-link> </el-menu-item> <el-menu-item index="1-2"> <!--插入的地方--> <router-link to="/user/list">用户列表</router-link> </el-menu-item> </el-menu-item-group> </el-submenu> <el-submenu index="2"> <template slot="title"><i class="el-icon-caret-right"></i>内容管理</template> <el-menu-item-group> <el-menu-item index="2-1">分类管理</el-menu-item> <el-menu-item index="2-2">内容列表</el-menu-item> </el-menu-item-group> </el-submenu> <el-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: #68e049; color: #343; line-height: 60px; } .el-aside { color: #333; } </style>
-
创建用户信息组件,在 views/user 目录下创建一个名为 Profile.vue 的视图组件;
<template> <h1>个人信息</h1> </template> <script> export default { name: "UserProfile" } </script> <style scoped> </style>
-
在用户列表组件在 views/user 目录下创建一个名为 List.vue 的视图组件;
<template> <h1>用户列表</h1> </template> <script> export default { name: "UserList" } </script> <style scoped> </style>
-
配置嵌套路由修改 router 目录下的 index.js 路由配置文件,使用children放入main中写入子模块,代码如下
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/list', component: UserList }, { path: '/user/profile', component: UserProfile } ] }, { path: '/login', component: Login, } ] });
-
路由嵌套效果图
14、参数传递
-
前端传递参数
<!--插入的地方 name 传组件名 params传递参数,需要对象:(v-bind) == (:to)--> <router-link :to="{name: 'UserProfile',params:{id:1}}">个人信息</router-link>
-
修改路由配置,增加props:true属性
{ path: '/user/profile/:id', name:'UserProfile', component: UserProfile, props: true }
-
前端显示
<template> <div> <h1>个人信息</h1> {{$route.params.id}} <!-- 使用pops--> {{id}} </div> </template> <script> export default { props: ['id','name','age'], name: "UserProfile", } </script> <style scoped> </style>
测试效果:
-
重定向
-
在router下面index.js的配置
{ path: '/goHome', redirect: '/main' }
-
Main.vue设置对应路径即可;
<el-menu-item index="1-3"> <!--插入的地方--> <router-link to="/goHome">回到首页</router-link> </el-menu-item>
-
15、路由模式与404
15.1、路由模式
- hash:路径
带#
符号,比如http://localhost/#/login - history:路径
不带 #
符号,比如http://localhost/login
如果需要路由模式不带#只需要在main.js中添加mode属性为history:
15.2、404
-
创建一个404页面NotFound.vue视图组件
<template> <div> <h1>404</h1> </div> </template> <script> export default { name: "NotFound" } </script> <style scoped> </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/list', component: UserList }, { path: '/user/profile/:id', name:'UserProfile', component: UserProfile, props: true } ] },{ path: '/login/', component: Login, },{ path: '/goHome', redirect: '/main' },{ path: '*', component:NotFound } ] });
15.3、路由钩子
beforeRouteEnter
:在进入路由前执行
beforeRouteLeave
:在离开路由前执行
在Profile.vue中写::
<template>
<div>
<h1>个人信息</h1>
{{$route.params.id}}
<!-- 使用pops-->
{{id}}
</div>
</template>
<script>
export default {
props: ['id','name','age'],
name: "UserProfile",
beforeRouteEnter: (to,from,next)=>{
console.log("进入路由之前"),
next();
},
beforeRouteLeave:(to,from,next)=>{
console.log("进入路由之后"),
next();
}
}
</script>
<style scoped>
</style>
参数说明:
- to:路由将要跳转的路径信息
- from:路径跳转前的路径信息
- next:路由的控制参数
- next() 跳入下一个页面
- next(’/path’) 改变路由的跳转方向,使其跳到另一个路由
- next(false) 返回原来的页面
- next((vm)=>{}) 仅在 beforeRouteEnter 中可用,vm 是组件实例
15.4、在钩子函数中使用异步请求
-
安装Axios
npm install --save vue-axios
-
mian.js中引用Axios
import axios from 'axios' import VueAxios from 'vue-axios' Vue.use(VueAxios, axios)
-
准备数据:只有static 目录下的文件是可以被访问到的,所以我们就把静态文件放入该目录下。
数据和之前用的json数据一样 需要的去上述axios例子里访问:http://localhost:8080/static/mock/data.json得到json中的数据
-
在 beforeRouteEnter 中进行异步请求
<script> export default { props: ['id','name','age'], name: "UserProfile", //相当于过滤器 beforeRouteEnter: (to,from,next)=>{ console.log("进入路由之前"),//加载数据 next(vm =>{ vm.getData();//进入路由之前执行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) }) } } } </script>
-
测试
效果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ySOP7x4k-1678171482858)(E:\笔记\typora-user-images\image-20230307143118173.png)]
-
可能碰到的报错
To install it, you can run: npm install --save axios
解决方式:cnpm install --save axios然后在运行
**参数说明:**
- to:路由将要跳转的路径信息
- from:路径跳转前的路径信息
- next:路由的控制参数
- next() 跳入下一个页面
- next(’/path’) 改变路由的跳转方向,使其跳到另一个路由
- next(false) 返回原来的页面
- next((vm)=>{}) 仅在 beforeRouteEnter 中可用,vm 是组件实例
### 15.4、在钩子函数中使用异步请求
1. 安装Axios
```a
npm install --save vue-axios
-
mian.js中引用Axios
import axios from 'axios' import VueAxios from 'vue-axios' Vue.use(VueAxios, axios)
-
准备数据:只有static 目录下的文件是可以被访问到的,所以我们就把静态文件放入该目录下。
数据和之前用的json数据一样 需要的去上述axios例子里访问:http://localhost:8080/static/mock/data.json得到json中的数据
-
在 beforeRouteEnter 中进行异步请求
<script> export default { props: ['id','name','age'], name: "UserProfile", //相当于过滤器 beforeRouteEnter: (to,from,next)=>{ console.log("进入路由之前"),//加载数据 next(vm =>{ vm.getData();//进入路由之前执行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) }) } } } </script>
-
测试
效果:
-
可能碰到的报错
To install it, you can run: npm install --save axios
解决方式:cnpm install --save axios然后在运行