赞
踩
我们通常可以对进行输入框进行数据的监听,只需要用到了input 事件或 change事件,就可以实时监听到数据的改变,但是如果只是一个单独的数据呢?怎么去做监听,watch吗??哈哈。
所以 vue响应式就用到了object.defineProperty 中的 get 和 set 方法 ,如果对方法不了解可访问蓝色文字。简单来说 只要一访问就会触发get,设置就会触发set。
基本语法:
Object.defineProperty(对象,键,{
get ( ) { },
set (val) { }
})
- let data = {
- name:'奥特曼'
- }
-
- Object.defineProperty(data,'name',{
- get(){
- console.log('访问了')
- },
- set(val){
- console.log('设置了,值是:',val)
- }
- })
实现效果:
为了和vue保持格式一致 我们先定义初始变量data ,并且一开始把值赋给类名为name的内容数据
- <div class="name"></div>
- <script>
- let data = {
- name:'奥特曼'
- }
-
- function setName() {
- document.querySelector('.name').innerHTML = username
- }
-
- setName()
- </script>
接下来要对data.name进行实时的监听,就要用到了obj.defineProperty
- let username = "奥特曼";
- Object.defineProperty(data, "name", {
- get() {
- console.log("访问了");
- return username;
- },
- set(val) {
- console.log("设置了,值是:", val);
- username = val;
- setName();
- },
- });
这里注意 特意用了一个中间变量 username,如果不这么用你可能会想到,错误写法别抄哦
- get(){
- console.log('访问了');
- return data.name
- },
为什么不直接把data.username给返回出去,为什么要返回一个值一样的username?原因就是 我们返回着data.name 其实也是在访问他,然后呢每次访问每次进入get函数 就会进入一个死循环。
这里就不过多解释了 只需要把对象循环一下 利用Object.defineProperty监听每个属性,我相信你可以看懂的
- <script>
- let data = {
- username:'奥特曼',
- age:18,
- }
-
- function setData() {
- username.innerHTML = data.username
- age.innerHTML = data.age
- }
-
- function observe(data) {
- for (const key in data) {
- let value = data[key]
- Object.defineProperty(data,key,{
- get(){
- return value
- },
- set(val){
- value = val
- setData()
- }
- })
- }
- }
-
- observe(data)
- setData()
-
- </script>
我们只需要判断当前的参数是否是对象 如果是对象利用一下递归。
- <script>
-
- let data = {
- username:'奥特曼',
- age:18,
- student:{
- name :'怪兽'
- }
- }
-
- function setData() {
- username.innerHTML = data.username
- age.innerHTML = data.age
- monster.innerHTML = data.student.name
- }
-
- function observe(data) {
- for (const key in data) {
- if(typeof data[key] == 'object') {
- observe(data[key])
- }
- let value = data[key]
- Object.defineProperty(data,key,{
- get(){
- return value
- },
- set(val){
- value = val
- setData()
- }
- })
- }
- }
-
- observe(data)
- setData()
-
- </script>
在vue中,我们是检测不到一个对象新增属性和直接修改数组某一项的变化,但是上面的代码中是能够对数组下标进行修改的,那为什么vue不可以呢?
尤大大也说考虑到了性能和用户体验的问题 如果一个数组10000条数据 监听这每一项的数据变化 确实也有很大的性能问题,但vue也提供了解决方案 $set
贴一下 修改数组下标 及 修改不了新增的对象属性代码
- <script>
- let data = {
- username:'奥特曼',
- age:18,
- student:{
- name :'怪兽'
- },
- arr:[0,1,2,3]
- }
-
- function setData() {
- username.innerHTML = data.username
- age.innerHTML = data.age
- monster.innerHTML = data.student.name
- // 无法对新增的属性进行监听 原因就是observe 一开始就对原数据进行数据的监听 这也是object.defineproperty的本身缺陷
- monsterAge.innerHTML = data.student.age
- number.innerHTML = data.arr[0]
- }
-
- function observe(data) {
- for (const key in data) {
- if(typeof data[key] == 'object') {
- observe(data[key])
- }
- let value = data[key]
- Object.defineProperty(data,key,{
- get(){
- return value
- },
- set(val){
- value = val
- setData()
- }
- })
- }
- }
-
- observe(data)
- setData()
-
- </script>
补充:但是有一点哈,有时候呢 你是可以修改数组某一项实现响应式的,什么时候呢看下面的例子
- <div>
- <div> {{arr[0]}}</div>
- {{ obj.a }}
- <button @click="editNumber">要修改了</button>
- </div>
-
- <script>
- export default {
- data () {
- return {
- arr: [0, 1, 2, 3, 4, 5],
- obj: { a: 1 }
- }
- },
- methods: {
- editNumber () {
- this.arr[0] = 999
- // 如果不加下面这一行代码,视图就不会更新
- // 更新的原因:下面的数据是响应式的数据他会去更新视图,一旦更新视图 数据是对整个组件进行更新的,所以arr[0] 会更新
- // 其实底层的object.defineProperty 可以对数组进行更新 但是尤大考虑到数组 的性能与用户体验不成正比 去掉了对数组的响应式 (获取涉及几万条数组非常的大)
- this.obj.a = 2
- }
- }
- }
- </script>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。