【Vue】data属性,v-for,diff算法,composition API,子传父,父传子

文章详细介绍了Vue3中的关键概念,包括data属性必须为函数,v-model的双向数据绑定,v-for的优化使用,以及响应式原理的变化。还探讨了Vue3的新特性如compositionAPI,setup函数,ref和reactive的区别,以及nextTick和watch函数在处理DOM更新中的作用。

❤️ Author: 老九
☕️ 个人博客:老九的CSDN博客
🙏 个人名言:不可控之事 乐观面对
😍 系列专栏:

Vue3

在这里插入图片描述

  • MVC和MVVM模型
    MVC是Model-View-Controller,MVVM是Model-View-ViewModel,html就相当于是view,javaScript就相当于controller,通过axios获取数据,获取的数据就是model,然后通过model返回给view,这样就是MVC模式;
    Vue就是MVVM的结构,ViewModel就是将模型里的数据绑定到View上了,如果view上发生了一些事件,通过ViewModel触发DOM Listeners之后操作model里面的值

data属性

  • Vue2中可以不写函数,Vue3的版本必须的是一个函数,Vue2通过Object.defineProperty实现,Vue3通过new Proxy实现

数组的重新检测机制

  • 注意数组更新的检测,如果是使用一些原生的数组方法,是直接修改了数组的值,如果是使用map,filter等高阶函数,会生成一个新的函数,不会修改原函数的值;如果要重新修改原数组的话,就重新赋值一下,这个比较重要

methods属性

  • 注意:如果在这里面定义函数,不能使用箭头函数

插值语法

  • 双花括号中不能插入html代码,为了避免xss的攻击,通过v-html可以实现

v-bind

  • 专门用于绑定属性的,动态绑定属性
    绑定style,绑定的是对象类型
    在这里插入图片描述

v-on

  • 用户绑定事件,缩写是@
    在这里插入图片描述

绑定事件的参数传递

默认参数有event对象,如果么有任何传递的参数,那么event对象就会默认传递进来
在这里插入图片描述
在这里插入图片描述

修饰符

  • prevent修饰符会告知v-on指令对触发事件调用event.preventDefault(),用来阻止事件的默认行为,例如a标签默认跳转连接等等
  • enter修饰符,自动添加回车确定事件
  • passive:被动事件表示该事件处理函数不会调用preventDefault(),浏览器可以不必等到这个函数运行完才执行默认行为,可以让默认行为更早的发生,让页面看起来更流畅
  • once:运行一次旧销毁

v-on的修饰符

  • .stop:调用event.stopPropagation(),用于阻止事件冒泡
  • .prevent:调用event.preventDefault(),用于阻止默认事件
  • .capture:添加事件监听器到指定事件的捕获阶段,正常事件触发的时候是在冒泡阶段,如果加了这个修饰符,点击父元素的时候就可以触发事件了

v-model

  • 用于双向数据绑定用的
  • 本身就是语法糖,负责监听用户的输入事件来更新数据,可以在表单input,textarea,select,checkbox,radio等元素上创建双向数据绑定,会根据控件的类型自动选取正确的方法来更新元素
  • 这里注意一下,如果是checkbox的多选框的话,需要确定一下value值才可以,v-model是一个数组
    在这里插入图片描述
  • 通过v-bind帮点value属性的值;绑定input事件或者change事件监听函数,函数会获取最新的值赋值到绑定的属性中
  • 默认情况下,v-model绑定的是input事件,如果在v-model后面加上lazy修饰符,就会切换为change事件,只要在提交(比如回车)才会触发
    -

v-for

  • 在使用v-for进行列表渲染的时候,通常会和key属性一起使用,key属性主要用于Vue的虚拟DOM算法,在新旧nodes对比时辨识VNodes
  • 首先认识一下VNode,VNode就是虚拟节点,无论是组件还是元素,他们最终在Vue中表示出来的都是一个个VNode,VNode本质是一个JS对象
    在这里插入图片描述
  • 元素先转化成VNode,然后VNode之后转换成真实的DOM
    在这里插入图片描述
  • 那么如果我们不只是一个简单的div,而是有一大堆的元素,那么他们应该会形成一个VNode Tree,多个VNode形成一个虚拟DOM
  • 那么为什么有一个虚拟DOM呢,方便我们后续的diff算法,也方便我们跨平台
    在这里插入图片描述

