lsdyna如何设置set中的node_list_简析 Vue 中的数据响应式

a41159adfdcc7aad179d9f9353d26208.png

其实关于 Vue 的数据响应式的主要原理在官方文档中已经介绍了(戳这里),但是看了好几次还是一知半解,接下来来看看 Vue 是如何实现的吧。

什么是响应式

首先,我们得知道什么是响应式,其实这是一个比较模糊的概念,举一个简单的例子:如果我朝你打一拳过去,你肯定会躲吧,我叫你一声你会应我吧(放心,不会收到葫芦里~)。还有更实际的例子:响应式页面 ——— 一种页面布局方式,页面的布局会随着页面大小的改变而改变。

而 Vue 的数据响应式是什么意思呢?其实文档中也写到了:

而当你修改它们时,视图会进行更新。

如何知道一个数据是否变化呢?答案是:监视他!给他装一个「监听器」!

那怎么装呢?先来看一个简单的 Vue 示例:

const _data = {
    n:1
}
console.log(_data)  // {n:0}

const vm = new Vue({
    data:_data,
    template: `
        <div>{{n}}</div>
    `
}).$mount("#app")

console.log(_data) // {__ob__: Observer}

这里我们发现控制台中打印的 _data 的不一样了,因为 Vue 对传入的 data 进行了处理,点开这个对象,我们发现对象内部多了几个函数,其中就有 getset,这就是 Vue 文档中说所的 getter/setter

ES6 的 getter/setter

getter 和 setter 怎么用呢?我们还是直接上代码:

// 一个人
const people = {
    姓:'张',
    名:'三'
}


//如果我想得到姓名,可以直接在对象中添加一个函数
const people1 = {
    姓:'张',
    名:'三',
    姓名(){
        return this.姓 + this.名
    }
}
console.log(people1.姓名()) // 张三


// 然后 ES6 的 getter 帮我们简化了一下
const people2 = {
    姓:'张',
    名:'三',
    get 姓名(){
        return this.姓 + this.名
    }
}
console.log(people2.姓名)    // 张三
// 只是简化了函数的括号,没什么大不了的


//然后我又需要对姓名进行设置,这时候就可以用到 setter
const people3 = {
    姓:'张',
    名:'三',
    get 姓名(){
        return this.姓 + this.名
    },
    set 姓名(name){
        this.姓 = name[0]
        this.名 = name.slice(1) 
        // 获取姓名的方式并不严谨,只是一个示例
    }
}
people3.姓名 = '王五'
console.log(people3.姓名)    // 王五
// 设置 set 以后,'= xxx' 这个操作便会调用 set 函数,等号后面的值便是函数的参数。

当我们将赋值取值的过程转变为函数以后,我们就可以在函数中添加各种操作了,比如告诉视图需要改变、告诉computedwatch 该工作啦,这个不属于本文的内容,我们只要知道这样就可以监听数据的变化就好了。

但是,getter 和 setter 只能在对象初始化的时候设置,可是 Vue 中传入的对象是已经初始化完毕的对象,Vue 是怎么对其进行监听的呢?答案是:Object.defineProperty

Object.defineProperty

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

其中也包括 getter/setter,废话不多,上代码:

// 我们需要让一个对象全面被我们监控,这样才能及时更新视图
let data = {
    n:0
}



// 使用 Object.defineProperty 
let data1 = {}
data1._n = 0  // 先用一个属性存住 n 的值
Object.defineProperty(data1,'n',{
    get(){
        return this._n
    },
    set(xxx){
        console.log('监听到了~')
        this._n = xxx
    }
})

data1.n = 5    // 监听到了~

//但是,这时如果我们直接操作 data1._n
data1._n = 6    // 什么都没输出
console.log(data1.n)    // 6




//继续改进!既然你喜欢直接操作对象,那我用一个代理函数,传入一个匿名对象,输出一个我监听的代理对象,这样你就操作不了了吧
function proxy({data}){
    const obj = {}
    // 这里写死了'n',正常时需要遍历 data 的所有 key 进行操作的
    Object.defineProperty(obj,'n',{
        get(){
            return data.n
        },
        set(xxx){
            data.n = xxx
            console.log('监听到了,值是'+data.n)
        }
    })
    return obj
}

let data2 = proxy({data:{n:0}})

//再试试
data2.n = 5    // 监听到了,值是5 

// 但是,好像还是有问题,如果我们像最上面的例子那样写
let _data = { n: 0 }
let data3 = proxy({data:_data})

data3.n = 7    // 监听到了,值是7 
_data.n = 8    // 什么都没有,值却改变了
console.log(data3.n)    // 8




// 既然这样,那我把传入的对象也一起监听上!
function proxy2({data}){
    // 这里写死了'n',正常时需要遍历 data 的所有 key 进行操作的
    let value = data.n
    Object.defineProperty(data,'n',{
        get(){
            return value
        },
        set(xxx){
            value = xxx
            console.log('原始对象监听到了,值是'+data.n)
        }
    })
    const obj = {}
    Object.defineProperty(obj,'n',{
        get(){
            return data.n
        },
        set(xxx){
            data.n = xxx
            console.log('代理对象监听到了,值是'+data.n)
        }
    })
    return obj
}
let _data = { n: 0 }
let data4 = proxy2({data:_data})

data4.n = 9    // 原始对象监听到了,值是9 
               // 代理对象监听到了,值是9 
_data.n = 10   // 原始对象监听到了,值是10

都搞定咯,这时我们回头看一眼最上面的案例

const vm = new Vue({data:_data})

let data4 = proxy2({data:_data})

是不是有点像?目前我们就简单实现了 Vue 数据响应式。当然,真正的代码肯定没有这么简单,大家有兴趣可以自行研究源代码~

如果有错误的地方,欢迎大家指正!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值