【Vue】基础(二)数据代理 - 事件处理 - 计算属性 - 监视属性 - 绑定样式

6. 数据代理

学习数据代理前需要js的一些知识:Object.defineProperty(),属性标志,属性描述符,getter,setter。。。

建议学习以下文章:

  1. 属性标志和属性描述符
  2. 属性的 getter 和 setter
6.1 回顾Object.defineProperty()方法

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

语法:Object.defineProperty(obj, prop, descriptor)

参数一:obj:要定义属性的对象。

参数二:prop:要定义或修改的属性的名称或 Symbol

参数三:descriptor:要定义或修改的属性描述符(数据描述符和存取描述符)。

  • 属性描述符有两种主要形式:数据描述符和存取描述符。数据描述符是一个具有值的属性,该值可以是可写的,也可以是不可写的。存取描述符是由 getter 函数和 setter 函数所描述的属性。一个描述符只能是这两者其中之一;不能同时是两者。两种描述符都是对象

两种描述符共享以下可选键值:

  • enumerable —> 默认值是 false ,如果为 true, 控制属性则可以枚举(枚举是指对象中的属性是否可以被遍历),可以在for.. .inObject.keys() 中遍历出来。
  • configurable —> 默认值是 false ,如果为 true, 控制属性则可以被删除,否则不可以。

数据描述符还具有以下可选键值:

  • value —> 该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。 默认为 undefined
  • writable —> 默认值是 false ,如果为 true,控制属性则可以被修改,否则只是可读的。

存取描述符还具有以下可选键值:

  • get —> 属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。 默认为 undefined
  • set —> 属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。 默认为 undefined

示例代码

<script type="text/javascript">
    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)就会背调用
        get() {
     
            console.log('有人读取了age属性');
            return number
        },

        // 当有人修改person的age属性时,set函数(setter)就会背调用
        set(value) {
     
            console.log('有人修改了age属性,且值是:', value);
            number = value;
        }
    });

    // console.log(person);
    // console.log(Object.keys(person));
</script>
6.2 什么是数据代理

数据代理:通过一个对象代理对另一个对象中属性的操作(读/写),就是数据代理。

先来看个案例:

let obj1 = {
    x: 100 }
let obj2 = {
    y: 200 }

这时候提一个需求:我们想要访问 obj1 中的 x 的值,但我们最好不要直接去访问 obj1 ,而是想要通过 obj2 这个代理对象去访问。

这时候就可以用 Object.defineProperty() 方法,给 obj2 添加上存取描述符(也叫访问器属性,就是gettersetter)

示例代码

let obj1 = {
    x: 100 }
let obj2 = {
    y: 200 }

Object.defineProperty(obj2, "x", {
   
    // 当读取obj2的x属性时,get函数(getter)就会被调用,且返回值就是x的值
    get() {
   
        return obj1.x;
    },
    // 当修改obj2的x属性时,set函数(setter)就会被调用,且会收到一个具体修改的值value
    set(value) {
   
        obj1.x = value;
    }
})

// 验证以上代码
console.log(obj1.x); // 输出结果:100
console.log(obj2.x);// 输出结果:100
console.log(obj2); // 输出结果:{ y: 200}  obj2下还有 x:300及get和set方法
obj2.x = 300;
console.log(obj1.x); //输出结果:300

这就是数据代理,简单吧!

6.3 Vue中的数据代理
  • Vue中的数据代理:通过vm对象来代理data对象中属性的操作(读/写)
  • Vue中数据代理的好处:更加方便的操作data中的数据
  • 基本原理:
    • 通过 Object.defineProperty() 把data对象中所有属性添加到vm上。
    • 为每一个添加到vm上的属性,都指定一个 getter/setter
    • getter/setter 内部去操作(读/写)data中对应的属性。

下面用一个案例来详细解释这个过程

<div id="app">
    <h1>网站名称:{
  {name}}</h1>
    <h1>网站地址:{
  {addrss}}</h1>
</div>

<script type="text/javascript">
    const vm = new Vue({
     
        el: '#app',
        data() {
     
            return {
     
                name: '百度',
                addrss: 'https://www.baidu.com/',
            }
        }
    });
    console.log(vm); // 输出结果:Vue实例对象
</script>

打印的 vm 在浏览器中如下:

在这里插入图片描述

从以上图中可以看到,写在配置项中的 data 数据被绑定到了 vm 实例对象中,结果就是,Vue 将 _data 中的name、addrss 使用数据代理到 vm 本身上。

那 _data 是个啥?

解释一波,_data 就是 vm 身上的 _data 属性,具体见上图的红色框下面第二行。

那这个 _data 又是哪里来的呢?

在解释一波,_data 就是下面代码中 data 内的数据,只是在 new Vue 时进行了一些处理。

<script type="text/javascript">
    const vm = new Vue({
     
        el: '#app',
        data() {
     
            return {
     
                name: '百度',
                addrss: 'https://www.baidu.com/',
            }
        }
    });
</script>

new Vue 时, Vue 通过一系列处理, 将匹配项上的 data 数据绑定到了 _data 这个属性上,并对这个属性进行了处理(数据劫持),但这个属性就是来源于配置项中的 data,我们可以来验证一下。

<script>
    let data1 = {
     
        name: '百度',
        addrss: 'https://www.baidu.com/',
    }
    
	const vm = new Vue({
     
        el: '#app',
        // 我们在 Vue 初始化的配置项中写了 data 属性。
        data: data1
    })
    
     console.log(vm._data === data1); // 输出结果:true
</script>

输出结果为true,说明两者就是同一个。

好了,再回到数据代理上来,将 vm._data 中的值,再代理到 vm 本身上来,用 vm.name 代替 vm._data.name。这就是 Vue 的数据代理。

我们来验证一下:

console.log(vm._data.name === vm.name); // 输出结果:true
console.log(vm._data.address === vm.address); // 输出结果:true

输出结果都为true。

这一切都是通过 Object.defineProperty() 方法来完成的,来模拟一下这个过程

Object.defineProperty(vm, 'name', {
   
    get() {
   
        return vm._data.name;
    },
    set(value) {
   
        vm._data.name = value
    }
})

到这可能就会有疑问了,明明可以通过 vm._data.name 访问 name 的值,为啥要费力去这样操作?

在Vue的插值语法中,{ { name }} 取到的值就相当于 { { vm.name }},不用数据代理的话,在插值语法中就要这样去写了。

<div id="app">
    <h1>网站名称:{
  {_data.name}}</h1>
    <h1>网站地址:{
  {_data.addrss}}</h1>
</div>

{ { _data.name }} 这种写法是不是感觉怪怪的。其实 { { name }} 这种写法更利于开发者开发,Vue 也是这样设计的,只不过我们在研究原理时会觉得有些复杂。

好了,不在磨磨唧唧了,直接上示意图:

数据代理示意图

7.事件处理

7.1 事件的基本使用

事件的基本使用:

  • 使用 v-on:xxx@xxx 绑定事件,其中 xxx 是事件名。
  • 事件的回调需要配置在 methods 对象中,最终会在 vm 上。
  • methods中配置的函数,不要用箭头函数,否则 this 就不是 vm 了。
  • methods中配置的函数,都是被Vue所管理的函数,this 的指向是 vm 或组件实例对象。
  • @click="demo"@click="demo($event)" 效果一致,但后者可以传参。
<div id="app">
    <h1>欢迎来到{
  {name}}</h1>
    <button v-on:click="showInfo">点我提示信息(不简写)</button
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值