前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Vue2 运行原理学习(一)初始化

Vue2 运行原理学习(一)初始化

原创
作者头像
测不准
发布2021-08-17 17:55:19
3420
发布2021-08-17 17:55:19
举报
文章被收录于专栏:与前端沾边

本次主要跟大家分享学习下 vue2 的部分知识。网上大部分知识讲解都是抽离的形式,对应哪个函数直接拿出来讲解,但是对于新手或者不了解内在原理的,逻辑图谱不是很清晰,不成体系。很容易忘记,所以本次系列计划从零还是手写,实现部分功能。

目前大部分公司还是使用的 2 版本,vue3.2 发布后,还不跟 3.0 兼容。求职应聘也主要是 2.0 为主,所以本次主要学习下 vue2 中的一些功能(后面有机会在整理下 vue3 的实现),例如:响应式实现、模板编译解析、依赖收集等功能的实现,尽量保证大家跟着写可以实现自己的版本,尽量把要点写清,有不对的欢迎指正,没懂的欢迎交流。面后会发布到 github,交流学习。

项目初始化

我们选用 rollup 进行项目启动,这里为什么不用 webpack 呢?

rollup 属于库开发用的,打包体积小,专注打包 jswebpack 当然也是可以的,但是它更适于应用类的,项目类的打包,需要处理 imgcssfont 等,而且打包体积也比较大。

  • npm init -y 初始化项目
  • 安装 rollup
    • npm i rollup rollup-plugin-babel @babel/core @babel/preset-env
    • rollup 打包使用的
    • rollup-plugin-babel 处理 rollup 和 babel 的,打包有的语法需要 babel 转义
    • @babel/core 核心模块,处理逻辑
    • @babel/preset-env 高级语法转换低级语法
  • 配置 rollup.config.js

我们运行按照自己配置的形式执行

代码语言:txt
复制
import babel from 'rollup-plugin-babel'

export default {
  // 入口文件
  input: './src/index.js',
  // 输出配置
  output: {
    // 输出的文件位置
    file: 'dist/vue.js',
    format: 'umd', // 打包规范,通用打包格式,包含 commonjs ,给node用的;amd 基本没用过;global 形式,声明变量到 window 上
    name: 'Vue', // window.Vue
    sourcemap: true
  },
  plugins: [
    babel({
      exclude: 'node_modules/**' // 打包排除第三方包
    })
  ]
}
  • 配置执行命令
代码语言:txt
复制
'start': 'rollup -cw' // w 监听文件改变, c 使用配置文件

写几行测试代码,执行命令 npm run start,我们测试一下

代码语言:txt
复制
/// src/index.js
let a = 123

function Vue(options) {
}

console.log(a, Vue)

export default Vue // 一定要导出

我们写个 html 文件,引入打包后的 js

代码语言:txt
复制
/// example/example.html
....
<script src="../dist/vue.js"></script>
......
console.log(Vue)  // 可以在浏览器中查看

小节:到这里我们的项目就搭建完成了,主要是配置 rollup 打包,能够在 html 我呢间中访问

Vue 初始化

  1. 注册全局函数
代码语言:txt
复制
// src/index.js

/**
  当我们 new Vue 时,其实就是初始化我们写的选项,data、props 等
*/

function Vue() {
  // 具体的初始化内容
  this._init()
}

export default Vue
这里我们为什么使用的函数,而不是 类?

因为这里方便我们在原型链上拓展,调用直接 this.xxx,如果写成类了,更多的是使用继承,需要维护比不方便;虽然类本质也是函数,但是很少见用了类再写个原型的,不规范;我们平时拓展也是 Vue.prototype.xxx = xxx,在全局都可以使用。

  1. 定义 _init

因为我们使用函数定义,所以调用原型方法都可以使用 this.xx,但是我们不好每个文件都引入 Vue 函数,去在原型挂载。所以这里我们导出初始化函数给 index.js,把 Vue 传进去,方便维护

代码语言:txt
复制
//// src/init.js
// 这样我们只需要在 src/index.js 中维护 Vue,
export function initMixin(Vue) {
  Vue.prototype._init = function(options) { // new Vue 参数
    console.log(options)
  }
}


//// example.html 文件中测试
const vm = new Vue({
  data: {
    a: 1,
    b: 2
  }
})
  1. 初始化选项

我们在 init 中主要做两件事,一个是初始化数据,datapropsmethods 等,一个是挂载到 el

代码语言:txt
复制
//// _init 函数

// 使用 vm ,避免都叫 this,多了分不清
const vm = this
// 初始化属性
initState(vm)

if(options.el) {
  // 有 el 执行挂载
  vm.$mount(options.el)
}
代码语言:txt
复制
//// src/state.js
export function initState(vm) {
  const options = vm.$options
  
  if (options.data) {
    initData(vm)
  }
  
  if (options.computed) {
    initComputed(vm)
  }
  
  if (options.watch) {
    initWatch(vm)
  }
}

function initData(vm) {}
// 后面去实现
function initComputed(vm) {}
function initWatch(vm) {}
代码语言:txt
复制
//// init.js
Vue.prototype.$mount = function (el) {
  el = document.querySelector(el)
  const vm = this
  vm.$el = el
  // 后面添加模板解析
}

目前得到的 vm 结构

  1. 代理 vm 数据指向 data

我们平时定义数据都是 this.xxx,访问的 data 中的值,实际上使用的代理

代码语言:txt
复制
function initData(vm) {
  let data = vm.$options.data // 用户传的 data
  
  // 如果传的是 函数,执行 _data 标识内部属性
  data = vm._data = typeof data === 'function' ? data.call(vm) : data
  
  for(let key in data) {
    proxy(vm, '_data', key)
  }
  
  // 下一篇实现数据响应式**
  observe(data)
}

function  proxy(target, key, property) {
  Object.defineProperty(target, property, {
    get() {
      return target[key][property]
    },
    set(v) {
      target[key][property] = v
    }
  })
}
为什么组件中 data 需要是函数?

其实如果保证组件使用一次,可以不使用函数。但是如果定义的组件被使用多次,如果 data 是对象的话,引用类型,就会相互影响。如果是函数的话,每次执行返回新的对象,不会冲突

本篇介绍了项目搭建和数据的初始化,我们下一篇去实现 vue2 响应式数据的实现,如何递归,怎么处理数组的。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 项目初始化
  • Vue 初始化
    • 这里我们为什么使用的函数,而不是 类?
      • 为什么组件中 data 需要是函数?
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档