初学vue(全家桶)-第二天:数据代理、事件处理

初学vue(全家桶)-第二天:数据代理、事件处理,第1张

文章目录 初学vue1、数据代理1.1 Object.defineProperty方法1.2 数据代理1.2.1 定义1.2.2 简单应用与分析 2、事件处理2.1 基本使用介绍2.2 事件修饰符vue中常用事件修饰符:实例 2.3 键盘事件

初学vue 1、数据代理 1.1 Object.defineProperty方法

语法:Object.defineProperty(obj, prop, descriptor);
参数说明:
1、obj:目标对象(必需)
2、prop:需定义或者修改的属性的名字(必需)
3、descriptor:目标属性所拥有的特性(必需)

返回值:所传入的函数的对象,及方法中的第一个参数obj
作用:修改属性的特性。
并且该方法设置的属性是不可枚举的,但可以通过enumerable特性修改成可枚举的。

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="../JS/vue.js">script>
    <title>Documenttitle>
head>
<body>
    <script>
        const person = {
            name:"张三",
            gender:"男"
        }

        Object.defineProperty(person,"age",{
            value:18,
            // 设置为可枚举属性
            // enumerable:true,
            // 设置属性值是否可以修改
            // writable:true,
            // 设置属性是否可以删除
            // configurable:true,
			
        })

        // console.log(person);
        // 将标签中的属性列出来,并且前面加上索引
console.log(Object.keys(person));
    script>
body>
html>
// 当defineProperty未设置可枚举时
console.log(person);

结果如下:

// 当defineProperty设置为可枚举时
console.log(person);

结果如下:

经过defineProperty设置的属性并不能进行值的修改,需要修改对应属性的特性writable的值为true,这样才可以修改值;经过defineProperty设置的属性并不能进行属性的删除,需要修改对应属性的configurable的值为true。

defineProperty()方法的高级特性:getter函数和setter函数

描述:定义一个全局变量,定义一个对象person,在这个person对象中有一个属性age的属性值是这个全局变量,要求当修改number变量的值时,这个age对应的值同时可以发生改变,使得不需要手动重新让number的值赋值给age。那么这里可以使用getter和setter函数,如下:

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="../JS/vue.js">script>
    <title>Documenttitle>
head>
<body>
    <script>
        let number=18;
        const person = {
            name:"张三",
            gender:"男"
        }

        Object.defineProperty(person,"age",{
            // 其他特性这里省略......

            // 当读取age属性时,get函数(getter)就会被调用,且返回的是age的值
            get:function(){
                console.log("有人读取age属性了");
                return number;
            },
            // 当修改age属性时,set函数(setter)就会被调用,切回收到修改的具体值
            
            set:function(value){
                console.log("有人修改age属性了,且修改的值为:",value);
                number = value;
            }
        });

    script>
body>
html>

1.2 数据代理 1.2.1 定义

数据代理:通过一个对象代理对另一个对象中属性的 *** 作(读/写)
例如:

<body>
    <script>
        let obj1 = {x:100};
        let obj2 = {y:200};

        Object.defineProperty(obj2,"x",{
            get(){
                return obj1.x;
            },
            set(value){
                obj1.x = value;
            }
        });
    script>
body>

上面例题就是简单的数据代理,通过defineProperty()方法中的get和set函数,修该obj2中的x的值以此来修改obj1中x的值。

1.2.2 简单应用与分析

如下

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
    <script src="../JS/vue.js">script>
head>
<body>
    <div id="root">
        <h2>姓名:{{name}}h2>
        <h2>居住地址:{{address}}h2>
    div>
    <script>
        const vm = new Vue({
            el:"#root",
            data:{
                name:"小明",
                address:"江苏苏州"
            }
        });
    script>
body>
html>

当控制台输出vm对象时,发现vm中有name和address两个属性,但其实这两个属性应该是在data中的,为什么这里会显示出来呢,这就与数据代理有关了。

数据代理通过getter和setter方法实现,如下图所示

vm实例中的属性name是通过getter函数获取到了data中的name。可以通过vm.name获取到值,但不能通过vm.data.namedata.name获取,因为这里的data是局部的,并不是全局的。
> 验证:将代码中name属性的值修改,可以发现页面控制台、页面中对应的值也修改了。

vm实例可以通过setter函数修改data中的name值。

那么问题来了,vm对象中的name和address属性是存在与data中的,而且不能通过data.name或者vm.data.name的方式获取到值,那么,为什么却可以通过vm.name的方式取到值和设置值呢?

在vm对象中,有这么一个属性_data

这个_data属性中存储了data中各个属性的的值,vm可以通过get函数从_data中拿到data中name和address的值,然后赋值给vm中的name和address,从而可以通过对象名.属性名的方式直接拿到值。并且在使用set函数设置值的时候,也是将重新设置的值放到_data中。关于为什么_data中可以存储data中的值,这就与数据劫持有关了,这里不做多余介绍。

