предисловие
Сегодня особенный день, желаю всем богинямсчастливого дня богиниХа, я поставлю красивое фото Killing Palace на обложку, чтобы выразить свои благословения, ха-ха
В этой статье в основном написан исходный код Vue2.0 от руки.Принцип начального рендеринга
В предыдущей статье мы в основном представили VueПринцип составления шаблонаЭто базовый шаблон Vue для создания виртуального дома. После компиляции и, наконец, преобразования его в функцию рендеринга, как можно сгенерировать реальный узел дома для замены конфигурации параметра el? Затем, изучив эту статью, вы можете узнать начальный процесс рендеринга Vue. Эта статья в основном включает в себя создание виртуального дома и реального дома
Для людей:Учащиеся, у которых нет времени смотреть официальный исходный код или которые запутались и не хотят смотреть исходный код
текст
1. Вход для монтажа компонента
// src/init.js
Vue.prototype.$mount = function (el) {
const vm = this;
const options = vm.$options;
el = document.querySelector(el);
// 如果不存在render属性
if (!options.render) {
// 如果存在template属性
let template = options.template;
if (!template && el) {
// 如果不存在render和template 但是存在el属性 直接将模板赋值到el所在的外层html结构(就是el本身 并不是父元素)
template = el.outerHTML;
}
// 最终需要把tempalte模板转化成render函数
if (template) {
const render = compileToFunctions(template);
options.render = render;
}
}
// 将当前组件实例挂载到真实的el节点上面
return mountComponent(vm, el);
};
Затем посмотрите на метод $mount.Мы в основном сосредоточимся на последнем предложении.mountComponent — это функция входа для монтирования экземпляра компонента. Этот метод помещается в файл жизненного цикла исходного кода, что означает, что он связан с жизненным циклом, поскольку наши компоненты имеют перед и после начального рендеринга компонента хуки жизненного цикла beforeMount и монтирования.
2. Основной метод монтажа компонентов MountComponent
// src/lifecycle.js
export function mountComponent(vm, el) {
// 上一步模板编译解析生成了render函数
// 下一步就是执行vm._render()方法 调用生成的render函数 生成虚拟dom
// 最后使用vm._update()方法把虚拟dom渲染到页面
// 真实的el选项赋值给实例的$el属性 为之后虚拟dom产生的新的dom替换老的dom做铺垫
vm.$el = el;
// _update和._render方法都是挂载在Vue原型的方法 类似_init
vm._update(vm._render());
}
Новый файл Lifecycle.js указывает, что функция MountComponent экспорта ядра функции, связанная с виртуальным периодом, в основном использует монтирование экземпляра метода VM._UPDATE (VM._RENDER ())
3. Функция рендеринга преобразуется в метод ядра виртуального дома _render.
// src/render.js
import { createElement, createTextNode } from "./vdom/index";
export function renderMixin(Vue) {
Vue.prototype._render = function () {
const vm = this;
// 获取模板编译生成的render方法
const { render } = vm.$options;
// 生成vnode--虚拟dom
const vnode = render.call(vm);
return vnode;
};
// render函数里面有_c _v _s方法需要定义
Vue.prototype._c = function (...args) {
// 创建虚拟dom元素
return createElement(...args);
};
Vue.prototype._v = function (text) {
// 创建虚拟dom文本
return createTextNode(text);
};
Vue.prototype._s = function (val) {
// 如果模板里面的是一个对象 需要JSON.stringify
return val == null
? ""
: typeof val === "object"
? JSON.stringify(val)
: val;
};
}
Метод _render в основном определяется в прототипе, а затем выполняется функция рендеринга.Мы знаем, что основной код функции рендеринга, скомпилированный из шаблона, в основном возвращает что-то вроде _c('div',{id:"app"},_c ('div',undefined ,_v("hello"+_s(name)),_c('span',undefined,_v("world")))) такой код, то нам также нужно определить _c _v _s Эти функции могут быть окончательно преобразованы в виртуальный дом
// src/vdom/index.js
// 定义Vnode类
export default class Vnode {
constructor(tag, data, key, children, text) {
this.tag = tag;
this.data = data;
this.key = key;
this.children = children;
this.text = text;
}
}
// 创建元素vnode 等于render函数里面的 h=>h(App)
export function createElement(tag, data = {}, ...children) {
let key = data.key;
return new Vnode(tag, data, key, children);
}
// 创建文本vnode
export function createTextNode(text) {
return new Vnode(undefined, undefined, undefined, undefined, text);
}
Создайте новую папку vdom для представления функций, связанных с виртуальным домом, определите класс Vnode, а методы createElement и createTextNode вернут vnode в конце.
4. Преобразование виртуального дома в настоящий основной метод _update
// src/lifecycle.js
import { patch } from "./vdom/patch";
export function lifecycleMixin(Vue) {
// 把_update挂载在Vue的原型
Vue.prototype._update = function (vnode) {
const vm = this;
// patch是渲染vnode为真实dom核心
patch(vm.$el, vnode);
};
}
// src/vdom/patch.js
// patch用来渲染和更新视图 今天只介绍初次渲染的逻辑
export function patch(oldVnode, vnode) {
// 判断传入的oldVnode是否是一个真实元素
// 这里很关键 初次渲染 传入的vm.$el就是咱们传入的el选项 所以是真实dom
// 如果不是初始渲染而是视图更新的时候 vm.$el就被替换成了更新之前的老的虚拟dom
const isRealElement = oldVnode.nodeType;
if (isRealElement) {
// 这里是初次渲染的逻辑
const oldElm = oldVnode;
const parentElm = oldElm.parentNode;
// 将虚拟dom转化成真实dom节点
let el = createElm(vnode);
// 插入到 老的el节点下一个节点的前面 就相当于插入到老的el节点的后面
// 这里不直接使用父元素appendChild是为了不破坏替换的位置
parentElm.insertBefore(el, oldElm.nextSibling);
// 删除老的el节点
parentElm.removeChild(oldVnode);
return el;
}
}
// 虚拟dom转成真实dom 就是调用原生方法生成dom树
function createElm(vnode) {
let { tag, data, key, children, text } = vnode;
// 判断虚拟dom 是元素节点还是文本节点
if (typeof tag === "string") {
// 虚拟dom的el属性指向真实dom
vnode.el = document.createElement(tag);
// 解析虚拟dom属性
updateProperties(vnode);
// 如果有子节点就递归插入到父节点里面
children.forEach((child) => {
return vnode.el.appendChild(createElm(child));
});
} else {
// 文本节点
vnode.el = document.createTextNode(text);
}
return vnode.el;
}
// 解析vnode的data属性 映射到真实dom上
function updateProperties(vnode) {
let newProps = vnode.data || {};
let el = vnode.el; //真实节点
for (let key in newProps) {
// style需要特殊处理下
if (key === "style") {
for (let styleName in newProps.style) {
el.style[styleName] = newProps.style[styleName];
}
} else if (key === "class") {
el.className = newProps.class;
} else {
// 给这个元素添加属性 值就是对应的值
el.setAttribute(key, newProps[key]);
}
}
}
Основной метод _update заключается в том, что начальный рендеринг патча и последующих обновлений является общим.Этот метод отличается только первым переданным параметром.Общая идея начального рендеринга заключается в вызове собственного метода js в соответствии с виртуальным домом (vnode), чтобы создать настоящий узел dom и заменить параметр el.
5. Смешивание методов прототипа _render и _update
// src/index.js
import { initMixin } from "./init.js";
import { lifecycleMixin } from "./lifecycle";
import { renderMixin } from "./render";
// Vue就是一个构造函数 通过new关键字进行实例化
function Vue(options) {
// 这里开始进行Vue初始化工作
this._init(options);
}
// _init方法是挂载在Vue原型的方法 通过引入文件的方式进行原型挂载需要传入Vue
// 此做法有利于代码分割
initMixin(Vue);
// 混入_render
renderMixin(Vue);
// 混入_update
lifecycleMixin(Vue);
export default Vue;
Наконец, метод, определенный в прототипе, вводится в запись основного файла Vue, чтобы все экземпляры могли совместно использовать этот метод.
6. Интеллект-карта составления шаблона
резюме
На данный момент первоначальный принцип рендеринга Vue завершен. В сочетании с первыми двумя адаптивными данными и компиляцией шаблона мы можем визуализировать шаблон, который мы написали, на страницу. Вы можете посмотреть на интеллект-карту и написать основной код самостоятельно. Если вы не понимаете или у вас есть споры, пожалуйста, оставьте комментарий
Наконец, если вы найдете эту статью полезной, помнитеКак СанлианБольшое спасибо!
Ссылка на сериал (будет обновлена позже)
- Написанный от руки исходный код Vue2.0 (1) — принцип адаптивных данных
- Рукописный исходный код Vue2.0 (2) - принцип компиляции шаблона
- Рукописный исходный код Vue2.0 (3) — принцип начального рендеринга
- Рукописный исходный код Vue2.0 (четыре) — принцип обновления рендеринга
- Рукописный исходный код Vue2.0 (5) - принцип асинхронного обновления
- Рукописный исходный код Vue2.0 (6) - принцип алгоритма diff
- Рукописный исходный код Vue2.0 (7) - Принцип микширования
- Рукописный исходный код Vue2.0 (8)-компонентный принцип
- Рукописный исходный код Vue2.0 (9) - принцип свойства прослушивания
- Рукописный исходный код Vue2.0 (10) — Принцип вычисляемых свойств
- Рукописный исходный код Vue2.0 (11) — принцип глобального API
- Самые полные вопросы интервью Vue + подробные ответы
- Рукописный исходный код vue-router
- Рукописный исходный код vuex
- Рукописный исходный код vue3.0
Группа передовых рыболовных технологий Brother Shark
Приветствую всех на технических биржахСвязь