Vue2源码梳理:关于vm.$mount的实现

Vue源码解析-$mount 前言 Vue实例是通过mount方法进行挂载的,上一篇说了new Vue这篇分析一下mount挂载方法。mount的定义在Vue源码中有多处,这是因为Vue需要适配不同的平台以及构建方式,本文这里主要分析一下带compiler的mount实现方式。 找入口 因为是需要适配不同平台,mount方法定义在src/platform/web/entry-runtime-with-compiler.js下,代码如下: const mount = Vue.prototype.$mount Vue.prototype.$ 阅读详情

$mount

  • vue实例挂载的实现,也就是执行 vm.$mount 的方法

  • 在 Runtime + Compiler 版本,入口文件是: src/platform/web/entry-runtime-with-compiler.js

  • $mount 方法也是在这个文件中被定义的

    const mount = Vue.prototype.$mount
    Vue.prototype.$mount = function (
      el?: string | Element,
      hydrating?: boolean
    ): Component {
      // 首先对于传入的这个 el 参数,做了一个处理,可以看到 el 参数,可以是个字符串,也可以是个 Element
      // 这里调用了query方法,query方法实际上就是原生的方法,有则document.querySelector,无则,document.createElement 返回一个div 等处理
      el = el && query(el)
    
      // 拿到这个 el 以后,这里就已经被转化成了这个 dom 对象,然后它又做了一个简单的判断
      // 也就是说我的 el 如果是 body 或者是 html 标签的话,它就会报一个错
      // 就是 vue 不可以直接挂载到这个 body 或者 html 上,因为它是会覆盖的,你挂载的话,你会把整个body覆盖,那整个HTML文档不对了
      // 所以说这里在开发环境下,就报了这个警告
      /* istanbul ignore if */
      if (el === document.body || el === document.documentElement) {
        process.env.NODE_ENV !== 'production' && warn(
          `Do not mount Vue to <html> or <body> - mount to normal elements instead.`
        )
        return this
      }
      // 拿到这个options。判断有没有定义render方法,因为平时开发的过程中,代码都是脚手架生成,会有一个 render
      const options = this.$options
      // resolve template/el and convert to render function
      if (!options.render) {
        // 再次判断你有没有写template,一般模板默认是有index.html的,在组件内部也可以使用 template, 有则进行处理
        let template = options.template
        if (template) {
          if (typeof template === 'string') {
            if (template.charAt(0) === '#') {
              template = idToTemplate(template)
              /* istanbul ignore if */
              if (process.env.NODE_ENV !== 'production' && !template) {
                warn(
                  `Template element not found or is empty: ${options.template}`,
                  this
                )
              }
            }
          } else if (template.nodeType) {
            template = template.innerHTML
          } else {
            if (process.env.NODE_ENV !== 'production') {
              warn('invalid template option:' + template, this)
            }
            return this
          }
        } else if (el) {
          // 如果没有 templete 则执行 getOuterHTML 拿到html
          template = getOuterHTML(el)
        }
        if (template) {
          /* istanbul ignore if */
          if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
            mark('compile')
          }
    
          // 这一块就是跟编译相关了, 编译的话,它其实是调用这个 compileToFunction
          // 拿到生成的一个 render 函数,还有 staticRenderFns
          const { render, staticRenderFns } = compileToFunctions(template, {
            outputSourceRange: process.env.NODE_ENV !== 'production',
            shouldDecodeNewlines,
            shouldDecodeNewlinesForHref,
            delimiters: options.delimiters,
            comments: options.comments
          }, this)
          // 这个 options.render 会在渲染 vnode 的时候会用到
          options.render = render
          options.staticRenderFns = staticRenderFns
    
          /* istanbul ignore if */
          if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
            mark('compile end')
            measure(`vue ${this._name} compile`, 'compile', 'compile end')
          }
        }
      }
      // 调用 mount, 这个mount 是 runtimeOnly 时的 $mount
      return mount.call(this, el, hydrating)
    }
    
  • 它首先获得了 Vue.prototype.$mount 方法,用这个 mount 变量缓存起来,然后又重新定义了一遍这个方法

  • 回到最初的定义,在 src/platforms/web/runtime/index.js 中,是最原始的定义

    // public mount method
    Vue.prototype.$mount = function (
      el?: string | Element,
      hydrating?: boolean
    ): Component {
      el = el && inBrowser ? query(el) : undefined
      return mountComponent(this, el, hydrating)
    }
    
    // devtools global hook
    /* istanbul ignore next */
    if (inBrowser) {
      setTimeout(() => {
        if (config.devtools) {
          if (devtools) {
            devtools.emit('init', Vue)
          } else if (
            process.env.NODE_ENV !== 'production' &&
            process.env.NODE_ENV !== 'test'
          ) {
            console[console.info ? 'info' : 'log'](
              'Download the Vue Devtools extension for a better development experience:\n' +
              'https://github.com/vuejs/vue-devtools'
            )
          }
        }
        if (process.env.NODE_ENV !== 'production' &&
          process.env.NODE_ENV !== 'test' &&
          config.productionTip !== false &&
          typeof console !== 'undefined'
        ) {
          console[console.info ? 'info' : 'log'](
            `You are running Vue in development mode.\n` +
            `Make sure to turn on production mode when deploying for production.\n` +
            `See more tips at https://vuejs.org/guide/deployment.html`
          )
        }
      }, 0)
    }
    
  • 在我们的这个入口, 为什么会重新定义一遍 $mount?

  • 实际上, 上面这块最原始的代码是给 RuntimeOnly 版本复用用的一个函数

  • 在 Runtime + Compiler 版本,在 src/core/instance/init.js 的 initMixin 中

  • 执行 vm.$mount 时候,实际上调的就是 src/platform/web/entry-runtime-with-compiler.js 这个入口文件

  • 中的 Vue.prototype.$mount 这个函数,现在回到入口文件中的代码中,查看相关代码上的注释

  • 在执行了入口文件中的 .$mount, 最终调用了 RuntimeOnly 的 $mount, 最终执行 mountComponent 方法

  • 而 mountComponent 是在 src/core/instance/lifecycle.js 中定义的

    export function mountComponent (
      vm: Component,
      el: ?Element,
      hydrating?: boolean
    ): Component {
      // 首先会把这个 el 的dom 被 vm.$el 缓存起来
      vm.$el = el
      // 判断有没有 render 函数(或没有 template转换来的 render), 没有则创建一个空的 vnode, 并在开发环境警告
      if (!vm.$options.render) {
        vm.$options.render = createEmptyVNode
        // 这个警告就是写了 template,但是没有使用含有编译的版本,或者两者都没有写
        if (process.env.NODE_ENV !== 'production') {
          /* istanbul ignore if */
          if ((vm.$options.template && vm.$options.template.charAt(0) !== '#') ||
            vm.$options.el || el) {
            warn(
              'You are using the runtime-only build of Vue where the template ' +
              'compiler is not available. Either pre-compile the templates into ' +
              'render functions, or use the compiler-included build.',
              vm
            )
          } else {
            warn(
              'Failed to mount component: template or render function not defined.',
              vm
            )
          }
        }
      }
    
      // 这里先执行 beforeMount 的钩子函数,跳过
      callHook(vm, 'beforeMount')
    
      let updateComponent
      // 在dev环境上是更多做了性能埋点相关的处理,当性能比较卡顿时,可以利用这些东西,看文档就行,跳过
      /* istanbul ignore if */
      if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
        updateComponent = () => {
          const name = vm._name
          const id = vm._uid
          const startTag = `vue-perf-start:${id}`
          const endTag = `vue-perf-end:${id}`
    
          mark(startTag)
          const vnode = vm._render()
          mark(endTag)
          measure(`vue ${name} render`, startTag, endTag)
    
          mark(startTag)
          vm._update(vnode, hydrating)
          mark(endTag)
          measure(`vue ${name} patch`, startTag, endTag)
        }
      } else {
        // 这里才是我们需要关注的
        updateComponent = () => {
          vm._update(vm._render(), hydrating)
        }
      }
    
      // 这个函数就是调用了 vm._update,第一个参数是通过 vm._render渲染出来一个vnode, 第二个参数理解为 false 就可以了
      // 之后,调用 new Watcher 这里实际上是 渲染 watcher
      // 因为 watcher 这个东西其实是跟响应式原理强相关的一个类
      // 它实际上就是一个观察者模式,它其实有很多自定义 watcher,也会有一个叫渲染 watcher
      // 调用 new Watcher 的的时候,三个参数,第一个vm, 第二个 updateComponent函数, 第三个 noop(空函数), 第四个配置对象,第五个布尔值
      // we set this to vm._watcher inside the watcher's constructor
      // since the watcher's initial patch may call $forceUpdate (e.g. inside child
      // component's mounted hook), which relies on vm._watcher being already defined
      new Watcher(vm, updateComponent, noop, {
        before () {
          if (vm._isMounted && !vm._isDestroyed) {
            callHook(vm, 'beforeUpdate')
          }
        }
      }, true /* isRenderWatcher */) // 注意这里第5个参数是 true, 表示是一个渲染watcher
      hydrating = false
    
      // manually mounted instance, call mounted on self
      // mounted is called for render-created child components in its inserted hook
      if (vm.$vnode == null) {
        vm._isMounted = true
        callHook(vm, 'mounted')
      }
      return vm
    }
    
    • 进入 Watcher 的定义,在 src/core/observer/watcher.js 中
      /**
       * A watcher parses an expression, collects dependencies,
      * and fires callback when the expression value changes.
      * This is used for both the $watch() api and directives.
      */
      export default class Watcher {
        vm: Component;
        expression: string;
        cb: Function;
        id: number;
        deep: boolean;
        user: boolean;
        lazy: boolean;
        sync: boolean;
        dirty: boolean;
        active: boolean;
        deps: Array<Dep>;
        newDeps: Array<Dep>;
        depIds: SimpleSet;
        newDepIds: SimpleSet;
        before: ?Function;
        getter: Function;
        value: any;
      
        constructor (
          vm: Component,
          expOrFn: string | Function,
          cb: Function,
          options?: ?Object,
          isRenderWatcher?: boolean // 是否是渲染 watcher
        ) {
          this.vm = vm
          if (isRenderWatcher) {
            vm._watcher = this
          }
          vm._watchers.push(this) // 收集watcher
          // 这里忽略这个options
          // options
          if (options) {
            this.deep = !!options.deep
            this.user = !!options.user
            this.lazy = !!options.lazy
            this.sync = !!options.sync
            this.before = options.before
          } else {
            this.deep = this.user = this.lazy = this.sync = false
          }
          this.cb = cb
          this.id = ++uid // uid for batching
          this.active = true
          this.dirty = this.lazy // for lazy watchers
          this.deps = []
          this.newDeps = []
          this.depIds = new Set()
          this.newDepIds = new Set()
          this.expression = process.env.NODE_ENV !== 'production'
            ? expOrFn.toString()
            : ''
          // 注意这里,这里就是调用方传进来的 updateComponent
          // parse expression for getter
          if (typeof expOrFn === 'function') {
            this.getter = expOrFn
          } else {
            this.getter = parsePath(expOrFn)
            if (!this.getter) {
              this.getter = noop
              process.env.NODE_ENV !== 'production' && warn(
                `Failed watching path: "${expOrFn}" ` +
                'Watcher only accepts simple dot-delimited paths. ' +
                'For full control, use a function instead.',
                vm
              )
            }
          }
          this.value = this.lazy
            ? undefined
            : this.get()
        }
      
        // 这里有依赖收集,相关的
        /**
         * Evaluate the getter, and re-collect dependencies.
        */
        get () {
          pushTarget(this)
          let value
          const vm = this.vm
          try {
            value = this.getter.call(vm, vm) // 这里会调用 getter, 也就是上层调用方传进来的 updateComponent 方法,就会执行方法内部的 update
          } catch (e) {
            if (this.user) {
              handleError(e, vm, `getter for watcher "${this.expression}"`)
            } else {
              throw e
            }
          } finally {
            // "touch" every property so they are all tracked as
            // dependencies for deep watching
            if (this.deep) {
              traverse(value)
            }
            popTarget()
            this.cleanupDeps()
          }
          return value
        }
      
        /**
         * Add a dependency to this directive.
        */
        addDep (dep: Dep) {
          const id = dep.id
          if (!this.newDepIds.has(id)) {
            this.newDepIds.add(id)
            this.newDeps.push(dep)
            if (!this.depIds.has(id)) {
              dep.addSub(this)
            }
          }
        }
      
        /**
         * Clean up for dependency collection.
        */
        cleanupDeps () {
          let i = this.deps.length
          while (i--) {
            const dep = this.deps[i]
            if (!this.newDepIds.has(dep.id)) {
              dep.removeSub(this)
            }
          }
          let tmp = this.depIds
          this.depIds = this.newDepIds
          this.newDepIds = tmp
          this.newDepIds.clear()
          tmp = this.deps
          this.deps = this.newDeps
          this.newDeps = tmp
          this.newDeps.length = 0
        }
      
        /**
         * Subscriber interface.
        * Will be called when a dependency changes.
        */
        update () {
          /* istanbul ignore else */
          if (this.lazy) {
            this.dirty = true
          } else if (this.sync) {
            this.run()
          } else {
            queueWatcher(this)
          }
        }
      
        /**
         * Scheduler job interface.
        * Will be called by the scheduler.
        */
        run () {
          if (this.active) {
            const value = this.get()
            if (
              value !== this.value ||
              // Deep watchers and watchers on Object/Arrays should fire even
              // when the value is the same, because the value may
              // have mutated.
              isObject(value) ||
              this.deep
            ) {
              // set new value
              const oldValue = this.value
              this.value = value
              if (this.user) {
                const info = `callback for watcher "${this.expression}"`
                invokeWithErrorHandling(this.cb, this.vm, [value, oldValue], this.vm, info)
              } else {
                this.cb.call(this.vm, value, oldValue)
              }
            }
          }
        }
      
        /**
         * Evaluate the value of the watcher.
        * This only gets called for lazy watchers.
        */
        evaluate () {
          this.value = this.get()
          this.dirty = false
        }
      
        /**
         * Depend on all deps collected by this watcher.
        */
        depend () {
          let i = this.deps.length
          while (i--) {
            this.deps[i].depend()
          }
        }
      
        /**
         * Remove self from all dependencies' subscriber list.
        */
        teardown () {
          if (this.active) {
            // remove self from vm's watcher list
            // this is a somewhat expensive operation so we skip it
            // if the vm is being destroyed.
            if (!this.vm._isBeingDestroyed) {
              remove(this.vm._watchers, this)
            }
            let i = this.deps.length
            while (i--) {
              this.deps[i].removeSub(this)
            }
            this.active = false
          }
        }
      }
      

