模板语法
插值:{{ }},在标签体内输出数据
指令
v-bind:,简写为:,用来给标签的属性绑定变量
v-model:用来给表单类标签做数据的双向绑定
el与data的两种写法
el的两种写法
MVVM
1.M:模型,对应data中的数据
2.V:视图,模板
3.VM:视图模型:Vue实例对象,作为模板和视图的中间层,处理双向绑定
数据代理
通过一个对象可以操作另一个对象中属性的值,即通过对象a可以操作对象b中属性的值
// 想通过操作obj1来操作obj2
let obj1 = {}
let obj2 = {
age:20
}
// 如果访问obj1中的age,那么getter会去查obj2中的age
// 如果修改obj1中的age,那么setter会将修改的值赋给obj2中的age
// 达成了通过obj1来操作obj2中的属性
Object.defineProperty(obj1,'age',{
// 当obj1对象的age属性被查看时触发get方法,get方法的返回值就是age属性的值
get() {
return obj2.age
},
// 当obj1对象的age属性被修改时触发set方法,参数就是被修改的值
set(val) {
obj2.age = val
}
})
Vue中的数据代理
vue中通过new Vue()实例出的vm对象来代理对data对象中属性的操作
具体来讲,就是vue先将data保存在vm对象自身的_data属性中,其中有数据劫持的操作暂时忽略,然后把data中的每一个属性通过Object.defineProperty添加属性到vm实例对象中,当我们通过vm访问name属性时,触发getter方法,实际访问的是_data中的name,修改也是一样,触发setter
const vm = new Vue({
el:'#app',
data:{
name:'张三'
}
})
数据代理的好处:利于操作data中数据,比如不用数据代理使用data中数据时得加上_data,{{data_.name}}, 数据代理后直接写{{name}}
Vue中的事件处理
通过指令v-on:可以绑定事件,简写为@,事件的回调函数需要写在methods中
<div id="app">
<button v-on:click='handle1'>按钮1</button>;
<button @click='handle2(12,$event)'>按钮2</button>;
</div>
<script>
Vue.config.productionTip = false
const vm = new Vue({
el: '#app',
data: {
},
methods: {
handle1(event) {
console.log(event);
},
handle2(age, event) {
console.log(age, event);
}
}
})
</script>
其中有三点需要注意
1、如果回调函数不传参,默认传一个事件对象event,如果回调函数传参数则需要用$event占位,不然接收不到事件对象
2、methods中方法要用普通函数定义,方法内this指向vm或组件实例,如果用箭头函数定义,方法内this会指向window
3、传入的methods也会挂在vm上,但是不会数据代理,也不要将方法定义在data,会让vue累成狗
事件修饰符
1、.prevent:阻止默认事件
2、.stop:阻止冒泡
3、.once:事件只触发一次
4、.capture:使用事件的捕获模式,即在捕获阶段就开始触发事件
5、.self:当前操作的元素是e.target时才触发事件
6、.passive:事件的默认行为立即执行,无需等待事件回调执行完毕
键盘事件
vue中可以使用按键别名来实现特定按键事件
<input @keyup.enter='handle'></input>
enter:回车, delete:删除, esc:返回, space:空格,up:上,down:下,left:左,right:右
计算属性
依赖已有属性计算出的属性,依赖属性发生改变时计算属性也会改变
计算属性存在缓存,只要依赖的值不发生改变,访问计算属性会返回缓存中之前计算的值,不会触发getter重新计算
computed:{
age:{
get(){
return age + 1;
},
set(value){
console.log(value);
}
}
}
getter的触发时机:
1、初次访问age
2、依赖的值age发生改变
如果计算属性只用来访问可以简写
computed:{
age(){
return age + 1;
}
}
侦听属性
侦听vue实例上数据的变化情况,被侦听的数据发生变化时触发侦听方法
immediate配置项为true会在注册侦听属性时执行一次侦听函数
watch默认不会侦听对象内部的数据变化,只会侦听一层,使用deep可以侦听对象内部属性变化
watch:{
age:{
immediate: true,//age初始化侦听时会先执行一次侦听函数
deep:true,
handler(new,old) {
console.log(new);//变化后的值
console.log(old);//变化前的值
}
}
}
如果没有配置项可以简写
watch:{
age(new,old) {
console.log(new);//变化后的值
console.log(old);//变化前的值
}
}
绑定样式
vue中尽量避免直接操作dom,如果要修改样式,通过v-bind绑定动态属性实现
动态class
- 字符串方式
<div id="app">
<div :class="class"></div>
</div>
<script>
new Vue({
el: '#app',
data: {
class: 'flex'
}
})
</script>
- 数组方式
<div id="app">
<div :class="class"></div>
</div>
<script>
new Vue({
el: '#app',
data: {
class: ['flex1','flex2','flex3']
}
})
</script>
- 对象方式
<div id="app">
<div :class="class"></div>
</div>
<script>
new Vue({
el: '#app',
data: {
class:{
flex1:true,
flex2:true
}
}
})
</script>
动态style
<div id="app">
<div :style="style"></div>
</div>
<script>
new Vue({
el: '#app',
data: {
style:{
color:'red',
fontSize:'16px',
backgroundColor:'#000',
width:'100px',
height:'100px'
}
}
})
</script>
条件渲染
v-if
1、不渲染时节点不存在于dom
2、适合切换频率较低的场景
v-show
1、不渲染的元素只是用样式隐藏
2、适合切换频率较高的场景
列表渲染
key的原理:vue中发生数据更新时,会创建新的虚拟dom,vue会对比新旧虚拟dom来更新真实dom,而对比虚拟dom时,vue会将相同key的节点进行对比,其中有不同的元素则重新创建生成真实元素,相同的元素则不重新创建而是直接复用,
用index作为key:如果对数据的顺序进行了破坏,那么遍历时的索引就会改变,相应的key就会和之前的key对应不上,这样在vue进行对比时会进行不必要的dom生成消耗性能,如果渲染项存在表单输入,那么页面还会错乱
vue监测对象数据的原理
模拟一个简单的vue监测对象数据,它只能监测一层数据
let data = {
name: '张三',
age: 18
}
// 定义一个观察者构造函数,通过构造出的实例来监测数据
function Observe(obj) {
// 首先获取对象的所有key
let keys = Object.keys(obj)
// 遍历keys
keys.forEach(key =>{
// 向观察者实例添加getter,setter做数据劫持
Object.defineProperty(this,key,{
get() {
return obj[key]
},
set(val) {
obj[key] = val
console.log(`${key}改变了,我要去更新模板了`);
}
})
})
}
// 创建一个观察者实例,通过观察者实例可以监测data数据
let obs = new Observe(data)
//创建一个vm实例
let vm = {}
vm._data = obs
vue监测数组
没有对数组中的属性进行数据劫持,通过数组下标修改数组数据时,vue不能监听,不是响应式的
通过数组方法操作数组时,vue可以监听到,是响应式的