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已经相当成熟了,主要运用但不仅仅在网络应用程序开发中。当下流行的MVVM框架有Vue.js
,Anfular JS
MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大好处
MVVM组成部分
(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(因为IDEA可以安装Vue的插件 )
Vue.js:我们通常使用cdn导入
<script src=“https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js”>script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>cVzhanshititle>
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">
// 创建一个Vue实例
var vm = new Vue({
el:"#app",
/*Model:数据*/
data:{
message:"hello,vue -----cvzhanshi!"
}
});
script>
body>
html>
说明
运行效果
测试
为了能够更直观的体验Vue带来的数据绑定功能, 我们需要在浏览器测试一番, 操作流程如下:
1、在浏览器上运行第一个Vue应用程序, 进入开发者工具
2、在控制台输入vm.message=‘HelloWorld’, 然后回车, 你会发现浏览器中显示的内容会直接变成HelloWorld,不需要刷新页面
此时就可以在控制台直接输入vm.message来修改值, 中间是可以省略data的, 在这个操作中, 我并没有主动操作DOM, 就让页面的内容发生了变化, 这就是借助了Vue的数据绑定功能实现的; MV VM模式中要求View Model层就是使用观察者模式来实现数据的监听与绑定, 以做到数据与视图的快速响应
理解View Model:它可以类比成一个观察者,监测到了数据的变化,就立马更新页面与之绑定的值,无需更新页面,也无需操作DOM对象,相当于一个虚拟DOM对象
测试代码
DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>cVzhanshititle>
head>
<body>
<div id="app">
<span v-bind:title="message">
鼠标悬停几秒钟查看此处动态绑定的提示信息!
span>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
<script type="text/javascript">
// 创建一个Vue实例
var vm = new Vue({
el:"#app",
/*Model:数据*/
data:{
message:"hello,vue -----cvzhanshi!"
}
});
script>
div>
body>
html>
说明**:
看到的 v-bind
attribute 被称为指令。指令带有前缀 v-
,以表示它们是 Vue 提供的特殊 attribute
它们会在渲染的 DOM 上应用特殊的响应式行为
在这里,该指令的意思是:“将这个元素节点的
title
attribute 和 Vue 实例的message
property 保持一致”如果你再次打开浏览器的 JavaScript 控制台,输入
app.message = '新消息'
,就会再一次看到这个绑定了title
attribute 的 HTML 已经进行了更新
测试代码1
DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>cVzhanshititle>
head>
<body>
<div id="app">
<h1 v-if="type">Yesh1>
<h1 v-else>Noh1>
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:{
type: true
}
});
script>
body>
html>
测试
1.在浏览器上运行,打开控制台
2.在控制台输入vm.type=false
然后回车,你会发现浏览器中显示的内容会直接变成NO
注:使用v-*
属性绑定数据是不需要双花括号
包裹的
测试代码2
DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>cVzhanshititle>
head>
<body>
<div id="app">
<h1 v-if="type==='A'">Ah1>
<h1 v-else-if="type==='B'">Bh1>
<h1 v-else-if="type==='D'">Dh1>
<h1 v-else>Ch1>
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:{
type: 'A'
}
});
script>
body>
html>
测试
1.在浏览器上运行,打开控制台
2.在控制台输入vm.type="D"
然后回车,你会发现浏览器中显示的内容会直接变成D
注:===
三个等号在JS中表示绝对等于(就是数据与类型都要相等)
测试代码
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>cVzhanshititle>
head>
<body>
<div id="app">
<li v-for="(item,index) in items">
{{item.message}}---{{index}}
li>
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:{
items:[
{message:'cvzhanshi'},
{message:'ursula'},
{message:'cvzhanshi-ursula'}
]
}
});
script>
body>
html>
格式说明
<div id="app">
<li v-for="(item,index) in items">
{{item.message}}---{{index}}
li>
div>
注:items
是数组,item
是数组元素迭代的别名,index是迭代的序号
测试
vm.items.push({message:'vue hello'})
,尝试追加一条数据,会发现页面也添加了数据1、可以用
v-on
指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码
示例代码1
DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>cVzhanshititle>
head>
<body>
<div id="example-1">
<button v-on:click="counter += 1">Add 1button>
<p>The button above has been clicked {{ counter }} times.p>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
<script type="text/javascript">
var example1 = new Vue({
el: '#example-1',
data: {
counter: 0
}
});
script>
body>
点击按钮属性值就 + 1
2、然而许多事件处理逻辑会更为复杂,所以直接把 JavaScript 代码写在
v-on
指令中是不可行的。因此v-on
还可以接收一个需要调用的方法名称
测试代码2
DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>cVzhanshititle>
head>
<body>
<div id="example-2">
<button v-on:click="greet">Greetbutton>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
<script type="text/javascript">
var example2 = new Vue({
el: '#example-2',
data: {
name: 'Vue.js'
},
// 在 `methods` 对象中定义方法
methods: {
greet: function (event) {
// `this` 在方法里指向当前 Vue 实例
alert('Hello ' + this.name + '!')
// `event` 是原生 DOM 事件
if (event) {
alert(event.target.tagName)
}
}
}
})
;
script>
body>
html>
数据双向绑定, 即当数据发生变化的时候, 视图也就发生变化, 当视图发生变化的时候,数据也会跟着同步变化。
注意 : 我们所说的数据双向绑定,一定是对于UI控件来说的非UI控件不会涉及到数据双向绑定。
你可以用v-model指令在表单、及元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。v-model负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
注意:v-model会忽略所有表单元素的value、checked、selected特性的初始值而总是将Vue实例的数据作为数据来源。你应该通过JavaScript在组件的data选项中声明初始值
v-model
在内部为不同的输入元素使用不同的 property 并抛出不同的事件:
value
property 和 input
事件;checked
property 和 change
事件;value
作为 prop 并将 change
作为事件。单行文本
DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>cVzhanshititle>
head>
<body>
<div id="example-2">
<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}p>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
<script type="text/javascript">
var example2 = new Vue({
el: '#example-2',
data: {
message: ''
}
});
script>
body>
html>
多行文本
DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>cVzhanshititle>
head>
<body>
<div id="example-2">
<span>Multiline message is:span>
<p style="white-space: pre-line;">{{ message }}p>
<br>
<textarea v-model="message" placeholder="add multiple lines">textarea>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
<script type="text/javascript">
var example2 = new Vue({
el: '#example-2',
data: {
message: ''
}
});
script>
body>
html>
注意 :在文本区域插值 (
{{text}}
) 并不会生效,应用v-model
来代替
复选框
<div id="example-2">
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}label>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
<script type="text/javascript">
var example2 = new Vue({
el: '#example-2',
data: {
checked: 'true'
}
});
script>
<div id="example-2">
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jacklabel>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">Johnlabel>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mikelabel>
<br>
<span>Checked names: {{ checkedNames }}span>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
<script type="text/javascript">
var example2 = new Vue({
el: '#example-2',
data: {
checkedNames: []
}
});
script>
单选按钮
<div id="example-2">
<input type="radio" id="one" value="One" v-model="picked">
<label for="one">Onelabel>
<br>
<input type="radio" id="two" value="Two" v-model="picked">
<label for="two">Twolabel>
<br>
<span>Picked: {{ picked }}span>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
<script type="text/javascript">
var example2 = new Vue({
el: '#example-2',
data: {
picked: ''
}
});
script>
选择框
<div id="example-2">
<select v-model="selected">
<option disabled value="">请选择option>
<option>Aoption>
<option>Boption>
<option>Coption>
select>
<span>Selected: {{ selected }}span>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
<script type="text/javascript">
var example2 = new Vue({
el: '#example-2',
data: {
selected: ''
}
});
script>
如果
v-model
表达式的初始值未能匹配任何选项,`` 元素将被渲染为“未选中”状态。在 iOS 中,这会使用户无法选择第一个选项。因为这样的情况下,iOS 不会触发 change 事件。因此,更推荐像上面这样提供一个值为空的禁用选项。
组件是可复用的
Vue
实例, 说白了就是一组可以重复使用的模板, 跟JSTL
的自定义标签、Thymeleal
的th:fragment
等框架有着异曲同工之妙,通常一个应用会以一棵嵌套的组件树的形式来组织
例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件
<div id="app">
<cvzhanshi>cvzhanshi>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
<script type="text/javascript">
Vue.component("cvzhanshi",{
template: 'Hello cVzhanshi '
});
var vm = new Vue({
el: '#app',
data: {
selected: ''
}
});
script>
说明:
Vue.component()
:注册组件cvzhanshi
:自定义组件的名字template
:组件的模板
props
属性传递参数
<div id="app">
<cvzhanshi v-for="item in items" v-bind:course="item">cvzhanshi>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
<script type="text/javascript">
Vue.component("cvzhanshi",{
props: ['course'],
template: '{{course}} '
});
var vm = new Vue({
el: '#app',
data:{
items:["java","Linux","前端"]
}
});![在这里插入图片描述](https://img-blog.csdnimg.cn/20200616222020393.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3Bhbl9oMTk5NQ==,size_16,color_FFFFFF,t_70#pic_center)
script>
说明:
- v-for=“item in items”:遍历Vue实例中定义的名为items的数组,并创建同等数量的组件
- v-bind:course=“item”:将遍历的item项绑定到组件中props定义名为course属性上;= 号左边的course为props定义的属性名,右边的为item in items 中遍历的item项的值
Axios是一个开源的可以用在浏览器端和Node JS的异步通信框架, 她的主要作用就是实现AJAX异步通信,其功能特点如下:
由于Vue.js是一个视图层框架并且作者(尤雨溪) 严格准守SoC(关注度分离原则)所以Vue.js并不包含AJAX的通信功能, 为了解决通信问题, 作者单独开发了一个名为vue-resource的插件, 不过在进入2.0版本以后停止了对该插件的维护并推荐了Axios框架。
由于jQuery操作Dom太频繁,所以少用
{
"name": "cv战士",
"url": "https://blog.csdn.net/qq_45408390?spm=1001.2101.3001.5343",
"page": 1,
"isNonProfit": true,
"address": {
"street": "含光门",
"city": "陕西西安",
"country": "中国"
},
"links": [
{
"name": "bilibili",
"url": "https://bilibili.com"
},
{
"name": "cv战士",
"url": "https://blog.csdn.net/qq_45408390?spm=1001.2101.3001.5343"
},
{
"name": "百度",
"url": "https://www.baidu.com/"
}
]
}
DOCTYPE html>
<html lang="en" xmlns:v-binf="http://www.w3.org/1999/xhtml" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<style>
[v-cloak]{
display: none;
}
style>
head>
<body>
<div id="vue" v-cloak>
<div>地名:{{info.name}}div>
<div>地址:{{info.address.country}}--{{info.address.city}}--{{info.address.street}}div>
<div>链接:<a v-bind:href="info.url">{{info.url}}a> div>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
<script src="https://unpkg.com/axios/dist/axios.min.js">script>
<script type="text/javascript">
var vm = new Vue({
el:"#vue",
//data:属性:vm
data(){
return{
info:{
name:null,
address:{
country:null,
city:null,
street:null
},
url:null
}
}
},
mounted(){//钩子函数
axios
.get('../data.json')
.then(response=>(this.info=response.data));
}
});
script>
body>
html>
说明:
Ajax
响应回来的数据格式匹配Vue生命周期图
计算属性的重点突出在
属性
两个字上(属性是名词),首先它是个属性
其次这个属性有计算
的能力(计算是动词),这里的计算
就是个函数:简单点说,它就是一个能够将计算结果缓存起来的属性(将行为转化成了静态的属性),仅此而已;可以想象为缓存
测试代码
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<p>currentTime1:{{currentTime1()}}p>
<p>currentTime2:{{currentTime2}}p>
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",
data:{
message:"cvzhanshi"
},
methods:{
currentTime1:function(){
return Date.now();//返回一个时间戳
}
},
computed:{
currentTime2:function(){//计算属性:methods,computed方法名不能重名,重名之后,只会调用methods的方法
this.message;
return Date.now();//返回一个时间戳
}
}
});
script>
body>
html>
注意:methods和computed里的东西不能重名,重名之后,只会调用methods的方法
说明:
methods:定义方法, 调用方法使用currentTime1(), 需要带括号
computed:定义计算属性, 调用属性使用currentTime2, 不需要带括号:this.message是为了能够让currentTime2观察到数据变化而变化
如何在方法中的值发生了变化,则缓存就会刷新!可以在控制台使用vm.message=”cvzhanshi", 改变下数据的值,再次测试观察效果!
总结
调用方法时,每次都需要讲行计算,既然有计算过程则必定产生系统开销,那如果这个结果是不经常变化的呢?此时就可以考虑将这个结果缓存起来,采用计算属性可以很方便的做到这点,计算属性的主要特性就是为了将不经常变化的计算结果进行缓存,以节约我们的系统开销;
在
Vue.js
中我们使用``元素作为承载分发内容的出口,可以称其为插槽,可以应用在组合组件的场景中
需求:需要把下面的内容,让标题和内容通过插槽插入内容
<p>标题p>
<ul>
<li>abcdli>
<li>abcdli>
<li>abcdli>
ul>
Vue.component('todo',{
template:'\
代办事项\
\
- cvzhanshi study Java
\
\
'
});
Vue.component('todo',{
template:'\
\
\
\
\
'
});
Vue.component('todo-title',{
props:['title'],
template:'{{title}}'
});
//这里的index,就是数组的下标,使用for循环遍历的时候,可以循环出来!
Vue.component("todo-items",{
props:["item","index"],
template:"{{index+1}},{{item}} "
});
Vue.component('todo',{
template:'<div>\
<slot name="todo-title">slot>\
<ul>\
<slot name="todo-items">slot>\
ul>\
div>'
});
var vm = new Vue({
el:"#vue",
data:{
todoItems:['test1','test2','test3']
}
});
<todo>
<todo-title slot="todo-title" v-bind:title="title">todo-title>
<todo-items slot="todo-items" v-for="item in todoItems" :item="item" >todo-items>
todo>
说明:
slot:是绑定组件用的
:title --> 是v-bind:title的缩写
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="vue">
<todo>
<todo-title slot="todo-title" v-bind:title="title">todo-title>
<todo-items slot="todo-items" v-for="item in todoItems" :item="item" >todo-items>
todo>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
<script type="text/javascript">
Vue.component('todo',{
template:'\
\
\
\
\
'
});
Vue.component('todo-title',{
props:['title'],
template:'{{title}}'
});
//这里的index,就是数组的下标,使用for循环遍历的时候,可以循环出来!
Vue.component("todo-items",{
props:["item"],
template:"{{item}} "
});
var vm = new Vue({
el:"#vue",
data:{
title:"cvzhanshi study java",
todoItems:['test1','test2','test3']
}
});
script>
body>
html>
通过上诉代码我们可以发现一个问题,如果删除操作要在组件中完成,那么组件如何删除Vue实例中的数据?
例:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6cl2ga6d-1624517862625)(Vue.assets/1624501228359.png)]
删除按钮是在组件中的,点击删除按钮删除对应的数据。
阅读Vue教程可知,此时就涉及到参数传递与事件分发了, Vue为我们提供了自定义事件的功能很好的帮助我们解决了这个问题; 组件中使用this.$emit(‘自定义事件名’, 参数) ,而在视图层通过自定义事件绑定Vue中的删除操作的方法
步骤:
methods: {
removeItems: function (index) {
this.todoItems.splice(index,1);
}
}
说明splice(index,n)方法是操作index下标开始的n个元素
<div id="vue">
<todo>
<todo-title slot="todo-title" v-bind:title="title">todo-title>
<todo-items slot="todo-items" v-for="(item,index) in todoItems"
:item="item" :index="index" v-on:remove="removeItems(index)">todo-items>
todo>
div>
自定义事件为remove,通过v-on绑定removeItems方法
Vue.component("todo-items",{
props:["item","index"],
template:"{{item}}---{{index}} ",
methods: {
remove: function (index) {
this.$emit('remove',index);
}
}
});
完整代码如下
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="vue">
<todo>
<todo-title slot="todo-title" v-bind:title="title">todo-title>
<todo-items slot="todo-items" v-for="(item,index) in todoItems"
:item="item" :index="index" v-on:remove="removeItems(index)">todo-items>
todo>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
<script type="text/javascript">
Vue.component('todo',{
template:'\
\
\
\
\
'
});
Vue.component('todo-title',{
props:['title'],
template:'{{title}}'
});
//这里的index,就是数组的下标,使用for循环遍历的时候,可以循环出来!
Vue.component("todo-items",{
props:["item","index"],
template:"{{item}}---{{index}} ",
methods: {
remove: function (index) {
this.$emit('remove',index);
}
}
});
var vm = new Vue({
el:"#vue",
data:{
title:"cvzhanshi study java",
todoItems:['test1','test2','test3']
},
methods: {
removeItems: function (index) {
this.todoItems.splice(index,1);
}
}
});
script>
body>
html>
逻辑理解
核心:数据驱动,组件化
优点:借鉴了AngularJS的模块化开发和React的虚拟Dom,虚拟Dom就是把Demo操作放到内存中执行;
常用的属性:
组件化:
遵循SoC关注度分离原则,Vue是纯粹的视图框架,并不包含,比如Ajax之类的通信功能,为了解决通信问题,我们需要使用Axios框架做异步通信;
vue-cli官方提供的一个脚手架,用于快速生成一个vue的项目模板
预先定义好的目录结构及基础代码,就好比咱们在创建Maven项目时可以选择创建一个骨架项目,这个估计项目就是脚手架,我们的开发更加的快速
项目的功能
下载地址: http://nodejs.cn/download/ 安装的时候一直下一步直到结束
确认是否安装成功:
- 在cmd中运行node -v命令,查看是否能够输出版本号
- 在cmd中运行npm -v命令,查看是否能够输出版本号
# -g 就是全局安装
npm install cnpm -g
# 或使用如下语句解决npm速度慢的问题,但是每次install都需要(妈发)
npm install --registry=https://registry.npm.taobao.org
cnpm instal1 vue-cli-g
#测试是否安装成功#查看可以基于哪些模板创建vue应用程序,通常我们选择webpack
vue list
找到一个项目路径(空文件夹)
创建一个基于webpack模板的vue应用程序
#1、首先需要进入到对应的目录 cd E:\study\Java\workspace\workspace_vue
#2、这里的myvue是顶日名称,可以根据自己的需求起名
vue init webpack myvue
创建过程需要的操作
一路选no
Project name:项目名称,默认回车即可
Project description:项目描述,默认回车即可
Author:项目作者,默认回车即可
Install vue-router:是否安装vue-router,选择n不安装(后期需要再手动添加)
Use ESLint to lint your code:是否使用ESLint做代码检查,选择n不安装(后期需要再手动添加)
Set up unit tests:单元测试相关,选择n不安装(后期需要再手动添加)
Setupe2etests with Nightwatch:单元测试相关,选择n不安装(后期需要再手动添加)
Should we run npm install for you after the,project has been created:创建完成后直接初始化,选择n,我们手动执行;运行结果
当出现问题时,它会给出提示我们按照提示来就行
cd myvue
npm install
npm run dev
访问localhost:8080即可
WebPack是一款模块加载器兼打包工具, 它能把各种资源, 如JS、JSX、ES 6、SASS、LESS、图片等都作为模块来处理和使用
安装:
npm install webpack -g
npm install webpack-cli -g
测试安装成功:
webpack -v
webpack-cli -v
配置:
module.exports = {
entry:"",
output:{
path:"",
filename:""
},
module:{
loaders:[
{test:/\.js$/,;\loade:""}
]
},
plugins:{},
resolve:{},
watch:true
}
直接运行webpack
命令打包
在workspace中创建文件夹webpack-study,然后用IDEA打开
//暴露一个方法:sayHi
exports.sayHi = function(){
document.write("Hello Webpack");
}
//require 导入一个模块,就可以调用这个模块中的方法了
var hello = require("./hello");
hello.sayHi();
module.exports = {
entry:"./modules/main.js",
output:{
filename:"./js/bundle.js"
}
}
打包:
说明:打包如果失败,就用管理员权限运行webpack
doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>狂神说Javatitle>
head>
<body>
<script src="dist/js/bundle.js">script>
body>
html>
注:
# 参数--watch 用于监听变化,如果要打包的东西有变化,就重新打包
webpack --watch
vue-cli
进行测试学习; 先查看node modules中是否存在vue-router, vue-router是一个插件包, 所以我们还是需要用n pm/cn pm来进行安装的npm install vue-router --save-dev
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter);
components
目录下存放我们自己编写的组件Content.vue
内容页
Main.vue
首页
cVzhanshi.vue
cVzhanshi
router
,专门存放路由,配置路由index.jsimport Vue from'vue'
//导入路由插件
import Router from 'vue-router'
//导入上面定义的组件
import Content from '../components/Content'
import Main from '../components/Main'
import cVzhanshi from "../components/cVzhanshi";
//安装路由
Vue.use(Router) ;
//配置路由
export default new Router({
routes:[
{
//路由路径
path:'/content',
//路由名称
name:'content',
//跳转到组件
component:Content
},{
//路由路径
path:'/main',
//路由名称
name:'main',
//跳转到组件
component:Main
}
,{
//路由路径
path:'/cvzhanshi',
//路由名称
name:'main',
//跳转到组件
component:cVzhanshi
}
]
});
main.js
中配置路由import Vue from 'vue'
import App from './App'
import router from './router'//自动扫描里面的路由配置
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: ' '
})
App.vue
中使用路由
cVzhanshi
首页
内容
cVzhanshi
vue init webpack hello-vue
#进入工程目录
cd hello-vue
#安装vue-routern
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 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为该命令的缩写
说明:
- assets:用于存放资源文件
- components:用于存放Vue功能组件
- views:用于存放Vue视图组件
- router:用于存放vue-router配置
首页
欢迎登录
登录
请输入账号和密码
index.js
的vue-router路由配置文件//导入vue
import Vue from 'vue';
import VueRouter from 'vue-router';
//导入组件
import Main from "../views/Main";
import Login from "../views/Login";
//使用
Vue.use(VueRouter);
//导出
export default new VueRouter({
routes: [
{
//登录页
path: '/main',
component: Main
},
//首页
{
path: '/login',
component: Login
},
]
})
main.js
中配置路由import Vue from 'vue'
import App from './App'
import router from "./router"
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.config.productionTip = false
Vue.use(router)
Vue.use(ElementUI)
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
render:h=>h(App)
})
说明: 如果出现错误: 可能是因为sass-loader的版本过高导致的编译错误 ,可以去package.json文件中把sass-loder的版本降低,也有可能是node-sass版本过高,看报错内容修改相应的版本
嵌套路由又称子路由,在实际应用中,通常由多层嵌套的组件组合而成
个人信息
用户列表
用户管理
个人信息
用户列表
内容管理
分类管理
内容列表
个人信息
退出登录
//导入vue
import Vue from 'vue';
import VueRouter 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(VueRouter);
//导出
export default new VueRouter({
routes: [
{
//登录页
path: '/main',
component: Main,
// 写入子模块
children: [
{
path: '/user/profile',
component: UserProfile,
}, {
path: '/user/list',
component: UserList,
},
]
},
//首页
{
path: '/login',
component: Login
},
]
})
方法一
{
path: '/user/profile/:id',
name:'UserProfile',
component: UserProfile
}
个人信息
说明: 此时我们在Main.vue中的route-link位置处 to 改为了 :to,是为了将这一属性当成对象使用,注意 router-link 中的 name 属性名称 一定要和 路由中的 name 属性名称 匹配,因为这样 Vue 才能找到对应的路由路径
个人信息
{{$route.params.id}}
说明:所有的元素必须在根节点下面,否则会报错
方法二 使用props 减少耦合
{
path: '/user/profile/:id',
name:'UserProfile',
component: UserProfile,
props: true
}
个人信息
{{ id }}
Vue 中的重定向是作用在路径不同但组件相同的情况
{
path: '/main',
name: 'Main',
component: Main
},
{
path: '/goHome',
redirect: '/main'
}
返回首页
路由模式有两种
修改路由配置
export default new VueRouter({
mode:'history',
routes: []
)}
在路由的配置中修改
404,你的页面走丢了
import NotFound from '../views/NotFound'
{
path: '*',
component: NotFound
}
除了之前的钩子函数还存在两个钩子函数
beforeRouteEnter:在进入路由前执行
beforeRouteLeave:在离开路由前执行
参数说明:
to:路由将要跳转的路径信息
from:路径跳转前的路径信息
next:路由的控制参数
next() 跳入下一个页面
next(’/path’) 改变路由的跳转方向,使其跳到另一个路由
next(false) 返回原来的页面
next((vm)=>{}) 仅在 beforeRouteEnter 中可用,vm 是组件实例
在钩子函数中进行异步请求
cnpm install --save vue-axios
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios)
{
"name": "cv战士",
"url": "https://blog.csdn.net/qq_45408390?spm=1001.2101.3001.5343",
"page": 1,
"isNonProfit": true,
"address": {
"street": "含光门",
"city": "陕西西安",
"country": "中国"
},
"links": [
{
"name": "bilibili",
"url": "https://bilibili.com"
},
{
"name": "cv战士",
"url": "https://blog.csdn.net/qq_45408390?spm=1001.2101.3001.5343"
},
{
"name": "百度",
"url": "https://www.baidu.com/"
}
]
}
说明: 只有我们的 static 目录下的文件是可以被访问到的,所以我们就把静态文件放入该目录下