VUE数据监测的原理
- vue会监视data中所有层次的数据
如何检测对象中的数据?
通过setter实现监视,且要在new Vue时就传入要检测的数据 (1)、对象中后追加的属性,vue默认不做响应式处理 (2)、如需给后添加的属性做响应式,请使用如下API: Vue.set(target,propertyName/index, value) 或 this.$set(target,propertyName/index, value)
- 如何检测数组中的数据?
通过包裹数组更新元素的方法实现,本质就是做了两件事:
(1)、调用原生对应的方法对数组进行更新。
(2)、重新解析模板,进而更新页面。
- 在vue修改数组中的某一个元素一定要用如下方法:
1、使用这些API:push() 、pop() 、shift()、unshift()、splice()、sort()、reverse()
2、Vue.set() 或 this.$set()
特别注意:Vue.set() 和 this.$set() 不能给vm(this)或者vm的根数据对象(在这里指vm.data 或 vm._data) 添加属性
<div id="root">
<h2>学生信息</h2>
<button @click="student.age++">年龄+1</button><br/>
<button @click="addSex">添加性别属性,默认值:男(测试是否能响应式添加)</button><br/>
<button @click="student.sex = '未知'">修改性别(测试是否能响应式修改)</button><br/>
<button @click="addFriend">在列表首位添加一个朋友</button><br/>
<button @click="updateFirstFriendName">修改第一个朋友的名字为:张三</button><br/>
<button @click="addHobby">添加一个爱好</button><br/>
<button @click="updateHobby">修改第一个爱好为:开车</button><br/>
<button @click="removeHobby">过滤掉一个爱好为:睡觉</button><br/>
<h2>学生姓名:{{student.name}}</h2>
<h2>学生年龄:{{student.age}}</h2>
<h2 v-show="student.sex">学生性别:{{student.sex}}</h2>
<h2>爱好:</h2>
<ul>
<li v-for="(h,index) in student.hobby" :key="index">
{{h}}
</li>
</ul>
<h2>朋友们:</h2>
<ul>
<li v-for="(f,index) in student.friends" :key="index">
{{f.name}}--{{f.age}}
</li>
</ul>
</div>
data:{
student:{
name:'tom',
age:18,
hobby:['吃饭','睡觉','打豆豆'],
friends:[
{id:'001',name:'Bob',age:10,sex:'男'},
{id:'002',name:'Alice',age:11,,sex:'女'},
{id:'003',name:'Jame',age:12,sex:'男'}]
},
},
methods:{
addSex(){
//Vue.set(this.student,'sex','男') // 第一种
this.$set(this.student,'sex','男') // 第二种
},
addFriend(){
this.student.friends.unshift({name:'jack',age:70})
},
updateFirstFriendName(){
this.student.friends[0].name = '张三'
this.student.friends[0].age = 15
},
addHobby(){
this.student.hobby.push('学习')
},
updateHobby(){
//this.student.hobby.splice(0,1,'开车')
//Vue.set(this.student.hobby,0,'开车')
this.$set(this.student.hobby,0,'开车')
},
removeHobby(){
this.student.hobby = this.student.hobby.filter((h)=>{
return h !== '睡觉'
})
}
}
收集表单数据
- 若:
<input type="text"/>
, 则v-model收集的是value值,用户输入的就是value值。 - 若:
<input type="radio"/>
, 则v-model收集的是value值,且要给标签配置value值。 若:
<input type="checkbox"/>
,1、没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值) 2、配置input的value属性: (1)、v-model的初始值就是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值) (2)、v-model的初始值就是数组,那么收集的就是value组成的数组
备注:v-mdel的三个修饰符:
- lazy:失去焦点再收集
- number:输入字符串转为有效的数字
- trim:输入首尾空格并过滤掉
过滤器
- 定义:对要显示的数据进行特定格式化后再显示(适用于一些简单的逻辑的处理)
- 语法:
1、注册过滤器:Vue.filter(name,callback) 或 new Vue{filters: {}}
2、使用过滤器:{{ xxx | 过滤器名称}} 或者 v-bind: 属性 = “xxx | 过滤器名称”
- 备注:
1、过滤器也可以接收额外参数、多个过滤器也可以串联,串联的过滤器过滤的数据是前一个过滤器return的数据
2、并没有改变原本的数据,是产生新的对应的数据
<div id="root">
<!-- 过滤器会把你需要过滤的数据默认作为第一个参数,不需要你手动传参,你手动传参会作为第二个参数-->
<!-- 1、在插值语法里面使用过滤器 -->
<h2>过滤时间:{{time | timeFormter('YYYY-MM-DD') | mySlice}}</h2>
<!-- 2、在v-bind单向绑定数据里面使用过滤器 -->
<h2 :attr="name | mySlice">v-bind单向绑定属性</h2>
</div>
// 全局过滤器,在全局的组件和Vue实例都可以起作用
Vue.filter('mySlice',function(value){
return value.slice(0,4)
})
new Vue({
data:{
time:1621561377603, // 时间戳
},
// 局部过滤器,只在当前vue实例起作用
filters:{
timeFromter(value,str="YYYY-MM-DD HH:mm:ss"){
return dayjs(value).format(str)
}
}
})
vue指令
- v-bind :单向绑定解析表达式,可简写为 :xxx
- v-model:双向数据绑定
- v-for:遍历数组、对象、字符串
- v-on:绑定事件监听,可以简写为 @事件名称
- v-if:条件渲染(动态控制节点是否存在)
- v-else:条件渲染(动态控制节点是否存在)
- v-show:条件渲染(动态控制节点是否展示)
v-text:
1、作用:向其所在的节点中渲染文本内容 2、与插值语法的区别:v-text会替换掉节点中的内容,而{{xxx}}则不会替换节点的其他内容
v-html:
1、作用:向指定节点中渲染包含html结构的内容。 2、与插值语法的区别: (1)、v-html会替换掉节点中所有的内容,{{xxx}}则不会 (2)、v-html可以识别html结构。 3、严重注意:v-html有安全性问题!!! (1)、在网站上动态任意HTML是非常危险的,容易导致XSS攻击 (2)、一定要在可信的内容上使用v-html,永远不要用在用户提交的内容上!
v-cloak:没有值,是一个特殊属性
1、本质是一个特殊的属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性 2、使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题
<style>
[v-cloak]{
display:none;
}
</style>
<body>
<div id="root">
<h2 v-cloak>{{name}}</h2>
</div>
</body>
data:{
name:'test'
}
- v-once:没有值
1、v-once所在的节点在初次动态渲染后,就视为静态内容了。
2、以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。
<div id="root">
<h2 v-noce>初始化的值{{num}}</h2> // 1,不会随着按钮的点击再次变化
<h2 >自增计算后的值{{num}}</h2> // 随着按钮点击自增
<button @click="num++">点我num+1</button>
</div>
data:{
num:1
}
- v-pre:
1、跳过其所在节点的编译过程
2、可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。
<br/>
vue自定义指令
练习1、定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍。
练习2、定义一个v-fbind指令,和v-bind功能类似,但是可以让其所绑定的input元素默认获取焦点
<div id="root">
<h2 >当前的值:<span v-text="num"></span></h2>
<h2 >自增计算后的值:<span v-big="num"></span></h2>
<button @click="num++">点我num+1</button>
<input type="text" v-fbind:value="n" />
</div>
data:{
num:1
},
directives:{
// big函数何时会被调用?1.指令与元素成功绑定时(初次)。2.指令所在的模板被重新解析时。
big(element,binding){
console.log('big')
element.innerText = binding.value * 10
},
// 当指令直接写成函数时,相当于bind与update的方法功能
fbind:{
// 指令与元素成功绑定时
bind(element,binding){
element.innerText = binding.value
},
//指令所在元素被插入页面时
inserted(element,binding){
element.focus()
},
// 指令所在的模板被重新解析时
update(element,binding){
element.innerText = binding.value
}
}
}
// 全局指令
Vue.directive('fbind',{
// 指令与元素成功绑定时
bind(element,binding){
element.innerText = binding.value
},
//指令所在元素被插入页面时
inserted(element,binding){
element.focus()
},
// 指令所在的模板被重新解析时
update(element,binding){
element.innerText = binding.value
}
})
Vue.directive('big',function(element,binding){
console.log('big')
element.innerText = binding.value * 10
})
自定义指令总结:
一、定义语法
1、局部指令:
new Vue({ directives:{指令名:配置对象} }) 或 new Vue({ directives:{指令名:回调函数} })
2、全局指令:
Vue.directive(指令名,配置对象) 或 Vue.directive(指令名,回调函数)
二、配置对象中常用的3个回调:
1、bind:指令与元素成功绑定时调用
2、inserted:指令所在元素被插入页面时调用。
3、update:指令所在模板结构被重新解析时调用。
三、备注:
1、指令定义时不加v- ,但是使用时要加v-;
2、指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名。
3、指令内回调函数指向的this时window,不是vm