MVVM结构
![8c11bbfb03ebeb60551ac59ea9f86380.png](https://i-blog.csdnimg.cn/blog_migrate/d08420146df974ad62b23e08b0262439.png)
在MVVM中View和Model是不可以直接进行通信的,它们之间存在这ViewModel这个中介充当着观察者的角色。当用户操作View,ViewModel感知到变化,然后通知Model发生相应改变,反之亦然。ViewModel向上与视图层View进行双向数据绑定,向下与Model通过接口请求进行数据交互,起到承上启下的作用。
VUE的实现MVVM方式
- 数据监听器
Observer将普通的JS对象传递给VUE实例的data选项,Vue将遍历此对象所有属性,并使用Object.defineProperty()方法将属性全部转换成setter和getter方法。当data中的属性被调用访问时,则会调用getter方法。当data中的属性被改变时,则会调用setter方法。 - 指令解析器
Compiler 的作用是对每个元素节点的指令进行解析,替换模板数据,并绑定对应的更新函数,初始化相应的订阅。 - 订阅者
Watcher作为连接Observer和Compiler的桥梁,能够订阅并接收每个属性变动的通知,执行指令绑定相应回调函数。 - 消息订阅器
Dep内部维护了一个数组,用来执行收集订阅者Watcher,数据变动触发notify()
函数,在调用订阅者的update()
方法。
![767ce08726876a6d61cd552dcfc9284d.png](https://i-blog.csdnimg.cn/blog_migrate/ddb8ac68dc9aca8917c8084efcb5416a.png)
第一个demo
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<!-- 导入该包后在浏览器中多了vue的构造函数 -->
<script src="./vue-2.4.0.js"></script>
</head>
<body>
<!-- vue控制这个元素中所有内容 -->
<div id="app">
<p >{{msg}}</p>
</div>
<script>
// 创建一个vue实例,就是MVVM中的VM调度者
var vm= new Vue({
//vue要控制的元素
el:'#app',
//vue将数据渲染到页面,这里的data就是MVVM中的M,专门用来保存页面数据
data:{
msg:'hello word'
}
})
</script>
</body>
</html>
命令
- v-clock
//解决插值表达式闪烁问题
<style>
[v-clock]{
display: none;
}
</style>
- v-text/v-html
//标签内文本显示
//v-text没有插值表达式的闪烁问题
//v-text完全覆盖元素中的内容
<p >{{msg}}</p>
<p v-text="msg"></p>
//v-html解析data内的标签
<p v-html='msg2'></p>
- v-bind
//绑定msg3的属性,而不是使用msg3这个文本,将msg3当做一个变量
//也可以使用:
<input type="button" value="按钮" v-bind:title="msg3">
<input type="button" value="按钮" :title="msg3">
- v-on
//v-on事件绑定
//可以简写为@
//methods是一个对象
<input type="button" value="按钮" :title="msg3" v-on:click="show">
<script>
// 创建一个vue实例
var vm= new Vue({
el:'#app',
//vue将数据渲染到页面
data:{
methods:{
show:function(){
alert('我被点击了')
}}
})
</script>
- v-model model和表单元素之间双向绑定
<div id="app">
<p>{{msg}}</p>
//修改input的值会反向展示在页面
<input type="text" v-model:value="msg">
</div >
//表单元素
//input(text,radio,email,address)
//chceckbox
//textarea
//select
- 使用v-model实现calc
<body>
<div id="app">
<input type="text" v-model="n1">
<select v-model="opt">
<option value="+">+</option>
<option value="-">-</option>
<option value="*">*</option>
<option value="/">/</option>
</select>
<input type="text" v-model="n2">
<input type="button" value="=" @click="getResult">
<input type="text" v-model="result">
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
n1: 0,
n2: 0,
result: 0,
opt:'+'
},
methods: {
getResult(){
this.result= eval(this.n1 +this.opt+ this.n2 )
}
}
})
</script>
</body>
事件修饰符
- .stop阻止其他所有的事件冒泡
<div id="app">
<div class="inner" @click="divHandler">
//在点击button时div的事件不触发
<input type="button" value="点击我" @click.stop="buttonHander">
</div>
</div >
- .prevent 阻止本身的默认行为
<div id="app">
<div class="inner" @click="divHandler">
//点击后不再跳转链接
<a href="www.baidu.com" @click.prevent.stop="linkClick">去百度</a>//事件修饰符可以串联
</div>
</div >
- .capture 事件捕获
<body>
<div id="app">
//事件触从外到里,先执行divHandler(),再执行buttonHander
<div class="inner" @click.capture="divHandler">
<input type="button" value="点击我" @click.stop="buttonHander">
</div>
</div >
- .self 仅阻止当前元素的冒泡
<div id="app">
//只有点击当前元素才会触发,冒泡无法触发
<div class="inner" @click.self="divHandler">
<input type="button" value="点击我" @click="buttonHander">
</div>
</div >
第一个practise
<body>
<div id="app">
<input type="button" value="滚起来" @click="run">
<input type="button" value="停止" @click="stop">
<p >{{msg}}</p>
</div>
<div id="app"></div>
<script>
// 在vm实例中,如果想要获取data中的数据或者调用methods中的方法
// 必须通过this.数据属性名 或者 this. 方法名来进行访问
// this指的是new 出来的 VM对象
var vm= new Vue({
el:'#app',
data:{
msg:'hello word',
intervalId:null
},
methods:{
run(){
if(this.intervalId!=null) return;
this.intervalId= setInterval(() => {
var start=this.msg.substring(0,1)
var end=this.msg.substring(1)
this.msg=end+start
}, 400);
// VM实例会监听自身的data变化,只要数据发生变化,会自动将数据将数据同步到页面上
// 只用关心数据变化,不用再关心页面结构
},
stop(){
clearInterval(this.intervalId)
this.intervalId=null
}
}
})
</script>
</body>
样式设置
- 属性绑定的方式(数组/三元表达式/数组内存放对象/直接使用对象)
<style>
.inner {
height: 150px;
},
.red{
color: red
},
.thin{
font-weight: 200
}
</style>
<div id="app">
//添加引号寻找样式进行匹配,不添加单引号使用变量进行匹配
//样式使用数组进行存放
<p :class="['thin','red']">我是样式设置</p>
</div>
//样式设置的三元表达式
<div id="app">
<p :class="['thin',flag?'red':'']">我是样式设置</p>
//数组里面添加对象代替三元表达式
<p :class="['thin','red',{'inner':flag}]">我是样式设置</p>
</div>
//样式内直接使用对象
//对象内的key值可以带引号,也可以不带引号
<p :class="{thin:true,inner:true}">我是样式设置</p>
//对象也可以存放在data中
<body>
<div id="app">
<p :class="ObjectStyle">我是样式设置</p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
ObjectStyle:{thin:true,inner:true}
},
methods: {
}
})
</script>
</body>
- 内联样式
//使用对象
<div id="app">
<p :style= "{color: 'red'}">我是样式设置</p>
</div>
//对象可以放在data中
<body>
<div id="app">
<p :style= "ObjectStyle">我是样式设置</p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
ObjectStyle:{color:'red'},
},
methods: {
}
})
</script>
</body>
//内联样式使用数组存放样式对象
<body>
<div id="app">
<p :style= "[ObjectStyle,ObjectStyle2]">我是样式设置</p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
ObjectStyle:{'color':'red'},
ObjectStyle2:{'font-style':'italic'}
},
methods: {
}
})
</script>
其他指令
- v-for
//遍历数字
//从1开始,其他从0开始
<div id="app">
<p v-for="i in 10">第{{i}}次循环</p>
</div>
//循环遍历数组
<body>
<div id="app">
<p v-for="user in list">id:{{user.id}}------name:{{user.name}}</p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
list:[
{id:1,name:"张三1"},
{id:2,name:"张三2"},
{id:3,name:"张三3"},
{id:4,name:"张三4"}
]
},
methods: {
}
})
</script>
</body>
//key值为number或string
//保证页面上的数据和data相关联
//在使用v-for出现问题的使用注意使用key值
<body>
<div id="app">
<label >ID:
<input type="text" v-model="id">
</label>
<label >NAME:
<input type="text" v-model="name">
</label>
<input type="button" value="添加" @click="add">
<p v-for="item in list" :key="item.id"><input type="checkbox">{{item.id}}---------{{item.name}}</p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
id:"",
name:"",
list:[
{id:1,name:"张三"},
{id:2,name:"李四"},
{id:3,name:"王五"}
]
},
methods: {
add(){
// this.list.push({id:this.id,name:this.name})
this.list.unshift({id:this.id,name:this.name})
}
}
})
</script>
//v-for遍历对象
<body>
<div id="app">
<p v-for="(item,key,i) in user">值:{{item}}--------键:{{key}}---------索引:{{i}}</p>
<!-- 值:1--------键:id---------索引:0
值:tom--------键:name---------索引:1
值:male--------键:sex---------索引:2 -->
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
user: {
id: 1,
name: "tom",
sex: "male"
}
},
methods: {
}
})
</script>
</body>
- v-if/v-show
//v-if每次会删除或创建元素,切换性能效率低
//v-show 只是切换display,较低的初始渲染效率
<body>
<div id="app">
<input type="button" @click="showOrHide" value="控制显示">
<p v-if="flag">if控制显示</p>
<p v-show="flag">show控制显示</p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
flag:true
},
methods: {
showOrHide(){
this.flag=!this.flag
}
}
})
</script>
</body>