Vue实例挂载的过程

2023-11-17

 一、思考与分析

我们都听过知其然知其所以然这句话

那么不知道是否思考过new Vue()这个过程中究竟做了些什么?

过程中是如何完成数据的绑定,又是如何将数据渲染到视图的等等

首先找到vue的构造函数

源码位置:src\core\instance\index.js

function Vue (options) {
  if (process.env.NODE_ENV !== 'production' &&
    !(this instanceof Vue)
  ) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  this._init(options)
}

options是用户传递过来的配置项,如data、methods等常用的方法

vue构建函数调用_init方法,但我们发现本文件中并没有此方法,但仔细可以看到文件下方定定义了很多初始化方法

initMixin(Vue);     // 定义 _init
stateMixin(Vue);    // 定义 $set $get $delete $watch 等
eventsMixin(Vue);   // 定义事件  $on  $once $off $emit
lifecycleMixin(Vue);// 定义 _update  $forceUpdate  $destroy
renderMixin(Vue);   // 定义 _render 返回虚拟dom

首先可以看initMixin方法,发现该方法在Vue原型上定义了_init方法

源码位置:src\core\instance\init.js

Vue.prototype._init = function (options?: Object) {
    const vm: Component = this
    // a uid
    vm._uid = uid++
    let startTag, endTag
    /* istanbul ignore if */
    if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
      startTag = `vue-perf-start:${vm._uid}`
      endTag = `vue-perf-end:${vm._uid}`
      mark(startTag)
    }

    // a flag to avoid this being observed
    vm._isVue = true
    // merge options
    // 合并属性,判断初始化的是否是组件,这里合并主要是 mixins 或 extends 的方法
    if (options && options._isComponent) {
      // optimize internal component instantiation
      // since dynamic options merging is pretty slow, and none of the
      // internal component options needs special treatment.
      initInternalComponent(vm, options)
    } else { // 合并vue属性
      vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
      )
    }
    /* istanbul ignore else */
    if (process.env.NODE_ENV !== 'production') {
      // 初始化proxy拦截器
      initProxy(vm)
    } else {
      vm._renderProxy = vm
    }
    // expose real self
    vm._self = vm
    // 初始化组件生命周期标志位
    initLifecycle(vm)
    // 初始化组件事件侦听
    initEvents(vm)
    // 初始化渲染方法
    initRender(vm)
    callHook(vm, 'beforeCreate')
    // 初始化依赖注入内容,在初始化data、props之前
    initInjections(vm) // resolve injections before data/props
    // 初始化props/data/method/watch/methods
    initState(vm)
    initProvide(vm) // resolve provide after data/props
    callHook(vm, 'created')

    /* istanbul ignore if */
    if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
      vm._name = formatComponentName(vm, false)
      mark(endTag)
      measure(`vue ${vm._name} init`, startTag, endTag)
    }
    // 挂载元素
    if (vm.$options.el) {
      vm.$mount(vm.$options.el)
    }
  }

仔细阅读上面的代码,我们得到以下结论:

  • 在调用beforeCreate之前,数据初始化并未完成,像dataprops这些属性无法访问到

  • 到了created的时候,数据已经初始化完成,能够访问dataprops这些属性,但这时候并未完成dom的挂载,因此无法访问到dom元素

  • 挂载方法是调用vm.$mount方法

initState方法是完成props/data/method/watch/methods的初始化

源码位置:src\core\instance\state.js

export function initState (vm: Component) {
  // 初始化组件的watcher列表
  vm._watchers = []
  const opts = vm.$options
  // 初始化props
  if (opts.props) initProps(vm, opts.props)
  // 初始化methods方法
  if (opts.methods) initMethods(vm, opts.methods)
  if (opts.data) {
    // 初始化data  
    initData(vm)
  } else {
    observe(vm._data = {}, true /* asRootData */)
  }
  if (opts.computed) initComputed(vm, opts.computed)
  if (opts.watch && opts.watch !== nativeWatch) {
    initWatch(vm, opts.watch)
  }
}

我们和这里主要看初始化data的方法为initData,它与initState在同一文件上

