Vue3源码梳理:computed计算属性的核心实现

【VUE】源码分析 - computed计算属性的实现原理 从源码出发,剖析computed计算属性的响应式原理、缓存原理。 阅读详情

概述

  • 计算属性 computed 会基于其响应式依赖被缓存,并且在依赖的响应式数据发生变化时,重新计算

Debug Computed 源码

  • 测试示例: computed.html,测试vue源码的属性

    <script src='../../dist/vue.global.js'></script>
    
    <body>
      <div id='app'></div>
    </body>
    
    <script>
      const { ref, effect, computed } = Vue
      const obj = ref({
        name: '张三'
      })
      const computedObj = computed(()=>{
        return '姓名: ' + obj.value.name
      })
      effect(() => {
        document.querySelector('#app').innerText = computedObj.value
      })
      const timer = setTimeout(() => {
        clearTimeout(timer)
        obj.value.name = '李四'
      }, 2000)
    </script>
    
  • 进入computed函数

    export function computed<T>(
      getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>,
      debugOptions?: DebuggerOptions,
      isSSR = false
    ) {
      // 首先创建两个变量:getter和setter
      let getter: ComputedGetter<T>
      let setter: ComputedSetter<T>
      // getterOrOptions 是 我们传入的第一个参数
      const onlyGetter = isFunction(getterOrOptions)
      if (onlyGetter) {
        getter = getterOrOptions
        // 这里没有 setter函数,初始化一个
        setter = __DEV__
          ? () => {
              console.warn('Write operation failed: computed value is readonly')
            }
          : NOOP
      } else {
        getter = getterOrOptions.get
        setter = getterOrOptions.set
      }
      // 创建一个 ComputedRefImpl 实例
      const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR)
    
      if (__DEV__ && debugOptions && !isSSR) {
        cRef.effect.onTrack = debugOptions.onTrack
        cRef.effect.onTrigger = debugOptions.onTrigger
      }
      // 这里返回其实例
      return cRef as any
    }
    
  • 进入 ComputedRefImpl 类查看

    export class ComputedRefImpl<T> {
      public dep?: Dep = undefined // 这里是我们依赖收集的Set
    
      private _value!: T
      public readonly effect: ReactiveEffect<T>
    
      public readonly __v_isRef = true // 这里是一个true的标识,所有的计算属性的 这个属性都是真
      public readonly [ReactiveFlags.IS_READONLY]: boolean = false
    
      public _dirty = true // 这里声明一个脏变量
      public _cacheable: boolean
    
      constructor(
        getter: ComputedGetter<T>, // 我们传入的 getter
        private readonly _setter: ComputedSetter<T>, // setter 是只读的
        isReadonly: boolean,
        isSSR: boolean
      ) {
        // 创建一个 effect 实例,第一个参数就是我们的fn回调参数,第二个参数是个匿名参数
        this.effect = new ReactiveEffect(getter, () => {
          // 这里重新进行赋真值和依赖触发,这个脏变量的本质就是为了控制触发依赖,也就是在其值为假的时候
          if (!this._dirty) {
            this._dirty = true
            triggerRefValue(this)
          }
        })
        this.effect.computed = this
        this.effect.active = this._cacheable = !isSSR
        this[ReactiveFlags.IS_READONLY] = isReadonly
      }
    
      get value() {
        // the computed ref may get wrapped by other proxies e.g. readonly() #3376
        const self = toRaw(this)
        trackRefValue(self)
        if (self._dirty || !self._cacheable) {
          self._dirty = false
          self._value = self.effect.run()!
        }
        return self._value
      }
    
      set value(newValue: T) {
        this._setter(newValue)
      }
    }
    
  • 从这里我们可知:

    • 在computed中有一个getter函数和一个setter函数
    • getter函数就是我们传递进来的一个函数,而setter函数默认是一个空的函数
    • 在computed函数中生成了一个 ComputedRefImpl 实例,并作为返回值返回
    • 而 ComputedRefImpl 内部 通过 ReactiveEffect 生成了一个 effect 实例
    • 并且赋值挂载到了 this.effect 上,也就是说我们所有计算属性的实例都包括 effect
    • 其中,在 new ReactiveEffect 时候,第一个参数是getter,是computed传入的回调函数,也是我们的fn函数
    • 也就是实例 this.effect 执行run函数的时候,就会触发当前的回调
    • 传入了第二个参数是个匿名函数,使用脏变量来触发依赖的, 在this._dirty为false的时候,执行将自身变为真,再调用triggerRefValue进行依赖触发
    • 脏变量核心的本质是用于控制何时触发依赖的,只有脏变量为假的时候,才会触发,否则依赖不会触发
  • 接下来,业务代码中在effect函数中触发了getter行为,当执行了 第一个 回调 函数之后,就会触发 getter行为,进入 vue源码 computed 的 get value() 函数中

    • 执行了 trackRefValue 用于收集依赖的作用,这个函数就是 ref.ts中的依赖收集的函数
    • 在我往下走,到 if (self._dirty || !self._cacheable) {}
    • 在这个if代码块中,当 self._dirty 为真 或 self._cacheable 为假的时候,才会把 self._dirty 变为假
    • 之后,执行 run 函数,内部也就是我们的依赖 fn 函数
  • 对于 ComputedRefImpl 而言,它也没有实现代理监听机制,它是通过 get value() 和 调度器 完成的触发

    • 在每一次 get value 触发的时候,都进行依赖的收集,同时根据脏状态来判断是否需要执行run函数
    • 最后computed的返回值就是run函数执行之后的结果
    • 如果当前脏状态是false的时候则不会执行run函数,直接使用上次的value作为新的value进行返回,完成了数据缓存的功能
  • 对于计算属性而言,当它依赖的响应式数据发生变化时,将重新计算

    • 换句话说,当响应式数据触发setter行为的时候,计算属性需要重新触发依赖
    • 每一次get value() 时都会主动执行依赖收集,那触发依赖在哪里?
    • 实际上经上面分析,在构造器 constructor 中,new ReactiveEffect 的时候,第二个参数就是触发依赖的回调
    • 它是由脏变量控制的,所以触发依赖在于脏变量状态的变更时,这第二个参数实际上是一个 scheduler
    • 它本质上是一个调度器,实际上我们可以在源码 effect.ts 中可以看到 effect.scheduler 的使用
      // effect.ts 源码中
      function triggerEffect(
        effect: ReactiveEffect,
        debuggerEventExtraInfo?: DebuggerEventExtraInfo
      ) {
        if (effect !== activeEffect || effect.allowRecurse) {
          if (__DEV__ && effect.onTrigger) {
            effect.onTrigger(extend({ effect }, debuggerEventExtraInfo))
          }
          if (effect.scheduler) {
            // 这里
            effect.scheduler()
          } else {
            effect.run()
          }
        }
      }
      
    • 也就是说,effect 中如果包含scheduler时,将会执行调度器,否则执行run函数
  • 在业务代码中,2s之后,触发 setter 行为,也就是统一走 baseHandlers 中的 createSetter方法

    • 在最底部,会进入到 trigger 方法中,如下:
      if (target === toRaw(receiver)) {
        if (!hadKey) {
          trigger(target, TriggerOpTypes.ADD, key, value)
        } else if (hasChanged(value, oldValue)) {
          // 走这里
          trigger(target, TriggerOpTypes.SET, key, value, oldValue)
        }
      }
      return result
      
    • 进入这个 trigger 函数中 会进入 triggerEffects中
      if (deps.length === 1) {
        if (deps[0]) {
          if (__DEV__) {
            // 走到这里
            triggerEffects(deps[0], eventInfo)
          } else {
            triggerEffects(deps[0])
          }
        }
      }
      
    • 之后,triggerEffects 内部触发 triggerEffect
        export function triggerEffects(
          dep: Dep | ReactiveEffect[],
          debuggerEventExtraInfo?: DebuggerEventExtraInfo
        ) {
          // spread into array for stabilization
          const effects = isArray(dep) ? dep : [...dep]
          // 下面两个for循环
          for (const effect of effects) {
            if (effect.computed) {
              triggerEffect(effect, debuggerEventExtraInfo)
            }
          }
          for (const effect of effects) {
            if (!effect.computed) {
              triggerEffect(effect, debuggerEventExtraInfo)
            }
          }
        }
      
      • 在 triggerEffect
        function triggerEffect(
          effect: ReactiveEffect,
          debuggerEventExtraInfo?: DebuggerEventExtraInfo
        ) {
          if (effect !== activeEffect || effect.allowRecurse) {
            if (__DEV__ && effect.onTrigger) {
              effect.onTrigger(extend({ effect }, debuggerEventExtraInfo))
            }
            // 这里就是调度器的属性
            if (effect.scheduler) {
              effect.scheduler()
            } else {
              effect.run()
            }
          }
        }
        
      • 这个 scheduler 就是计算属性的构造函数里面 传进来的 第二个参数,debugger 进入 scheduler 函数
      • 就会跳转到 ComputedRefImpl 这个计算属性类的构造函数constructor中的 new ReactiveEffect 的第二个参数
      • 继续debugger 查看this对象,发现当前的 脏变量 this._dirty 是 false,是因为之前执行了 get value(), 内部变更了其状态
      • 脏状态是 false 就意味着将要执行:把当前脏状态 改为 true,并且进行触发依赖 triggerRefValue,进入这个函数
        export function triggerRefValue(ref: RefBase<any>, newVal?: any) {
          ref = toRaw(ref)
          if (ref.dep) {
            if (__DEV__) {
              triggerEffects(ref.dep, {
                target: ref,
                type: TriggerOpTypes.SET,
                key: 'value',
                newValue: newVal
              })
            } else {
              triggerEffects(ref.dep)
            }
          }
        }
        
      • 这个我们之前分析过,后面就不再继续了,触发依赖,执行回调,页面渲染出新的值
      • 这里,就是完整的一次 setter 行为
  • 对业务代码中 2s 后的过程进行一次总结

    • obj.value.name = '李四' 这行代码会触发 proxy 的 setter 行为
    • 在 setter 行为中,会触发 trigger 完成第一次的依赖收集, 此时依赖收集中的 effect 中包含调度器
    • 因包含调度器,所以会执行调度器 effect.scheduler() 指向到 computed源码中 new ReactiveEffect 的第二个参数
    • 第二个参数内部,会再次触发 triggerRefValue
    • 以上是两次触发依赖,第二次的触发会导致业务代码中的 effect函数的回调执行,也就是被收集的依赖fn函数