怎么验证vm._data=data?
>
这里data并不存在在全局中,而是在vm对象中。
可以通过将data中的数据从vm对象中抽取成一个对象,如下:

<body>
    <div id="root">
        <h2>姓名:{{name}}h2>
        <h2>居住地址:{{address}}h2>
    div>
    <script>
        let data={
            name:"小明",
            address:"江苏苏州"
        }
        const vm = new Vue({
            el:"#root",
            data:data
        });
    script> 
body>

然后比较vm._data=data,vue的配置对象是options,这里的options.data=data,options中的data指的就是定义在vm外部的变量data。

总结下来,获取、修改对象属性值的方式有
(1)vm.属性名
(2)vm._data.属性名
如果通过vm._data.属性名的形式获取值明显复杂点,而通过数据代理,使用vm.属性名的方式来获取值更加方便简单。
回到代码中

这是通过Object.defineProperty()方法实现的,如图:
上面两根线代表使用了defineproperty方法在vm对象中定义了name和address属性。

总结:
(1)vue中的数据代理就是通过vm对象来代理data对象中属性的 *** 作(读/写)
(2)vue中数据代理的好处就是能够更见方便简单的 *** 作data中的数据,例如:vm._data.name ⇒ 简写成vm.name
(3)基本原理就是:通过Object.defineProperty()方法把对象中所有的属性添加到vm上。为每一个添加到vm上的属性都指定一个getter和setter,在getter/setter内部去 *** 纵data中对应的属性。

2、事件处理 2.1 基本使用介绍

(1)使用v-on:xxx或者 @xxx 绑定事件,xxx是指事件名

<body>
    <div id="root">
        <h2>欢迎您,{{name}}h2>
        <button v-on:click="sayHi">点我说Hibutton>
        
        <button @click="sayHi">点我也说Hibutton>

        
    div>
    <script>
        const vm = new Vue({
            el:"#root",
            data:{
                name:"小明"
            },
            methods:{
                sayHi(){
                    alert("Hi!!!")
                }
            }
        });
    script>

(2)当往函数中添加任意个形参时,第一个形参代表event对象,其他形参的输出undefined。

<body>
    <div id="root">
        <h2>欢迎您,{{name}}!!!h2>
        <button v-on:click="sayHi">点我说Hibutton>
        <button v-on:click="sayGoodBye">点我说goodByebutton>
    div>
    <script>
        Vue.config.productionTip = false;

        const vm = new Vue({
            el:"#root",
            data:{
                name:"小明"
            },
            methods:{ 
                sayHi(a,b,c,d){
                    console.log("Hi")
                    console.log(a,b,c,d); 
                },
                sayGoodBye(event){
                    console.log("goodBye");
                    console.log(event);
                }
            }
        });
    script>
body>

(3)事件的回调需要配置在methods对象中,并且这个回调最终会在出现在vm实例上。

并且methods中的方法并不会数据代理,以内方法不需要展示在页面上。

(4)methods中配置的函数最好不要使用箭头函数,避免this不是指向vm实例。
(5)methods中配置的函数都是被Vue所管理的函数,this指向的是vm或者组件实例对象

<body>
    <div id="root">
        <button v-on:click="clickMe">点我啊button>
        <button v-on:click="clickMeTo">点我呀button>
    div>
    <script>
        Vue.config.productionTip = false;
        const vm = new Vue({
            el:"#root",
            data:{
                name:"小明",
            },
            methods:{
                clickMe(){
                    console.log("你怎么敢点我啊");
                    console.log(this === vm); // true
                    console.log(this); // vm
                },
                clickMeTo:(event) => {
                    console.log("你怎么也敢点我呀");
                    console.log(this); // window
                }
            }
        });
    script>
body>


(5)可以在事件函数中传入参数

<body>
    <div id="root">
        <button v-on:click="clickMe">点我啊button>
        <button v-on:click="clickMeTo(666)">点我呀button>
        
    div>
    <script>
        Vue.config.productionTip = false;
        const vm = new Vue({
            el:"#root",
            data:{
                name:"小明",
            },
            methods:{
                clickMe(){
                    console.log("你怎么敢点我啊");
                    
                },
                clickMeTo(number){
                    console.log("你怎么也敢点我呀");
                    console.log(number);
                }
            }
        });
    script>
body>

这么做会忽略掉event对象,所以可以在事件中使用占位符$event来表示event,如下:

<body>
    <div id="root">
        <button v-on:click="clickMe">点我啊button>
        <button v-on:click="clickMeTo(666,$event)">点我呀button>
        
    div>
    <script>
        Vue.config.productionTip = false;
        const vm = new Vue({
            el:"#root",
            data:{
                name:"小明",
            },
            methods:{
                clickMe(){
                    console.log("你怎么敢点我啊");
                    
                },
                // 这里的a代表了event
                clickMeTo(number,a){
                    console.log("你怎么也敢点我呀");
                    console.log(number,a);
                }
            }
        });
    script>
body>

2.2 事件修饰符 vue中常用事件修饰符:

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