function initData (vm: Component) {
  let data = vm.$options.data
  // 获取到组件上的data
  data = vm._data = typeof data === 'function'
    ? getData(data, vm)
    : data || {}
  if (!isPlainObject(data)) {
    data = {}
    process.env.NODE_ENV !== 'production' && warn(
      'data functions should return an object:\n' +
      'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
      vm
    )
  }
  // proxy data on instance
  const keys = Object.keys(data)
  const props = vm.$options.props
  const methods = vm.$options.methods
  let i = keys.length
  while (i--) {
    const key = keys[i]
    if (process.env.NODE_ENV !== 'production') {
      // 属性名不能与方法名重复
      if (methods && hasOwn(methods, key)) {
        warn(
          `Method "${key}" has already been defined as a data property.`,
          vm
        )
      }
    }
    // 属性名不能与state名称重复
    if (props && hasOwn(props, key)) {
      process.env.NODE_ENV !== 'production' && warn(
        `The data property "${key}" is already declared as a prop. ` +
        `Use prop default value instead.`,
        vm
      )
    } else if (!isReserved(key)) { // 验证key值的合法性
      // 将_data中的数据挂载到组件vm上,这样就可以通过this.xxx访问到组件上的数据
      proxy(vm, `_data`, key)
    }
  }
  // observe data
  // 响应式监听data是数据的变化
  observe(data, true /* asRootData */)
}

仔细阅读上面的代码,我们可以得到以下结论:

  • 初始化顺序:propsmethodsdata

  • data定义的时候可选择函数形式或者对象形式(组件只能为函数形式)

关于数据响应式在这就不展开详细说明

上文提到挂载方法是调用vm.$mount方法

源码位置:

Vue.prototype.$mount = function (
  el?: string | Element,
  hydrating?: boolean
): Component {
  // 获取或查询元素
  el = el && query(el)

  /* istanbul ignore if */
  // vue 不允许直接挂载到body或页面文档上
  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
  }

  const options = this.$options
  // resolve template/el and convert to render function
  if (!options.render) {
    let template = options.template
    // 存在template模板,解析vue模板文件
    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) {
      // 通过选择器获取元素内容
      template = getOuterHTML(el)
    }
    if (template) {
      /* istanbul ignore if */
      if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
        mark('compile')
      }
      /**
       *  1.将temmplate解析ast tree
       *  2.将ast tree转换成render语法字符串
       *  3.生成render方法
       */
      const { render, staticRenderFns } = compileToFunctions(template, {
        outputSourceRange: process.env.NODE_ENV !== 'production',
        shouldDecodeNewlines,
        shouldDecodeNewlinesForHref,
        delimiters: options.delimiters,
        comments: options.comments
      }, this)
      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')
      }
    }
  }
  return mount.call(this, el, hydrating)
}

阅读上面代码,我们能得到以下结论:

  • 不要将根元素放到body或者html

  • 可以在对象中定义template/render或者直接使用templateel表示元素选择器

  • 最终都会解析成render函数,调用compileToFunctions,会将template解析成render函数

template的解析步骤大致分为以下几步:

  • html文档片段解析成ast描述符

  • ast描述符解析成字符串

  • 生成render函数

生成render函数,挂载到vm上后,会再次调用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)
}

调用mountComponent渲染组件

export function mountComponent (
  vm: Component,
  el: ?Element,
  hydrating?: boolean
): Component {
  vm.$el = el
  // 如果没有获取解析的render函数,则会抛出警告
  // render是解析模板文件生成的
  if (!vm.$options.render) {
    vm.$options.render = createEmptyVNode
    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 {
        // 没有获取到vue的模板文件
        warn(
          'Failed to mount component: template or render function not defined.',
          vm
        )
      }
    }
  }
  // 执行beforeMount钩子
  callHook(vm, 'beforeMount')

  let updateComponent
  /* 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 = () => {
      // 实际调⽤是在lifeCycleMixin中定义的_update和renderMixin中定义的_render
      vm._update(vm._render(), hydrating)
    }
  }
  // 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 */)
  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
}

