Skip to content

Latest commit

 

History

History
219 lines (118 loc) · 8.51 KB

笔记.md

File metadata and controls

219 lines (118 loc) · 8.51 KB

rollup rollup-plugin-babel // rollup和babel做一个关联 @babel/core 核心模块 @babel/preset-env 预设,方便开发人员使用 rollup-plugin-serve 启动本地服务

rollup.config.js 这个文件是rollup的配置文件

主要的配置如下:

import babel from 'rollup-plugin-babel';
import serve from 'rollup-plugin-serve';

export default {
  input: './src/index.js', // 入口配置, 以这个入口打包。
  output: {
    format: 'umd', // 模块化的类型 这里使用umd的规范 这个规范的
    name: 'Vue', // 全局变量的名字
    file: 'dist/umd/vue.js',
    sourcemap: true // 源码映射
  },
  plugins: [
    babel({
      exclude: 'node_module/**' // 对于node_module 中的文件不做转义
    }),
    serve({
      open: true, // 是否打开浏览器
      port: 9000, // 端口
      contentBase: '', // 空字符串表示当前目录
      openPage: '/index.html' // 打开的页面是是
    })
  ]
}

1、vue组件中有很多状态,每一次通过new Vue 都是创建一个vue实例,也可以称之为创建了一个组件。vue中有 data props watch computed 初始化方法暂且叫它init, 这个init方法是一个公共方法,可以单独抽离出来一个文件。 因此创建一个单独的js文件存放init方法。

2、初始化数据和状态 创建 initState

3、vue中对于对象有数据劫持方案 使用的是object.definePrperty。对于数组是单独处理的。

4、vue2中在初始化阶段,如果数据层级很深, 会不断的进行递归操作,执行响应式的逻辑。因此初始化的时候效率并不是很高。

5、用户在设置值的时候有可能 设置一个对象,当我们再次对这个数据进行访问的时候,也想要这个数据进行响应式处理。

6、我们开发功能的时候很少有对数组索引进行操作的,为了性能考虑不对数组进行拦截,而是重新方法。

7、渲染操作分为两种情况,第一种情况是没有写template,这个时候 就会以 index.html 中的div id=app 为根节点 去进行插入dom操作, 如果写了template就会将template替换掉根标签的内容。这是两种方案。

8、用官方的话说:

  1. 默认会先寻找 render 方法
  2. 默认没有传入render 方法会查找 template 3)如果template也没有,找到当前el 指定的元素中的内容进行渲染。

从上面这条笔记可以看出,render的优先级更高一些。如果写了render el的中的模板 就会被忽略。

9、ast语法解析树, 将字符串解析成 render 函数

10、我们在有些场景中可以看到 $mount('#app'); 这个和 在 new Vue 中传入 #el 是等价的。

11、compiler 这个模块存放的是编译相关的代码

12、虚拟dom是用对象来描述DOM,ast语法树是可以用来描述语言本身

const a = 1;
// 上面这个变量生声明的代码 如果使用ast来描述
{
  identifier: const,
  name: a,
  value: 1
}

且ast的语法树 是根据语法生成的固定的逻辑, 对于虚拟dom来说,里面可以添加自定义的属性。

13、模板解析的精髓其实是利用正则进行匹配,匹配一点就将这个字符串删除,匹配一点就将这个字符串删除。

14、对于标签来,一定是以尖角号开头,所以在源码中使用了indexOf 判断标识。

15、解析标签的时候, 很大程度上是依赖于正则表达式的,在判断标签的合法性的时候用到了栈这种数据结构,判断的是标签是否是成对存在的。

对于一个对象类型来说,在做响应式操作的时候,使用object.keys 遍历的是已经存在的属性, 对于新增的属性 �并不会去做响应式拦截 比如 data = { a: { a: 1 } } 这里对a做了响应式处理,然后假设我做这样的一个操作 vm.a.b = 1; 响应式是检测不到的。

vue中为了提高性能,没有对数组的每一项做响应式操作,而是通过对 数组的变异方法最拦截,做了切面编程的处理。

如果是数组,做了一个这样的操作:

data.proto = arrayMethod 而这个arrayMethod 指向原生数组的原型链。 对于重写的数组来说, 如果我们的枚举中不包含 还是走老的方法。