删减后的核心实现代码

  • 参考之前的rollup构建环境搭建

  • 创建实例程序 computed.html 用于测试我们拆解后的 computed 源码

    <script src="../dist/vue.js"></script>
    <body>
      <div id='app'></div>
    </body>
    
    <script>
      const { reactive, effect, computed } = Vue
      const obj = reactive({
        name: '张三'
      })
      const computedObj = computed(()=>{
        return '姓名: ' + obj.name
      })
      effect(() => {
        document.querySelector('#app').innerText = computedObj.value
      })
      const timer = setTimeout(() => {
        clearTimeout(timer)
        obj.value.name = '李四'
      }, 2000)
    </script>
    
  • 创建 reactivity/computed.ts 模块

    import { isFunction } from '@vue/shared'
    import { Dep } from './dep'
    import { ReactiveEffect } from './effect'
    import { trackRefValue, triggerRefValue } from './ref'
    
    export class ComputedRefImpl<T> {
      public dep?: Dep = undefined
      private _value!: T
      public readonly effect: ReactiveEffect<T>
      public readonly __v_isRef = true
      public _dirty = true
    
      constructor(getter) {
        this.effect = new ReactiveEffect(getter, () => {
          if (!this._dirty) {
            this._dirty = true
            triggerRefValue(this)
          }
        })
        this.effect.computed = this
      }
      get value() {
        trackRefValue(this)
        // 缓存处理
        if (this._dirty) {
          this._dirty = false // 更新脏状态
          this._value = this.effect.run()
        }
        return this._value
      }
    }
    
    export function computed(getterOrOptions) {
      let getter
      const onlyGetter = isFunction(getterOrOptions)
      if (onlyGetter) {
        getter = getterOrOptions
      }
      const cRef = new ComputedRefImpl(getter)
      return cRef
    }
    
  • 更新 effect.ts 中的 ReactiveEffect, 用于补充私有属性 computed

    import { ComputedRefImpl } from './computed' // 导入相关类型
    
    export type EffectScheduler = (...args: any[]) => any
    
    export class ReactiveEffect<T = any> {
      // 添加这行,用于协同 computed 处理
      computed?: ComputedRefImpl<T>
      // 这里添加 scheduler 属性
      constructor(public fn: () => T, public scheduler: EffectScheduler | null = null) {}
      run() {
        activeEffect = this
        return this.fn()
      }
    }
    
  • 更新 effect.ts 中的 triggerEffect 用于调度器的参与

      // 触发指定依赖
      export function triggerEffect(effect: ReactiveEffect) {
        effect.scheduler ? effect.scheduler() : effect.run()
      }
    
  • 以上,我们完成了 最简洁版的 computed 函数

