当前位置: 首页 > news >正文

【Vue2】数据绑定_MVVM模型_数据代理_事件处理

目录

一、 数据绑定

1. Vue中有2种数据绑定的方式:

2. 响应式原理

el 与 data 的两种写法

二、 MVVM模型

三、 数据代理

1.回顾Object defineproperty方法

2. 何为数据代理

3.Vue中的数据代理

四、 事件处理

1.事件的基本使用:

2. Vue中的事件修饰符:

3. 键盘事件

总结不易~ 本章节对我有很大的收获,希望对你也是!!!


一、 数据绑定

Vue2 的数据绑定是其核心特性之一,它采用 双向数据绑定(Two-way Data Binding) 机制,使数据和视图保持同步更新。

1. Vue中有2种数据绑定的方式:

  1. 单向绑定(v-bind):数据只能从data流向页面。
  2. 双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data。

 备注:

  1. 双向绑定一般都应用在表单类元素上(如:input、select等)
  2. v-model:value 可以简写为 v-model,因为v-model默认收集的就是value值。

单向绑定(v-bind

<p v-bind:title="message">{{ message }}</p>

双向绑定(v-model

<input v-model="name">

2. 响应式原理

Vue2 通过 数据劫持 + 观察者模式,当 data 发生变化时,Vue 触发 getter/setter 监听变化,并通知依赖更新视图。

  <div class="root">

    <!-- 普通写法 -->
    单向数据绑定: <input type="text" v-bind:value="name"> <br>
    双向数据绑定: <input type="text" v-model:value="name"><br>

    <!-- 简写 -->
    单向数据绑定: <input type="text" :value="name"> <br>
    双向数据绑定: <input type="text" v-model="name"><br>

  </div>

当我对data里面的name值直接进行修改的时候,不论是单向还是双休, 都要对页面渲染的数据发生变化,因为他们都是要从data存储数据的地方获取name值,都是互通的

当我只对单向数据绑定修改时:

只能实现单向数据传递,没法将数据从页面流向data

当我对双向数据绑定修改时:

都能够实现页面 <--->data数据的双向流动完成修改

    <!-- 如下代码是错误的 因为v-model  只能应用在表单元素上(输入类元素)   -->
    <h2 v-model:x="name">你好啊</h2>

el 与 data 的两种写法

el 的第一种写法:

在new的Vue里面通过el来获取与div容器的对应关系

    const v = new Vue({
      el: '.root', // 第一种写法 来绑定容器跟Vue一一对应
      data: {
        name: ""
      }
    })

el 的第二种写法:

由于已经构建好了元素v, 那么直接用v的内置函数$mount来进行挂载 于外面的div容器进行一一对应

    const v = new Vue({
        name: ""
      }
    })

    v.$mount('.root') // 第二种写法

data数据的第一种写法:

对象式,进行数据构造 

      const v = new Vue({
      el: '.root', 
      data: { 第一种写法 对象式
        name: ""
      }

data数据的第二种写法,函数式

可能现在不常用,但是到后面如果不用函数式写法,就会报错!直接对该函数只进行返回,这里照样在div容器内可以直接获取到{{name}} 


      // data 的第二种写法 函数式 (常用 )
      data: function () {
        console.log(this) // 这里的this就是Vue实例对象
        return {
          name: '我是哈哈'
        }
      }

      // 简写
      data() {
        console.log(this)
        return {
          name: 'hh'
        }
      }
    })

二、 MVVM模型

MVVM模型

  1. M:模型(Model) :data中的数据
  2. V:视图(View) :模板代码
  3. VM:视图模型(ViewModel):Vue实例

观察发现:

  1. data中所有的属性,最后都出现在了vm身上。
  2. vm身上所有的属性 及 Vue原型上所有属性,在Vue模板中都可以直接使用。
  <div class="root">
    <h1>学校名称:{{name}}</h1>
    <h1>学校地址:{{address}}</h1>
    <h1>测试一下1:{{1+1}}</h1>
    <h1>测试一下2:{{$emit}}</h1>
  </div>
</body>

<script>
  const vm = new Vue({
    el: '.root',
    data: function () {
      return {
        name: "hh",
        address: "湖北武汉"
      }
    }
  })

  console.log(vm)
</script>

测试一下2:就是vm里面新建new的内置函数了

在 Vue 开发中,通常使用 `const vm = new Vue({...})` 创建 Vue 实例,其中 `vm` 代表 ViewModel(视图模型),符合 MVVM(Model-View-ViewModel)架构。它作为数据(Model)和视图(View)之间的桥梁,实现数据绑定和 DOM 更新。`vm` 命名简洁明了,有助于区分 Vue 实例与普通变量,提高代码可读性。因此,`vm` 作为 Vue 实例的命名已成为开发中的常见约定。

三、 数据代理

1.回顾Object defineproperty方法

  let number = 81
  let person = {
    name: '张三',
    sex: '男',
    // age: 18
  }

  // 此时 这里的age属性 是不可以被遍历的 , 并且这个age是不可以被修改的
  Object.defineProperty(person, 'age', {
    // value: 18,
    // enumerable: true, // 控制属性是否可以枚举 默认值是false
    // writable: true, // 控制属性是否可以被修改 默认值是false
    // configurable: true, // 控制属性是否可以被删除 默认值是false 

    // 当有人读取person的age属性时,get函数就会被调用, 且返回值就是age
    // get: function () {
    //   return number
    // }
    get() {
      return number
    },
    // 修改
    set(value) {
      number = value
    }
  })
  console.log(person)

这里我们可以看到,通过Object.defineProperty(person, 'age', {}) 新添加的age属性的颜色是跟person对象中自己定义的name 和 sex属性颜色是不一样的

因为该person属性的自定义对象中无论是访问还是修改,都是随意的,这样对数据都没有得到安全的保障,而这里的age 确实要通过get 和 set函数来进行访问分别来得到 和 修改该age属性的值,这里就有点向C++的私有化 对象的构建,为了类里面的数据安全,只有通过重新构建函数来得到private私有化数据的值才是更安全的,这样外面的对象就不能直接对类里面的属性值进行修改!

2. 何为数据代理

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

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

    Object.defineProperty(obj2, 'x', {
      get() {
        return obj.x   // 当访问 obj2.x 时,实际返回 obj.x 的值
      },
      set(value) {
        obj.x = value  // 当修改 obj2.x 时,实际修改的是 obj.x
      }
    })
    console.log(obj)
    console.log(obj2)

通过 obj2 访问 obj 中的 x 属性,让 obj2.x 读写时实际上操作的是 obj.x

  • get() 作用:当 console.log(obj2.x) 时,实际返回 obj.x 的值,即 100

  • set(value) 作用:当 obj2.x = 300 时,实际上 obj.x 也会变成 300

        obj2.x = 300
        console.log(obj)
        console.log(obj2)

3.Vue中的数据代理

        1.Vue中的数据代理:

              通过vm对象来代理data对象中属性的操作(读/写)

        2.Vue中数据代理的好处:

              更加方便的操作data中的数据

        3.基本原理:

  •               通过Object.defineProperty()把data对象中所有属性添加到vm上。
  •               为每一个添加到vm上的属性,都指定一个getter/setter。
  •               在getter/setter内部去操作(读/写)data中对应的属性。
  <div class="root">
    <h2>学校名称:{{name}}</h2>
    <h2>学校地址:{{address}}</h2>
  </div>

</body>
<script src="../js/vue.js"></script>
<script>
  const vm = new Vue({
    el: '.root',
    data: {
      name: "我是哈哈",
      address: '湖北武汉'
    }
  })


</script>

证明:当我们把data数据单独抽离出来的时候,证明vm._data 这内置_data数据就是跟data对象是一模一样,说明vm._data 就是我们传入的data

  let data = {
    name: "我是哈哈",
    address: '湖北武汉'
  }

  const vm = new Vue({
    el: '.root',
    data
  })

  // 这里就有 vm._data === option.data === data
  // 说明vm._data 就是我们传入的data

四、 事件处理

1.事件的基本使用:

  1. 使用v-on:xxx 或 @xxx 绑定事件,其中xxx是事件名;
  2. 事件的回调需要配置在methods对象中,最终会在vm上;
  3. methods中配置的函数,不要用箭头函数!否则this就不是vm了;
  4. methods中配置的函数,都是被Vue所管理的函数,this的指向是vm 或 组件实例对象;
  5. @click="demo" 和 @click="demo($event)" 效果一致,但后者可以传参;

    <button v-on:click="showInfo">点我提示信息</button>
    <!-- 简写 -->
    <button @click="showInfo1">点我提示信息1</button>

v-on 是 Vue.js 的一个指令,用于监听 DOM 事件,并在触发时执行指定的方法或表达式。它的作用相当于原生 JavaScript 中的 addEventListener

当我们想要进行函数传参时:

    <!-- 传参  但是这样会将event弄丢 就要用$event关键字来提前占位-->
    <button @click="showInfo2(66, $event)">点我提示信息2</button>

其中showInfo()是vm对象里面的一个方法:

  const vm = new Vue({
    el: '.root',
    // 只有配置在data里面的数据才会做数据劫持 进行数据代理 有 set get
    data: {
      name: "武汉传媒学院",
    },
    // method 可以设置很多的回调 这里面设置方法 只要写方法名即可!!
    methods: {
      showInfo1(e) {
        console.log(e.target.innerText)
        alert('欢迎报考武汉传媒学院')
      },
      showInfo2(number, e) {
        console.log(number)
        console.log(e.target.innerText)
        alert('欢迎报考武汉传媒学院')
      }
    }
  })

2. Vue中的事件修饰符:

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

1.阻止默认事件 :

本该点击后进行跳转到百度网页的,却没有进行跳转!

<!-- 阻止默认事件(常用) -->
    <a href="http://www.baidu.com" @click.prevent="showInfo">点击我提示信息</a>

2. 阻止事件冒泡:

如果不添加stop事件修饰符, 那么从button位置开始就会依次网上冒泡,来调用两次showInfo函数,但是添加了stop时间修饰符后,该冒泡事件就会在当前button按钮位置停止

<!-- 阻止事件冒泡(常用) -->
    <div class="demo1" @click="showInfo">
      <button @click.stop="showInfo">点位提示信息</button>
    </div>

3. 只触发一次事件:

如果不添加once事件修饰符,那么点一次button就会调一次showInfo函数,但是添加了once事件修饰符后,多次点检button按钮只会触发一次调用showInfo函数

    <!-- 事件只触发一次(常用)  -->
    <button @click.once="showInfo">点位提示信息</button>

4. 事件捕获:

当我们点击第二个div 也就是box2的时候,首先就是要发生事件捕获 从外层依次往里找 就是从box1 找到box2 , 然后开始调用showMsg函数 依次往上冒泡 在到box1 再次调用showMsg,这里就会有一个问题,明明已经从box1开始往下寻找,为何不直接在这个时候就进行执行当前的函数调用呢?? 这也就是说是一种事件捕获,那么添加事件修饰符capture,当前事件就在捕获阶段执行,不会在进行冒泡

    <!-- 使用事件的捕获模式 -->
    <!-- 在捕获阶段就进行事件操作 完成事件操作后 就不会发生事件冒泡-->
    <div class="box1" @click.capture="showMsg(1)">
      div1
      <div class="box2" @click="showMsg(2)">
        div2
      </div>
    </div>

5.self 只有执行事件是当前DOM标签所触发的,才会执行和触发当前事件:

self事件修饰符标签可以看出来,当外面点击button按钮向上进行冒泡的时候,在demo1位置所触发的事件还是button事件冒泡上来的

    <!-- 只有event.target 是当前操作的元素时才触发事件 就算是冒泡冒上去的 那么触发该位置的事件也只是原来冒泡的原事件,而不是当前事件-->
    <!-- 那么这个self修饰符 就只能执行当前div所触发的事件 同样也能阻止冒泡-->
    <div class="demo1" @click.self="showInfo">
      <button @click="showInfo">点位提示信息</button>
    </div>

6.passive:事件的默认行为立即执行,无需等待事件回调执行完毕;

    .list {
      width: 200px;
      height: 200px;
      background-color: peru;
      overflow: auto; // 添加滚动条
    }

    li {
      height: 100px;
    }


    <!-- passive:事件的默认行为立即执行,无需等待事件回调执行完毕; -->
    <!-- scroll 滚动条的滚动 -->
    <!-- wheel 滚轮的滚动 -->
    <!-- 当我滚动滚轮的时候 为什么滚动条没有动? 因为要触发了当前事件立即执行 要把当前事件执行完后 才能触发滚动条 -->
    <!-- 那么passive 就会立即让滚动条进行滚动 直接进行触发 -->
    <ul @wheel.passive="demo" class="list">
      <li>1</li>
      <li>2</li>
      <li>3</li>
      <li>4</li>
    </ul>

3. 键盘事件

1.Vue中常用的按键别名:

  •                   回车 => enter
  •                   删除 => delete (捕获“删除”和“退格”键)
  •                   退出 => esc
  •                   空格 => space
  •                   换行 => tab (特殊,必须配合keydown去使用)
  •                   上 => up
  •                   下 => down
  •                   左 => left
  •                   右 => right

            2.Vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab-case(短横线命名)

            3.系统修饰键(用法特殊):ctrl、alt、shift、meta

  • 配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。
  • 配合keydown使用:正常触发事件。

            4.也可以使用keyCode去指定具体的按键(不推荐)

            5.Vue.config.keyCodes.自定义键名 = 键码,可以去定制按键别名

  <div class="root">
    <h2>欢迎来到{{name}}学习</h2>
    <!-- .enter 代表该键盘事件 回车键 -->
    <input type="text" placeholder="按下回车提示输入" @keyup.enter="showInfo">

    <!-- 额外补充 如果要按切换大小这个键 CapsLock(不常见) 那么就要将大写转成小写 并且 由多个单词组成之间的单词要用-来进行链接 -->
    <input type="text" placeholder="按下回车提示输入" @keyup.caps-lock="showInfo">

    <!-- 系统修饰键(用法特殊):ctrl、alt、shift、meta
    (1).配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。
    (2).配合keydown使用:正常触发事件。 -->
    <input type="text" placeholder="按下回车提示输入" @keyup.ctrl="showInfo">
    <!-- 只有在 ctrl + y 才适配 -->
    <input type="text" placeholder="按下回车提示输入" @keyup.ctrl.y="showInfo">
  </div>
</body>

<script>
  const vm = new Vue({
    el: '.root',
    data: {
      name: ""
    },
    methods: {
      showInfo(e) {
        // console.log(e.target.value)
        // console.log(e.keyCode)
        // if (e.keyCode !== 13) return
        console.log(e.target.value)
      }
    }
  })

总结不易~ 本章节对我有很大的收获,希望对你也是!!!

http://www.dtcms.com/a/107956.html

相关文章:

  • 手动实现一个迷你Llama:使用SentencePiece实现自己的tokenizer
  • 构造超小程序
  • 小程序30-wxml语法-声明和绑定数据
  • 数据库管理-第308期 用MySQL客户端访问国产Halo数据库(20250402)
  • DataX 3.0 实战案例
  • wireshark抓包分析数据怎么看 wireshark使用教程_wireshark怎么看
  • 前端图片压缩实战:基于compressorjs的高效解决方案
  • Flutter极速接入IM聊天功能并支持鸿蒙
  • ArcGIS Pro/GeoScene Pro AI 助手 2.1
  • SQL WHERE 与 HAVING
  • Scala集合
  • PostgreSQL JSON 与 JSONB 类型查询详解:差异、示例与最佳实践
  • 【STM32设计】基于STM32的智能门禁管理系统(指纹+密码+刷卡+蜂鸣器报警)(代码+资料+论文)
  • Gartner预计2025年AI支出达6440亿美元:数据中心与服务器市场的关键驱动与挑战
  • R语言、MaxEnt模型丨物种分布模拟技术的研究进展与技术挑战
  • mapbox_gl The requested URL returned error: 401
  • 小程序json对象数据从上一个页面传给下一个页面
  • 最短路径--SPFA算法
  • 软考中级网络工程师第十一章网络管理
  • Winform MQTT客户端连接方式
  • 力扣268.丢失的数字
  • 树莓派超全系列文档--(16)无需交互使用raspi-config工具其三
  • 【微知】ARM CPU是如何获取某个进程的页表的?(通过TTBR寄存器,MMU进行处理)
  • 基于javaweb的SSM+Maven校园共享自行车管理系统设计与实现(源码+文档+部署讲解)
  • 基于策略模式的CATIA元素显隐控制工具开发实践——PySide6与PyCATIA深度整合方案
  • 什么是PID控制?
  • FFmpeg命令详解
  • 波动率 计算学习 离散系数
  • 【JavaScript】十四、轮播图
  • 探索Ark-TS语言:什么是Ark-TS?如何入门?有什么基础容易上手?