​Vue2、3【响应式原理、API类型、生命周期、fragment】

目录

核心变化

响应式原理

Vue2 :数据劫持+发布订阅(Object.defineProperty,getter,setter(通知变化))

Vue3 :ES6的Proxy API对数据代理( track 收集依赖, trigger 触发更新)

API 类型

Vue2 :Options API选项类型(属性data、methods、computed)

Vue3 :Composition API合成型(函数定义组件逻辑,不同组件中可复用)

定义数据变量和方法

Vue2:数据放在data选项 中

Vue3 :setup()方法

生命周期

Vue3

使用:先导入

合并:beforeCreate+created=setup

新增on:destroy->unmount

onErrorCaptured监听组件的统一报错:onErrorCaptured(error, component, details)

Fragment碎片组件:树

Vue2 不支持碎片Vue3 支持碎片,可以拥有多个根节点

非核心变化【但重要,可根据标题引导一波提问】

优化

diff方法优化:只对比有静态标记(patchflag)的节点

静态提升:不参与更新的元素,只会被创建一次,在渲染时直接复用即可。

事件侦听器缓存

按需引入:treeSharking 体积更小

computed:监听多值,有缓存,依赖值发生变化触发重算,用于计算

计算属性本质上是 computed watcher

缓存通过dirty控制

初始化时,计算属性并不会立即计算(vue的优化)

都支持函数(仅可读)、对象字面量(可写)写法

vue2 函数

vue3对象字面量

watch:监听值,无缓存,用于执行操作

watch本质上是 user watcher

vue2 属性(配置项:immediate,deep)

immediate: 【默认false】,是否在组件创建时立即执行一次

deep:【默认false】,是否实现深度监听

vue3 函数(监听的属性,(newVal, oldVal) => { ... },配置项(+flush,debug))

nextTick:DOM更新之后执行回调函数,返回一个Promise

vue2:基于promise>MutationObserver>setImmediate>setTimeout实现

vue3:基于Promise实现

this

vue2:this=组件实例($router,$ref)

vue3:{ proxy, appContext } = getCurrentInstance()


核心变化

响应式原理


Vue2 :数据劫持+发布订阅(Object.defineProperty,getter,setter(通知变化))

Vue3 :ES6的Proxy API对数据代理( track 收集依赖, trigger 触发更新)

API 类型


Vue2 :Options API选项类型(属性datamethodscomputed

选项在组件实例化后会被合并到组件实例中,可以在组件内部访问和使用。

Vue3 :Composition API合成型(函数定义组件逻辑,不同组件中可复用)


定义数据变量和方法

Vue2:数据放在data选项 中


Vue3 :setup()方法

生命周期

Vue3

使用:先导入
// vue3
<script setup>     
import { onMounted } from 'vue';   // 使用前需引入生命周期钩子
 
onMounted(() => {
  // ...
});
 
// 可将不同的逻辑拆开成多个onMounted,依然按顺序执行,不会被覆盖
onMounted(() => {
  // ...
});
</script>
 
// vue2
<script>     
export default {         
  mounted() {   // 直接调用生命周期钩子            
    // ...         
  },           
}
</script> 
合并:beforeCreate+created=setup
新增on:destroy->unmount

onErrorCaptured监听组件的统一报错:onErrorCaptured(error, component, details)
<template>
  <div>
    <p>{{ message }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: 'Hello, Vue!'
    };
  },
  methods: {
    throwError() {
      // 人为地抛出一个错误
      throw new Error('An error occurred.');
    }
  },
  onErrorCaptured(error, component, details) {
    console.error('Captured an error in component:', component);
    console.error('Error details:', error);
    console.error('Details:', details);
    // 可以选择返回 false 来阻止错误继续传播
    // return false;
  }
};
</script>

Fragment碎片组件:树

本质上 Vue3 每个组件还是一个根节点,因为 DOM 树只能是树状结构的,只是 Vue3 在编译阶段新增了判断,如果当前组件不只一个根元素,就添加一个 fragment 组件把这个多根组件的给包起来,相当于这个组件还是只有一个根节点。而 fragment 跟 keep-alive 一样是一个不会被渲染出来的内置组件

Vue2 不支持碎片
Vue3 支持碎片,可以拥有多个根节点

// vue2中在template里存在多个根节点会报错
<template>
  <header></header>
  <main></main>
  <footer></footer>
</template>
 
// 只能存在一个根节点,需要用一个<div>来包裹着
<template>
  <div>
    <header></header>
    <main></main>
    <footer></footer>
  </div>
</template>

非核心变化【但重要,可根据标题引导一波提问】

优化

diff方法优化:只对比有静态标记(patchflag)的节点

静态提升:不参与更新的元素,只会被创建一次,在渲染时直接复用即可。

vue2无论元素是否参与更新,每次都会重新创建然后再渲染

事件侦听器缓存


默认情况下onClick会被视为动态绑定,所以每次都会追踪它的变化,但是因为是同一个函数,所以不用追踪变化,直接缓存起来复用即可

按需引入:treeSharking 体积更小

computed:监听多值,有缓存,依赖值发生变化触发重算,用于计算

