введение
Я считаю, что большинство фронтенд-партнеров не могут вспомнить, сколько проектов они сделали и сколько кода они написали.Все пишут код 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метод._initVue будет инициализирован в соответствии с переданными параметрами. В этом процессе завершается инициализация реквизита, данных, жизненного цикла и механизма событий.
Взяв за пример инициализацию данных, 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 и т. д., так что следите за обновлениями.