阅读上面代码,我们得到以下结论:

  • 会触发beforeCreate钩子
  • 定义updateComponent渲染页面视图的方法
  • 监听组件数据,一旦发生变化,触发beforeUpdate生命钩子

updateComponent方法主要执行在vue初始化时声明的renderupdate方法

render的作用主要是生成vnode

源码位置:src\core\instance\render.js

// 定义vue 原型上的render方法
Vue.prototype._render = function (): VNode {
    const vm: Component = this
    // render函数来自于组件的option
    const { render, _parentVnode } = vm.$options

    if (_parentVnode) {
        vm.$scopedSlots = normalizeScopedSlots(
            _parentVnode.data.scopedSlots,
            vm.$slots,
            vm.$scopedSlots
        )
    }

    // set parent vnode. this allows render functions to have access
    // to the data on the placeholder node.
    vm.$vnode = _parentVnode
    // render self
    let vnode
    try {
        // There's no need to maintain a stack because all render fns are called
        // separately from one another. Nested component's render fns are called
        // when parent component is patched.
        currentRenderingInstance = vm
        // 调用render方法,自己的独特的render方法, 传入createElement参数,生成vNode
        vnode = render.call(vm._renderProxy, vm.$createElement)
    } catch (e) {
        handleError(e, vm, `render`)
        // return error render result,
        // or previous vnode to prevent render error causing blank component
        /* istanbul ignore else */
        if (process.env.NODE_ENV !== 'production' && vm.$options.renderError) {
            try {
                vnode = vm.$options.renderError.call(vm._renderProxy, vm.$createElement, e)
            } catch (e) {
                handleError(e, vm, `renderError`)
                vnode = vm._vnode
            }
        } else {
            vnode = vm._vnode
        }
    } finally {
        currentRenderingInstance = null
    }
    // if the returned array contains only a single node, allow it
    if (Array.isArray(vnode) && vnode.length === 1) {
        vnode = vnode[0]
    }
    // return empty vnode in case the render function errored out
    if (!(vnode instanceof VNode)) {
        if (process.env.NODE_ENV !== 'production' && Array.isArray(vnode)) {
            warn(
                'Multiple root nodes returned from render function. Render function ' +
                'should return a single root node.',
                vm
            )
        }
        vnode = createEmptyVNode()
    }
    // set parent
    vnode.parent = _parentVnode
    return vnode
}

_update主要功能是调用patch,将vnode转换为真实DOM,并且更新到页面中

源码位置:src\core\instance\lifecycle.js

Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {
    const vm: Component = this
    const prevEl = vm.$el
    const prevVnode = vm._vnode
    // 设置当前激活的作用域
    const restoreActiveInstance = setActiveInstance(vm)
    vm._vnode = vnode
    // Vue.prototype.__patch__ is injected in entry points
    // based on the rendering backend used.
    if (!prevVnode) {
      // initial render
      // 执行具体的挂载逻辑
      vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */)
    } else {
      // updates
      vm.$el = vm.__patch__(prevVnode, vnode)
    }
    restoreActiveInstance()
    // update __vue__ reference
    if (prevEl) {
      prevEl.__vue__ = null
    }
    if (vm.$el) {
      vm.$el.__vue__ = vm
    }
    // if parent is an HOC, update its $el as well
    if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) {
      vm.$parent.$el = vm.$el
    }
    // updated hook is called by the scheduler to ensure that children are
    // updated in a parent's updated hook.
  }

