Подробное объяснение Vue (повторное изучение интерфейса vue, глава 1)

Vue.js

1 Что такое адаптивный Vue?

После изменения данных страница будет перерисована, что соответствует Vue.

响应式图例

Отзывчивая легенда

2 Что нам нужно сделать, чтобы завершить процесс

  • Обнаружение изменений в данных
  • На какие данные опирается представление коллекции
  • При изменении данных автоматически «уведомлять» ту часть представления, которую необходимо обновить, и обновлять ее.

«Они соответствуют профессиональным идиомам:»

  • Перехват данных/брокерство данных
  • Коллекция зависимостей
  • модель публикации-подписки

3. Что такое модель публикации-подписки

  • Шаблон наблюдателяЭто запланировано определенной целью.Например, когда событие срабатывает, Dep вызовет метод наблюдателя, поэтому существует зависимость между подписчиком и издателем режима наблюдателя.
  • опубликовать/подписать модельВызывается единым диспетчерским центром, поэтому издателю и подписчику не нужно знать о существовании друг друга.

image.png

Vue Reactive использует модель публикации-подписки.

Например:

image.png

4. Как обнаружить изменения данных

Есть два способа обнаружить изменения:
использоватьObject.definePropertyи ES6Proxy, что является перехватом данных или проксированием данных.

3.1 Реализация Object.defineProperty

Vue, задав свойства объектаsetter/getterспособ отслеживания изменений данных,getterсделать сбор зависимостей, и каждыйsetterметод представляет собой观察者,существует数据变更уведомить, когда订阅者Обновите вид.

код показывает, как показано ниже:

function render () {
//set的时候会走这里,重新渲染
  console.log('模拟视图渲染')
}
let data = {
  name: '浪里行舟',
  location: { x: 100, y: 100 }
}
// 请看下一节
observe(data)

определить основные функции

function observe (obj) { // 我们来用它使对象变成可观察的
  /**
      判断类型,obj可能是vue中的data对象,也可以是data中的某个属性值,
      例如:data:{ name: '浪里行舟', location:{  x: 100, y: 100 } },这里的值可能是整个data,
      也可能是location的值,当location值也是对象的时候就需要再次监听location值对象。
      而属性name和location在监听data的时候就会监听这2个属性。
  */
  if (!obj || typeof obj !== 'object') {
    return
  }
  Object.keys(obj).forEach(key => {
    defineReactive(obj, key, obj[key])
  })
  
  //监听对象的每个属性
  function defineReactive (obj, key, value) {
    // 递归子属性
    observe(value)
    Object.defineProperty(obj, key, {
      enumerable: true, //可枚举(可以遍历)
      configurable: true, //可配置(比如可以删除)
      get: function reactiveGetter () {
        console.log('get', value) // 监听
        return value
      },
      set: function reactiveSetter (newVal) {
        observe(newVal) //如果赋值是一个对象,也要递归子属性
        //如果有新值
        if (newVal !== value) {
          console.log('set', newVal) // 监听
          render() //执行渲染逻辑
          value = newVal
        }
      }
    })
  }
}

Изменение свойств данных вызовет set, затем получение свойств данных вызовет get

data.location = {
  x: 1000,
  y: 1000
}         //打印=》     set {x: 1000,y: 1000} 染
data.name //打印=》   get 浪里行舟

Основная функция приведенного выше кода:

Функция наблюдения проходит вobj(需要被追踪变化的对象), обходя все атрибуты, каждый атрибут объекта проходит черезdefineReactiveобработка, добавление к каждому атрибутуsetа такжеgetметод, чтобы добиться обнаружения изменений объекта. Стоит отметить, что наблюдать делает рекурсивные вызовы.

Итак, как мы обнаруживаем данные в данных в Vue, на самом деле это очень просто:

class Vue {
    /* Vue构造类 */
    constructor(options) {
        this._data = options.data;
        observer(this._data);
    }
}

Таким образом, пока мы создаем новый объект Vue, данные в данных будут отслеживаться и изменяться.