总结下 $mount

  • 1 ) 在含有 compiler 版本中,先对 el 做一些处理
  • 2 ) 在没有定义 render 函数的时候,尝试获取一下 render 函数
    • 也就是说,把整个template通过一系列的逻辑判断,也是因为它支持很多很多种写法
      • 可以直接写 template
      • 也可以直接 template 是个dom对象
      • 如果不写 templete 的话,通过 el 的 outHTML 来获取这个 templete
    • 把这个template 通过这个编译的手段也转化成这个render函数
    • 也就是说整个 $mount 在这个带compiler版本的前提,要拿到这个render函数
  • 3 ) 然后就会调用这个 mountComponent 的这个方法
    • 这个方法其实很简单,就是定义了 updateComponent 这个函数
  • 4 ) 这个函数它实际上被用到渲染 watcher 里面,为什么要通过 watcher 呢?
    • 是因为这个 updateComponent 这个方法,实际上执行了一次真实的渲染
    • 这个渲染过程,除了我们首次,之后再更新数据的时候,还是会触发这个渲染watcher
    • 再次执行这个updateComponent方法,它是一个监听到执行的这样一个过程
    • 当我们的数据发生变化,它的更新入口也是这个 updateComponent 方法
    • 这就是渲染 watcher所要做的事情
