Недавно я изучаю исходный код Vue, а затем в основном резюмирую первый рендеринг Vue~
Сначала посмотрите на картинку ниже, затем я объясню шаг за шагом
Исходный адрес Vue, здесь в основном смотрите исходный код в каталоге src
1. Начните с входного файла
определено вsrc/platform/web/entry-runtime-with-compiler.js
2. Процесс инициализации Vue
1. Сначала удалите Vue$mount,правильно$mountпереписать, дать$mountДобавить новые функции
// src/platform/web/entry-runtime-with-compiler.js
// 保留 Vue实例的 $mount 方法
const mount = Vue.prototype.$mount
Vue.prototype.$mount = function (
el?: string | Element,
// 非ssr情况下的为false, ssr时候为true
hydrating?: boolean
): Component {
// 获取el对象
el = el && query(el)
...
}
2. Определить, есть лиrenderвариант, если нетrenderвариант, шаблон будетtemplateВыньте и скомпилируйте шаблон вrenderфункция, затем вызовитеmountметод, рендерDOM.
3. Добавлен статический объект во Vue.compileметод, функция состоит в том, чтобыHTMLСтрока компилируется вrenderфункция
if (!options.render) {
let template = options.template
if (template) {
...
}
}
Vue.compile = compileToFunctions
export default Vue
4. Этот файл в основном черезextendДирективы и компоненты зарегистрированы глобально для Vue, а компонентыTransitionа такжеTransitionGroup, командаv-modelа такжеv-show, затем вVueзарегистрирован на прототипе_patch_функция,_patch_Функция функции состоит в том, чтобы преобразовать виртуальный DOM в реальный DOM,patchКогда функция назначена, она будет определять, является ли это средой браузера
5 Продолжаем находить конструктор Vue
// src/platforms/web/runtime/index.js
extend(Vue.options.directives, platformDirectives)
extend(Vue.options.components, platformComponents)
// 判断是否是浏览器环境
Vue.prototype.__patch__ = inBrowser ? patch : noop
"инициализировать статические члены"
6. Определено вsrc/core/index.js
- вызов в этом файле
initGlobalAPI(Vue)метод, добавьте статический метод в конструктор Vue
initGlobalAPI(Vue)
7.initGlobalAPI(Vue)определено вsrc/core/global-api/index.js
- инициализация
Vue.configобъект - настраивать
keep-aliveкомпоненты - регистр
Vue.use()Используется для регистрации плагинов - регистр
Vue.mixin()реализовать миксин - регистр
Vue.extend()Конструктор, который возвращает компонент на основе переданных опций - регистр
Vue.directive(),Vue.component(),Vue.filter
export function initGlobalAPI (Vue: GlobalAPI) {
const configDef = {}
configDef.get = () => config
if (process.env.NODE_ENV !== 'production') {
configDef.set = () => {
warn(
'Do not replace the Vue.config object, set individual fields instead.'
)
}
}
// 初始化 Vue.config对象
Object.defineProperty(Vue, 'config', configDef)
// exposed util methods.
// NOTE: these are not considered part of the public API - avoid relying on
// them unless you are aware of the risk.
// 这些工具方法不视作全局Api的一部分,除非你已经意识到某些风险,否则不要去依赖他们
Vue.util = {
warn,
extend,
mergeOptions,
defineReactive
}
// 静态方法 set/delete/nextTick
Vue.set = set
Vue.delete = del
Vue.nextTick = nextTick
// ...
Vue.options._base = Vue
// 设置keep-alive 组件
extend(Vue.options.components, builtInComponents)
// 注册Vue.use()用来注册插件
initUse(Vue)
// 注册Vue.mixin()实现混入
initMixin(Vue)
// 注册Vue.extend()基于传入的options返回一个组件的构造函数
initExtend(Vue)
// 注册Vue.directive(), Vue.component(), Vue.filter
initAssetRegisters(Vue)
}
Инициализировать члены экземпляра
- _init()
- определено в
src/core/instance/index.js - Конструктор определен и вызывается
this._init(options)метод - Смешанные общие элементы экземпляра в 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')
}
// 调用 _init()方法
this._init(options)
}
// 注册vm的_init()方法, 初始化vm
initMixin(Vue)
// 注册vm 的$data/$props/$set/$delete/$watch
stateMixin(Vue)
// 初始化事件相关方法
//$on/$once/$off/$emit
eventsMixin(Vue)
// 初始化生命周期相关的混入方法
// _update/$forceUpdate/$destroy
lifecycleMixin(Vue)
// 混入 render
// $nextTick/_render
renderMixin(Vue)
export default Vue
Инициализировать члены экземпляра init()
- Когда инициализируются как статические члены, так и члены экземпляра, затем вызывается конструктор Vue, а в конструкторе вызывается метод _init().
- _init инициализируется в initMixin, в основном для инициализации экземпляра Vue.
// vm的生命周期相关变量初始化
initLifecycle(vm)
// vm的事件监听初始化,父组件绑定在当前组件上的事件
initEvents(vm)
// vm的编译render初始化
// $slots/$scopedSlots/_c/$createElement/$attrs/$listeners
initRender(vm)
// beforeCreate 生命钩子的回调
callHook(vm, 'beforeCreate')
// 把inject的成员注入到vm上
initInjections(vm) // resolve injections before data/props
// 初始化vm的 _props/methods/_data/computed/watch
initState(vm)
// 初始化provide
initProvide(vm) // resolve provide after data/props
// created 生命钩子回调
callHook(vm, 'created')
Инициализировать члены экземпляра initState()
Инициализировать виртуальные машины_props/methods/_data/computed/watch
export function initState (vm: Component) {
vm._watchers = []
const opts = vm.$options
if (opts.props) initProps(vm, opts.props)
if (opts.methods) initMethods(vm, opts.methods)
if (opts.data) {
initData(vm)
} else {
observe(vm._data = {}, true /* asRootData */)
}
if (opts.computed) initComputed(vm, opts.computed)
if (opts.watch && opts.watch !== nativeWatch) {
initWatch(vm, opts.watch)
}
}
-
существует
instance/state.js, сначала полученоVueв случае$options, а потом судитьoptionsбудь то вprops,methods,dataтак же какcomputedа такжеwatchЭти свойства, если таковые имеются, передаются черезinitPropsинициализироватьinitProps(vm, opts.props)Получил два параметра, одинVueнапример, одинPropsсвойства, мы переходим кinitPropsфункция, сначала дайтеVueэкземпляр определяет_Propsобъект и сохранить его в константеconst props = vm._props = {} -
Затем начните обход
PropsOptionsвсе свойства , это на самом делеinitPropsВторой параметр в методе, итерация по каждому свойству, затем передачаdefineReactiveвводить вPropsна этом объекте, этоpropsНа самом деле этоvm._propsВсе участники пройдутdefineReacttiveпревратиться вgetа такжеset, наконец вPropsхранится объект,"Уведомление" -
В режиме разработки, если мы присвоим значение этому свойству напрямую, будет выдано предупреждение,
-
непосредственно в производстве
defineReactiveПучокpropsСвойства в конвертируются вgetа такжеset -
Наконец судили
propsЯвляется ли имущество вVueЭкземпляр существует, не существует черезProxyЭта функция внедряет наши свойства вVueв случае -
существует
Proxy, позвонивObject.defineProperty(target, key,sharePropertyDefinition)
Суммировать
initPropsРоль состоит в том, чтобы поставить нашуPropsчлены преобразуются в отзывчивые данные и вводятся вVueв случае
initMethods
-
существует
initMethods(vm, opts.methods)Кроме того, он получает два параметра: экземпляр Vue и параметры вmethods, сначала получите Props в опциях, затем пройдитесь по всем свойствам методов, а затем оцените, является ли текущая среда разработкой или производством Среда разработки будет определять, являются ли методы функциональными -
Тогда судите
methodsИмя метода вPropsЕсли объект существует, существование отправит предупреждение, предупреждение находится в свойстве по адресуPropsуже существует, потому чтоPropsа такжеmethodsВ конце концов, его нужно внедрить в экземпляр Vue, и такое же имя не может появиться. -
Продолжайте судить
keyВы вVueсуществует в , и вызываетisReserved(key), судя по нашимkeyначинается ли он с _ или$начало Наконец положитьmethodsВнедренный в экземпляр Vue, он будет судить, является ли онfunction, если не вернутьnoop, если да, вернуть функциюbind(methods[key], vm)
Суммировать
initMethodsЭффект заключается в том, чтобы поставить опциюmethodsВнедренный в экземпляр vue, перед внедрением он сначала определит, находится ли наше имя вPropsсуществует, и соглашение об именах оценивается, не рекомендуется начинать с _ и $
initData(vm)
-
когда
optionsимеютdataвариант, он вызоветinitData(vm) -
Если нет, он инициализирует виртуальную машину в это время.
_data属性observe(vm._data = {}, true)Затем вызовите функцию наблюдения,observeэто функция реактивного -
существует
initDataполучено вoptionsизdataварианты, рассудилdataЯвляется ли вариантfunction, если звонитьgetData(data,vm)затем получитьdataВсе свойства в , при полученииprops,methodsвсе объекты в
// src/core/instance/state.js
const keys = Object.keys(data)
const props = vm.$options.props
const methods = vm.$options.methods
Наконец, сделайте реактивный процесс
observe(data, true)
В конце функция _init вызывается снова$mountсмонтировать всю страницу
// src/core/instance/init.js
if (vm.$options.el) {
vm.$mount(vm.$options.el)
}
Краткое описание первого процесса рендеринга
- Перед первым рендерингом сначала выполните инициализацию Vue, инициализируйте элементы экземпляра и статические элементы.
- Когда инициализация завершена, вызывается конструктор Vue.
new Vue(), который вызывается в конструкторе_init()метод, этот метод эквивалентен вводу всего нашего Vue - существует
_initметод, который в итоге вызывает$mount, всего два$mount, первое определяется вentry-runtime-with-compiler.jsфайл, который является нашим входным файлом$mount,это$mount()Основная роль заключается в том, чтобы помочь нам скомпилировать шаблон вrenderфункцию, но сначала определит, передается ли она в данный момент вrenderпараметры, если они не переданы, он получит нашtemplateвариант, еслиtemplateЕсли нет выбора, онelСодержимое в качестве нашего шаблона, а затем скомпилируйте шаблон вrenderфункция, котораяcompileToFunctions()функция, которая поможет нам скомпилировать шаблон вrenderфункционально, когдаrenderПосле компиляции функция будетrenderфункция существует в нашемoptions.renderсередина. - затем позвонит
src/platforms/web/runtime/index.jsв файле$mountметод, в этом сначала будет повторно извлеченel, потому что, если это рабочая версия, она не пойдетentry-runtime-with-compiler.jsЭта запись получает el, поэтому, если это версия среды выполнения, мы снова получим el в $mount() runtime/index.js. - Следующий звонок
mountComponent(), этот методsrc/core/instance/lifecycle.jsопределено вmountComponent(), первый судьяrenderвариант, если нетrenderвариант, но мы передаем шаблон, и текущая среда разработки отправит предупреждение, цель состоит в том, если мы в настоящее время используем версию Vue во время выполнения, и мы не передалиrender, но передается шаблон, сообщающий нам, что версия среды выполнения не поддерживает компилятор. сработает следующийbeforeMountФункция крюка в этом жизненном цикле, то есть до начала монтирования. - а затем определить
updateComponent(), в этой функции вызовитеvm._renderа такжеvm._update,vm._renderРоль заключается в создании виртуального DOM,vm._updateРоль виртуала.DOMпреобразовать в реальныйDOM, и смонтировать его на странице - Создайте
Watcherобъект при созданииWatcher, прошлоupdateComponentЭта функция, эта функция, наконец, вWatcherЗвонил вовнутрь. существуетWatcherбудет использоваться внутриgetметод, когда Watcher будет создан, он вызоветmountedФункция ловушки в методе get будет вызыватьсяupdateComponent() - Монтирование завершено, и экземпляр Vue наконец-то возвращен.
Выше показан процесс первого рендеринга Vue.
Спасибо всем
Наконец, спасибо, что нашли свое драгоценное время, чтобы прочитать этот контент. Если вы считаете, что этот контент полезен для вас, пожалуйста, поставьте лайк этой статье. (Спасибо за вашу поддержку и поддержку 🌹🌹🌹)
В этой статье используетсяmdniceнабор текста