Но мы обнаружили проблему, приведенный выше код не может определить свойство объекта添加或删除(Например, data.location.a=1, добавьте свойство a).
Это связано с тем, что Vue использует Object.defineProperty для преобразования ключа объекта в форму геттера/сеттера для отслеживания изменений, но геттер/сеттер может отслеживать только одни данные.是否被修改, невозможно отследить新增属性和删除Атрибуты. Если нужно удалить атрибут, мы можем использоватьvm.$deleteЕсли он реализован, что мне делать, если это новый атрибут?

  1. Реактивные свойства можно добавлять к вложенным объектам с помощью метода Vue.set(location, a, 1);
  2. Вы также можете переназначить этот объект, например data.location = {...data.location,a:1}

Object.defineProperty не может отслеживать изменения массива, и метод массива необходимо переписать

4 Наблюдатель Наблюдатель

4.1 Зачем вводить Watcher

Определите класс Watcher в Vue для представления观察订阅依赖. Что касается введения Watcher, «углубленный поверхностный Vue.js» дает хорошее объяснение:

когда属性После изменений мы хотим уведомить用到数据Есть много мест, где эти данные используются, и типы разные.Это может быть шаблон или часы, написанные пользователем.На данный момент необходимо абстрагировать能集中处理Класс этих ситуаций. Затем мы собираем только экземпляры этого инкапсулированного класса на этапе сбора зависимостей и уведомляем только один из них, а затем он отвечает за уведомление других мест.

«Целью сбора зависимостей является:»Сохраните объект Watcher наблюдателя в подпрограммах подписчика Dep в текущем закрытии. Сформируйте такую ​​связь, как показано ниже (рисунок см. в разделе «Анализ внутреннего рабочего механизма Vue.js»).

5.2 Простая реализация Watcher

class Watcher {
  constructor(obj, key, cb) {
    // 将 Dep.target 指向自己
    // 然后触发属性的 getter 添加监听
    // 最后将 Dep.target 置空
    Dep.target = this
    this.cb = cb
    this.obj = obj
    this.key = key
    this.value = obj[key]
    Dep.target = null
  }
  update() {
    // 获得新值
    this.value = this.obj[this.key]
   // 我们定义一个 cb 函数,这个函数用来模拟视图更新,调用它即代表更新视图
    this.cb(this.value)
  }
}

Выше приведена простая реализация Watcher.При выполнении конструктора Dep.target указывает на себя, так что соответствующий Watcher собирается, а соответствующий Watcher извлекается при отправке обновления, а затем выполняется функция обновления.

«Суть зависимости:»
Так называемый依赖, по фактуWatcher.
Что касается того, как собирать зависимости, то это можно резюмировать одним предложением:
существуетgetterСобираем зависимости в (собираем Watch как в Dep), вsetterтриггерные зависимости. Сначала соберите зависимости, то есть где используются данные收集起来, затем подождите属性发生变化Когда, поставить ранее собранные зависимости循环触发Один проход сделает.

В частности, когда внешний мир проходит мимо Наблюдателя读取数据, это вызоветgetterтаким образом будетWatcher添加到依赖中, который Watcher запускает геттер, который Watcher собирается в Dep. Когда данные изменяются, они циклически зависят от списка и один раз уведомляют всех Наблюдателей.

Наконец, мы изменили функцию defineReactive, добавив код, связанный со сбором зависимостей и отправкой обновлений в пользовательскую функцию, а также реализовали простой ответ данных:

function observe (obj) {
  // 判断类型
  if (!obj || typeof obj !== 'object') {
    return
  }
  Object.keys(obj).forEach(key => {
    defineReactive(obj, key, obj[key])
  })
  function defineReactive (obj, key, value) {
    observe(value)  // 递归子属性
    let dp = new Dep() //新增
    Object.defineProperty(obj, key, {
      enumerable: true, //可枚举(可以遍历)
      configurable: true, //可配置(比如可以删除)
      get: function reactiveGetter () {
        console.log('get', value) // 监听
     // 将 Watcher 添加到订阅
     // target挂载发生在new Watch的时候
       if (Dep.target) {
         // 新增Watch到dep的subs中,就是说new了哪个Watch就要把哪个Watch收集进来
         dp.addSub(Dep.target) 
       }
        return value
      },
      set: function reactiveSetter (newVal) {
        // 如果赋值是一个对象,也要递归子属性
        // 例如上面的location是一个对象,那么这个对象是要继续observe的
        observe(newVal) 
        if (newVal !== value) {
          console.log('set', newVal) // 监听
          render()
          value = newVal
         // 执行 watcher 的 update 方法
          dp.notify() //新增
        }
      }
    })
  }
}