vue2源码分析:patch函数 目录 1.patch函数的脉络 2.类vnode的设计 3.createPatch函数中的辅助函数和patch函数 4.源码运行展示(DEMO) 一.patch函数的脉络 首先梳理一下patch函数的脉络。 第一,patch核心函数createPatchFunction, 然后,runtime/index.js中将patch方法挂载到vue的原型属性__patch__上。 Vue.pro... 阅读详情

相关推荐

Part3-2-1 Vue.js 源码剖析-首次渲染过程

1

m0_38066007的博客 266

Vue2手动挂载组件$mount()学习

Vue2手动挂载组件$mount()学习

Amtai的博客 1483

5060TI显卡深度学习环境搭建:CUDA12.8与CUDNN9.8.0的完美搭配

本文详细介绍了在Win10系统下为5060TI显卡搭建深度学习环境的最佳实践,重点配置CUDA12.8与CUDNN9.8.0的完美组合。通过优化OpenCV编译选项和YOLOv5环境设置,显著提升模型训练和推理效率,帮助开发者充分发挥5060TI显卡的性能潜力。

weixin_29065791的博客 491

vue源码学习(4)vm.$mount()

1. vm.$mount的使用 vm.$mount的作用:手动地挂载一个未挂载的实例到元素上 vm.$mount官网示例 vm.$mount的源码 //原函数 // Vue.prototype.$mount = function ( // el, // hydrating // ) { // el = el && inBrowser ? query(el) : undefined; // return mountComponent(this, el, hydrating)

