введение
Я считаю, что большинство фронтенд-партнеров не могут вспомнить, сколько проектов они сделали и сколько кода они написали.Все пишут код Vue как учебник:
// 单文件组件中常见代码
export default {
data () {
return {
msg: 'click me'
}
},
methods: {
say () {
this.msg = 'well done'
}
}
}
// 入口文件中的常见代码
new Vue({
el: '#app',
router: router,
render: h => h(App)
})
Все кажется таким естественным. Тем не менее, в напряженном графике кто-нибудь из ваших друзей когда-нибудь задумывался о том, как небольшой экземпляр Vue может иметь столько энергии для создания такого сложного внешнего проекта. Итак, как Vue работает внутри и что он делает?
Vue может работать на нескольких платформах, таких как браузеры, weex и т. д. В этой статье анализируется только основной процесс выполнения Vue в среде браузера.
инициализация
Давайте сначала посмотрим на конструктор Vue:
// Vue构造函数
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)
}
Как видно из конструктора Vue, когда мы выполняемnew Vue()
, единственный_init
метод._init
Vue будет инициализирован в соответствии с переданными параметрами. В этом процессе завершается инициализация реквизита, данных, жизненного цикла и механизма событий.
Взяв за пример инициализацию данных, vue пройдетObject.defineProperty
Способ определения атрибутов данных для экземпляра vue. Это также объясняет, почему мы можем передатьthis.msg
Чтобы назначить значение, вы можете изменить значение данных в данных.
Описанная выше обработка данных — это только начало. Чтобы реализовать так называемое адаптивное или управляемое данными обновление, vue провел дальнейшую обработку.Конкретный метод заключается в созданииobserver
объект, который привязан к данным, черезObject.defineProperty
Преобразование всех атрибутов данных вgetter/setter
. Когда свойства в данных доступны в экземпляре vue (будет запущен геттер),observer
Объект будет собирать свойство какwatcher
Зависимости экземпляра, затем, когда свойства данных изменяются в экземпляре vue (установщик будет запущен),observer
уведомит тех, кто зависит от этого свойстваwatcher
Экземпляр повторно отображает страницу.
Примечание. Каждый наблюдатель соответствует экземпляру vue.
Вышеуказанные потоки обработки связаны вместе, и Vue реализуется путем измененияthis.msg
Это запускает автоматическое обновление страницы.
Наконец, позаимствуйте схематическую диаграмму на официальном сайте Vue, чтобы помочь вам понять этот процесс:
Разбор шаблона
Благодаря приведенному выше анализу мы уже знаем, что при изменении данных страница будет перерисована. Далее давайте проанализируем, как vue отрисовывает.
Во-первых, vue проанализирует шаблон HTML, который мы написали, в объект описания AST, который передается черезchildren
а такжеparent
Связанная древовидная структура полностью описывает всю информацию тегов HTML.
Например, следующий HTML-шаблон:
<div id="app">
<p>{{msg}}</p>
</div>
В конечном итоге он будет преобразован в объект AST следующего вида:
{
attrs: [{name: "id", value: ""app"", dynamic: undefined, start: 5, end: 13}],
attrsList: [{name: "id", value: "app", start: 5, end: 13}],
attrsMap: {id: "app"},
children: [{
attrsList: [],
attrsMap: {},
children: [],
end: 33,
parent: {type: 1, tag: "div", ...},
plain: true,
pre: undefined,
rawAttrsMap:{},
start: 19
tag: "p",
type: 1
}],
end: 263,
parent: undefined,
plain: false,
rawAttrsMap:{id: {name: "id", value: "app", start: 5, end: 13}},
start: 0
tag: "div",
type: 1
}
потомvue
Объекты, сгенерированные ASTrender
функция, тело функции функции примерно выглядит следующим образом:
with(this){
return _c('div', {attrs:{"id":"app"}}, [_c('p', [_v(_s(msg))])])
}
То есть наш шаблон окажется внутри vue сrender
существует в виде функции.
Это также упоминается на официальном веб-сайте vue.Обычно рекомендуется использовать шаблон, el и т. д. для указания шаблонов. функция.
Реальность первая
у нас естьrender
После функции vue не выполняет рендеринг напрямую в DOM-дерево, а сначала передаетrender
функция получаетvnode
. На самом деле, этот шаг очень необходим, и все мы знаем, что частая работа с узлами DOM в больших количествах чрезвычайно требовательна к производительности. vue передает пару перед рендерингомvnode
Сравнение может значительно избежать ненужных манипуляций с DOM. Ниже приведенvnode
Грубая структура:
{
tag: "div",
children: [{tag: "p", ...}],
data: {attrs: {id: "app"}}
elm: DOM节点(div#app),
parent: undefined,
context: Vue实例,
...
}
Наконец, Vue выполняет такие операции, как вставка, обновление и удаление реальных узлов DOM в соответствии с результатами после сравнения и запускает функцию ловушки жизненного цикла экземпляра Vue. После этого Vue должен наблюдать за изменениями в данных, а затем решать, следует ли повторно отображать страницу.
Суммировать
Вышеупомянутый основной процесс vue в начальном процессе рендеринга.Вообще говоря, это сначала инициализировать объект опции, а затем передатьObject.defineProperty
Создайте отзывчивую систему, а затем разберите шаблон наrender
функцию, затем используйтеrender
Функция генерирует vnode перед рендерингом дляvnode
Выполните операцию diff и, наконец, выполните необходимый рендеринг.
В этой статье мы не будем вдаваться в подробности кода при каждом выполнении.Далее мы подробно расскажем об инициализации, принципе адаптивной реализации, рендеринге шаблонов, разборе инструкций, различиях vnode и т. д., так что следите за обновлениями.