class Vue {
    constructor(options) {
        this._data = options.data;
        observer(this._data);
        /* 新建一个Watcher观察者对象,这时候Dep.target会指向这个Watcher对象 */
        new Watcher();
        console.log('模拟视图渲染');
    }
}

Когда функция рендеринга визуализируется,读取Значение желаемого объекта, который вызываетreactiveGetterФункция собирает текущий объект Watcher (хранящийся в Dep.target) в класс Dep. после этого, если修改Значение объекта сработаетreactiveSetterметод, который уведомляет класс Dep о вызовеnotifyдля запуска всех объектов Watcherupdateспособ обновления соответствующего представления.

"Полная блок-схема:"

1460000013338807.webp

  • После new Vue() Vue вызовет функцию _init для инициализации, которая является процессом инициализации.В этом процессе данные преобразуются в форму геттера/сеттера через Observer для отслеживания изменений в данных.Когда считывается установленный объект Функция получения выполняется, когда ей присваивается значение, а функция установки выполняется, когда ей присваивается значение.
  • Когда внешний мир считывает данные через Watcher, геттер срабатывает, чтобы добавить Watcher в зависимость.
  • Когда значение объекта будет изменено, будет запущен соответствующий установщик, и установщик уведомит каждого наблюдателя в ранее собранном Dep, сообщив им, что их значение изменилось и представление необходимо повторно отобразить. В этот момент эти наблюдатели начнут вызывать update для обновления представления.

5. Соберите зависимости

5.1 Зачем собирать зависимости

Цель наблюдения за данными — уведомить те места, которые использовали данные, об изменении их свойств. Например, в примере данные о местоположении используются в шаблоне, и при их изменении отправляется уведомление в место, где они используются.

let globalData = {
    text: '浪里行舟'
};
let test1 = new Vue({
    template:
        `<div>
            <span>{{text}}</span> 
        <div>`,
    data: globalData
});
let test2 = new Vue({
    template:
        `<div>
            <span>{{text}}</span> 
        <div>`,
    data: globalData
});

Если мы выполним следующий оператор:

globalData.text = '前端工匠';

В этот момент мы должны сообщитьtest1 так же как test2Эти два экземпляра Vue выполняют представление更新, мы только проходим收集依赖чтобы знать, где на мои данные полагаются, и когда данные обновляются派发更新. Как реализован сбор зависимостей? Основная идея — «модель публикации и подписки на события». Далее мы сначала вводим две важные роли:订阅者 Depа также观察者 Watcher, а затем объясните, как реализована коллекция зависимостей.

6 Отношения между Депом и Наблюдателем

Наблюдатель отвечает за преобразование данных в форму получения/установки; Dep отвечает за управление списком зависимостей данных; это модель публикации-подписки, восходящий поток подключается к наблюдателю, а нисходящий поток подключается к наблюдателю. фактическая зависимость от данных, отвечающая за пересылку изменений данных во внешний мир (рендеринг, обратный вызов); во-первых, передать данные в Observer и преобразовать их в форму геттера/сеттера; когда экземпляр Watcher читает данные, он запускает геттер и быть собранными в хранилище Dep; когда данные будут обновлены, сеттер будет запущен, чтобы уведомить все данные в хранилище Dep. Обновление экземпляра Watcher, экземпляр Watcher отвечает за уведомление внешнего мира

  • Dep отвечает за сбор всех соответствующих наблюдателей-подписчиков.Неважно, кто и сколько наблюдателей.Ему нужно только собрать наблюдателей, которые подписываются на его новости в соответствии с расчетом, указанным таргетом, а затем опубликовать сообщение и уведомление.
  • Наблюдатель отвечает за подписку на Dep и позволяет Dep собирать его при подписке.При получении сообщения, опубликованного Dep, просто выполните его операцию обновления.

