草庐IT

【VUE前进之路】使用数据代理,计算属性与监视属性的妙用

大熊李子 2023-04-13 原文

1.数据代理

1.1什么是数据代理

通过一个对象代理对另一个对象中属性的操作(读/写)
1.Vue中的数据代理:通过vm对象来代理data对象中属性的操作(读/写)
2.Vue中数据代理的好处:更加方便的操作data中的数据
3.基本原理:通过0bject . defineProperty( )把data对象中所有属性添加到vm上。为每一一个 添加到vm上的属性,都指定个getter/setter。在getter/setter内部去操作(读/写) data中对应的属性。简单来说就是把data的属性全部都复制给了_data了一份,可以让vm进行使用

1.2了解使用数据代理

Object.defineProperty方法(给对象添加属性方法的一个方法)这个方法会传入三个参数分别是 对象名,属性名,配置项
在这里我们可以看到,这个颜色稍微的优点变化(这里就是使用Object.defineProperty方法进行添加的,这里的age是不可以进行枚举的,即不参与遍历)

    <script>
    let person = {
        name:'大熊'
        sex:'男',
    }    
    Object.defineProperty(person,'address',{
        value:18
    })
    console.log(person);
    </script>

这里可以使用Object.keys()进行验证一下(并没有age这个属性)(可以看到依然没有age)

当然也可以使用for… in进行遍历一下这个对象

如和才能让他可以被枚举呢?(这里就使用 enumerable 只要将它的值改为true即可)enumerable: true (是否可以被枚举)writable:true(是否可以修改属性)configurable: true(是否可以删除改属性)这四个基本配置项的内容(包括value)他们的默认值为false

    <script>
    let person = {
        name:'大熊',
        sex:'女',
    }    
    Object.defineProperty(person,'address',{
        value:18
    })
    for(k in person){
        console.log(k);
    }
    console.log(Object.keys(person));
    console.log(person);
    </script>

那问题来了,如何进行对数据的读取和修改呢?这里用到了两个方法,get和set
当有人读取person的age属性时,get函 数(getter)就会被调用,且返回值就是age值
当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具值

    <script>
        let number = 19;
        let person = {
            name: '大熊',
            sex: '女',
        }
        Object.defineProperty(person, 'address', {
            get() {
                console.log('age属性已被读取');
                return number;
            },
            set(value) {
                console.log('age属性已被修改');
                number = value
            }
        })
    </script>

2. 事件处理

1.使用v-on:xxx或@xxx绑定事件,其中xxx是事件名
2.事件的回调需要配置在methods对象中,最终会在vm上
3.methods中配置的函数,不可以使用箭头函数,否则this就不是vm了而是window
4.methods中配置的函数,都是被Vue所管理的函数,this的指向是vm或组件实例对象5.@click="demo"和@click="demo"效果一致,但后者可以传参
注:不要把事件回调方法data里,虽然可以实现相同的功能,但是这样会给增加一个数据代理,给一个方法添加数据代理是没有意义的

<div id="user">
        <h1>{{name}}吃饭了吗?</h1>
        <button v-on:click="showPage($event,18)">点击提示</button>
        <!-- 第一个参数是event,所以下面的参数顺序要和这里一致 -->
    </div>
    <script>
        let vm = new Vue({
            el: '#user',
            data: {
                name: '山鱼',
            },
            methods: {
                // 在这里配置各种事件回调
                showPage(event, number) {
                    alert('山鱼吃饭了!')
                    console.log(number);

                }
            }
        })
    </script>

2.1事件修饰符

1.prevent:阻止默认事件(常用)
2.stop: 阻止事件冒泡(常用)
3.once:事件只触发一次(常用)
4.capture: 使用事件的捕获模式
5.self: 只有event.target是当前操作的元素是才触发事件;
6.passive: 事件的默认行为立即执行,无需等待事件回调执行完毕;

<div id="user">
        <h1>欢迎来到{{name}}的小屋</h1>
        <!-- 1,阻止默认事件 -->
        <a href="http://baidu.com" @click.prevent = "showInfo">点我不跳转</a>
        <!-- 2,阻止事件冒泡 -->
        <div class="one" @click = 'showInfo'>
            <button @click.stop = 'showInfo'>点我</button>
        </div>
        <!-- 3,事件只触发一次 -->
        <button @click.once = 'showInfo'>只能点一次</button>
    </div>
    <script>
    const vm = new Vue({
        el:'#user',
        data:{
            name:'大熊',
        },
        methods:{
            showInfo(e){
                alert('同学,慢走!')
            }
        }
    })
    </script>

2.2键盘事件

常用的按键别名
回车=> enter,删除=>delete(捕获“删除”和“退格”键),退出=> esc,空格=> space,上=>up,下=> down,左=> left,右=> right

特殊的按键别名
1.换行=> tab (特殊,必须配合keydown使用)
2.系统修饰键 ctrl,alt,shift,meta(meta就是win键也就是windows徽标)
注:
(1).配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。
(2).配合keydown使用:正常触发事件。