计算属性本质上是 computed watcher

缓存通过dirty控制

初始化时,计算属性并不会立即计算(vue的优化)

都支持函数(仅可读)、对象字面量(可写)写法

vue2 函数

运行 this.fullName = 'John Doe' 时,收到警告

export default {
  data() {
    return {
      firstName: 'John',
      lastName: 'Doe'
    }
  },
  computed:{
 //  fullName计算属性的 getter
     fullName(){
        return this.firstName + ' ' + this.lastName
      }
    }
  }
}
vue3对象字面量

运行 this.fullName = 'John Doe' 时,setter 会被调用, this.firstName 和 this.lastName更新

<template>
  <div>
    <p>Full Name: {{ fullName }}</p>
  </div>
</template>
<script setup>
import { ref, computed } from 'vue'

const firstName = ref('John')
const lastName = ref('Doe')

const fullName = computed({
  // getter
  get() {
    return firstName.value + ' ' + lastName.value
  },
  // setter
  set(newValue) {
    // Note: we are using destructuring assignment syntax here.
    [firstName.value, lastName.value] = newValue.split(' ')
  }
})
</script>

watch:监听值,无缓存,用于执行操作

watch本质上是 user watcher

vue2 属性(配置项:immediate,deep)


immediate: 【默认false】,是否在组件创建时立即执行一次

deep:【默认false】,是否实现深度监听
watch: {
  // 监听 userId 的变化,触发 getData 方法
  userId: 'getData',
  
  // 监听 userName 的变化,触发 getData 方法
  userName(newName, oldName) {
    this.getData()
  },
  
  // 监听 userInfo 的变化,触发 getData 方法
  userInfo: {
    // 处理函数,在 userInfo 发生变化时触发
    handler(newVal, oldVal) {
      this.getData()
    },
    // 在组件创建时立即执行一次处理函数
    immediate: true,
    // 深度监听 userInfo 内部的属性变化
    deep: true
  }
}

vue3 函数(监听的属性,(newVal, oldVal) => { ... },配置项(+flush,debug))

<script setup>
import { watch, ref, reactive } from 'vue'

const name = ref('沐华')
const data = reactive({
    age: 18,
    money: 100000000000000000000,
    children: []
})

// 监听 ref 属性
watch(name, (newName, oldName) => { ... })

// 监听其他属性、路由或者状态管理的都这样
watch(
    () => data.age, 
    (newAge, oldAge) => { ... }
)

// 监听多个属性,数组放多个值,返回的新值和老值也是数组形式
watch([data.age, data.money], ([newAge, newMoney], [oldAge, oldMoney]) => { ... })

// 第三个参数是一个对象,为可配置项,有5个可配置属性
watch(data.children, (newList, oldList) => { ... }, {
    // 这两个和 Vue2 一样,没啥说的
    immediate: true,
    deep: true,
    // 回调函数的执行时机,默认在组件更新之前调用。更新后调用改成post
    flush: 'pre', // 默认值是 pre,可改成 post 或 sync
    // 下面两个是调试用的
    onTrack (e) { debugger }
    onTrigger (e) { debugger }
})
</script>

nextTick:DOM更新之后执行回调函数,返回一个Promise

function nextTick(callback?: () => void): Promise<void>

“tick”(事件循环)

在 Vue 中更改响应式状态时, Promise.then()将DOM更新事件缓存在微任务队列中

宏任务,微任务,事件循环event loop、setTimeout,setInterva、nextTick与process.nextTickl区别【示例讲解】_process.nexttick和vue的nexttick的区别-CSDN博客

vue2:基于promise>MutationObserver>setImmediate>setTimeout实现

执行优先级:微任务(MutationObserver>promise)>宏任务(setImmediate>setTimeout)

setImmediate 在当前事件循环的结束后立即执行

setTimeout 则是在指定的延迟时间后才执行。

因此,setImmediate 的执行时机比 setTimeout 更,更接近于微任务的执行时机,响应更快

async increment() {
      this.count++

      // DOM 还未更新
      console.log(document.getElementById('counter').textContent) // 0

      await nextTick()
      // DOM 此时已经更新
      console.log(document.getElementById('counter').textContent) // 1
    }

vue3:基于Promise实现

vue3基于 Proxy 响应式,而Proxy基于promise

<script setup>
import { nextTick} from 'vue'

// 方式 一
const handleClick = async () => {
  await nextTick()
  console.log('')
}

// 方式二
nextTick(() => {
    console.log('')
})

// 方式三
nextTick().then(() => {
    console.log('')
  })
</script>

this

vue2:this=组件实例($router,$ref)

vue3:{ proxy, appContext } = getCurrentInstance()

<script setup>
import { getCurrentInstance } from 'vue'

// proxy 就是当前组件实例,可以理解为组件级别的 this,没有全局的、路由、状态管理之类的
const { proxy, appContext } = getCurrentInstance()

// 这个 global 就是全局实例
const global = appContext.config.globalProperties
</script>

参考链接:盘点 Vue3 与 Vue2 的区别 - 掘金

「历时8个月」10万字前端知识体系总结(前端框架+浏览器原理篇)🔥 - 掘金

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值