Операция Vue заключается в присоединенииопубликовать подписатьсярежим, комбинированныйObject.definePropertyВозможность перехвата реализует двустороннюю привязку с высокой доступностью.

7. Отдел по подписке

image.png

«Зачем представлять Депа:»
Сбор зависимостей требует поиска места для хранения зависимостей для зависимостей, для этого мы создали Dep, который используется для收集依赖,删除依赖а также向依赖发送новости и т.д.
Итак, мы сначала реализуем订阅者 Dep 类, для解耦属性Сбор зависимостей и операции обновления отправки,"Быть конкретной": Его основная функция заключается в использовании存放 Watcher 观察者объект. Мы можем понимать Наблюдателя как中介характер,数据发生变化уведомляет, затем уведомляет其他地方.

"Простая реализация Dep:"

class Dep {
    constructor () {
        /* 用来存放Watcher对象的数组 */
        this.subs = [];
    }
    /* 在subs中添加一个Watcher对象 */
    addSub (sub) {
        this.subs.push(sub);
    }
    /* 通知所有Watcher对象更新视图 */
    notify () {
        this.subs.forEach((sub) => {
            sub.update();
        })
    }
}

Приведенный выше код в основном делает две вещи:

  • Использование метода addSub можно использовать в текущемDepдобавить один к объектуWatcherработа по подписке;
  • Используйте метод notify для уведомления о текущемDepобъектыsubsвсе вWatcherОбъект инициирует операцию обновления. так что когда нужно依赖收集вызовите addSub, когда派发更新При звонке уведомлять.

Другими словами, все наблюдения в конечном итоге будут храниться в подпрограммах Dep, а процесс обновления представления заключается в том, что Dep запускает каждое наблюдение в подпрограммах и выполняет логику обновления Watch.Операция Dep не может обойти Watch. , Watch играет посредническую роль.

Вызов также прост:

let dp = new Dep()
dp.addSub(() => {//依赖收集的时候
    console.log('emit here')
})
dp.notify()//派发更新的时候

8. Осознайте

8.1 Первая реализация захвата данных нового Vue

//遍历data,进行数据劫持
function Observer(data) {
  Object.keys(data).forEach((item) => {
    defineReactive(data, item, data[item])
  })
}

function defineReactive(data, key, val) {
  const self = this
  Object.defineProperty(data, key, {
    enumerable: true,
    configurable: true,
    get() {
      return val
    },
    set(newVal) {
      if (newVal === val) {
        return
      }
      val = newVal
    },
  })
}

class Vue {
  constructor(options) {
    if (options && typeof options.data == 'function') {
    //模拟vue源码,挂载data到Vue的_data上
      this._data = options.data.apply(this)
    }
    // 劫持传入的data项
    new Observer(this._data)
  }
}

const vue = new Vue({
  data() {
    return {
      text: 'hello',
    }
  },
})
console.log(vue)//data中属性已经被劫持了

8.2 После захвата vue.mount() связывает Watch

//遍历data,进行数据拦截
function Observer(data) {
  Object.keys(data).forEach((item) => {
    defineReactive(data, item, data[item])
  })
}

function defineReactive(data, key, val) {
  const self = this
  Object.defineProperty(data, key, {
    enumerable: true,
    // 设置当前描述属性可被修改
    configurable: true,
    get() {
      return val
    },
    set(newVal) {
      if (newVal === val) {
        return
      }
      val = newVal
    },
  })
}

class Watcher {
  //----------4
  constructor(vm, fn) {
    this.vm = vm //----------5
    fn() //----------6
  }
}

class Vue {
  constructor(options) {
    if (options && typeof options.data == 'function') {
      this._data = options.data.apply(this)
    }
    new Observer(this._data)
  }
  mount = () => {
    //--------------2
    new Watcher(this, this.render) //--------------3
  }
  render = () => {
    // 省略一系列的渲染逻辑
    return this._data.text //---------7
  }
}
const vue = new Vue({
  data() {
    return {
      text: 'hello',
    }
  },
})
vue.mount() //------------ 1


