目录
Vue检索数据 this.$set( target, key, value )
数据代理
- 了解Object.defineproperty方法
// Object.defineproperty 的作用就是直接在一个对象上定义一个新属性,或者修改一个已经存在的属性
// Object.defineproperty可以接收三个参数
// Object.defineproperty(obj, prop, desc)
// obj : 第一个参数就是要在哪个对象身上添加或者修改属性
// prop : 第二个参数就是添加或修改的属性名
// desc : 配置项,一般是一个对象
let number = 18
let person = {
name:'张三',
sex:'男',
}
Object.defineProperty(person,'age',{
// value:18,
// enumerable:true, //控制属性是否可以枚举,默认值是false
// writable:true, //控制属性是否可以被修改,默认值是false
// configurable:true //控制属性是否可以被删除,默认值是false
//当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值
get(){
console.log('有人读取age属性了')
return number
},
//当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值
set(value){
console.log('有人修改了age属性,且值是',value)
number = value
}
})
2. 拓展:关于Object.keys()和Object.values()的使用
// 关于Object.keys():查看一个对象本身的所有属性,返回一个数组,成员是参数对象自身的(不含继承的)//所有可遍历(enumerable)属性的键名 (取对象属性名转成数组)
let person ={ name:'张三',age:24,address:'杭州' }
Object.keys(person) // ['name', 'age', 'address']
Object.keys(person).forEach(key => {
console.log(key) //name, age, address
console.log(person[key]) //张三, 24, 杭州
})
//关于Object.values()
//Object.values()和Object.keys()是相反的操作,把一个对象的值转换为数组 (取对象属性值转成数组)
let person = { name: '张三', age: 24, address: '杭州', getName: function () {} }
console.log(Object.keys(person)) // ['name', 'age', 'address', 'getName']
Object.keys(person).map((key) => {
console.log(person[key], '属性值') //获取到属性对应的值,根据需求做一些处理
})
3. 数据代理的定义:通过一个对象代理对另一个对象中属性的操作(读|写)
let obj = {x:100}
let obj2 = {y:200}
Object.defineProperty(obj2,'x',{
//当有人读取obj2的x属性时,get函数(getter)就会被调用,且返回值就是x的值
get(){
return obj.x
},
//当有人修改obj2的x属性时,set函数(setter)就会被调用,且会收到修改的具体值
set(value){
obj.x = value
}
})
4. vue中的数据代理
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Vue中的数据代理</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--
vm:vue实例对象 vc:组件实例对象
1.Vue中的数据代理:
通过vm对象来代理data对象中属性的操作(读/写)
2.Vue中数据代理的好处:
更加方便的操作data中的数据
3.基本原理:
通过Object.defineProperty()把data对象中所有属性添加到vm上。
为每一个添加到vm上的属性,都指定一个getter/setter。
在getter/setter内部去操作(读/写)data中对应的属性。
-->
<!-- 准备好一个容器-->
<div id="root">
<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const vm = new Vue({
el:'#root',
data:{
name:'张三',
address:'杭州'
}
})
</script>
</html>
数据劫持
key作用与原理
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>key的原理</title>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--
面试题:react、vue中的key有什么作用?(key的内部原理)
1. 虚拟DOM中key的作用:
key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,
随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:
2.对比规则:
(1).旧虚拟DOM中找到了与新虚拟DOM相同的key:
①.若虚拟DOM中内容没变, 直接使用之前的真实DOM!
②.若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM。
(2).旧虚拟DOM中未找到与新虚拟DOM相同的key
创建新的真实DOM,随后渲染到到页面。
3. 用index作为key可能会引发的问题:
1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:
会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。
2. 如果结构中还包含输入类的DOM:
会产生错误DOM更新 ==> 界面有问题。
4. 开发中如何选择key?:
1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,
使用index作为key是没有问题的。
-->
<!-- 准备好一个容器-->
<div id="root">
<!-- 遍历数组 -->
<h2>人员列表(遍历数组)</h2>
<button @click.once="add">添加一个测试</button>
<ul>
<li v-for="(item,index) of persons" :key="index">
{{item.name}}-{{item.age}}
<input type="text">
</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
new Vue({
el:'#root',
data:{
persons:[
{id:'001',name:'张三',age:18},
{id:'002',name:'李四',age:19},
{id:'003',name:'王五',age:20}
]
},
methods: {
add(){
const p = {id:'004',name:'测试',age:40}
this.persons.unshift(p)
}
},
})
</script>
</html>
Vue检索数据 this.$set( target, key, value )
Vue中this.$set的用法
1. Vue.set( target, propertyName/index, value )
数组:第一个参数是要修改的数组, 第二个值是修改的下标或字段,第三个是要修改成什么值。
2. this.$set(this._data,”key”,value')
对象:第一个参数是要修改的对象, 第二个值是修改属性字段,第三个是要修改成什么值。
target: 要更改的数据源(可以是一个对象或者数组) key 要更改的具体数据 (索引) value 重新赋的值。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>总结vue数据监视</title>
<style>
button{
margin-top: 10px;
}
</style>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--
Vue监视数据的原理:
1. vue会监视data中所有层次的数据。
2. 如何监测对象中的数据?
通过setter实现监视,且要在new Vue时就传入要监测的数据。
(1).对象中后追加的属性,Vue默认不做响应式处理
(2).如需给后添加的属性做响应式,请使用如下API:
Vue.set(target,propertyName/index,value) 或
vm.$set(target,propertyName/index,value)
3. 如何监测数组中的数据?
通过包裹数组更新元素的方法实现,本质就是做了两件事:
(1).调用原生对应的方法对数组进行更新。
(2).重新解析模板,进而更新页面。
4.在Vue修改数组中的某个元素一定要用如下方法:
1.使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
2.Vue.set() 或 vm.$set()
特别注意:Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象(vm._data) 添加属性!!!
-->
<!-- 准备好一个容器-->
<div id="root">
<h1>学生信息</h1>
<button @click="addSex">添加性别属性,默认值:女</button> <br/>
<button @click="addFriend">添加一个朋友</button> <br/>
<button @click="updateFirstFriendName">修改第一个朋友的名字为:张三</button> <br/>
<button @click="addHobby">添加一个爱好</button> <br/>
<button @click="updateHobby">修改第一个爱好为:开车</button> <br/>
<button @click="removeSmoke">过滤掉爱好中的抽烟</button> <br/>
<h3>姓名:{{student.name}}</h3>
<h3>年龄:{{student.age}}</h3>
<h3 v-if="student.sex">性别:{{student.sex}}</h3>
<h3>爱好:</h3>
<ul>
<li v-for="(h,index) in student.hobby" :key="index">
{{h}}
</li>
</ul>
<h3>朋友们:</h3>
<ul>
<li v-for="(f,index) in student.friends" :key="index">
{{f.name}}--{{f.age}}
</li>
</ul>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const vm = new Vue({
el:'#root',
data:{
student:{
name:'mary',
age:18,
hobby:['唱歌','跳舞','跑步'],
friends:[
{name:'jerry',age:25},
{name:'tony',age:16}
]
}
},
methods: {
addSex(){
// Vue.set(this.student,'sex','女')
this.$set(this.student,'sex','女')
},
addFriend(){
this.student.friends.unshift({name:'jack',age:50})
},
updateFirstFriendName(){
this.student.friends[0].name = '张三'
},
addHobby(){
this.student.hobby.push('学习')
},
updateHobby(){
// this.student.hobby.splice(0,1,'看书')
// Vue.set(this.student.hobby,0,'看书')
this.$set(this.student.hobby,0,'看书')
},
removeSmoke(){
this.student.hobby = this.student.hobby.filter((h)=>{
return h !== '跑步'
})
}
}
})
</script>
</html>