实例 阻止默认事件
<body>
    <div id="root">
        <h2>请点击连接h2>
        <a href="http://www.baidu.com" @click.prevent="showInfo">百度一下a>
    div>
    <script>
        const vm = new Vue({
            el:"#root",
            data:{
                name:"小明"
            },
            methods:{
                showInfo(){
                    console.log("你好");
                }
            }
        });
    script>
body>

结果:超链接不会跳转,阻止了默认事件,也就是点击连接后不会进行默认跳转。

阻止事件冒泡
<body>
    <div id="root">
        <h2>阻止事件冒泡h2>
        <div class="demo01" @click="showInfo">
            <button @click.stop="showInfo">点我提示信息button>
		   
        div>
    div>
    <script>
        const vm = new Vue({
            el:"#root",
            data:{
                name:"test"
            },
            methods:{
                showInfo(){
                    alert("d窗!!!");
                }
            }
        });
    script>
body>
事件只触发一次
<body>
    <div id="root">
        <button class="first" @click.once="showInfo">点我触发事件button>
    div>
body>
<script>
    const vm = new Vue({
        el:"#root",
        data:{

        },
        methods:{
            showInfo(){
                alert("这是一次d窗!");
            }
        }
    });
script>
事件捕获阶段触发事件
<body>
    <div id="root">
        <div class="outer" @click.capture="showMsg('outer')">
                outer
            <div class="inner" @click="showMsg('inner')">
                inner
            div>
        div>
    div>

    <script>
        new Vue({
            el:"#root",
            data:{},
            methods:{
                showMsg(position){
                    console.log(position,"触发了事件");
                }
            }
        });
    script>
body>

经过捕获后的结果就是先触发outer,再触发inner。如果没有被捕获就是先触发inner,后触发outer。
捕获和冒泡的演示如下图:

event.target是当前 *** 作的元素时才触发事件
<body>
	<style>
        div{
            height: 50px;
            background-color:yellow;
        }
    style>
    <div id="root" @click.self="showInfo">
        <button @click="showInfo">点我触发事件button>
    div>

    <script>
        new Vue({
            el:"#root",
            data:{},
            methods:{
                showInfo(){
                    alert("触发事件");
                }
            }
        });
    script>
body>

分析,不给父标签加.self时,会受冒泡影响触发两次事件,而在父标签使用事件中使用了.self修饰后,发现点击按钮时,只触发一次,**原因是div上的事件被.self修饰后,只有当event.target是这个div元素时才会触发事件,(也就是直接点击div元素区域时才会触发这个事件),而这里点击按钮触发的事件也只是按钮上绑定的事件触发的。这也可以作为阻止冒泡的方式

2.3 键盘事件 vue中常用的按键别名:

回车:enter
删除:delete(捕获”删除“和“退格”键)
空格:space
退出:esc
换行:tab(特殊:必需配合keyDown使用)
上:up
下:down
左:left
右:right

<body>
    <div id="root">
        <label for="input">请输入:label>
        
        <input type="text" id="input" @keyup.enter="showInfo">
    div>
    <script>
        new Vue({
            el:"#root",
            data:{},
            methods:{
                // 设置回车后输出值的第一种方式
                // showInfo(e){
                //     if(e.keyCode !== 13) return ; // 13是enter键的编码,keyCode可以获取到键盘按键的编码
                //     console.log(e.target.value); // 获取输入框中输入的值
                // }

                // 在键盘事件后使用键的别名
                showInfo(e){
                    console.log(e.target.value);
                }
            }
        });
    script>
body>
html>
key和keyCode的区别:
key获取键的名字,keyCode获取按键的编码
<body>
    <div id="root">
        <label for="input">请输入:label>
        <input type="text" id="input" @keyup="showInfo">
        
    div>
    <script>
        new Vue({
            el:"#root",
            data:{},
            methods:{
                // 在键盘事件后使用键的别名
                showInfo(e){
                    // console.log(e.target.value);
                    console.log(e.key,e.keyCode);
                }
            }
        });
    script>
body>

vue没有提供别名的按键可以使用按键原始的key值去绑定,但要注意字母转为大小写,不同意思单词之间用-分开,例如转换大小的键caps lock写成caps-lock

系统修饰键(用法特殊)
如ctrl、alt、shift、meta(window)
(1)配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发,例如按下ctrl键,同时按下y键,然后释放y键,事件被触发。
(2)配合keydown使用:能够正常出发事件。

Vue.config.keyCodes.自定义键名=键码,自定义按键别名(不推荐)

<body>
    <div id="root">
        <label for="input">请输入:label>
        
        <input type="text" id="input" @keyup.huiChe="showInfo">
    div>
    <script>
        // 自定义按键别名
        Vue.config.keyCodes.huiChe = 13;

        new Vue({
            el:"#root",
            data:{},
            methods:{
                showInfo(e){
                    console.log(e.target.value);
                }
            }
        });
    script>
body>

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1296641.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-10
下一篇 2022-06-10

发表评论

登录后才能评论

评论列表(0条)

保存