Функция функции монтирования Vue состоит в том, чтобы перейти к读取data中的属性,渲染на страницу. Ключевым шагом здесь является读数据,

Затем чтение данных, в конечном счете, приведет к вводу метода получения захвата данных. В это время мы можем создать Watch (наблюдателя) в качестве посредника и позволить ему войти.

Роль mount заключается в рендеринге.Естественно, функция рендеринга должна быть передана при конструировании Watch.

Возвращаясь к тому, что мы сказали ранее, Watch выступает в роли посредника, так кто же это и чей предыдущий посредник? По сути, это посредник между Observer и Dep, о котором мы поговорим позже.

Поскольку это посредник, ему необходимо получить данные обеих сторон. И поскольку Observer должен наблюдать за данными, здесь нам нужно смонтировать весь конструктор Vue для самого Watch.

Упорядочить процесс:

воплощать в жизньvue.mount()Для рендеринга страницы вам нужно определить функцию рендеринга render в Vue, а затем выполнить функцию рендеринга, определенную во Vue, через посредника Watch in mount.

Создайте посредник Watch и выполните входящую функцию рендеринга. Рендеринг должен основываться на том, какие атрибуты данных привязаны к странице для чтения данных. В это время будет запущен метод get.

Введите get, чтобы получить соответствующее значение.

8.3 Примерная структура после добавления dep

  //defineReactive是对Observer的抽离
  const defineReactive = function(obj, key) {
    // 以下代码省略
  }
  
  const Vue = function(options) {
    console.log("Vue",this)
    //打印1  Vue {
                  _data:{
                      text: "123"
                      get text: ƒ get()
                      set text: ƒ set(newVal)
                    },
                  mount: ƒ (),
                  render: ƒ ()
                }
    // 以下代码省略
  }
  
  const Watcher = function(vm, fn) {
    console.log("Watcher",this)
    //打印3 Watcher  this是下面的Dep中subs的对象
    // 以下代码省略
  }
  
  const Dep = function() {
    console.log("Dep",this)
    //打印2  Dep   { 
                    target: null,
                    subs: [
                      {        //是一个Watcher实例
                        subs: Array(1)
                        0: Watcher
                        vm: {    //是一个Vue实例
                            _data:{
                              text: "123",//该属性有了get和set方法
                              get text: ƒ get(),
                              set text: ƒ set(newVal)
                            },
                            mount: ƒ (),
                            render: ƒ ()
                          },

                        addDep: ƒ (dep),
                        update: ƒ (),
                        value: undefined
                      }
                    ],
                    depend: ƒ (),
                    addSub: ƒ (watcher),
                    notify: ƒ ()
                  }

    // 以下代码省略
  }
  
  const vue = new Vue({
    data() {
      return {
        text: 'hello world'
      };
    }
  })
  
  vue.mount(); 
  vue._data.text = '123';

8.4 Подробный код

Глядя на эту картинку, вы увидите это более четко.Обратите внимание на порядок выполнения.При создании нового Vue каждый конструктор будет инициализирован по порядку.

image.png

/**
 * 
 * 作用:
 * 劫持data的各个属性,挂载set和get方法
 * 在get中将Watch添加到dep的subs中
 * 在set中触发dep.notify更新视图
 */
const Observer = function (data) {
    console.log(1)   //开始4 new Vue的时候就会执行
    // 循环修改为每个属性添加get set
    for (let key in data) {
        defineReactive(data, key);
    }
}

const defineReactive = function (obj, key) {
    console.log(2)    //开始5 new Vue的时候就会执行
    // 局部变量dep,用于get set内部调用
    const dep = new Dep();
    // 获取当前值
    let val = obj[key];
    Object.defineProperty(obj, key, {
        // 设置当前描述属性为可被循环
        enumerable: true,
        // 设置当前描述属性可被修改
        configurable: true,
        get() {
            console.log(3)//开始10  开始19
            console.log('in get');
            // 调用依赖收集器中的addSub,用于收集当前属性与Watcher中的依赖关系
            dep.depend();
            return val;
        },
        set(newVal) {
            console.log(4)//开始15
            if (newVal === val) {
                return;
            }
            val = newVal;
            // 当值发生变更时,通知依赖收集器,更新每个需要更新的Watcher,
            // 这里每个需要更新通过什么断定?dep.subs
            dep.notify();
        }
    });
}

