Vue响应式原理--初始化过程

目标

Vue.js静态成员和实例成员的初始化过程(vue.set、vue.get、vue.extend等)
首次渲染的过程
数据响应式的原理

准备
源码地址: https://github.com/vuejs/vue
结构

 dist:存放打包后文件
 examples:存放示例文件,例如表格的使用等
 src:compile/模板编译
      core:vue核心 
           components:存放组件,例如keep-live
           global-api:存放use、mixin、extends等
           instance:存放vue实例,vue生命周期,初始化等
           observer:实现响应式机制
           util:存放公共成员位置
           vdom:vue虚拟DOM,vue增强了,可以存放组件相关
  platforms:存放平台相关内容,例如web,weex
  sfc:单文件组件,把组件转换成js对象

了解Flow
vue源码使用了flow声明类型,并且每个文件开头都有flow标记

官网:https://flow.org/
JS的静态类型检查器
Flow的静态类型检查错误是通过静态类型腿短实现的
· 文件开头通过 // @flow 或者 /@flow/ 声明

调试

打包工具Rollup
Vue.js源码打包使用的是Rollup,比webpack轻量
webpack将所有文件当成模块,rollup只处理js文件,更适合vue这种类库的使用
Rollup打包不会生成冗余代码

安装

npm install

设置sourcemap
 package.json中的dev添加参数 --sourcemap
"dev": "rollup -w -c scripts/config.js --sourcemap --environment TARGET:web-full-dev",

执行dev
npm run dev  执行打包,使用rollup,-w 参数是监听文件的变化,文件变化自动重新打包

Vue的不同构建版本

使用 npm run build  重新打包所有文件,可以在dist下查看
完整版:同时包含编译器和运行时的版本
编译器:用来将模板字符串编译成JS渲染函数的代码体积大,效率低
运行时:创建Vue实例,渲染Vnode等代码,体积小,效率高,基本就是编译的代码
UMD: 通用的模块版本,支持多种模块方式。Vue默认文件是运行时 + 编译器的UMD版本
CommonJS:用来配合老的打包工具Browserify 或 webpack1.0
ES Module:2.6之后提供两个ES Module构建文件,提供现代打包提供版本
      ESM格式设计为可以被静态分析,所以攻击可以利用这点来进行“tree-shaking”,排除无用代码
Vue脚手架对webpack进行深度封装,可以通过命令行工具查看vue的配置
vue inspect
vue inspect > output.js  将vue配置输出到output.js中 
查看resolve可以看到vue运行时使用的是vue.runtaime.esm.js
是运行时版本,且使用esm的方式
开发项目时会有很多单文件组件,浏览器是不支持这种方式,
vue会将单文件转换为JS对象,转换过程中会将模板转换成render函数,所以运行时不需要编译器

入口文件

查看dist/vue.js的构建过程
先执行构建 npm run dev

"dev": "rollup -w -c scripts/config.js --sourcemap --environment TARGET:web-full-dev",

script/config.js的执行过程
作用:生成rollup构建的配置文件
使用环境变量TARGET = web-full-dev
找到

'web-full-dev': {
   
    entry: resolve('web/entry-runtime-with-compiler.js'), //入口
    dest: resolve('dist/vue.js'),  //生成文件
    format: 'umd',   //模块化方式
    env: 'development',  //模式,开发模式
    alias: {
    he: './entity-decoder' }, 
    banner // 生成每一个文件头的注释内容
  },

src/platform/web/entry-runtime-with-compiler.js

 // 如果同时设置template 和 render此时会渲染什么?
 // 如果有render。不会执行template,如果有render,直接调用组件的mount渲染render函数
 const vm = new Vue({
   
    el: "#app",
    template:"<h1>hello tempalte</h1>",
    render(h){
   
        return h("h1","hello Render")
    }
 })

vue 执行过程 vue-》init -》mount
Vue.prototype.$mount 执行到mount

el不能是body 或者 html
如果没有render,将template转换成render函数
如果有render函数,直接调用mount挂载DOM

const idToTemplate = cached(id => {
   
  const el = query(id)
  return el && el.innerHTML
})

// 保留 Vue 实例的$mount 方法
const mount = Vue.prototype.$mount
Vue.prototype.$mount = function (
  el?: string | Element,
  // 非ssr情况下为false,ssr时候为true
  hydrating?: boolean
): Component {
   
  // 获取 el 对象
  el = el && query(el)

  /* istanbul ignore if */
  // el 不能是 body 或者html
  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
  // 把 template/el 转换成render函数
  if (!options.render) {
   
    let template = options.template
    // 如果模板存在
    if (template) {
   
      if (typeof template === 'string') {
   
        // 如果模板是 id 选择器
        if (template.charAt(0) === '#') {
   
          // 获取对应节点的 innerHTML
          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')
      }

      const {
    render, staticRenderFns } = compileToFunctions(template, {
   
        outputSourceRange: process.env.NODE_ENV !== 'production',
        shouldDecodeNewlines,
        shouldDecodeNewlinesForHref,
        delimiters: options.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值