实现 computed 的缓存功能

  • 也就是我们如果没有对数据做变更,仍旧使用之前的数据,不必每次都收集依赖和触发依赖

  • 修改业务测试代码 computed.html或新建 computed-cache.html 文件

    <script src="../dist/vue.js"></script>
    <body>
      <div id='app'></div>
    </body>
    
    <script>
      const { reactive, effect, computed } = Vue
      const obj = reactive({
        name: '张三'
      })
      const computedObj = computed(()=>{
        console.log('cccc') // 这里打印computed的getter执行了多少次
        return '姓名: ' + obj.name
      })
      effect(() => {
        document.querySelector('#app').innerText = computedObj.value
        document.querySelector('#app').innerText = computedObj.value // 执行第二次 getter
      })
      const timer = setTimeout(() => {
        clearTimeout(timer)
        obj.name = '李四'
      }, 2000)
    </script>
    
  • 以上代码,我们打开控制台,可以看到 seHandlers.ts:12 Uncaught RangeError: Maximum call stack size exceeded 循环调用,报错了

  • 如果业务代码因为重复的调用而导致框架内部循环调用变成了死循环,这样的框架肯定是不鲁棒的,需要尽快修复,这里就需要用到缓存相关的优化了

  • 产生死循环的原因是第二次触发 effect时,也就是 triggerEffect(effect), 拿到的 effect 是计算属性的effect, 从而导致触发effect的调度系统,导致了死循环的执行

    • 调度器中会把 this._dirty 标识修改为 true
    • 问题就在这个脏状态标识导致的循环调用
  • 在vue源码中,effect.ts中,有两个for循环,以前以为这种写法是多余的,实际上这里有特殊的含义,通过两次for循环来构建执行的顺序,让计算属性先执行,非计算属性后执行

    export function triggerEffects(
      dep: Dep | ReactiveEffect[],
      debuggerEventExtraInfo?: DebuggerEventExtraInfo
    ) {
      // spread into array for stabilization
      const effects = isArray(dep) ? dep : [...dep]
      // 注意看这里,下面的两个 for 循环
      for (const effect of effects) {
        if (effect.computed) {
          triggerEffect(effect, debuggerEventExtraInfo)
        }
      }
      for (const effect of effects) {
        if (!effect.computed) {
          triggerEffect(effect, debuggerEventExtraInfo)
        }
      }
    }
    
  • 我们来修改下自己实现的删减版代码,在 effect.ts 中

    export function triggerEffects(dep: Dep) {
      const effects = Array.isArray(dep) ? dep : [...dep]
      // 依次触发循环
      for (const effect of effects) {
        effect.computed && triggerEffect(effect) // 先执行computed属性的
      }
      for (const effect of effects) {
        !effect.computed && triggerEffect(effect) // 后执行非computed属性的
      }
    }
    
  • 这时候就没有循环调用的报错了

总结

  • 计算属性的实例,是 ComputedRefImpl 的实例
  • 在 ComputedRefImpl 实例中通过 脏变量来控制 run 和 triggerRefValue 函数的触发
  • 计算属性的值,通过 .value 来访问,因其内部和 ref 一样是通过 get value 来实现的
  • 每次 .value 访问computed数据时,都会触发依赖的收集,即调用 trackRefValue函数
  • computed中的一项避免循环调用的优化:先触发 computed 的 effect, 再触发 非computed 的 effect
【vue3源码】四、computed源码解析 介绍vue3中computed的实现原理。 阅读详情

相关推荐

Vue computed 辅助函数:用声明式筛选替代手写 filter/map

在 Vue.js 开发中,computed 属性常需对数组执行过滤、计数、查找等操作,但原生 Array 方法(如 filter、find、some)易导致样板代码冗余、可读性差、调试困难。声明式数据处理通过对象匹配规则(如 { status: 'active' } 或 { retryCount: { $gt: 3 } })替代内联函数,显著提升语义清晰度与 Devtools 可调试性;其底层仍是纯函数,完全兼容 Vue 2/3 响应式追踪,不侵入框架。该模式特别适用于中后台系统中高频出现的列表筛选、状态统

weixin_30325487的博客 359

error Unexpected side effect in computed function vue/no-side-effects-in-computed-properties --c