tangkebo的博客 1786

矢量量化的基本原理:高效数据压缩与信息检索的关键矢量量化(Vector Quantization,简称VQ)是一种数据压缩和信

此外,在矢量量化过程中,可能会引入一定的信息损失,对一些精细特征的表示可能存在一定的误差。它通过将高维数据映射到低维码本空间中,并将相似的数据映射到相同的码本向量中,实现对数据的高效表示和存储。最重要的是,矢量量化可以用于数据的检索和分析,提供了高效的数据查询和处理手段。通过使用码本索引,我们可以高效地存储和检索大量的数据。在图像处理中,矢量量化可以用于图像压缩,将复杂的图像数据转化为较少的码字,实现图像的存储和传输。矢量量化通过将连续的高维数据分割并映射到有限的码本集合中,实现数据的离散表示和压缩。

m0_70886513的博客 1374

不只是烧录:深入理解英飞凌Aurix MCU的HSM安全模块与UDE Memtool解锁操作

本文深入探讨了英飞凌Aurix MCU的HSM安全模块设计与UDE Memtool解锁操作,揭示了硬件安全模块的架构、安全启动链机制及调试接口的安全特性。通过分析UDE Memtool的解锁逻辑和量产环境下的最佳实践,帮助工程师更好地应对MCU锁定问题,提升汽车电子和工业控制领域的安全烧录效率。

