1.依赖关系
- runtime-dom 依赖于runtime-core,runtime-core 依赖于reactivity和shared
- runtime-core提供跨平台的渲染方法createRenderer,用户可以自己转达节点渲染的渲染方法renderOptions,本身不关心用户使用什么API
- runtime-dom提供了为浏览器而生的渲染方法render,render方法调用runtime-core的createRenderer方法转达的renderOptions 是runtime-dom封装好的一系列关于渲染浏览器dom节点的操纵
- const renderOptions = Object.assign({ patchProp }, nodeOps);
- export const render = (vnode,container)=>{
- return createRenderer(renderOptions).render(vnode,container)
- }
复制代码 2.init
2.1 package init
runtime-core/package.json
- {
- "name": "@vue/runtime-core",
- "version": "1.0.0",
- "main": "index.js",
- "module": "dist/runtime-core.esm-bundler.js",
- "unpkg": "dist/runtime-core.global.js",
- "buildOptions": {
- "name": "RuntimeCore",
- "formats": [
- "esm-bundler",
- "esm-browser",
- "cjs",
- "global"
- ]
- },
- "dependencies": {
- "@vue/reactivity": "^3.4.30",
- "@vue/shared": "*"
- }
- }
复制代码 2.2 调整runtime-dom/index依赖
- import { nodeOps } from "./nodeOps";
- import patchProp from "./patchProp";
- import {createRenderer} from '@vue/runtime-core'
- const renderOptions = Object.assign({ patchProp }, nodeOps);
- export { renderOptions };
- // 如果我们采用的是runtime-dom中的render方法,我们不需要传递renderOptions,因为会把runtime-dom 这一层的dom处理方法传递进去,主要为浏览器而生的
- // 如果我们用的是runtime-core 中的createRenderer,需要用户自己传递renderOptions 并不关心采用什么api
- // runtime-dom 是内置的dom api 会去调用createRenderer,传入渲染选项,返回的渲染器有一个render方法
- // 采用dom api 进行渲染
- export const render = (vnode,container)=>{
- return createRenderer(renderOptions).render(vnode,container)
- }
- export * from "@vue/runtime-core"
复制代码 3.实现
3.1 init
createRenderer接受一个参数dom渲染相关配置,提供一个render方法,参数为虚拟节点和真实的dom元素
- export function createRenderer(renderOptions) {
- const {
- insert: hostInsert,
- remove: hostRemove,
- patchProp: hostPatchProp,
- createElement: hostCreateElement,
- createText: hostCreateText,
- setText: hostSetText,
- setElementText: hostSetElementText,
- parentNode: hostParentNode,
- nextSibling: hostNextSibling,
- } = renderOptions;
- const render = (vnode, container) => {
- // 将虚拟节点变成真实节点进行渲染
- };
- return {
- render,
- };
- }
复制代码 3.2 render实现
- const mountElement = (vnode, container) => {
- console.log(vnode);
- const { type, children, props } = vnode;
- let el = hostCreateElement(type);
- if (props) {
- for (let key in props) {
- hostPatchProp(el, key, null, props[key]);
- }
- }
- hostSetElementText(el, children);
- hostInsert(el, container);
- };
- const patch = (n1, n2, container) => {
- if (n1 == n2) {
- return;
- }
- if (n1 == null) {
- mountElement(n2, container);
- }
- };
- // core 中不关心如何渲染
- const render = (vnode, container) => {
- // 将虚拟节点变成真实节点进行渲染
- patch(container._vnode || null, vnode, container);
- container._vnode = vnode;
- };
复制代码 vnode如图:
- const ele1 = h(
- "h1",
- { style: { color: "red" }},
- "hello world"
- );
- const ele2 = h(
- "h1",
- { style: { color: "green" } },
- "hello world"
- );
- render(ele1, document.getElementById("app"));
- setTimeout(()=>{
- render(ele2, document.getElementById("app"));
- },3000)
复制代码 此时可以实现底子渲染,由于我们知道节点children是文本,可以直接使用文本进行渲染,那如果dom内里又嵌套一个dom呢?
3.3 shapeFlag
为了能够判断子节点的类型,界说一个枚举
- export const enum ShapeFlags { // vue3提供的形状标识
- ELEMENT = 1,
- FUNCTIONAL_COMPONENT = 1 << 1,
- STATEFUL_COMPONENT = 1 << 2,
- TEXT_CHILDREN = 1 << 3,
- ARRAY_CHILDREN = 1 << 4,
- SLOTS_CHILDREN = 1 << 5,
- TELEPORT = 1 << 6,
- SUSPENSE = 1 << 7,
- COMPONENT_SHOULD_KEEP_ALIVE = 1 << 8,
- COMPONENT_KEPT_ALIVE = 1 << 9,
- COMPONENT = ShapeFlags.STATEFUL_COMPONENT | ShapeFlags.FUNCTIONAL_COMPONENT
- }
复制代码 比如const ele1 = h("h1", { style: { color: "red" } }, "hello world");是节点和文本的组合,节点为1,文本为8,接纳或运算,得出节点类型数据9,可以看到上图中节点的shapeFlag为9,接纳&运算得出节点具体类型 8&9=1000&1001=1000>0 则证明包含这个类型
- const mountChildren = (children, container) => {
- for(let i=0;i<children.length;i++) {
- // 数组可能为字符串而不是节点
- patch(null, children[i], container)
- }
- };
-
- const { type, children, props, shapeFlag } = vnode;
- if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {
- hostSetElementText(el, children);
- } else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
- mountChildren(children, el);
- }
复制代码 此处判断了TEXT_CHILDREN是文本,ARRAY_CHILDREN是数组
- const ele3 = h("h1", { style: { color: "red" } }, [
- h("p", "hello"),
- h("p", "world"),
- ]);
复制代码 可以精确渲染
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |