VUE
什么是MVVM
MVVM (Model-View-ViewModel)是一种软件架构设计模式,由微软WPF(用于替代WinForm,以前就是用这个技术开发桌面应用程序的)和Silverlight(类似于Java Applet,简单点说就是在浏览器上运行的WPF)的架构师Ken Cooper和Ted Peters开发,是一种简化用户界面的事件驱动编程方式。由John Gossman (同样也是 WPF和Silverlight 的架构师)于2005年在他的博客上发表。
MVVM源自于经典的 MVC (Model-View-Controller)模式。MVVM的核心是ViewModel层,负责转换 Model 中的数据对象来让数据变得更容易管理和使用,其作用如下:
- 该层向上与视图层进行双向数据绑定
- 向下与 Model 层通过接口请求进行数据交互
什么是vue
Vue (读音/vj,类似于view)是一套用于构建用户界面的渐进式框架,发布于2014年2月。与其它大型框架不同的是,Vue被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库(如: vue-router,vue-resource,vuex)或既有项目整合。
MVVM的实现者
- Model:模型层,在这里表示JavaScript 对象
- View:视图层,在这里表示 DOM(HTML操作的元素)
- ViewModel:连接视图和数据的中间件,Vue.js 就是MVVM中的ViewModel层的实现者
- 在MVVM架构中,是不允许数据和视图直接通信的,只能通过ViewModel来通信,而ViewModel就是定义了一个 Observer观察者
- **ViewModel 能够观察到数据的变化,并对视图对应的内容进行更新. **
- ViewModel能够监听到视图的变化,并能够通知数据发生改变
- 至此,我们就明白了,Vue.js就是一个MVVM的实现者,他的核心就是实现了DOM监听与数据绑定
视图状态和行为都封装在了ViewModel里。这样的封装使得ViswModel可以完整地去描述View层。由于实现了双向绑定,ViewModel的内容会实时展现在View层,这是激动人心的,因为前端开发者再也不必低效又麻烦地通过操纵DOM去更新视图。
MVVM框架已经把最脏最累的一块做好了,我们开发者只需要处理和维护ViewModel,更新数据视图就会自动得到相应更新,真正实现事件驱动编程。
视图状态和行为都封装在了ViewModel里。这样的封装使得ViswModel可以完整地去描述View层。由于实现了双向绑定,ViewModel的内容会实时展现在View层,这是激动人心的,因为前端开发者再也不必低效又麻烦地通过操纵DOM去更新视图。
View层展现的不是Model层的数据,而是ViewModel 的数据,由ViewNodel负责与Mode层交互,这就完全解耦了View层和Model层,这个解耦是至关重要的,它是前后端分离方案实施的重要一环。
快速入门
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--view层-->
<div id="app">
<p>{{msg}}</p>
</div>
</body>
<!--导包-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
//定义一个vue对象
var vm = new Vue({
el:"#app",
//model层
data:{
msg:"hello,vue"
}
});
</script>
</html>
vm层
在控制台中输入信息,页面会立即响应前段改变页面内容,本质上是vm层
view —> model
model —> model
所以是双向绑定
vue基本语法
v-bind: 绑定数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--view层-->
<div id="app">
<p>{{msg}}</p>
</div>
</body>
<!--导包-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
//定义一个vue对象
var vm = new Vue({
el:"#app",
//model层
data:{
msg:"hello,vue"
}
});
</script>
</html>
v-if 判断
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<div id="app">
<span v-if="type=== 'A' ">A</span>
<span v-else-if="type=== 'B'">B</span>
<span v-else>C</span>
</div>
<script>
var vue = new Vue({
el:"#app",
data:{
//设置默认值
type:"A"
}
})
</script>
</body>
</html>
v-for 循环
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<div id="app">
<span v-for="item in items">{{item.message }}</span>
</div>
<script>
var vue = new Vue({
el:"#app",
data:{
items:[
{message:"哈哈"},
{message: "嘿嘿"},
{message:"吼吼"}
]
}
})
</script>
</body>
</html>
v-on 绑定事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<div id="app">
<!--绑定事件-->
<button v-on:click="sayHello">戳我</button>
</div>
<script>
var vue = new Vue({
el:"#app",
data:{
message:"hello"
},
//注意是methods而不是method
methods:{
sayHello: function (){
alert(this.message)
}
}
})
</script>
</body>
</html>
不知道有哪些时间怎么办:搜jQuery文档
Vue7大属性
data | Vue实例数据对象 |
methods | 定义Vue实例中的方法 |
components | 定义子组件 |
computed | 计算属性 |
filter | 过滤器 |
el | 唯一根元素 |
watch | 监听数据变化 |
el唯一根标签
在创建Vue实例时,el表示唯一根标签,class或id选择器可用来将页面结构与Vue实例对象vm中的el绑定。
data初始数据
Vue实例的数据对象为data,Vue会将data的属性转换为getter、setter,从而让data的属性能够响应数据变化。
Vue实例创建之后,可以通过vm.data访问原数据对象 。Vue实例也代理了data对象上所 有 的 属 性 , 因 此 访 问 v m . n a m e 相 当 于 访 问 v m . data访问原始数据对象。Vue实例也代理了data对象上所有的属性,因此访问vm.name相当于访问vm.data访问原始数据对象。Vue实例也代理了data对象上所有的属性,因此访问vm.name相当于访问vm.data.name。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
{{msg}}
</div>
<script>
new Vue({
el: "#app",
data: {
msg: "Vue实例创建成功"
}
})
</script>
</body>
</html>
methods定义方法
methods属性用来定义方法,通过Vue实例可以直接访问这些方法在定义的方法中,this指向Vue实例本身定义在methods属性中的方法可以作为页面中的事件处理方法使用当事件触发后,执行相应的事件处理方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
{{msg}}
<br>
<button @click="showInfo()">单击</button>
</div>
<script>
new Vue({
el: "#app",
data: {
msg: "Vue实例创建成功"
},
methods: {
showInfo(){
this.msg = "Hello Methods"
}
}
})
</script>
</body>
</html>
computed计算属性
计算属性结果会被缓存起来,当依赖的响应式属性发生变化时,才会重新计算,返回最终结果。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
{{msg}}
<br>
<button @click="showInfo()"> 单击 </button>
<br>
单价 : {{price}} <br>
数量 : {{num}} <br>
总价 : {{totlaPrice}}
<button @click="num++"> 单击 </button>
</div>
<script>
new Vue({
el: "#app",
data: {
msg: "Vue实例创建成功",
price: 100,
num: 3
},
methods: {
showInfo(){
this.msg = "Hello Methods"
}
},
computed: {
totlaPrice() {
return this.price * this.num;
}
}
});
</script>
</body>
</html>
watch状态监听
Vue中的事件处理方法是根据用户所需自行定义的,它可以通过单击事件、键盘事件等触发条件来触发,但不能自动监听当前Vue实例的状态变化。为解决这个问题,Vue提供了watch状态监听的功能,只需要监听当前Vue实例中的数据变化,就会调用当前数据所绑定的事件处理方法。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
{{msg}}
<br>
<button @click="showInfo()"> 单击 </button>
<br>
单价 : {{price}} <br>
数量 : {{num}} <br>
总价 : {{totlaPrice}} <br>
<button @click="num++"> 单击 </button> <br>
city :<input type="text" v-model="city">
</div>
<script>
new Vue({
el: "#app",
data: {
msg: "Vue实例创建成功",
price: 100,
num: 3,
city: "shanghai"
},
methods: {
showInfo(){
this.msg = "Hello Methods"
}
},
computed: {
totlaPrice() {
return this.price * this.num;
}
},
watch: {
city(newName,oldName){
newName = "new " + newName;
oldName = "old " + oldName;
console.log(newName,oldName);
}
}
});
</script>
</body>
</html>
filters过滤器
在前端页面开发中,通过数据绑定可以将data数据绑定到页面中,页面中的数据经过逻辑层处理后展示最终的结果。数据的变化除了在Vue逻辑层进行操作外,还可以通过过滤器来实现。过滤器常用于对数据进行格式化,如字符串首字母改大小写,格式化等。过滤器有两种使用方式:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
{{msg}} <br>
<br>
<button @click="showInfo()"> 单击 </button>
<br>
单价 : {{price}} <br>
数量 : {{num}} <br>
总价 : {{totlaPrice}} <br>
<button @click="num++"> 单击 </button> <br>
city :<input type="text" v-model="city">
{{msg | toUpcase}}
<div v-bind:id="dataId | formatId"> hello world </div>
</div>
<script>
new Vue({
el: "#app",
data: {
msg: "Vue实例创建成功",
price: 100,
num: 3,
city: "shanghai",
dataId: "div1"
},
methods: {
showInfo(){
this.msg = "Hello Methods"
}
},
computed: {
totlaPrice() {
return this.price * this.num;
}
},
watch: {
city(newName,oldName){
newName = "new " + newName;
oldName = "old " + oldName;
console.log(newName,oldName);
}
},
filters: {
// 将value转换成大写
toUpcase(value){
return value ? value.toUpperCase() : ""
},
formatId(value){
return value ? value.charAt(1) + value.indexOf("d") : "";
}
}
});
</script>
</body>
</html>
双向绑定
当数据发生变化时,视图跟着发生变化,当视图发生变化时,数据也跟着变化。
注意事项:
v-model 会忽略所有表单元素的value、checked、selected特性的初始值而总是将Vue实例的数据作为数据来源。你应该通过JavaScript在组件的data选项中声明初始值!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<input type="text" name="" v-model="message">
<span>{{message}}</span>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
var vue = new Vue({
el: "#app",
data: {
message: "123"
},
methods: {
}
});
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<input type="radio" value="男" v-model="sex">男
<input type="radio" value="女" v-model="sex">女
<p>{{sex}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
var vue = new Vue({
el: "#app",
data: {
message: "123",
sex: false
},
methods: {
}
});
</script>
</body>
</html>
可以用v-model自动选定某个值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<select v-model="selected">
<!--预留默认项-->
<option>请选择</option>
<option>A</option>
<option>B</option>
<option>C</option>
<option>D</option>
</select>
<span>value:{{selected}}</span>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
var vue = new Vue({
el: "#app",
data: {
selected:"请选择"
},
methods: {
}
});
</script>
</body>
</html>
注意:
如果v-model表达式的初始值未能匹配任何选项,元素将被渲染为“未选中”状态。在 iOS 中,这会使用户无法选择第一个选项。因为这样的情况下,iOS不会触发change事件。因此,更推荐像上面这样提供一个值为空的禁用选项。
组件
组件是可复用的vue实例,说白了就是一组可以复用的模板通常一个应用会以一颗嵌套的嵌套组件树的形式来组织
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!--组件:传递给组件中的值:props-->
<moban v-for="item in items" v-bind:msg="item"></moban>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
//vue组件示例
Vue.component("moban",{
//定义一个Vue组件component
props:['msg'],
template: '<li>{{msg}}</li>'
});
var vm = new Vue({
el: "#app",
data: {
items: ["java","python","vue"]
},
methods: {
}
});
</script>
</body>
</html>
要引入component中的组件:
<template>
<tree></tree>
</template>
<script>
import trees from "../components/tree2";
export default{
components:{
trees
}
}
</script>
Axios异步通信入门
简单用例
<!--导包-->
<script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js"></script>
<script>
var axios = axios.create({ headers: {'content-type': 'application/x-www-form-urlencoded'} });
// 向给定ID的用户发起请求
axios.get('../data.json')
.then(function (response) {
// 处理成功情况
console.log(response);
})
.catch(function (error) {
// 处理错误情况
console.log(error);
})
.then(function () {
// 总是会执行
});
let vm = new Vue({
el: "#app",
data: {
},
methods: {
},
});
</script>
创建axios实例
各有两种写法:
get
//写法1
axios实例名.请求方法("url",{参数}).then(res =>{处理操作})
//写法2
axios实例名({
url:"URL",
method:"请求方法",
data:
params:请求带的参数
...
}).then(res =>)
//axios实例
const require = axios.create({
baseURL:"../",
timeout:1000
})
/*
*post请求
*/
//写法1
require({
url:"data.json",
method:"get",
//发送请求时带的参数,
params:{
name:"zyp",
age:18,
gender:"女"
},
//超时时间
timeout: 1000,
}).then(function(response){
console.log(response.data)
})
//这里要注意一点,如果将该请求封装到一个方法中,那么this的作用域就到不了这个function中,解决方法是在外方法中定义that
//原因:function指向调用它的对象,箭头指向上一层作用域的对象
.then(function(res){
that.tableData = res.data
})
//写法2
request.get("/procbatch/findpage", {
//params:与请求一起发送的参数,一般用于get
params: {
pageNum: this.pageNum,
pageSize: this.pageSize,
customer: this.customer
},
timeout:2000,
}).then(res => {
console.log(res)
this.tableData = res.data
this.total = res.total
})
post
/*
*post请求
*/
//写法1
insert() {
let that = this
request({
url:"/procbatch/insert",
method:"post",
data:this.form
}).then(function (res) {
if (res) {
that.$message.success("保存成功")
that.dialogFormVisibleAdd = false
that.load()
} else {
that.$message.error("保存失败")
}
})
}
//写法2
insert(){
request.post("/procbatch/insert", this.form).then(res => {
if (res) {
this.$message.success("保存成功")
this.dialogFormVisibleAdd = false
this.load()
} else {
this.$message.error("保存失败")
}
})
}
注意
如果处理函数用function而不是箭头函数时要提升this作用域,方法是
外部方法体中:let that = this
计算属性
计算属性的重点突出在属性两个字上(属性是名词),首先它是个属性其次这个属性有计算的能力(计算是动词),这里的计算就是个函数;简单点说,它就是一个能够将计算结果缓存起来的属性(将行为转化成了静态的属性).仅此而已;可以想象为缓存!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<p>{{currentTime1()}}</p>
//computed突出的是属性,所以是以属性的方式调用
<p>{{currentTime2}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
},
methods: {
currentTime1(){
return Date.now()
}
},
computed:{ //计算属性,computed和methods的方法不要重名,否则只会执行methods中方法
//调用时由于是属性,所以不需要带括号
//如果在方法中值发生了变化,则缓存就会刷新
currentTime2(){
return Date.now()
}
}
});
</script>
</body>
</html>
slot插槽
首先它是个属性其次这个属性有计算的能力(计算是动词),这里的计算就是个函数;简单点说,它就是一个能够将计算结果缓存起来的属性(将行为转化成了静态的属性).仅此而已;可以想象为缓存!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<p>{{currentTime1()}}</p>
//computed突出的是属性,所以是以属性的方式调用
<p>{{currentTime2}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
},
methods: {
currentTime1(){
return Date.now()
}
},
computed:{ //计算属性,computed和methods的方法不要重名,否则只会执行methods中方法
//调用时由于是属性,所以不需要带括号
//如果在方法中值发生了变化,则缓存就会刷新
currentTime2(){
return Date.now()
}
}
});
</script>
</body>
</html>