weixin_32770423的博客 301

vue2 框架运行原理剖析系列(二)之 组件挂载$mount神秘之旅!!!

vue 的 抽象语法树与渲染函数生成、挂载方式、模板编译

1324

别再让PyCharm吃光你的C盘!保姆级教程:安全迁移config、plugins和remote sources到D盘

本文提供了一份详细的PyCharm配置与缓存文件迁移指南,帮助开发者将config、plugins和remote sources等占用大量C盘空间的文件安全转移到D盘。通过修改data.properties文件和正确迁移顺序,确保PyCharm功能不受影响,同时释放宝贵的系统盘空间。

weixin_28836989的博客 424

Vue2.x 源码 - 初始化:实例挂载($mount)的实现

上一篇:Vue2.x 源码 - 初始化:stateMixin(Vue)、eventsMixin(Vue)、lifecycleMixin(Vue)、renderMixin(Vue) Vue 中是通过 $mount 实例方法来挂载 vm 的;然而这个方法在很多个文件里都有定义:src/platform/web/entry-runtime-with-compiler.js 、src/platform/web/runtime/index.js 、 src/platform/weex/runtime/index..

weixin_43299180的博客 1491

学习笔记:物理信息神经网络(PINN)

PINN 的强大在于它打破了传统数值方法的限制,将神经网络的非线性拟合能力与物理方程的严谨性结合起来。它在处理高维、数据稀缺、复杂物理约束的场景下尤其出色。当然,PINN 也有收敛慢、梯度消失等挑战,比如,复杂 PDE 可能导致梯度传播困难,收敛慢(梯度消失)、于具有快速变化特征的系统,如冲击波,标准 PINN 可能精度不足,需要改进策略,比如自适应采样或多尺度特征提取。但随着研究深入,这些问题正在不断被解决。物理或化学方程为什么往往是偏微分方程?什么是物理信息神经网络(PINN)?x_%7Bi%7D。