new Vue的 时候回调用init 方法 这个方法的作用就是将用户传入的options配置选项传递给 vm 实例。

vue中还有一些静态方法 vue.component vue.directive vue.extend vue.mixin ... 这些全局的方法可以创建一个全局的文件夹 global-api

我们定义的全局的方法 配置 最终都会合并到 vue.options里面。合并选项。这里需要做两次合并

当前组件中也可以有mixin 属性,这个属性只会作用于当前组件。

vue中的生命周期函数其实可以看成是回调函数,现在当前的vue实例中注册好了, 然后等到一个合适的时机,将这个函数 拿出来调用。

如果我们同时new两个vue实例, 这两个实例里面有相同的内容,我们想将这个功能抽象出啦,这个时候可以使用 vue.mixin 混入的方式进行处理,在执行的时候,先执行全局的,再执行自己的。内部的原理是会将生命周期组成一个数组。然后依次执行。

对于合并生命周期来说,父一直是options, 子是mixin, 合并的时候 第一次 options 是一个空的对象 {} 然后将第一个 mixin 放进去 然后父中存放了 第一个mixin 再次合并的时候 这个就是父亲了 准备合并第二个mixin。

用户在new Vue的时候里面也会传递 created 这种钩子函数,那怎么和全局的options 进行合并呢?

全局组件和局部组件之间的关系 这两者有什么不同呢? 这是一道面试题目。

vue的更新策略是以组件为单位的, 给每个组件都增加了一个watcher 属性变化变化后调用这个watcher,这个watcher被称之为渲染 watcher。_updata 本身就是一个方法。 本身也是一个发布订阅模式,先订阅更新,然后等触发数据的时候,执行这个操作。

渲染watcher这部分比较复杂,是vue中比较难懂的部分,因为会经常被调用,所以这块封装成一个类。 这个watcher 放在响应式数据里面

将这个watcher封装好了之后, 需要做的就是将属性和 watcher 做一个关联,也就是说,在属性变化之后,能够触发watcher的get方法 做页面的重新渲染。

事实上,就是将属性和watcher 绑定在一起。

那应该如何做才能做到这种形式的更新呢? 这里我们还需要借助一个类,就是 dep

一个属性拥有一个dep, dep是用来收集watcher的, dep可以存放多个watcher, 一个watcher可以对应多个dep

在什么时候增加这个dep呢?是在属性响应式的时候做的dep操作。每一个属性都有一个dep 参考defineReactive这个方法

当我们在页面中取值的时候 会调用get方法, 渲染的时候肯定会触发update方法,将update方法包装到了渲染watcher里面,说明这个值被用作渲染了。这个时候将这个watcher和这个属性对应起来,上面已经说过了,每一个属性都有一个dep,

当我们new Watcher 的时候: 前提:在数据劫持的时候,也就是调用defineProperty 时候,给每一个属性定义了一个dep。 1、是想把这个渲染watcher放到Dep.target属性上面 2、开始渲染 取值的时候会调用get方法, 让这个属性的dep 存储当前的 watcher 3、页面上所需要的属性都会将这个watcher存在自己的dep中。 4、等会属性更新了,就重新调用渲染逻辑,通知自己存储的watcher来更新。

vue中修改数组的索引对应的值是不会触发更新操作的。换一种说法,通过索引更新数组和长度更新是无效的。

数组的更新操作 1、当我们在页面的模板中取值的时候 {{arr}} 会触发get方法。 2、我会让这个数组记录它所依赖的关系。 我希望让这个数组记住这个渲染watcher。 3、等我更新数组的时候,也就是 调用push、shift 方法的时候,找到数组对应的watcher来更新。 4、给所有对象类型 无论是对象 还是数组 都增加一个dep 属性。

vue异步更新,更新数据之后,不能立刻拿到最新的节点。

每一次更新的时候走的其实是 watcher的update方法。

computed:{

}

会根据依赖的数据进行更新, 内部使用了defineProperty 内部有一个变量 dirty computed 有两种写法 一种是函数,一种是对象。 可以认为 computed 也是一个watcher firstname 是一个watcher lastname 也是一个watcher。