二、结论

  • new Vue的时候调用会调用_init方法

    • 定义 $set$get 、$delete$watch 等方法
    • 定义 $on$off$emit$off等事件
    • 定义 _update$forceUpdate$destroy生命周期
  • 调用$mount进行页面的挂载

  • 挂载的时候主要是通过mountComponent方法

  • 定义updateComponent更新函数

  • 执行render生成虚拟DOM

  • _update将虚拟DOM生成真实DOM结构,并且渲染到页面中

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Vue实例挂载的过程 的相关文章

  • Javascript:将 JSON 字符串转换为 ES6 映射或其他形式以保留键的顺序

    ES6 或后续版本 Javascript 或 TypeScript 中是否有原生 内置 方法将 JSON 字符串转换为 ES6 映射 或者可以选择要实现的自制解析器 目标是保留 JSON 字符串编码对象的键顺序 Note 我故意不使用 解析
  • Google 地图上的自定义路线/路径/道路

    我需要能够使用 V2 或 V3 最好是 3 创建在某种意义上忽略建筑物的路径 我试图创建一个 kml 文件来自己绘制所有路径 然后找到某种方法根据需要打开 关闭它们 例如 用户想要从 A 点前往 B 点 这些点之间有许多建筑物 用户可以实际
  • 在承诺中运行同步函数

    我是 JS 和异步操作的新手 在使用express的nodeJS路由器中 我使用mongoose从mongo聚合了一些数据 该数据是每隔 15 分钟从不同站点收集的天气数据 我使用猫鼬聚合管道处理数据 以获取每小时数据并按每个站点进行分组
  • 将 Javascript 正则表达式转换为 PHP

    我知道这个问题已经被问了大约十几次 但是从技术上讲 这个问题并不是一个骗局 如果您愿意 请检查其他问题 基本上 我有一个 Javascript 正则表达式来检查用于前端验证的电子邮件地址 并且我使用 CodeIgniter 在后端进行双重检
  • React useEffect hook 和 Async/await 自己的获取数据函数?

    我尝试创建一个从服务器获取数据的函数 并且它有效 但我不确定这是否正确 我创建了一个函数组件来获取数据 使用useState 使用效果 and 异步 等待 import React useState useEffect from react
  • 在 Javascript 中获取文本框的值

    我有这个html代码 table border cellpadding 3 cellspacing 0 tbody tr td Song td td td tr tbody table
  • HTML5 游戏到本机应用程序 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在用 HTML5 制作游戏 我最熟悉 HTML5 并且比 C 等更高级的语言更喜欢它 HTML5
  • 无法读取未定义错误的属性“匹配”

    我试图在 React JS 前端显示一些文本来代替个人资料图像 当它不可用时 基本上 我将当前客户名称传递给一个函数 该函数提取名称中所有单词的第一个字符 我能够仅显示名称 但是当我执行函数调用时 出现 无法读取未定义的属性 匹配 错误 并
  • 如何隐藏 URL 中的 ID

    我以前在 Stack Overflow 上见过这类问题 但没有一个真正有帮助 我也用谷歌搜索过 但没有骰子 我想知道如果用户单击选项卡本身是否可以隐藏 URL 中的 ID 这是网页 www planet nu dev new experia
  • 如何使用 jQuery Validate 正确验证放置在多个选项卡上的 Twitter Bootstrap 表单?

    我有一个表单位于多个 Twitter 的 Bootstrap 选项卡上
  • 如何在Android上获取角度中的按键事件?

    我们如何在 Android 上的 Angular 中获取按键事件及其值 我使用phonegap Cordova Angular JS
  • 查找 JavaScript 中函数参数的数量[重复]

    这个问题在这里已经有答案了 可能的重复 获取函数的元数 https stackoverflow com questions 4848149 get a functions arity 假设我有 function a x function b
  • 使用XMLHttpRequest自动网页刷新内存泄漏

    问候 我一直在为一些使用 8 位微控制器的硬件开发网络界面 该网页使用 HTML javascript JSON 和 XHR XMLHttpRequest 进行通信 我想做的是创建一个页面 使用 setInterval 使用控制器中的新值每
  • ES6 模板文字可以在运行时替换(或重用)吗?

    tl dr 是否可以制作可重用的模板文字 我一直在尝试使用模板文字 但我想我就是不明白 现在我感到沮丧 我的意思是 我想我明白了 但 它 不应该是它的运作方式 或者它应该如何实现 它应该变得不同 我看到的所有示例 甚至标记模板 都要求 替换
  • 允许在 Safari 上聊天应用程序使用 audio.play()

    由于苹果禁用了自动播放音频的功能HTMLMedia Element play https developer mozilla org en US docs Web API HTMLMediaElement play在没有用户交互的 java
  • Cypress.io 如何处理异步代码

    我正在将旧的水豚测试转移到 cypress io 因为我们的应用程序正在采用 SPA 方式 在我们的案例中 我们有超过 2000 个测试 涵盖了很多功能 因此 测试功能的常见模式是让用户创建并发布报价 一开始我写了 cypress 浏览页面
  • NodeJS 错误堆栈未定义 [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我正在使用节点检查器 我注意到new Error 有未定义的堆栈 如果我将此值分配给一个变量 该变量将显示堆栈未定义 有趣的是 跑步new
  • 出于安全目的,您是否有理由不执行自己的算法来打乱 ID?

    我计划实现我自己的非常简单的 哈希 公式 为具有多个用户的应用程序添加一层安全性 我目前的计划如下 用户创建一个帐户 此时后端会生成一个 ID ID 通过公式运行 假设 ID 57 8926 36 7 或同样随机的东西 然后 我将新的用户
  • 更改哈希值而不触发 hashchange 事件

    我使用哈希来动态加载内容 为了使后退按钮正常工作 我正在捕获哈希更改 然而 有时我需要更改哈希值而不触发哈希更改函数 例如 当页面重定向到服务器端时 我需要在内容返回后更新哈希值 我想出的最佳解决方案是取消绑定 hashchange 事件
  • 如何使用 Typescript 设置 Material-UI for React?

    我在将 Material UI 添加到我的 React 项目中时遇到了一些问题 该项目是用 Typescript 编程的 根据教程 我首先添加react tab event plugin import injectTapEventPlugi

随机推荐

  • 静息态fMRI状态依赖的有效连接

    文章来源于微信公众号 茗创科技 欢迎有兴趣的朋友搜索关注 导读 大脑在静息状态下存在着不同脑区间的功能连接 并且在多重稳态之间具有内在动态平衡过程 因此 探索特定状态下的功能连接 有利于以加深对精神疾病的理解 然而 与功能连接相比 有效连接
  • 【深入理解C++】运算符重载、插入和提取运算符、拷贝赋值运算符

    文章目录 1 运算符重载 2 重载为友元函数 3 重载为成员函数 4 插入和提取运算符 5 拷贝赋值运算符 5 1 深拷贝 1 运算符重载 运算符重载可以为运算符增加一些新的功能 C 中绝大部分的运算符允许重载 不能重载的运算符有以下几个
  • excel柱状图堆叠图显示总和_如何在Excel堆积柱形图中显示合计值

    在Excel中 用堆积柱形图可以比较相交于类别轴上的每一数值占总数值的大小 对于普通的簇状柱形图 我们可以在每个柱形系列的顶端放置一个数据标志 如数值 来反映各系列数据的大小 对于堆积柱形图 Excel没有提供直接的方法将数据标志显示在柱形
  • mysql - windows下my.ini和linux下my.cnf简单配置

    mysql 设置mysql客户端默认字符集 default character set utf8 mysqld 设置3307端口 port 3307 设置mysql的安装目录 basedir G a workIndex mysql mysq
  • MFC创建窗口流程

    一个MFC程序框架 1 应用程序类 CWinApp 2 框架类 CFrameWnd 流程 1 有且仅有一个全局的应用程序类对象 MyApp myApp 2 在程序入口函数实现 InitInstance 1 给框架类对象动态分配空间 自动调用
  • mysql 大数据量如何导入

    MySQL 有多种方法可以用来导入大数据量 这里列举几种常见的方法 导入数据库备份文件 如果你已经有了数据库的备份文件 可以使用 MySQL 的 mysql 命令行工具来导入 例如 mysql u username p db name lt
  • 【微信小程序】运行机制和更新机制

    观众老爷们好呀 牛牛又更文了 上文我们对部分比较常用的组件进行了讲解 作为开发者 我们还需要对小程序的运行机制和更新机制做一定的了解 那问题来了 你对它们了解多少呢 今天牛牛就带大家测一测 不了解的还不笔记做起来 文章目录 一 运行机制 1
  • 图像相似度计算之直方图方法OpenCV实现

    操作步骤 1 载入图像 灰度图或者彩色图 并使其大小一致 2 若为彩色图 增进行颜色空间变换 从RGB转换到HSV 若为灰度图则无需变换 3 若为灰度图 直接计算其直方图 并进行直方图归一化 4 若为彩色图 则计算其彩色直方图 并进行彩色直
  • HTTP首部(下)

    开始头大 哈哈 这个东西真的很无聊且枯燥 奈何最近的学习中经常用到这些知识 还是过一遍比较放心 上一篇博客中我们讨论了http报文首部 其划分为请求头和响应头 请求头主要由请求行 请求字段 通用字段 实体字段组成 那么响应头也由响应行 响应
  • go hash中的读写操作

    在 Go 语言中 我们可以使用 for 循环来遍历哈希表 hash 中的键值对 针对不同的操作进行读写操作 示例代码如下 创建一个映射类型的哈希表 hash map string int apple 2 banana 3 orange 4
  • uni-app实现PDA采集器扫码

    uni app实现PDA采集器扫码 一 开发建议 1 建议使用nvue开发 体检会非常好 使用uni preloadPage url pages index 预加载页面 页面的流畅程度会提高非常多 单独vue的写法 打包成安卓体验很不好 模
  • IntelliJ IDEA 编译程序出现非法字符的解决方法

    最近编码完成后总是报非法字符 项目启动不起来 网上有很多说是File gt Setting gt File Encoding 将IDE Encoding和Project Encoding 都设置为UTF 8就行 可是我试了不行 后来看到另外
  • 不会把if-else重构成高质量代码的程序员,不是个优秀的程序员

    为什么我们写的代码都是 if else 程序员想必都经历过这样的场景 刚开始自己写的代码很简洁 逻辑清晰 函数精简 没有一个 if else 可随着代码逻辑不断完善和业务的瞬息万变 比如需要对入参进行类型和值进行判断 这里要判断下对象是否为
  • 3、backbone中的model实例

    关于backbone 最基础的一个东西就是model 这个东西就像是后端开发中的数据库映射那个model一样 也是数据对象的模型 并且应该是和后端的model有相同的属性 仅是需要通过前端来操作的属性 下面就从实例来一步一步的带大家来了解b
  • 文心一言、讯飞星火与GPT-4/3.5在回答中文历史问题的表现

    最近 随着备受关注的文心一言正式免费向全社会开放 再次引起了社会层面对国产大模型的兴趣 以文心一言为代表的国产大模型性能究竟如何 如果将它们相互比较 并且和GPT系列模型等国际前沿水平的LLM进行比较 会得到什么样的结果呢 笔者对此非常好奇
  • Python所有方向的学习路线图

    在放这个路线图之前 我先做一个简单的介绍 避免新手小白有什么不理解的 这个学习路线上面写的是某个方向建议学习和掌握的知识带你 这样学习下来之后会更加容易掌握 知识体系会比较全面 比自己单纯的自学效果好很多 不至于看到什么就学什么 容易走弯路
  • 二,ES6中新增const关键字的使用方法

    之前用var声明变量 变量想怎么改就怎么改 这里const关键字也是声明变量的 不过声明的是常量 常量就是固定的一个值 不能改变 例如 const name 唐僧 name 老沙 报错 因为它要更改常量name 只在块级作用于起作用 和le
  • Windows10 java环境变量的配置详细教程(Windows10 和Windows11)

    java环境变量的配置详细教程 1 首先要区分一下Windows10 2021年之前的版本和Windows10 2021年之后的版本 Windows10 2021年之后的版本和Windows11 系统在配置java上差不多 故不作区分 1
  • Intellij IDEA svn的使用记录

    这里的忽略一直灰色的 可以进入 这里的版本控制里进行忽略选择 或者 这里进行添加 这里有三个选择 按照顺序 1 忽略指定的文件 2 忽略文件夹下所有文件 3 忽略符合匹配规则的文件 到Commit Changes 这里有几个选项需要了解的
  • Vue实例挂载的过程

    一 思考与分析 我们都听过知其然知其所以然这句话 那么不知道是否思考过new Vue 这个过程中究竟做了些什么 过程中是如何完成数据的绑定 又是如何将数据渲染到视图的等等 首先找到vue的构造函数 源码位置 src core instanc