qq_52635735的博客 1万+

C语言专升本编程题

湖南省专升本选拔考试,C语言程序设计内部习题

weixin_45729947的博客 2118

Vue2源码梳理:render函数的实现

在 $mount 时,会调用 render 方法,在写 template 时,最终也会转换成 render 方法,Vue 的 _render 方法是实例的一个私有方法,它用来把实例渲染成一个虚拟 Node

Wang的专栏 1322

SAP ABAP 接口管理服务(ZIF)开源项目介绍

接口管理服务(ZIF)开源项目基于 SAP ABAP系统,是一款对标SAP PI/PO 的轻量接口管理产品。他通过独立开发包部署在ABAP系统中,包含接口注册、接口管理、日志服务及其他配套功能,拥有丰富的技术沉淀并通过市场检验,目前已被多家企业应用在SAP ERP系统中。

SAP李斌,本人承诺所有原创文章均不使用任何AI生成技术,请大家放心阅读。 1745

Vue(2.5.22) 数据劫持、发布-订阅 源码梳理

着重于数据劫持、发布-订阅模式,我们只关注相关的代码 1. 从代码入口开始(instance/index) function Vue (options) { if (process.env.NODE_ENV !== 'production' && !(this instanceof Vue) ) { warn('Vue is a constructor...

NewWent的博客 631

CDD数据库文件制作(二)——服务配置(0x27)

主要根据诊断调查表,针对0x27服务在CDD中的每一步配置给出详细介绍 1.会话切换配置 1.1.根据诊断调查表进行信息提取 1.2.子功能添加 1.2.1.Level1安全等级1创建 1.2.2.Level3安全等级3创建 1.2.3.安全等级名字查看与修改 1.3.会话切换信息提取(应用程序下) 1.4.会话转换配置(应用程序下) 1.5.会话切换信息提取(引导程序下) 1.6.会话转换配置(引导程序下) 2.安全等级配置信息提取 2.1.安全访问配置(level1) 2.2.安全访问配置(level2

LOVE135149的博客 2932

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Vue2源码梳理:update的整体实现流程

回到之间 $mount时,mountComponent 函数的过程,vm._render 是如何创建了一个 VNode,接下来就是要把这个 VNode 渲染成一个真实的 DOM 并渲染出来,这个过程是通过 vm._update 完成的,_update 它是一个vue 的私有方法,它把我们的 vnode 渲染成真实的 dom,_update的方法,也是原型上的一个方法, 它的定义在src/core/instance/lifecycle.js 中

Wang的专栏 2308

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

vue实例没有挂载到html上,vue 源码学习 - 实例挂载

前言在学习vue源码之前需要先了解源码目录设计(了解各个模块的功能)丶Flow语法。src├── compiler # 把模板解析成 ast 语法树,ast 语法树优化,代码生成等功能。├── core # 核心代码 Vue.js 的灵魂├── platforms # 不同平台的支持 web 和 weex├── server # 服务端渲染这部分代码是跑在服务端...

weixin_34107887的博客 625

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

第十六节:带你梳理Vue2: 生命周期与钩子函数

通过前面几节的学习,我们已经对vue有了初步的了解,大致了解了vue可以帮我们干什么,那么接下来我们就来看看vue的生命周期和它常用的钩子函数,

我们专注于分享最实用的编程技术和干货,帮助你提升编程能力,感谢您的支持和关注! 723

Vue2源码梳理:vdom结构与createElement的实现

浏览器原生dom对象,本身就是一个非常复杂的对象,单单把 div 这个dom对象拿出来,遍历它的属性,将是一个庞大的存在,因为浏览器的标准就是把这个dom设计的非常复杂,所以当我们去频繁的操作dom的话,一定会有一些性能问题,vdom(Virtual DOM), 其实就是用一个原生的js对象去描述一个dom节点,它的创建比创建一个真实的dom的代价要小很多,在vue.js中的 vdom 的定义在 src/core/vdom/vnode.js

Wang的专栏 1426

vm options什么意思_vue2.0源码解读 数据驱动:new Vue() 发生了什么?

关注“前端学苑” ,坚持每天进步一点点「~vue2.0源码解读~」Vue 一个核心思想是数据驱动,相信大家一定对这个不陌生。所谓数据驱动,就是视图由数据驱动生成。相比传统的使用jQuery等前端库直接操作DOM,大大提高了开发效率,代码简洁易维护。本篇文章主要是 Vue源码探秘之 “ 数据驱动 ”。主题内容:new Vue()发生了什么?这同样也是Vue必考面试题之一。正文从这里...

weixin_39627408的博客 357

Vue2源码梳理:关于数据驱动,与new Vue时的初始化操作

因为dom变成了数据的映射,我们所有的逻辑都是对数据的修改,而并不关注dom,这样的代码非常有利于维护。它大大简化了代码量,特别是当交互复杂的时候,只关心数据的修改会让代码的逻辑变得非常清晰。它相比我们传统的前端开发,如使用 jQuery 的前端库直接去修改 dom 的的话。在vue.js中,可以采用简洁的模板语法来声明式的将数据渲染为 dom,示例。这个例子是为了说明这个数据在js中定义的这个数据 最终是怎么渲染到dom上的。所谓数据驱动,就是指视图是由数据驱动生成的。2 )数据驱动的关注。

Wang的专栏 1187

Vue - 以$、_开头命名的问题及源码梳理

data 中以 $、_ 开头的属性不会被代理到 this 上,但是可以通过 _data、$data 访问因为 this 上没有 $、_ 的属性,所以 watch 也无法监听 $、_ 属性的变化由于 vm._data 被 defineReactive 处理过,所以可以通过 watch _data.$xxx、_data._xxx 监听属性的变化。

Moon Star 897

【手写 Vue2.x 源码】第七篇 - 阶段性梳理

第七篇 - 阶段性梳理;通过断点调试,对当前版本数据劫持、数据代理进行了简单的流程梳理;同时,对照 Vue2.x 提供的功能,分析了当前版本数据观测的问题和不足;

BraveWangDev 898

vue2数据劫持(源码剖析)

vue2中如何实现对data数据的监听,以及数组的添加、删除等方法的监听和更新视图

IT_Mr_wu的博客 1178

【记录】Vue2初始化到挂载过程(梳理总结)

dep订阅者,用于收集依赖watcher,在访问属性触发get的时候,收集依赖,当设置值触发set的时候通过dep.notify通知收集到的列表里边的每个watcher去更新。d.触发evaluate,涉及到data的数据会被访问,触发data的get,这个时候data数据收集了computed的watcher。c.当render函数执行,触发该计算属性getter,触发收集依赖,首先订阅的是当前vue的渲染watcher。2.优化语法树,也就是深度遍历AST树,optimize主要做了两件事,一个是。

qq_41630414的博客 1230
上一篇: Vue2源码梳理:关于数据驱动,与new Vue时的初始化操作
下一篇: Vue2源码梳理:render函数的实现
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、付费专栏及课程。

余额充值