一,MVVM框架简介:
1,基本概念:
MVVM框架主要包括三个部分,View(视图 DOM) ViewModel(通讯 链接视图和数据的中间件) Model (数据 JavaScipt对象)
当数据发生变化 ViewMdel 能够观察到数据这种变化,通知到对应的视图做自动更新,当用户操作视图,ViewModel也能监听到视图的变化,然后通知数据做改动,实现了数据的双向绑定;
2,应用场景:
针对具有复杂交互逻辑的前端应用
提供基础架构抽象
通过Ajax数据持久化,保证前端用户体验
二,什么是 Vue.js:
1, 轻量级MVVM框架
数据驱动 + 组件化的前端开发 社区完善
2,DOM是数据的一种自然映射
如果没有 ViewModel 数据和视图发生改变 就需要手动改变(容易出错),使用了vue.js后,省去了手动操作DOM变化的部分,只需要改变数据,Vue.js 通过 Directives指令 对Dom做一层封装,当数据发生变化,会通知指令修改对应的DOM,数据驱动DOM变化,DOM是数据的自然映射;还会对操作做些监听,当修改视图的时候,Vue.js监听到视图的变化,从而改变数据;
3,数据响应原理:数据(model)如何改变驱动视图(view)自动更新:
上面图片来自 Vue.js官网
原理:有一份数据a.b 在一个Vue对象实例化的过程中,会给 a.b 这份数据 通过es5的 Object.defineProperty(直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象)添加getter,setter,同时会对模板做编译,解析生成指令对象,每个指令对象都会关联 一个Watcher,当我们对对应的指令做操作时 就会触发getter ;再次改变a.b的值,会触发setter。会通知对应关联的Watcher,当Watcher发生改变时,由于指令是对DOM的封装,所以会调用原生DOM的方法更新视图,从而完成数据改变视图更新;
4,组件化 :
(1), 扩展HTML元素,封装可重用的代码
上图 左侧是一个页面 被拆分成小的区块,每个区块对应一个组件,组件可以嵌套,最终组合成完成页面;
(2), 组件设计原则
页面上每个独立的可视/可交互区域视为一个组件
每个组件对应一个工程目录,组件所需要的各种资源在这个目录下就近维护
页面不过是组件的容器,组件可以嵌套自由组合形成完整的页面
三,Vue常用指令及基本语法:
1,Vue语法及简单案例
基本语法:
var wm = new Vue({
el:"#app" ,//配置模板(界面)
data:{
//配置数据
title:'哈哈哈哈哈 小菜鸡'
},
})
el:是 DOM 元素中的 id;
data 用于定义属性
{{ }} 用于输出对象属性和函数返回值
案例代码:实现一个简易商品管理功能 (可复制到编辑器中运行)
<div id="appProduct">
<h1>{{title}}</h1>
商品名称:<input type="text" v-model="newProducts.name">
商品数量:<input type="text" value="0" v-model="newProducts.stock">
<button @click ="addProduct()">添加</button>
<ul>
<li v-for = "(item, i) in products">
名称:{{item.name}} 库存:{{item.stock}}
</li>
</ul>
</div>
<script>
var proVm = new Vue({
el:'#appProduct',
data:{
title:'简易商品管理系统',
newProducts:{
name:'默认名称',
stock:50
},
products:[
{name:'iphone',stock:500},
{name:'huawei',stock:100},
{name:'Vivo',stock:50},
],
},
methods:{
addProduct(){
//添加数据
this.products.push({
name:this.newProducts.name,
stock:this.newProducts.stock
});
}
}
})
</script>
页面效果:
methods:用于定义的函数,可以通过 return 来返回函数值
v-model:来实现双向数据绑定
v-for:循环语句,后面会详细讲解;
2,Vue常用模板语法
指令是带有 v- 前缀的特殊属性,指令用于在表达式的值改变时,将某些行为应用到 DOM 上
(1) v-html指令:用于输出html代码
<div id="app" >
<div v-html = 'title'></div>
</div>
<script>
var wm = new Vue({
el:"#app" ,
data:{
title:'<h1>哈哈哈哈哈 小菜鸡</h1>'
},
})
</script>
(2) v-bind指令:html中属性中的值
示例:判断文字颜色,如果true 颜色为红色 false为绿色
<div id="app">
<label>修改帽子的颜色</label> <input type="checkbox" v-model = 'use'>
<div class ="color" v-bind:class = "{'color1':use}">我是帽子</div>
</div>
<script>
var wm = new Vue({
el:"#app" ,
data:{
use:false
},
})
</script>
v-bind 指令可以缩写:
<!-- 完整语法 -->
<div v-bind:class="{'color1':use}"></div>
<!-- 缩写 -->
<div :class="{'color1':use}"></div>
(3) v-if 指令:根据表达式 的值(true 或 false )来决定是否将某些行为应用到Dom上
<div id="app">
<div class ="color" v-if = "use">我是帽子</div>
</div>
<script>
var wm = new Vue({
el:"#app" ,
data:{
use:true
},
})
</script>
(4) v-on 指令:用于监听DOM事件
<div id="app">
<p>{{msg}}</p>
<button class ="color" v-on:click= "reverseMessage">改变顺序</button>
</div>
<script>
var wm = new Vue({
el:"#app" ,
data:{
msg:'helloword'
},
methods:{
reverseMessage:function(){
this.msg = this.msg.split('').reverse().join('')
}
}
})
</script>
(5) v-model 指令:实现双向数据绑定
用来在 input、select、textarea、checkbox、radio 等表单控件元素上创建双向数据绑定,根据表单上的值,自动更新绑定的元素的值
<div id="app">
<p>{{messsage}}</p>
<input class="color" v-model="messsage"></input>
</div>
<script>
var vm = new Vue({
el:'#app',
data:{
messsage:'123456789',
}
})
</script>
3,Vue常用修饰符
修饰符是以半角句号 . 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定
(1) .lazy: 光标离开input框才会更新数据:
<input class="color" v-model.lazy="messsage"></input>
(2) .trim: 输入框过滤收尾空格:
<div id="app">
<p>{{messsage}}</p>
<input class="color" v-model.trim="messsage"></input>
</div>
<script>
var vm = new Vue({
el:'#app',
data:{
messsage:'123456789',
}
})
</script>
(3) .number: 先输入数字就会限制输入只能是数字,先字符串就相当于没有加number
注意,不是输入框不能输入字符串,是这个数据是数字
<input class="color" v-model.number="messsage"></input>
(4) .stop: 阻止事件冒泡
相当于调用了event.stopPropagation()方法
<button @click.stop="message">message</button>
(5) .prevent: 阻止默认行为
相当于调用了event.preventDefault()方法,比如表单的提交、a标签的跳转就是默认事件
<a @click.prevent="message">message</a>
(6) .once: 只能用一次,执行一次之后就不会在执行
不管点击几次,只是执行一次
button class="color" @click.once="showMessage">点击我</button>
4,Vue过滤器
过滤器是对即将显示的数据进行进一步的筛选处理,然后显示,并没有改变原来的数据,只是在原有数据基础上产生新的数据;过滤器分 全局过滤器和局部过滤器
Vue.js 允许你自定义过滤器,被用作一些常见的文本格式化。由"管道符"指示, 格式如下:
<!-- 在两个大括号中 -->
<div>{{数据属性名称 | 过滤器名称}}</div>
<div>{{数据属性名称 | 过滤器名称(参数值)}}</div>
<!-- 在 v-bind 指令中 -->
<div v-bind:id="数据属性名称 | 过滤器名称"></div>
<div v-bind:id="数据属性名称 | 过滤器名称(参数值)"></div>
(1)全局过滤器:
语法:
Vue.filter('过滤器名称', function (value1[,value2,...] ) {
//逻辑代码
})
示例:把 hellovue 变成大写 (传递一个参数的全局过滤器)
<div id="app">
<p>{{messsage | capitalize}}</p>
</div>
<script>
Vue.filter('capitalize',function(value){
return value.toUpperCase()
})
var vm = new Vue({
el:'#app',
data:{
messsage:'hellovue',
}
})
</script>
(2)局部过滤器:
语法:
new Vue({
filters: {
'过滤器名称': function (value1[,value2,...] ) {
// 逻辑代码
}
}
})
示例:
<div id="app">
<p>{{n1 | param(n2,n3)}}</p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
messsage: 'hellovue',
n1: 10,
n2: 10,
n3: 10
},
filters: {
'param': function (n1, n2, n3) {
return n1 * n2 * n3
}
}
})
</script>
四,Vue条件语句和循环语句:
1,条件语句:
(1) v-if:条件判断:
下面代码 v-if 指令将根据表达式 show 的值(true 或 false )来决定是否插入 p 元素
<div id="app">
<p v-if ="show">哈哈哈哈</p>
<h3 v-if ="ok">我可能要隐藏</h3>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
show:true,
ok:false
}
})
</script>
(2) v-else:
可以用 v-else 给v-if添加一个 else块
<div id="app">
<p v-if ="ok">OK</p>
<h3 v-else>No</h3>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
ok:false
}
})
</script>
(3) v-else-if:用作v-if的else-if块 可以链式的多次使用
<div id="app">
<p v-if ="message == 1">1</p>
<p v-else-if ="message == 2">2</p>
<p v-else-if ="message == 3">3</p>
<p v-else>No number</p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
message:3
}
})
</script>
注意:v-else,v-else-if必须跟在v-if 或者v-else-if之后
2,循环语句:
(1)v-for指令:
v-for指令需要以 site in sites形式的特殊语法,sites是源数据数组,site是数据组元素迭代的别名
v-for渲染列表:
<div id="app">
<ul>
<li v-for='site in msgName'>{{site.name}}</li>
</ul>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
msgName:[
{name:'张三'},
{name:'李四'},
{name:'王五'},
{name:'孙八'},
]
}
})
</script>
(2)v-for迭代对象:
可以提供第二个的参数为键名
<div id="app">
<ul>
<li v-for='(message,key) in sites'>{{key}}:{{message}}</li>
</ul>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
sites:{
name:'张三',
sex:'男',
profession:'教师'
}
}
})
</script>
运行结果:
第三个参数为索引
<div id="app">
<ul>
<li v-for='(message,key,index) in sites'>{{index}}:{{key}}:{{message}}</li>
</ul>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
sites:{
name:'张三',
sex:'男',
profession:'教师'
}
}
})
</script>
用v-for实现九九加法表:
<div id="app">
<div>
<p v-for='n in 9'>
<b v-for ='m in n'>
{{m}}+{{n}}={{m+n}}
</b>
</p>
</div>
</div>
<script>
var vm = new Vue({
el: '#app'
})
</script>
运行结果:
五,Vue计算属性和监听属性:
1,计算属性:
(1)computed:
<div id="app">
<div>
<p>原始字符串:{{message}}</p>
<p>反转后字符串:{{reversedMessage}}</p>
</div>
</div>
<script>
var vm = new Vue({
el: '#app',
data:{
message:'abcdefg'
},
computed:{
reversedMessage:function(){
return this.message.split('').reverse().join('')
}
}
})
</script>
说明:上面案例中 声明了一个计算属性 reversedMessage ,提供的函数将用作属性 vm.reversedMessage 的 getter ,vm.reversedMessage 依赖于 vm.message,在 vm.message 发生改变时,vm.reversedMessage 也会更新
(2)computed setter
computed 属性默认只有 getter ,不过在需要时你也可以提供一个 setter
<div id="app">
<div>
<p>{{ reversedMessage }}</p>
</div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'abcdefg',
explain:'这些是英文字母'
},
computed: {
reversedMessage: {
get: function () {
return this.message + this.explain
},
set:function(newValue){
var msg = newValue.split(' ')
this.message = msg[0]
this.explain = msg[msg.length - 1]
}
}
}
})
vm. reversedMessage ='哈哈哈哈 你好呀'
document.write('message:' + vm.message)
document.write('<br>')
document.write('explain:' + vm.explain)
</script>
在运行 vm.site = '哈哈哈 你好呀'; 时,setter 会被调用, vm.message 和 vm.explain 也会被对应更新
(3)methods:
可以使用methods来代替computed 效果是一样的,computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。而使用 methods ,在重新渲染的时候,函数总会重新调用执行。
使用 computed 性能会更好,但是如果你不希望缓存,你可以使用 methods 属性
2,监听属性:watch
通过watch来响应数据的变化,
<div id="app">
<p>计数器:{{ count }}</p>
<button @click = 'count++'>按钮</button>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
count:1
}
})
vm.$watch('count',function(nval,oval){
console.log('数值变化:' + oval + '变为' + nval)
})
</script>
实现简单购物车:
<div id="app">
<table>
<tr>
<th>序号</th>
<th>名称</th>
<th>价格</th>
<th>购买数量</th>
<th>操作</th>
</tr>
<tr v-for='iphone in iphone_json'>
<td>{{iphone.id}}</td>
<td>{{iphone.name}}</td>
<td>{{iphone.price}}</td>
<td>
<button v-bind:disabled='iphone.count == 0' @click='iphone.count-=1'>-</button>
{{iphone.count}}
<button @click='iphone.count+=1'>+</button>
</td>
<td>
<button @click='iphone.count = 0'>移除</button>
</td>
</tr>
</table>
总价:${{totalPrice()}}
</table>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
iphone_json: [
{
id: 1,
name: '华为P30',
price: 3000,
count: 1
},
{
id: 2,
name: '华为P40',
price: 5000,
count: 1
}
]
},
methods:{
totalPrice: function() {
var totalIphone = 0;
var len = this.iphone_json.length;
for (var i = 0;i < len; i++) {
totalIphone += this.iphone_json[i].price * this.iphone_json[i].count
}
return totalIphone;
}
}
})
</script>
六,Vue样式绑定:
1,用v-bind来设置样式属性:
案例1:改变d-act的颜色
<div id="app">
<div class="d-act" v-bind:class="{'actives':isAct}"></div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
isAct:true
}
})
</script>
案例2:绑定返回对象的计算属性
<div id="app">
<div v-bind:class="classObject"></div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
isAct:true,
error:{
value:true,
type:'fatal'
}
},
computed:{
classObject:function(){
return{
base:true,
actives:this.isAct && !this.error.value,
'd-act':this.error.value && this.error.type === 'fatal'
}
}
}
})
</script>
案例3:使用三元表达式来切换列表中的class
errorClass 是始终存在的,isActive 为 true 时添加 activeClass 类
<div id="app">
<div v-bind:class="[errorClass,isAct ? activeClass : '']"></div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
isAct: true,
activeClass: 'active',
errorClass: 'd-act'
}
})
</script>
2,内联样式:style
<div id="app">
<div v-bind:style="{color:activeColor,fontSize: fontSize + 'px'}">哈哈哈哈哈哈</div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
activeColor: 'red',
fontSize: 25
}
})
</script>
也可以吧样式绑定到一个对象上:
<div id="app">
<div v-bind:style="styleObj">哈哈哈哈哈哈</div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
styleObj: {
color: 'red',
fontSize: '50px'
}
}
})
</script>
七,事件处理器:
1, v-on:事件监听指令
<div id="app">
<div>{{count}}</div>
<button v-on:click="count+=2">点击+2</button>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
count:1
}
})
</script>
2,可以使用内联的JavaScript 语句:
<div id="app">
<button v-on:click="conSay('hahha')">what??</button>
</div>
<script>
var vm = new Vue({
el: '#app',
methods:{
conSay:function(msg){
console.log(msg)
}
}
})
</script>
3,事件修饰符:
<!-- 阻止单击事件冒泡 不会一直传递,自己运行结束就结束了-->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件侦听器时使用事件捕获模式 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当事件在该元素本身(而不是子元素)触发时触发回调 -->
<div v-on:click.self="doThat">...</div>
<!-- click 事件只能点击一次-->
<a v-on:click.once="doThis"></a>
4,按键修饰符
<input v-on:keyup.enter="submit">
.enter
.tab
.delete (捕获 "删除" 和 "退格" 键)
.esc
.space
.up
.down
.left
.right
.ctrl
.alt
.shift
.meta