**问题来源:**TS+VUE的项目报错 报错: *error Unexpected side effect in computed function vue/no-side-effects-in-computed-properties --computed函数在vue中不存在意外的副作用 原因:Vue 的 计算属性 (computed) 中应当仅包含用于返回值的计算—不能改变变量值 **解决方案:**检查是否有不应该包含 DOM操作,修改外部变量,异步操作等,有则改之 ...

m0_46183615的博客 6405

A Mathematical Framework for Transformer Circuits—(一)

transformer数学理解理论

qq_42208244的博客 2665

“Unexpected side effect in computed function“在计算属性中修改响应式数据报错

在这个示例中,fetchDataBasedOnTabsName 是一个异步函数,根据传入的 tabsName 参数向服务端发起请求,并返回相应的数据。如果项目没有使用类似的异步请求库,可以根据实际情况使用其他方法来获取数据。2.在计算属性中执行具有副作用的操作: 计算属性应该只是根据输入的数据计算新的值,而不应该执行可能引起副作用的操作,比如网络请求、异步操作等。1.在计算属性中修改响应式数据: 计算属性应该是纯粹的,不应该修改响应式数据。如果你在计算属性中修改了 data 中的数据,可能导致此错误。

qq_45525250的博客 2991

【教程】ENVI主成分分析详解

主成分分析(PCA)是一种统计方法,简而言之就是用几种特性去描述事物。每个事物都可以用不同的特性去进行表达,但这些特性一般而言是存在相互的融合和冗余,而用主成分分析方法将这些特性进行转换成不相关的新特性。 在ENVI软件中共提供了三种主成分分析方式分别为:(1)Forward PCA Rotation Existing Statistics(2)Forward PCA Rotation New Statistics and Rotate(3)Inverse PCA Rotati...

YW_remote的博客 1万+

深度学习之Pytorch---本人踩过的坑(报错总结)第十篇

深度学习之Pytorch安装时遇到的问题—本人踩过的坑(报错总结) 报错一:pip install torchvision 出现“由于目标计算机积极拒绝,无法连接”的问题 解决方案:找到自己浏览器的工具或选项,我的是火狐,具体解决方案如下图 然后找到桌面左下角,点击搜索internet,然后点击internet选项 最后回到Anaconda Prompt命令行输入pip install...

qq_41570307的博客 1914

vue3 源码解析(3)— computed 计算属性的实现

通过对computed的源码分析,我们可以看到 vue3 如何实现计算属性的。当我们创建一个计算属性时,vue 会收集这个计算属性的所有依赖项。然后,当这些依赖项发生变化时,vue 会重新计算这个计算属性的值。并通过_dirty这个标志位来判断是否需要执行副作用函数并更新_value的值。这种机制使得我们可以方便地创建基于其他响应式依赖项的计算属性。

old brother stable 2095

深入解析YT8521S千兆以太网PHY芯片的设计与调试要点