<div class="user">
        <h1>欢迎加入{{uname}}</h1>
        <!--.enter 就是按下回车触发事件,也成为按键别名-->
        <input type="text" placeholder="按下回车提示输入" @keyup.enter = 'showInfo'>
        <!--删除 del -->
        <input type="text" placeholder="按下del提示输入" @keyup.delete = 'showInfo'>
        <!-- 退出esc -->
        <input type="text" placeholder="按下ESC提示输入" @keyup.esc = 'showInfo'>
        <!-- 特殊按键别名 -->
        <input type="text" placeholder="一同按下ctrl+‘其他按键’并释放提示输入" @keyup.ctrl = 'showInfo'>
        <!-- 自定义别名 -->
        <input type="text" placeholder="按下回车提示输入" @keyup.huiche = 'showInfo'>
    </div>
    <script>
        // 也可以自定义按键别名
        Vue.config.keyCodes.huiche = 13;
        const vm = new Vue({
        el:'.user',
        data:{
            uname:'山鱼社区'
        },
        methods:{
            showInfo(e){
                console.log(e.target.value);
            }
        }
    })
    </script>

3.计算属性

1.定义: 要用的属性不存在,要通过已有属性计算得来。
2.原理:底层借助了objcet . defineproperty方法提供的getter和Isetter.
3. get函数什么时候执行?
(1).初次读取时会执行一次。
(2).当依赖的数据发生改变时会被再次调用。
4.优势:与jmethods 实现相比,内部有缓存机制(复用),效率更高,调试方便。
5.注:
1.计算属性最终会出现在:vm上,直接读取使用即可。
2.如果i计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发发生变化
3.计算属性内不能够开启异步任务(如:定时器)

<body>
    <!-- 容器 -->
    <div class="user">
        姓:<input type="text" v-model="firstName"><br>
        名:<input type="text" v-model="lastName"><br>
        姓名:<span>{{fullName}}</span>
    </div>
    <script>
        const vm = new Vue({
            el: '.user',
            data: {
                firstName: '李',
                lastName: '四'
            },
            // 计算属性
            computed: {
                fullName: {
                    // 当ful1Name被读取时,get就会被调用,且返回值就作为fullName的值,而且get有个缓存效果
                    // 这里的get在初次读取fullName时会被调用,在所依赖的数据进行改变时也会调用
                    // 这里所依赖的数据有俩分别是firstName和lastName
                    get() {
                        return this.firstName +"-" +this.lastName
                    },
                    // 当fullName被修改时调用
                    set(value){
                        console.log('set被hi行');
                        
                        const arr = value. split('-');
                        this.firstName = arr[0];
                        this.lastName = arr[1];
                    }
                }
            }
        })
    </script>
</body>

简写计算属性(前提是只用到get的时候可以简写)

4.侦听属性

监视属性watch:
1.当被监视的属性变化时,回调函数自动调用,进行相关操作
2.监视的属性必须存在,I才能进行监视! !
3.监视的两种写法:
(1) . new Vue时传入watch配置
(2) .通过vm. $watch监视

<body>
    <div class="user">
        <h1>今天我很{{info}}</h1>
        <button @click='changeMood'>点击切换心情</button>
    </div>
    <script>
        new Vue({
            el: '.user',
            data: {
                mood: true
            },
            computed: {
                info() {
                    return this.mood ? '开心' : '不开心'
                },
            },
            methods: {
                changeMood() {
                    this.mood = !this.mood
                }
            },
            watch: {
                // 被监视的是谁
                mood: {
                    immediate: true,// 初始化时 让handler调用一次
                    // handler有俩参数分别是修改前的值和修改后的值
                    handler(newValue, oldValue) {
                        console.log('mood被修改了', newValue, oldValue);
                    }
                },
                // 这个监视属性也可以监视计算属性
                info: {
                    immediate: true,// 初识化时 让handler调用一次
                    // handler有俩参数分别是修改前的值和修改后的值
                    handler(newValue, oldValue) {
                        console.log('info被修改了', newValue, oldValue);
                    }
                },

            }
        })
        // 也可以用vm.$watch进行监视 =》vm.$watch(监视对象,如何监视)
        vm.$watch('mood', {
            immediate: true,// 初识化时 让handler调用一次
            // handler有俩参数分别是修改前的值和修改后的值
            handler(newValue, oldValue) {
                console.log('info被修改了', newValue, oldValue);
            }
        })
    </script>
</body>

4.1深度监视

深度监视
①Vue中的watch默认不监测对象内部值的改变
②配置deep:true可以监测对象内部值改变
备注:
①Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以
②使用watch时根据数据的具体结构,决定是否采用深度监视

4.2监视属性简写

简写(但是不能配置immediate:true,deep:true)

 watch: {
                // 完整写法
                // mood: {
                // deep:true
                //     handler(newValue, oldValue) {
                //         console.log("mood被修改", newValue, oldValue);

                //     }
                // }
                // 简写
                mood(newValue, oldValue) {
                    console.log('mood被修改', newValue, oldValue);
                }
            }
        })
         // 正常写法
        vm.$watch('mood',{
                immediate:true,
                deep:true,
                handler(newValue, oldValue) {
                    console.log('mood被修改', newValue, oldValue);
                }
            })
            // 简写
            vm.$watch('mood',function(newValue, oldValue){
                console.log('mood被修改', newValue, oldValue);
            })

4.3computed & watch之间的区别

1.computed能完成的功能,watch 都可以完成。
2.watch能完成的功能,computed不一定能完成,例如: watch可以进行异步操作。
3.两个重要的小原则:
①所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm或组件实例对象。
②所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等),最好写成箭头函数,这样this的指向才是vm或组件实例对象。

5.写在最后

大家好我是大熊🐻
一个学前端的旅行者也是一个前进的创作者,奋进再这篇土地,希望能和您相遇
✍善于利用零星时间的人,才会做出更大的成绩来。——华罗庚

有关【VUE前进之路】使用数据代理,计算属性与监视属性的妙用的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  5. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  6. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  7. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  8. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  9. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  10. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

随机推荐