Soc原则:关注点分离原则
Vue 的核心库只关注视图层,方便与第三方库或既有项目整合。
HTML + CSS + JS : 视图 : 给用户看,刷新后台给的数据
网络通信 : axios
页面跳转 : vue-router
状态管理:vuex
Vue-UI : ICE , Element UI
CSS层叠样式表是一门标记语言,并不是编程语言,因此不可以自定义变量,不可以引用等,换句话说就是不具备任何语法支持,它主要缺陷如下:
什么是CSS预处理器?
CSS预处理器定义了一种新的语言,其基本思想是,用一种专门的编程语言,为CSS增加了一些编程的特性,将CSS作为目标生成文件,然后开发者就只需要使用这种语言进行CSS的编码工作。转化成通俗易懂的话来说就是“用一种专门的编程语言,进行Web页面样式设计,再通过编译器转化为正常的CSS文件,以供项目使用”。
常用的CSS预处理器有哪些?
JavaScript一门弱类型脚本语言,其源代码在发往客户端运行之前不需要经过编译,而是将文本格式的字符代码发送给浏览器,由浏览器解释运行。
JavaScript框架
MVVM(Model-View-ViewModel)是一种软件设计模式,由微软WPF(用于替代WinForm,以前就是用这个技术开发桌面应用程序的)和Silverlight(类似于Java Applet,简单点说就是在浏览器上运行WPF)的架构师Ken Cooper和Ted Peters开发,是一种简化用户界面的事件驱动编程方式。由John Gossman(同样也是WPF和Sliverlight的架构师)与2005年在他的博客上发表。
MVVM源自于经典的MVC(Model-View-Controller)模式。MVVM的核心是ViewModel层,负责转换Model中的数据对象来让数据变得更容易管理和使用。其作用如下:
MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大好处
(1)View
View是视图层, 也就是用户界面。前端主要由HTH L和csS来构建, 为了更方便地展现vi eu to del或者Hodel层的数据, 已经产生了各种各样的前后端模板语言, 比如FreeMarker,Thyme leaf等等, 各大MV VM框架如Vue.js.Angular JS, EJS等也都有自己用来构建用户界面的内置模板语言。
(2)Model
Model是指数据模型, 泛指后端进行的各种业务逻辑处理和数据操控, 主要围绕数据库系统展开。这里的难点主要在于需要和前端约定统一的接口规则
(3)ViewModel
ViewModel是由前端开发人员组织生成和维护的视图数据层。在这一层, 前端开发者对从后端获取的Model数据进行转换处理, 做二次封装, 以生成符合View层使用预期的视图数据模型。
需要注意的是View Model所封装出来的数据模型包括视图的状态和行为两部分, 而Model层的数据模型是只包含状态的
视图状态和行为都封装在了View Model里。这样的封装使得View Model可以完整地去描述View层。由于实现了双向绑定, View Model的内容会实时展现在View层, 这是激动人心的, 因为前端开发者再也不必低效又麻烦地通过操纵DOM去更新视图。
MVVM框架已经把最脏最累的一块做好了, 我们开发者只需要处理和维护View Model, 更新数据视图就会自动得到相应更新,真正实现事件驱动编程。
View层展现的不是Model层的数据, 而是ViewModel的数据, 由ViewModel负责与Model层交互, 这就完全解耦了View层和Model层, 这个解耦是至关重要的, 它是前后端分离方案实施的重要一环。
Vue(读音/vju/, 类似于view) 是一套用于构建用户界面的渐进式框架, 发布于2014年2月。与其它大型框架不同的是, Vue被设计为可以自底向上逐层应用。Vue的核心库只关注视图层, 不仅易于上手, 还便于与第三方库(如:vue-router,vue-resource,vue x) 或既有项目整合。
(1)MVVM模式的实现者
在MVVM架构中, 是不允许数据和视图直接通信的, 只能通过ViewModel来通信, 而View Model就是定义了一个Observer观察者
至此, 我们就明白了, Vue.js就是一个MV VM的实现者, 他的核心就是实现了DOM监听与数据绑定
(2)为什么要使用Vue.js
【说明】IDEA可以安装Vue的插件!
注意:Vue不支持IE 8及以下版本, 因为Vue使用了IE 8无法模拟的ECMAScript 5特性。但它支持所有兼容ECMAScript 5的浏览器。
(1)下载地址
<script src=“https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js”></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
(2)代码编写
Vue.js的核心是实现了MVVM模式, 她扮演的角色就是View Model层, 那么所谓的第一个应用程序就是展示她的数据绑定功能,操作流程如下:
1、创建一个HTML文件
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
body>
html>
2、引入Vue.js
<script
src="https://cdn.bootcss.com/vue/2.5.2/vue.min.js">script>
3、创建一个Vue实例
<div id="app">
{{message}}
div>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
/*Model:数据*/
data:{
message:"hello,vue!"
}
});
script>
说明:
el: '#app'
:绑定元素的IDdata:{message:'Hello Vue!'}
:数据对象中有一个名为message的属性,并设置了初始值 Hello Vue!4、将数据绑定到页面元素
<div id="app">
{{message}}
div>
说明:只需要在绑定的元素中使用双花括号将Vue创建的名为message属性包裹起来, 即可实现数据绑定功能, 也就实现了View Model层所需的效果, 是不是和EL表达式非常像?
(3)完整的HTML
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
{{message}}
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
/*Model:数据*/
data:{
message:"hello,vue!"
}
});
script>
body>
html>
(4)测试
为了能够更直观的体验Vue带来的数据绑定功能, 我们需要在浏览器测试一番, 操作流程如下:
1、在浏览器上运行第一个Vue应用程序,F12 进入开发者工具
2、在控制台输入vm.message=‘HelloWorld’, 然后回车, 你会发现浏览器中显示的内容会直接变成HelloWorld
此时就可以在控制台直接输入vm.message来修改值, 中间是可以省略data的, 在这个操作中, 我并没有主动操作DOM, 就让页面的内容发生了变化, 这就是借助了Vue的数据绑定功能实现的; MV VM模式中要求View Model层就是使用观察者模式来实现数据的监听与绑定, 以做到数据与视图的快速响应。
Vue官方文档: https://cn.vuejs.org/v2/guide/.
我们已经成功创建了第一个Vue应用!看起来这跟渲染一个字符串模板非常类似, 但是Vue在背后做了大量工作。现在数据和DOM已经被建立了关联, 所有东西都是响应式的。我们在控制台操作对象属性,界面可以实时更新!
我们还可以使用v-bind来绑定元素特性!
上代码
鼠标悬停几秒查看此处动态绑定的提示信息
你看到的v-bind等被称为指令。指令带有前缀v以表示它们是Vue提供的特殊特性。可能你已经猜到了, 它们会在渲染的DOM上应用特殊的响应式行为在这里,该指令的意思是:“将这个元素节点的title特性和Vue实例的message属性保持一致”。
如果你再次打开浏览器的JavaScript控制台, 输入app, message=‘新消息’,就会再一次看到这个绑定了title特性的HTML已经进行了更新。
什么是条件判断语句,就不需要我说明了吧,以下两个属性!
v-if
v-else
上代码
DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<h2 v-if="ok">Yesh2>
<h2 v-else>Noh2>
div>
<script src="https://cdn.bootcss.com/vue/2.5.2/vue.min.js">script>
<script>
var vm=new Vue({
el: "#app",
data:{
ok: true
}
})
script>
body>
html>
测试:
1.在浏览器上运行,打开控制台!
2.在控制台输入vm.ok=false
然后回车,你会发现浏览器中显示的内容会直接变成NO
注:使用v-*
属性绑定数据是不需要双花括号包裹的
v-else-if
===
三个等号在JS中表示绝对等于(就是数据与类型都要相等)==
只要数据相等,类型可以不相等<body>
<div id="app">
<h1 v-if="type==='a'">Ah1>
<h1 v-else-if="type==='b'">Bh1>
<h1 v-else>Ch1>
div>
<script src="https://cdn.bootcss.com/vue/2.5.2/vue.min.js">script>
<script>
var vm=new Vue ({
el:"#app", //绑定标签
data:{ //数据模板
type: "a"
}
});
script>
body>
测试:
在控制台输入vm.type='b'
,页面显示B,证明不涉及类型是==
也能判断,但最好使用===
{{item.message}}---{{index}}
注:items
是数组,item
是数组元素迭代的别名。我们之后学习的Thymeleaf模板引擎的语法和这个十分的相似!
测试:在控制台输入vm.items.push({message: "狂神前端2"})
,尝试追加一条数据,你会发现浏览器中显示的内容会增加一条狂神前端2---2
v-on
监听事件
事件有Vue的事件、和前端页面本身的一些事件!我们这里的click是vue的事件, 可以绑定到Vue中的methods
中的方法事件!
上代码:
Vue.js是一个MV VM框架, 即数据双向绑定, 即当数据发生变化的时候, 视图也就发生变化, 当视图发生变化的时候,数据也会跟着同步变化。这也算是Vue.js的精髓之处了。
值得注意的是,我们所说的数据双向绑定,一定是对于UI控件来说的非UI控件不会涉及到数据双向绑定。单向数据绑定是使用状态管理工具的前提。如果我们使用vue x那么数据流也是单项的,这时就会和双向数据绑定有冲突。
(1)为什么要实现数据的双向绑定
在Vue.js
中,如果使用vuex
, 实际上数据还是单向的, 之所以说是数据双向绑定,这是用的UI控件来说, 对于我们处理表单, Vue.js
的双向数据绑定用起来就特别舒服了。即两者并不互斥,在全局性数据流使用单项,方便跟踪;局部性数据流使用双向,简单易操作。
你可以用v-model
指令在表单、及元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇, 但v-model
本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
注意:v-model
会忽略所有表单元素的value
、checked
、selected
特性的初始值而总是将Vue实例的数据作为数据来源。你应该通过JavaScript在组件的data选项中声明初始值!
Title
input 输入的文本:
{{message}}
textarea 输入的文本:
{{message}}
男
女
单选框选中了谁:{{AA}}
下拉框:
下拉框选择了:{{BB}}
注意:v-model
表达式的初始值未能匹配任何选项,元素将被渲染为“未选中”状态。 在iOS中, 这会使用户无法选择第一个选项,因为这样的情况下,iOS不会触发change
事件。因此,更推荐像上面这样提供一个值为空的禁用选项
组件是可复用的Vue
实例, 说白了就是一组可以重复使用的模板, 跟JSTL
的自定义标签、Thymeleal
的th:fragment
等框架有着异曲同工之妙,通常一个应用会以一棵嵌套的组件树的形式来组织:
例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。
(1)第一个Vue组件
注意:在实际开发中,我们并不会用以下方式开发组件,而是采用vue-cli创建,vue模板文件的方式开发,以下方法只是为了让大家理解什么是组件。
使用Vue.component()
方法注册组件,格式如下:
说明:
(2)使用props属性传递参数
像上面那样用组件没有任何意义,所以我们是需要传递参数到组件的,此时就需要使用props
属性了!
注意:默认规则下props属性里的值不能为大写;例:CP
,而Cp
可以
------------------------
v-for="item in items"
:遍历Vue实例中定义的名为items的数组,并创建同等数量的组件
v-bind:shuxing="item"
:将遍历的item
项绑定到组件中定义的名为shuxing
属性上;= 号左边的shuxing
为props
定义的属性名
Axios是一个开源的可以用在浏览器端和Node JS的异步通信框架, 她的主要作用就是实现AJAX异步通信,其功能特点如下:
GitHub:https://github.com/axios/axios
中文文档:http://www.axios-js.com/
由于Vue.js
是一个视图层框架并且作者(尤雨溪) 严格准守SoC(关注度分离原则)所以Vue.js
并不包含AJAX的通信功能, 为了解决通信问题, 作者单独开发了一个名为vue-resource
的插件, 不过在进入2.0版本以后停止了对该插件的维护并推荐了Axios
框架。少用jQuery, 因为它操作Dom太频繁!
咱们开发的接口大部分都是采用JSON格式, 可以先在项目里模拟一段JSON数据, 数据内容如下:创建一个名为data.json的文件并填入上面的内容, 放在项目的根目录下
{
"name": "狂神说Java",
"url": "https://blog.kuangstudy.com",
"page": 1,
"isNonProfit": true,
"address": {
"street": "含光门",
"city": "陕西西安",
"country": "中国"
},
"links": [
{
"name": "bilibili",
"url": "https://space.bilibili.com/95256449"
},
{
"name": "狂神说Java",
"url": "https://blog.kuangstudy.com"
},
{
"name": "百度",
"url": "https://www.baidu.com/"
}
]
}
测试代码
Title
名字:{{info.name}}
url:{{info.url}}
地址:{{info.address.street}}--{{info.address.city}}--{{info.address.country}}
links:{{link}}--{{index}}--{{link.name}}
链接:{{info.url}}
说明:
Vue实例有一个完整的生命周期,也就是从开始创建初始化数据、编译模板、挂载DOM、渲染一更新一渲染、卸载等一系列过程,我们称这是Vue的生命周期。通俗说就是Vue实例从创建到销毁的过程,就是生命周期。
在Vue的整个生命周期中,它提供了一系列的事件,可以让我们在事件触发时注册JS方法,可以让我们用自己注册的JS方法控制整个大局,在这些事件响应方法中的this直接指向的是Vue的实例。
1.初始化阶段
beforeCreated
执行时所有的data和methods中的数据都没有初始化。created
执行时,data和methods数据已经初始化好了,所以想操作data和methods中最早只能在created中。beforeMount
时,尚未挂载到界面中,界面还是旧的(Vue的白屏)。Mounted
阶段,组件已挂载,整个Vue实例已经初始化完毕。(created和Mounted操作数据的区别:beforeCreated阶段,界面没挂载,不能操作DOM节点,而Mounted阶段,界面已挂载,随便操作)2.更新阶段
beforeUpdate
,此时data是最新的,但是界面还没有与data同步,updated
执行时,界面已经是最新的,data和界面已经同步。3.销毁阶段
计算属性的重点突出在属性
两个字上(属性是名词),首先它是个属性
其次这个属性有计算
的能力(计算是动词),这里的计算
就是个函数:简单点说,它就是一个能够将计算结果缓存起来的属性(将行为转化成了静态的属性),仅此而已;可以想象为缓存!
上代码
currentTime1:{{currentTime1()}}
currentTime1:{{currentTime2}}
注意:methods和computed里的东西不能重名
说明:
结论:
调用方法时,每次都需要讲行计算,既然有计算过程则必定产生系统开销,那如果这个结果是不经常变化的呢?此时就可以考虑将这个结果缓存起来,采用计算属性可以很方便的做到这点,计算属性的主要特性就是为了将不经常变化的计算结果进行缓存,以节约我们的系统开销;
在Vue.js
中我们使用
元素作为承载分发内容的出口,作者称其为插槽,可以应用在组合组件的场景中;
测试
比如准备制作一个待办事项组件(todo) , 该组件由待办标题(todo-title) 和待办内容(todo-items)组成,但这三个组件又是相互独立的,该如何操作呢?
第一步定义一个待办事项的组件
真实的模板里的值不会像这样是写死了,所以需要一个东西替代,使用插槽
,修改如下。
Vue.component("todo",{
template:'<div>' +
'<slot>slot>' +
'<ul>' +
'<slot>slot>' +
'ul>' +
'div>'
});
第二步定义一个待办标题组件和一个待办内容组件
创建一个待办标题组件和待办内容组件,使用插槽的name
绑定对应组件。
<body>
<div id="app">
<todo>
<todo-title slot="todo-title">todo-title>
<todo-items slot="todo-items">todo-items>
todo>
div>
<script src="https://cdn.bootcss.com/vue/2.5.2/vue.min.js">script>
<script>
//待办事项组件
Vue.component("todo",{
template:'' +
' ' +
''
+
' ' +
'' +
''
});
//待办标题组件
Vue.component("todo-title",{
props:['td-title'],
template:'{{td-title}}'
})
//待办内容组件
Vue.component("todo-items",{
props:['td-items'],
template:'{{td-items}} '
})
var app = new Vue({
el: '#app'
})
script>
body>
第三步定义一个Vue实例并传入数据,使前台界面可以显示
<body>
<div id="app">
<todo>
<todo-title slot="todo-title" :ttitle="title">todo-title>
<todo-items slot="todo-items" v-for="item in items" :titems="item">todo-items>
todo>
div>
<script src="https://cdn.bootcss.com/vue/2.5.2/vue.min.js">script>
<script>
var app = new Vue({
el: '#app',
data:{
title:"待办标题",
items:['待办事项1','待办事项2','待办事项3']
}
})
script>
body>
总体代码如下:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<todo>
<todo-title slot="todo-title" :ttitle="title">todo-title>
<todo-items slot="todo-items" v-for="item in items" :titems="item">todo-items>
todo>
div>
<script src="https://cdn.bootcss.com/vue/2.5.2/vue.min.js">script>
<script>
//待办事项组件
Vue.component("todo",{
template:'' +
' ' +
''
+
' ' +
'' +
''
});
//待办标题组件
Vue.component("todo-title",{
props:['ttitle'],
template:'{{ttitle}}'
})
//待办内容组件
Vue.component("todo-items",{
props:['titems'],
template:'{{titems}} '
})
var app = new Vue({
el: '#app',
data:{
title:"待办标题",
items:['待办事项1','待办事项2','待办事项3']
}
})
script>
body>
html>
总结:
代替。name
进行绑定。slot
属性绑定组件<todo-title slot="todo-title">todo-title>
data
中拿到模拟数据,然后通过绑定属性ttitle
和titems
传递,组件使用props
接收数据,并动态改变,所有数据都改变后就实现了插槽的动态拔插。注意:
:ttitle="title"
等价于v-bind:ttitle="title"
,是v-bind的简写。
@click="remove"
等价于v-on:click="remove"
,是v-on的简写。
组件的属性不能写成td-title
,这样会报错,写成ttitle
就没问题。
通以上代码不难发现,数据项在Vue的实例中, 但删除操作要在组件中完成, 那么组件如何才能删除Vue实例中的数据呢?此时就涉及到参数传递与事件分发了, Vue为我们提供了自定义事件的功能很好的帮助我们解决了这个问题; 使用this.$emit(‘自定义事件名’, 参数)
, 操作过程如下:
1.在vue的实例中增加了methods对象并定义了一个名为removeItems的方法
<script>
var app = new Vue({
el: '#app',
data:{
title:"待办标题",
items:['待办事项1','待办事项2','待办事项3']
},
methods:{
removeItems:function(index){
console.log("删除了"+this.items[index]+"OK");
//splice(2,2) 是从第二个开始删两个
//splice(2,2,"张三",'李四') 从第二个开始删两个,然后添加"张三","李四"
this.items.splice(index,1);
}
}
})
script>
2.修改todo-items待办内容组件的代码,增加一个删除按钮,并且绑定事件!
<script>
//待办内容组件
Vue.component("todo-items",{
props:['titems','tindex'],
template:'{{tindex}}--{{titems}} ',
methods:{
remove_method:function(index){
this.$emit("remove",index);
}
}
})
script>
3.修改todo-items待办内容组件的HTML代码,增加一个自定义事件,比如叫remove,可以和组件的方法绑定,然后绑定到vue的方法!
<todo-items slot="todo-items" v-for="(item,index) in items"
:titems="item" :tindex="index" v-on:remove="removeItems(index)" :key="index">todo-items>
完整代码如下:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<todo>
<todo-title slot="todo-title" :ttitle="title">todo-title>
<todo-items slot="todo-items" v-for="(item,index) in items"
:titems="item" :tindex="index" v-on:remove="removeItems(index)" :key="index">todo-items>
todo>
div>
<script src="https://cdn.bootcss.com/vue/2.5.2/vue.min.js">script>
<script>
//待办事项组件
Vue.component("todo",{
template:'' +
' ' +
''
+
' ' +
'' +
''
});
//待办标题组件
Vue.component("todo-title",{
props:['ttitle'],
template:'{{ttitle}}'
})
//待办内容组件
Vue.component("todo-items",{
props:['titems','tindex'],
template:'{{tindex}}--{{titems}} ',
methods:{
remove_method:function(index){
this.$emit("remove",index);
}
}
})
var app = new Vue({
el: '#app',
data:{
title:"待办标题",
items:['待办事项1','待办事项2','待办事项3']
},
methods:{
removeItems:function(index){
console.log("删除了"+this.items[index]+"OK");
//splice(2,2) 是从第二个开始删两个
//splice(2,2,"张三",'李四') 从第二个开始删两个,然后添加"张三","李四"
this.items.splice(index,1);
}
}
})
script>
body>
html>
核心:数据驱动,组件化
优点:借鉴了AngularJS的模块化开发和React的虚拟Dom,虚拟Dom就是把Demo操作放到内存中执行;
常用的属性:
组件化:
遵循SoC关注度分离原则,Vue是纯粹的视图框架,并不包含,比如Ajax之类的通信功能,为了解决通信问题,我们需要使用Axios框架做异步通信;
说明
Vue的开发都是要基于NodeJS,实际开发采用Vue-cli脚手架开发,vue-router路由,vuex做状态管理;Vue UI,界面我们一般使用ElementUI(饿了么出品),或者ICE(阿里巴巴出品)来快速搭建前端项目~~
vue-cli官方提供的一个脚手架,用于快速生成一个vue的项目模板;
预先定义好的目录结构及基础代码,就好比咱们在创建Maven项目时可以选择创建一个骨架项目,这个估计项目就是脚手架,我们的开发更加的快速;
项目的功能
确认nodejs安装成功:
node -v
,查看是否能够正确打印出版本号即可!npm -v
,查看是否能够正确打印出版本号即可!那么什么是npm?
npm是JavaScript运行时环境Node.js的默认包管理器。他集成在了node.js
里,类似于maven的作用。
安装Node.js淘宝镜像加速器(cnpm)
# -g 就是全局安装(不推荐,容易卡死,非常慢)
npm install cnpm -g
# 使用淘宝镜像安装(推荐,速度很快)
npm install -g cnpm --registry=https://registry.npm.taobao.org
如果安装的不是淘宝镜像可能使用命令npm install安装项目所需要的所有依赖时候卡着不动的化可以修改镜像网址,步骤
1.显示当前的镜像网址 npm get registry
2.使用淘宝的镜像网址 npm config set registry http://registry.npm.taobao.org
3. 查看当前镜像是否修改成功 npm get registry
安装的位置:C:\Users\刘辉\AppData\Roaming\npm
安装vue-cli
#安装vue-cli命令
cnpm install vue-cli -g
#测试是否安装成功,查看可以基于哪些模板创建vue应用程序,通常我们选择webpack
vue list
20个文件下载完成代表 vue-cli安装成功
如果出现vue不是内部或外部命令,可以输入
npm install vue
试一下(这里我安装的有点乱,安装vue-cli前就执行了这个命令,没啥影响,出现问题可以尝试下) npm install vue
到此vue-cli
安装完成。
1.创建一个Vue项目,我们随便建立一个空的文件夹在电脑上,我这里在D盘下新建一个目录
D:\Program Files\JetBrains\workspace\vue-study
2.创建一个基于webpack模板的vue应用程序
#1、首先需要进入到对应的目录 cd D:\Project\vue-study
cd D:\Program Files\JetBrains\workspace\vue-study
#2、这里的myvue是顶日名称,可以根据自己的需求起名
vue init webpack myvue
然后会跳出一些选项让你选,一路都选择no即可。
说明:
始化并运行
# 进入myvue项目
cd myvue
# 安装项目所需要的所有依赖,可能卡死
npm install
# 启动项目
npm run dev
打开浏览器输入http://localhost:8080/
能显示画面即创建成功!
然后可以使用idea打开myvue项目,查看目录结构及代码。
详细目录结构可参考:: https://www.cnblogs.com/huangfeihong/p/9141273.html.
本质上, 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代码,这给前端的开发流程和资源组织带来了巨大挑战。
前端开发和其他开发工作的主要区别,首先是前端基于多语言、多层次的编码和组织工作,其次前端产品的交付是基于浏览器的,这些资源是通过增量加载的方式运行到浏览器端,如何在开发环境组织好这些碎片化的代码和资源,并且保证他们在浏览器端快速、优雅的加载和更新,就需要一个模块化系统,这个理想中的模块化系统是前端工程师多年来一直探索的难题。
Script标签
<script src = "module1.js">script>
<script src = "module2.js">script>
<script src = "module3.js">script>
这是最原始的JavaScript文件加载方式,如果把每一个文件看做是一个模块,那么他们的接口通常是暴露在全局作用域下,也就是定义在window对象中,不同模块的调用都是一个作用域。
这种原始的加载方式暴露了一些显而易见的弊端:
的书写顺序进行加载CommonsJS
服务器端的NodeJS遵循CommonsJS规范,该规范核心思想是允许模块通过require方法来同步加载所需依赖的其它模块,然后通过exports或module.exports来导出需要暴露的接口。
require("module");
require("../module.js");
export.doStuff = function(){};
module.exports = someValue;
优点:
缺点:
实现:
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){});
优点
缺点
实现
CMD
Commons Module Definition规范和AMD很相似,尽保持简单,并与CommonsJS和NodeJS的Modules规范保持了很大的兼容性。
define(function(require,exports,module){
var $=require("jquery");
var Spinning = require("./spinning");
exports.doSomething = ...;
module.exports=...;
});
优点:
实现
ES6模块
EcmaScript 6标准增加了JavaScript语言层面的模块体系定义。ES 6模块的设计思想, 是尽量静态化, 使编译时就能确定模块的依赖关系, 以及输入和输出的变量。Commons JS和AMD模块,都只能在运行时确定这些东西。
import "jquery"
export function doStuff(){}
module "localModule"{}
优点
缺点
实现
大家期望的模块
系统可以兼容多种模块风格, 尽量可以利用已有的代码, 不仅仅只是JavaScript模块化, 还有CSS、图片、字体等资源也需要模块化。
WebPack是一款模块加载器兼打包工具, 它能把各种资源, 如JS、JSX、ES 6、SASS、LESS、图片等都作为模块来处理和使用。
安装:
npm install webpack -g
npm install webpack-cli -g 客户端 两个都要安装
测试安装成功
webpack -v
webpack-cli -v
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ol428q1c-1640158731636)(C:\Users\刘辉\AppData\Roaming\Typora\typora-user-images\image-20211221201150835.png)]
配置
创建 webpack.config.js
配置文件
module.exports = {
entry:"",
output:{
path:"",
filename:""
},
module:{
loaders:[
{test:/\.js$/,;\loade:""}
]
},
plugins:{},
resolve:{},
watch:true
}
打包
在控制台直接运行webpack
命令进行打包。
1.创建一个空项目
2.创建一个名为modules的目录,用于放置JS模块等资源文件
3.在modules下创建模块文件,如hello.js,用于编写JS模块相关代码
//暴露一个方法:sayHi
exports.sayHi=function (){
document.write("Hello Webpack!!!");
}
4.在modules下创建一个名为main.js的入口文件,用于打包时设置entry属性
//require 导入一个模块,就可以调用这个模块中的方法了
var hello = require("./hello");
hello.sayHi();
5.在项目目录下创建webpack.config.js配置文件,配置入口和输出位置
module.exports = {
entry:"./modules/main.js",
output:{
filename:"./js/bundle.js"
}
}
6.控制台输入webpack
命令进行打包。
打包完成后会在工程下生成一个/dist/js/bundle.js
文件。
测试
1.工程下创建一个index.html,导入打包后生成的js文件
doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>狂神说Javatitle>
head>
<body>
<script src="dist/js/bundle.js">script>
body>
html>
2.打开浏览器即可看到效果
说明
# 参数--watch 用于监听变化
webpack --watch
执行此命令,修改js内容,会自动打包。
Vue Router是Vue.js官方的路由管理器。它和Vue.js的核心深度集成, 让构建单页面应用变得易如反掌。包含的功能有:
基于第一个vue-cli进行测试学习; 先查看node modules中是否存在vue-router
vue-router是一个插件包, 所以我们还是需要用npm/cnpm来进行安装的。打开命令行工具,进入你的项目目录,输入下面命令。
npm install vue-router --save-dev
如果在一个模块化工程中使用它,必须要通过Vue.use()明确地安装路由功能:
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter);//显示声明使用
1.将项目原有的组件删除
2.在components
目录下存放我们自己编写的组件Content.vue
,Main.vue
组件
Content.vue
组件
<template>
<div>
<h6>内容页------------h6>
div>
template>
<script>
export default {
name: "Content"
}
script>
Main.vue
组件
<template>
<div>
<h6>首页------------h6>
div>
template>
<script>
export default {
name: "Main"
}
script>
3.安装路由,在src目录下,新建一个router
文件夹,专门存放路由,在router文件夹下创建一个index.js
配置路由
//导入vue,类似于java的导包
import Vue from 'vue'
//导入vue-router
import Router from 'vue-router'
//导入自定义的组件
import Content from '../components/Content'
import Main from '../components/Main'
//安装路由
Vue.use(Router);
//配置路由
export default new Router({
routes:[
{
//路由路径
path: '/content',
//路由名称
name: 'Content',
//跳转到组件
component: Content
},{
//路由路径
path: '/main',
//路由名称
name: 'Main',
//跳转到组件
component: Main
}
]
})
注意:
routes
}),不能写错,写错不报错(巨坑)4.在App.vue
中使用路由
<template>
<div id="app">
<h1>Vue-Router</h1>
<!--
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>
5.在main.js
中配置路由
import Vue from 'vue'
import App from './App'
//导入上面创建的路由配置目录
//自动扫描里面的路由配置
import router from './router'
//关闭生产模式下给出的提示
Vue.config.productionTip = false
new Vue({
el: '#app',
//配置路由
router,
components: { App },
template: ' '
})
6.在控制台输入npm run dev
,然后打开浏览器输入http://localhost:8080测试
1.打开命令行,进入目录D:\Program Files\JetBrains\workspace\Vue
,然后cmd执行vue init webpack myvue-elementui
创建一个名为myvue-elementui的工程
2.安装依赖, 我们需要安装vue-router、element-ui、sass-loader和node-sass四个插件
#1.在一个文件夹内必须管理员启动黑窗口,进入文件夹目录
vue init webpack 项目名字
#2.进入工程目录 必须进入!!!
cd myvue-elementui
#3.安装vue-router
npm install vue-router --save-dev
#4.安装element-ui 2+版本
npm i element-ui -S
#5.安装所有其他依赖
npm install //如果这个用不了再使用 cnpm install
# 6.安装SASS加载器 安装了2个
cnpm install sass-loader node-sass --save-dev
#7.启功测试
npm run dev
3、Npm命令解释:
npm install moduleName
:安装模块到项目目录下npm install -g moduleName
:-g的意思是将模块安装到全局,具体安装到磁盘哪个位置要看npm config prefix的位置npm install -save moduleName
:–save的意思是将模块安装到项目目录下, 并在package文件的dependencies节点写入依赖,-S为该命令的缩写npm install -save-dev moduleName
:–save-dev的意思是将模块安装到项目目录下,并在package文件的devDependencies节点写入依赖,-D为该命令的缩写删掉原有的组件并在src下创建如下结构:
创建首页视图,在views目录下创建一个名为Main.vue的视图组件:
<template>
<h1> 首页h1>
template>
<script>
export default {
name: "Main"
}
script>
<style scoped>
style>
创建登录页视图在views目录下创建名为Login.vue的视图组件,其中el-*的元素为ElementUI组件;
<template>
<div>
<el-form ref="loginForm" :model="form" :rules="rules" label-width="80px" class="login-box">
<h3 class="login-title">欢迎登录h3>
<el-form-item label="账号" prop="username">
<el-input type="text" placeholder="请输入账号" v-model="form.username"/>
el-form-item>
<el-form-item label="密码" prop="password">
<el-input type="password" placeholder="请输入密码" v-model="form.password"/>
el-form-item>
<el-form-item>
<el-button type="primary" v-on:click="onSubmit('loginForm')">登录el-button>
el-form-item>
el-form>
<el-dialog title="温馨提示" :visible.sync="dialogVisiable" width="30%" :before-close="handleClose">
<span>请输入账号和密码span>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="dialogVisible = false">确定el-button>
span>
el-dialog>
div>
template>
<script>
export default {
name: "Login",
data(){
return{
form:{
username:'',
password:''
},
//表单验证,需要在 el-form-item 元素中增加prop属性
rules:{
username:[
{required:true,message:"账号不可为空",trigger:"blur"}
],
password:[
{required:true,message:"密码不可为空",tigger:"blur"}
]
},
//对话框显示和隐藏
dialogVisible:false
}
},
methods:{
onSubmit(formName){
//为表单绑定验证功能
this.$refs[formName].validate((valid)=>{
if(valid){
//使用vue-router路由到指定界面,该方式称为编程式导航
this.$router.push('/main');
}else{
this.dialogVisible=true;
return false;
}
});
}
}
}
script>
<style lang="scss" scoped>
.login-box{
border:1px solid #DCDFE6;
width: 350px;
margin:180px auto;
padding: 35px 35px 15px 35px;
border-radius: 5px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
box-shadow: 0 0 25px #909399;
}
.login-title{
text-align:center;
margin: 0 auto 40px auto;
color: #303133;
}
style>
创建路由,在router目录下创建一个名为index.js的vue-router路由配置文件
//导入vue
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',
name: 'Main',
component: Main
},
{
//登录页
path: '/login',
name: 'Login',
component: Login
}
]
})
修改APP.vue
<template>
<div id="app">
<router-link to="/login">进入loginrouter-link>
<router-link to="/main">进入mainrouter-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>
修改main.js
import Vue 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)
new Vue({
el: '#app',
router,
render:h=>h(App)//ElementUI
})
然后测试,如出现错误可能是因为sass-loader的版本过高导致的编译错误,修改package.json内的版本
"sass-loader": "^7.3.1",
"node-sass": "^4.14.1",
可能会遇见的错误:
1.node版本过高,14以上版本,使用不了,关于如何降低node版本步骤:找到node版本安装目录删除所有文件,控制面板卸载node,再去重新下载低版本node即可。
2.(Module build failed: TypeError: this.getOptions is not a function ) ---sass-loader版本高了,应该改为
"sass-loader": "^7.3.1",
直接使用命令:npm install sass-loader@7.3.1 --save-dev 降低版本号
3.未解决,并且继续抛出异常(Node Sass version 5.0.0 is incompatible with ^4.0.0) 问题其实指明的很明显了,就是说@5.0.0版本过高了,需要换成@4.x版本的
"node-sass": "^4.14.1",
npm install node-sass@4.14.1 --save-dev
以上还要修改package.json文件中的版本与命令行版本一致后,再重新安装依赖可使用"npm install"或者"cnpm install"后者是淘宝镜像比较快,再执行 npm run dev 跑项目,在浏览器查看
嵌套路由又称子路由,在实际应用中,通常由多层嵌套的组件组合而成。
1、 创建用户信息组件,在 views/main目录下创建一个名为 Profile.vue 的视图组件;Profile.vue
<template>
<h1>个人信息h1>
template>
<script>
export default {
name: "UserProfile"
}
script>
2、在用户列表组件在 views/main 目录下创建一个名为 List.vue 的视图组件;
List.vue
<template>
<h1>用戶列表h1>
template>
<script>
export default {
name: "UserList"
}
script>
3、 修改首页视图,我们修改 Main.vue 视图组件,此处使用了 ElementUI 布局容器组件,代码如下:
Main.vue
<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="/main/profile">个人信息router-link>
el-menu-item>
<el-menu-item index="1-2">
<router-link to="/main/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="3">
<template slot="title"><i class="el-icon-caret-right">i>系统管理template>
<el-menu-item-group>
<el-menu-item index="3-1">分类管理el-menu-item>
<el-menu-item index="3-2">内容列表el-menu-item>
el-menu-item-group>
el-submenu>
el-menu>
el-aside>
<el-container>
<el-header style="text-align: right; font-size: 12px">
<el-dropdown>
<i class="el-icon-setting" style="margin-right: 15px">i>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>个人信息el-dropdown-item>
<el-dropdown-item>退出登录el-dropdown-item>
el-dropdown-menu>
el-dropdown>
el-header>
<el-main>
<router-view />
el-main>
el-container>
el-container>
div>
template>
<script>
export default {
name: "Main"
}
script>
<style scoped lang="scss">
.el-header {
background-color: #B3C0D1;
color: #333;
line-height: 60px;
}
.el-aside {
color: #333;
}
style>
4、 配置嵌套路由修改 router 目录下的 index.js 路由配置文件,使用children放入main中写入子模块,代码如下
index.js
//导入vue
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: 'Main',
component: Main,//嵌套路由
children:[
{
path:'/main/profile',component: UserProfile,
},
{
path:'/main/list',component: UserList,
}
]
},
{
//登录页
path: '/login',
name: 'Login',
component: Login,
}
]
})
5.运行测试
用的还是上述例子的代码 修改一些代码 这里不放重复的代码了
第一种传递方式
1、 修改路由配置, 主要是router下的index.js中的 path 属性中增加了 :id 这样的占位符
1、 修改路由配置, 主要是router下的index.js中的 path 属性中增加了 :id 这样的占
{
path: 'profile/:id', // 或者 path: '/main/profile/:id'
name: 'UserProfile',
component: UserProfile,
}
2、传递参数
此时我们在Main.vue中的route-link位置处 to 改为了 :to,是为了将这一属性当成对象使用,注意 router-link 中的 name 属性名称 一定要和 路由中的 name 属性名称 匹配,因为这样 Vue 才能找到对应的路由路径;
<router-link :to="{name:'UserProfile',params:{id: 1}}">个人信息router-link>
##或者:
<router-link v-bind:to="{name:'/main/profile',params:{id:1}}">个人信息router-link>
3、在要展示的组件Profile.vue中接收参数 使用 {{$route.params.id}}来接收
Profile.vue 部分代码
<template>
<div>
<h1>个人信息h1>
{{$route.params.id}}
div>
template>
第二种传递方式
使用props 减少耦合
1、修改路由配置 , 主要在router下的index.js中的路由属性中增加了 props: true 属性
{
path: 'profile/:id',// path: '/main/profile'
name: 'UserProfile',
component: UserProfile,
props: true
}
2、传递参数和之前一样 在Main.vue中修改route-link地址
<router-link :to="{name:'UserProfile',params:{id: 1}}">个人信息router-link>
3、在Profile.vue接收参数为目标组件增加 props 属性
Profile.vue
<template>
<div>
<h1>个人信息h1>
{{id}}
div>
template>
<script>
export default {
props:['id'],
name: "UserProfile"
}
script>
重定向的意思大家都明白,但 Vue 中的重定向是作用在路径不同但组件相同的情况下,比如:
在router下面index.js的配置
{
//回到首页
path: '/goHome',
redirect: '/main'
}
说明:这里定义了两个路径,一个是 /main ,一个是 /goHome,其中 /goHome 重定向到了 /main 路径,由此可以看出重定向不需要定义组件;
使用的话,只需要在Main.vue设置对应路径即可;
<el-submenu index="3">
<template slot="title"><i class="el-icon-caret-right">i>系统管理template>
<el-menu-item-group>
<el-menu-item index="3-1"><router-link to="/goHome">回到首页router-link>el-menu-item>
el-menu-item-group>
el-submenu>
测试:先点击个人信息,再点击回到首页,观察地址栏,会重定向到/main
路由模式有两种
export default new Router({
mode: 'history',
routes: [
]
});
404 demo
1.创建一个NotFound.vue视图组件
NotFound.vue
<template>
<div>404 你的页面走丢了div>
template>
<script>
export default {
name: "NotFound"
}
script>
2.修改路由配置index.js
//导入vue
import Vue from 'vue';
import router from 'vue-router';
//导入组件
import Main from '../views/Main';
import Login from '../views/Login';
import NotFound from '../views/NotFound';
//导入子模块
import UserProfile from '../views/main/Profile';
import UserList from '../views/main/List';
//使用路由
Vue.use(router);
//导出
export default new router({
mode: 'history',
routes:[
{
//首页
path: '/main',
name: 'Main',
component: Main,
children:[
{
path: 'profile/:id',// path: '/main/profile'
name: 'UserProfile',
component: UserProfile,
props: true
},
{
path: 'list',// path: '/main/list'
name: 'UserList',
component: UserList
}
]
},
{
//登录页
path: '/login',
name: 'Login',
component: Login
},
{
//回到首页
path: '/goHome',
redirect: '/main'
},
{
//404
path: '*',
component: NotFound
}
]
})
测试:地址栏输入不存在的路径,就跳到NotFound
组件
路由钩子与异步请求
beforeRouteEnter:在进入路由前执行
beforeRouteLeave:在离开路由前执行
在Profile.vue中写
export default {
name: "UserProfile",
beforeRouteEnter: (to, from, next) => {
console.log("准备进入个人信息页");
next();
},
beforeRouteLeave: (to, from, next) => {
console.log("准备离开个人信息页");
next();
}
}
参数说明:
to:路由将要跳转的路径信息
from:路径跳转前的路径信息
next:路由的控制参数
next() 跳入下一个页面
next(’/path’) 改变路由的跳转方向,使其跳到另一个路由
next(false) 返回原来的页面
next((vm)=>{}) 仅在 beforeRouteEnter 中可用,vm 是组件实例
路由钩子与异步请求
beforeRouteEnter:在进入路由前执行
beforeRouteLeave:在离开路由前执行
在Profile.vue中写
export default {
name: "UserProfile",
beforeRouteEnter: (to, from, next) => {
console.log("准备进入个人信息页");
next();
},
beforeRouteLeave: (to, from, next) => {
console.log("准备离开个人信息页");
next();
}
}
参数说明:
to:路由将要跳转的路径信息
from:路径跳转前的路径信息
next:路由的控制参数
next() 跳入下一个页面
next(’/path’) 改变路由的跳转方向,使其跳到另一个路由
next(false) 返回原来的页面
next((vm)=>{}) 仅在 beforeRouteEnter 中可用,vm 是组件实例
在钩子函数中使用异步请求
1、安装 Axios
cnpm install --save vue-axios
2、main.js引用 Axios
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios)
3、准备数据 : 只有我们的 static 目录下的文件是可以被访问到的,所以我们就把静态文件放入该目录下。
数据和之前用的json数据一样 需要的去上述axios例子里
// 静态数据存放的位置
static/mock/data.json
4.在 beforeRouteEnter 中进行异步请求
Profile.vue
export default {
//第二种取值方式
// props:['id'],
name: "UserProfile",
//钩子函数 过滤器
beforeRouteEnter: (to, from, next) => {
//加载数据
console.log("进入路由之前")
next(vm => {
//进入路由之前执行getData方法
vm.getData()
});
},
beforeRouteLeave: (to, from, next) => {
console.log("离开路由之前")
next();
},
//axios
methods: {
getData: function () {
this.axios({
method: 'get',
url: 'http://localhost:8080/static/mock/data.json'
}).then(function (response) {
console.log(response)
})
}
}
}