本文深入解析了YT8521S千兆以太网PHY芯片的设计与调试要点。重点剖析了硬件设计中的电源方案、RGMII接口电平配置(尤其是1.8V电平方案)以及PCB布局布线等关键细节,并提供了从硬件检查、驱动配置到性能测试的完整调试流程,帮助工程师规避常见陷阱,实现稳定可靠的千兆网络连接。

weixin_29190573的博客 690

浅谈Vue中计算属性computed的实现原理

虽然目前的技术栈已由Vue转到了React,但从之前使用Vue开发的多个项目实际经历来看还是非常愉悦的,Vue文档清晰规范,api设计简洁高效,对前端开发人员友好,上手快,甚至个人认为在很多场景使用Vue比React开发效率更高,之前也有断断续续研读过Vue的源码,但一直没有梳理总结,所以在此做一些技术归纳同时也加深自己对Vue的理解,那么今天要写的便是Vue中最常用到的API之一computed...

w18478272407的博客 3243

无线充电效率从75%到90%+:深入拆解LCC补偿网络如何成为电动汽车和智能车竞赛的‘稳压器’

本文深入探讨了LCC补偿网络如何显著提升无线充电效率至90%以上,成为电动汽车和智能车竞赛中的关键技术。通过分析LCC的三元件结构和双模式切换特性,揭示了其在负载突变和线圈错位情况下的稳定性优势,并展示了实际应用中的效率提升和产业化挑战。

weixin_42528191的博客 399

《惠普工作站设置BIOS从U盘装系统》

惠普工作站设置BIOS 惠普工作站在做服务器时应用广泛,本文介绍下其BIOS开机自启动设置,附上图片,以供学习参考。 惠普工作站设置BIOS 启动步骤如下: 第一步:根据需要对BIOS进行更改,并保存 1.重启工作站按F10进入BIOS设置(也可以按ESC键选择进入BIOS设置的选项)。 图1 惠普工作站B...

istrangeboy&begin zero的博客 2万+

浅谈 Vue 中 computed 实现原理

虽然目前的技术栈已由 Vue 转到了 React,但从之前使用 Vue 开发的多个项目实际经历来看还是非常愉悦的,Vue 文档清晰规范,api 设计简洁高效,对前端开发人员友好,上手快,甚至个人认为在很多场景使用 Vue 比React 开发效率更高,之前也有断断续续研读过 Vue 的源码,但一直没有梳理总结,所以在此做一些技术归纳同时也加深自己对 Vue 的理解,那么今天要写的便是 Vue 中最常...

如果我年少有为不自卑 1万+

Unity 面试篇|(二)Unity基础篇 【全面总结 | 持续更新】

在主线程运行的同时开启另一段逻辑处理,来协助当前程序的执行,协程很像多线程,但是不是多线程,Unity的协程实在每帧结束之后去检测yield的条件是否满足。一个程序在运行(执行)的过程中所需要的硬件和软件环境运行时的主要作用是提供程序运行所需要的环境和基础设施,通过为程序提供内存分配、线程管理、类型检查、对象实例化和垃圾回收等操作来支持程序的运行公共语言运行时(Common Language Runtime,CLR)是整个.NET框架的核心,它为.NET应用程序提供了一个托管的代码执行环境。

游戏开发小Y的博客 13万+

做面试的不倒翁:浅谈 Vue 中 computed 实现原理

编者按:我们会不时邀请工程师谈谈有意思的技术细节,希望知其所以然能让大家在面试有更出色表现。也给面试官提供更多思路。 虽然目前的技术栈已由 Vue 转到了 React,但从之前使用 Vue 开发的多个项目实际经历来看还是非常愉悦的,Vue 文档清晰规范,api 设计简洁高效,对前端开发人员友好,上手快,甚至个人认为在很多场景使用 Vue 比 React 开发效率更高,之前也有断断续续研读过 V...

weixin_33735077的博客 1112

扩散模型中的UNET

一、为什么UNET模型可以用于去噪网络 二、扩散模型中的UNET是一个条件去噪网络,怎么实现的 三、UNET用于分割和用去去噪的区别