const Vue = function (options) {
    console.log(6)//开始1 new Vue的时候就会执行
    const self = this;
    // 将data赋值给this._data,源码这部分用的Proxy,这里我们用最简单的方式临时实现
    if (options && typeof options.data === 'function') {
        console.log(7)//开始2  options.data是个函数,它返回了一个对象
        this._data = options.data.apply(this);
    }
    // 挂载Dom函数
    this.mount = function () {
        console.log(8)  //开始7  new Vue以后,执行vue.mount()
        new Watcher(self, self.render);
    }
    // 渲染函数
    this.render = function () {
        console.log(9) //开始9 开始18  render函数执行后走到这里
        return self._data.text;  //这里取data值的时候,就会走get方法
    }
    // 开始3, 监听this._data
    //new Vue的时候就会执行,这里执行完,就表示new Vue的过程执行完了
    new Observer(this._data);
}

const Watcher = function (vm, fn) {
    console.log(10)  //开始8  执行vue.mount()以后会走到这里
    const self = this;
    this.vm = vm;
    // 将当前Dep.target指向自己
    // 每次执行new Watch的时候,都会把当前的Watcher挂载到Dep.target
    Dep.target = this;
    // 向Dep方法添加当前Wathcer
    // this.addDep = function (dep) {
    //     console.log(11) //开始13  
    //     dep.addSub(self);
    // }
    // 更新方法,用于触发vm._render
    this.update = function () {
        console.log(12)//开始17
        console.log('in watcher update');
        fn(); //Vue中的render函数
    }
    // 这里会首次调用vm._render,从而触发text的get
    // 从而将当前的Wathcer与Dep关联起来
    this.value = fn();   //开始9  fn是Vue中的render函数,这里fn()在赋值的时候会执行
    // 这里清空了Dep.target,为了防止notify触发时,不停的绑定Watcher与Dep,
    // 造成代码死循环
    console.log('Watcher', this)
    Dep.target = null;
}

const Dep = function () {
    //开始6  new Vue》Observer》defineReactive》new Dep()
    console.log(13)
    const self = this;
    // 收集目标,先把它置空
    this.target = null;
    // 存储收集器中需要通知的Watcher
    this.subs = [];
    // 当有目标时,绑定Dep与Wathcer的关系

    this.depend = function () {
        console.log(14)  //开始11   开始20 走了get获取属性后,就要进行依赖收集 
        // targrt挂载发生在new Watch的时候
        if (Dep.target) {
            console.log(15)//开始12  
            self.addSub(Dep.target)
        }
    }
    // 为当前收集器添加Watcher
    this.addSub = function (watcher) {
        console.log(16)//开始14
        self.subs.push(watcher);
    }
    // 通知收集器中所的所有Wathcer,调用其update方法
    this.notify = function () {
        console.log(17) //开始16
        for (let i = 0; i < self.subs.length; i += 1) {
            self.subs[i].update();
        }
    }
}

const vue = new Vue({
    data() {
        return {
            text: 'hello world'
        };
    }
})

vue.mount(); // 挂载dom,渲染页面
vue._data.text = '123'; // 修改属性值,触发set