虚拟DOM

  • 虚拟DOM就在Vue的实例上面,叫做_vnode,首先tag是根元素div,div的id在data中的attrs展示是container,里面有一个children,里面就是一些子节点(包括文本节点)
    在这里插入图片描述
    在这里插入图片描述
  • vue的模板字符串编译成一个模板函数,vue里面自带一个函数可以实现这个,vue.compile('div @click=“foo()”></ div>),这个函数里面还有一个cache缓存函数,如果转化过了就不转化了,原理就是先通过模板生成一个抽象语法树 ,然后根据抽象语法树变成模板函数(这是一个匿名函数 ,通过With关键字传this),然后模板函数获得值再返回给你,这个东西才是我们真正可以用的东西,这个模板函数就是render函数,render 函数是用于生成组件的虚拟 DOM(Virtual DOM)的函数。
    在这里插入图片描述
  • 当修改界面上的东西的时候,就会在render函数中调用这句话创建一个新的vnode节点,这句话vm._renderProxy是vue对象,后面的createElement就相当于elt函数,这个函数里面有一个_c在这里插入图片描述通过这个_c函数就可以创建虚拟DOM节点,_v是创建文本节点,_c传进去三个参数,标签名,属性attrs,子节点在这里插入图片描述
  • 当我们创建完新的虚拟DOM节点之后,就会调用vm._update函数在这里插入图片描述
  • 把旧的vnode赋值给prevVnode,然后把新的vnode赋值给vm._vnode
    在这里插入图片描述
    -如果是第一次渲染,就直接创建真实的DOM节点,然后在页面上展示,如果不是第一次渲染,通过vm_patch_函数,进行打补丁,将两者的差异在真实的DOM上打上补丁,之后进行更新,在patch函数中有一个updateChildren函数,主要目的是对比新旧子节点并进行高效地更新
    在这里插入图片描述

diff算法

  • 我们先在有一个案例,假如当我点击按钮的时候,会在一个数组中间加一个f,然后通过v-for展示出来,在Vue中,对于相同给父元素的子元素节点并不会重新渲染整个列表,因为对于列表中abcd,他们都是没有变化的,在操作真实DOM的时候,我们只需要在中间插入一个f的li即可
  • Vue中对于有key和没有key会调用两个不同的方法,如果有key,就会使用patchKeyedChildren方法,如果没有key,就会使用patchUnkeyedChildren方法
    在这里插入图片描述
  • 子节点更新策略:
    四种命中查找
    1.新前与旧前
    2.新后与旧后
    3.新后于旧前
    4.新前于旧后
    先准备四个指针,旧前,旧后,新前,新后,首先对比新前与旧前是不是一个节点,如果相同就不执行节点移动操作,命中了一种就不再进行命中判断了,旧前指针往下移动,新前指针也往下移动,循环的条件就是新前<=新后 && 旧前<=旧后,如果旧节点先循环完毕了,说明新节点是有剩余的,就说明了新前和新后之间的节点都是新增的节点,这是新增的情况
    如果是删除的情况,前前比较,命中,指针下移,直到前前比较,不命中,让后后比,命中,指针都上移动,如果新节点先循环完毕,说明老节点中还有剩余节点,说明旧前和旧后之间卡住的节点就是他们是要被删除的节点
    如果都没有命中,就需要用循环来寻找,循环旧节点秒如果找到了,虚拟DOM就会给该节点打上undefined,但是真实DOM就会移动位置到旧前之前的位置
    当新前与旧后命中的时候,就会移动新前指向的这个节点在老节点中对应的节点,把老节点中这个节点移动到旧前的前面,然后新前往后移,旧后往前移
    当新后和旧前命中的时候,就会移动新后指向的这个节点在老节点中对应的节点,把老节点中这个节点移动到旧后的后面

v-for中的key

  • 文档中说,vue默认是按照“就地更新“的策略来更新通过v-for渲染的元素列表,当数据项的顺序改变时,vue不会移动DOM元素的顺序,而是就地更新每个元素,确保他们在原本指定的索引位置上渲染。

watch

  • 在代码逻辑中,监听某个数据的变化,需要用监听器watch来完成
  • watch的名字不能乱写,监听谁就写谁的名字,这里是监听question
    在这里插入图片描述
  • 但是注意,watch默认不会进行深度监听,即修改对象里面的属性的时候,是不会被监听到的,如果想进行深度监听的话,通过handler即可实现
  • immediate的作用是 第一次渲染直接执行一次监听器
    在这里插入图片描述

响应式原理

  • v2是通过getter和setter,v3是通过proxy对象修改,通过代理对象,当对对象继续操作之后,先告诉proxy,由proxy进行操作
  • v3中数据的操作都是通过proxy的,原来的对象还是不变的,变的都是proxy对应的代理对象

nextTick

  • vue 中的 nextTick 主要用于处理数据动态变化后,DOM 还未及时更新的问题,用nextTick 就可以获取数据更新后最新 DOM 的变化。 nextTick 是将回调函数推入微任务队列中,以便在当前宏任务执行完毕后执行。它能够在 Vue 完成一次 DOM 更新后执行回调函数,用于处理与 DOM 更新相关的操作。
  • 在旧版浏览器中,通过MutationObserver可以监控DOM对象的变化,可以监听属性attributes,子代节点childList
    在这里插入图片描述

父传子

  • 通过props属性传递
    首先在父组件,通过属性的形式,传递数据
    在这里插入图片描述
    在子组件中,通过props,通过数组接收父组件传递过来的属性
    在这里插入图片描述
    如果默认值是对象,必须要写成函数
    在这里插入图片描述

子传父

  • 当子组件有一些事件发生的时候,比如在组件中发生了点击,父组件需要切换内容;或者子组件有一些内容想要传递给父组件的时候
  • 通过$emit触发事件
    先在子组件中,发送一个自定义事件
    在这里插入图片描述
    父组件中
    在这里插入图片描述
    在这里插入图片描述

composition API

  • 在Vue2中,我们编写组件的方式是OptionsAPI,OptionsAPI一大特点就是在对应的属性中编写对应的功能模块,比如data定义数据,methods定义方法
  • 但是这种代码有很大的弊端:当我们实现某一个功能的时,这个功能对应的代码逻辑会被拆分到各个属性中,当我们的组件变得更大更复杂的时候,同一个功能的逻辑就会被拆分的很分散。
  • 如果我们能够将同一个逻辑关注点的代码收集在一起会更好。
  • 这个就是Composition API想做的事情,这个API我们就要在setup函数中编写。

setup函数

  • 注意:setup中,不能使用this
  • setup函数有两个参数,第一个参数是props,第二个参数是context
  • props其实就是父组件传递过来的属性会被放到props对象中,我们在setup中如果需要使用,那么就可以直接通过props参数获取,我们的setup中是没有this的
  • context是一个对象,有三个属性,attrs,slots,emit,slots是父组件传递过来的插槽,emit是我们组件内部需要发出事件的时候,会用到emit(但是不可以通过this.$emit发出事件)
<template>
  <div class="app">
    <h2>当前计数:{{ counter }}</h2>
    <button @click="increment">+1</button>
    <button @click="decrement">-1</button>
  </div>
</template>

<script>
import { ref } from "vue";
export default {
  setup() {
    let counter = ref(100);
    const increment = () => {
      counter.value += 1;
    };
    const decrement = () => {
      counter.value -= 1;
    };
    return {
      counter,
      increment,
      decrement,
    };
  },
};
</script>


<style lang="scss">
</style>

reactive函数

  • 用于定义复杂类型的数据,可以实现在setup中定义的数据提供响应式的特性
  • ref用于定义简单类型的数据,也可以定义复杂的数据
    在这里插入图片描述
<template>
  <div>message:{{ message }}</div>
  <button @click="changeMessage">修改message</button>
  <hr />
  <h2>账号:{{ account.username }}</h2>
  <h2>密码:{{ account.password }}</h2>
  <button @click="changAccount">修改账号</button>
</template>

<script>
import { ref, reactive } from "vue";
export default {
  setup() {
    let message = ref("hello world");
    const changeMessage = () => {
      message.value = "你好,世界";
    };

    const account = reactive({
      username: "coderwhy",
      password: "12345",
    });
    const changAccount = () => {
      account.username = "limingpu";
    };

    return { message, changeMessage, account, changAccount };
  },
};
</script>

<style>
</style>

Ref函数

  • ref是将数据变成响应式,在setup函数中,需要通过.value获取值,但是在template中,就不需要.value了,会自动解包
  • reactiveAPI对传入的类型是有限制的,只能是一个对象或者数组,如果我们传入一个基本类型就会报警告
  • 提供了另外一个可变的响应式对象,ref的值是用value属性维护的
  • 一般用ref接受网络中获取的数据
    在这里插入图片描述

computed函数

  • computed值返回的是一个ref,所以需要.value
    在这里插入图片描述

通过ref获取元素和组件

  • 因为没有this了,所有通过ref()函数进行获取,之后要在onMounted挂载的时候,获取到value值
    在这里插入图片描述

watch函数/watchEffect函数

  • watch:需要手动指定侦听的数据源,只要当被侦听的源发生变化时才会执行回调,默认情况下初始渲染时不执行回调函数
    在这里插入图片描述
  • watchEffect:自动收集依赖(依赖那些响应式数据),不需要显示指定要监视的数据源,默认情况下第一次立即执行回调函数;
    在这里插入图片描述
    当调用自己的返回值得时候,就停止监听了在这里插入图片描述

script setup语法糖

  • 在script旁边加一个setup,就可以直接使用composition API,也不需要返回了。
  • 更少的样板内容,更简洁的代码;更好的运行时性能。
    在这里插入图片描述
  • 导入的组件可以直接使用,不需要components
  • 定义props通过defineProps,这个函数不需要导入,就在当前的作用域中,如果需要发送事件,通过defineEmits([])
    在这里插入图片描述
    在这里插入图片描述
    ————————————————————————
    ♥♥♥码字不易,大家的支持就是我坚持下去的动力♥♥♥
    版权声明:本文为CSDN博主「亚太地区百大最帅面孔第101名」的原创文章
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李小浦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值