m0_37737957的博客 3819

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

Vue实例核心属性与生命周期详解:从data、computed到钩子函数

在Web前端开发中,响应式编程和组件化架构已成为构建现代用户界面的核心技术范式。其核心原理在于通过数据绑定机制,实现数据模型与视图层的自动同步,从而提升开发效率和用户体验。这一技术价值体现在能够大幅减少手动DOM操作,使开发者更专注于业务逻辑。在实际应用场景中,无论是构建单页面应用还是复杂的管理后台,理解框架实例的核心工作机制都至关重要。本文聚焦于Vue.js框架,深入剖析其**实例属性**如data、methods、computed、watch的设计哲学与协同机制,并系统讲解**生命周期钩子**的执行时机

weixin_34392435的博客 414

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

Vue3笔记

渲染快,虚拟 DOM 重写(优化 diff 算法),静态节点提升(Static Hoisting)和补丁标记(Patch Flags),减少运行时开销。Vue 3 于 2020 年 9 月发布,是 Vue.js 的重大升级版本,主要改进包括性能优化、新特性引入和更好的 TypeScript 支持。3.更好的 TypeScript 支持:源码使用 TypeScript 重写,提供完整的类型定义,开发体验更友好,IDE 提示更精准。目的:解决逻辑复用和代码组织问题(替代 Options API 的局限性)。

zxz86的博客 658

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

computed 和 watch

computed 计算属性的初始化是发生在 Vue 实例初始化阶段的initState函数中它的源码定义在src/core/instance/state.js中 执行了if (opts.computed) initComputed(vm, opts.computed) 核心方法 在渲染Computed watch 所在模板时会渲染到 计算属性 会触发c...

weixin_40874129的博客 168

VUE3 面试题总结

单文件组件< script setup > < script setup > </script> 可以直接引入,定义,逻辑,无需return返出数据 直接import引入子组件后在页面直接使用,无需注册 替代props功能的是: defineProps({}) 替代emit功能的是:defineEmits([]) 点击的dom上@click="skip" 例:cons...

hjdjhh的博客 2273

Vue2 的所有核心知识点

从基础入门到进阶应用。主要内容包括...

MR_bailu的博客 428

vue笔记

监听字符串、数字、布尔值等简单数据类型时,直接在watch中定义与数据同名的属性,属性值为处理函数(接收两个参数:新值newVal和旧值oldValdata() {return {username: '', // 简单数据age: 18},watch: {// 监听 username 的变化console.log('用户名从', oldVal, '变成了', newVal);},// 监听 age 的变化。

2301_79775040的博客 4300

Vue面试核心考点与实战解析

响应式系统是Vue框架的核心机制,通过数据劫持实现视图自动更新。Vue2采用Object.defineProperty,而Vue3升级为Proxy API,显著提升了性能并简化了数组处理。在工程实践中,组件化开发和状态管理是关键,Vue的单文件组件(SFC)和Pinia状态库提供了完整解决方案。性能优化方面,虚拟DOM的diff算法和组件懒加载能有效提升渲染效率。这些技术广泛应用于中后台管理系统和移动端项目,掌握Vue3的Composition API和静态提升等新特性,能更好应对现代前端开发需求。本文深入

weixin_34026276的博客 406

梳理vue双向绑定的实现原理

Vue 采用数据劫持结合发布者-订阅者模式的方式来实现数据的响应式,通过Object.defineProperty来劫持数据的setter,getter,在数据变动时发布消息给订阅者,订阅者收到消息后进行相应的处理。要实现mvvm的双向绑定,就必须要实现以下几点:Compile—指令解析系统,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数Ob...

weixin_34148456的博客 95
上一篇: 数据结构与算法之队列: LeetCode 621. 任务调度器 (Ts, Py, Go版)
下一篇: 数据结构与算法之链表: LeetCode 237. 删除链表中的节点 (Ts, Py, Go版)
Wang's Blog
博客等级 码龄12年 7434粉丝 2421原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

Wang's Blog

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

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

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

打赏作者

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

抵扣说明:

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

余额充值