"Анализ:"

    1. В начале нового Vue он перейдет к строке 46, чтобы выполнить конструктор Vue, распечатать 6, а затем определить, является ли входящий вызов функцией.Из нового Vue видно, что входящий вызов является функцией data(), а затем функция выполняется и возвращается Весь объект данных монтируется в vue_dataАтрибуты (настоящий Vue делает то же самое)
    1. Затем смонтируйтеmountа такжеrenderфункция.
    1. Затем новый наблюдатель (this._data);
    1. Когда новый Observer перейдет на первую строчкуObserver(关键函数), напечатайте 1. Мы обнаружили, что Observer фактически добавляет данные к данным.上get和setметод, но не добавленный метод defineReactive был извлечен.
    1. Затем перейдите к строке 9, выполните defineReactive и напечатайте 2. Роль defineReactive:
      • угонятьdataРазличные свойства , mountsetа такжеgetметод
      • существуетgetгенерал-лейтенантWatchдобавить вdepизsubsсередина
      • существуетsetсредний триггерdep.notifyобновить представление
    1. Затем перейдите к строке 12, когда появится новый Dep, он перейдет к строке 95 для выполнения Dep и напечатает 13. Каждый раз, когда запускается новый Dep, онПустая цель, this.target = null, остальная часть кода функции Dep предназначена только для определения зависимостей функций, а addSub, notify, не будет выполняться, будет выпрыгивать из функции Dep. Затем он перейдет к строке 13 функции defineReactive.
    1. затем по 15 строк для каждого属性плюсget和setметод. Примечание. В настоящее время он только монтируется, а не выполняется, поэтому он не войдет в методы get и set. То есть функции в оставшемся коде defineReactive не будут выполняться, поэтому он вернется в Observer, а затем вернется к строке 67 нового Observer, то естьПроцесс нового Vue завершен.

новый Vue выполняется

Начать выполнение vue.mount()

    1. Затем перейдите к vue.mount() в строке 135, перейдите к строке 56 и напечатайте 8. Запустите новый Watcher, войдите в конструктор Watcher, чтобы напечатать 10, а затемthis.vm = vm; , подключите экземпляр vue к свойству vm Watch.Dep.target = this, который подключает экземпляр наблюдения к целевому свойству Dep и связывает его. Затем смонтируйте методы addDep и update, которые только что определены и не выполняются.
    1. Затем строка 89 this.value = fn(): fn фактически передается вrenderФункция (Vue=>new Watcher(self, self.render)=>vm, fn) будет выполнена немедленно, потому что после нее стоит символ (). Затем перейдите к функции рендеринга в строке 60, напечатайте 9 и вернитеself._data.text, затем вернитесь к просмотруthis.valueВозвращаемое значение data.text. А вот и ключ:self._data.textТекст в данных читается здесь, затем этот шаг вызоветgetметод.
    1. Затем перейдите на строку 21 и выведите 3.
    1. Затем перейдите к строке 25, выполните dep.depend(), перейдите к строке 104, напечатайте 14.
    1. Судя по этому времениDep.target, так как шаг 8 будетwatchустановлен наDep.target, на этот раз верно, поэтому выведите 15. затем выполнитьDep.target.addDep(self), по сути, заключается в выполненииWatch.addDep(self), затем выполнитеself.addSub(Dep.target).
    1. затем введитеthis.addSubprint 16, полная коллекция зависимостей,В сабах есть часы. Затем он вернется к get, выполнит последнюю строку, выйдет из get, затем вернется к this.render, выйдет из функции рендеринга, а затем вернется к часам.this.value = fn(), продолжайте идти назад,Dep.target = null, чтобы не попасть в бесконечный цикл, после чего выполняется Watch.

vue.mount() также выполняется

начать изменять

    1. Затем идет операция присваивания 136 строк.vue._data.text = '123', то он перейдет к набору в строке 28, выведет 4, а затем设置值为新值.
    1. Продолжайте до строки 36,dep.notify(), затем перейдите к строке 119 и напечатайте 17.
    1. Затем он перейдет к строке 122,遍历Depсерединаsubsвсе в массивеWatch, активировать часыupdateметод, перейдите к строке 82 и напечатайте 12.
    1. затем выполнитьWatcherсерединаfn(),Прямо сейчасVueсерединаrenderFunction (функция рендеринга, переданная при новом Watcher(self, self.render)), перейдите к строке 60 и напечатайте 9. В функции рендеринга вы действительно можете выполнять некоторые операции рендеринга, такие как: получить узел, преобразовать его содержимое в полученное значение и завершить рендеринг страницы.
    1. Затем перейдите к строке 63, возьмите data.text, перейдите к get, перейдите к 21, напечатайте 3.
    1. затем выполнитьdep.depend(), иди в отд.this.depend, выведите 14. Однако из-заDep.target имеет значение null, 15 напечатано не будет, то есть все процессы на данный момент выполнены.

все казнены

Статья >