42-mini-vue 实现 transform 功能

实现 transform 功能

  1. transform 功能
  • transform 就是对生成的整颗 ast 树,做增删改查的操作。
  1. 具体需求, 给 hi, 后面拼接 mini-vue
html 复制代码
  <div>hi,{{message}}</div>
  <!-- 过程 -->
  root---> element----> text
  `----> 插值
  1. 核心点
  • 找到 hi, 这块的 text 节点
    • 遍历一棵树
      • 广度优先搜索
      • 深度优先搜索 ----> 我们这里使用深度优先搜索进行遍历 ----> 使用递归来做处理
  • 修改 content 这块的值
  1. 先简单实现一个 happy path
js 复制代码
import {
    baseParse
} from "../src/parse"
import {
    transform
} from "../src/transform"

describe("transform", () => {
    it("happy path", () => {
        const ast = baseParse("<div>hi,{{message}}</div>")
        transform(ast)
        const nodeText = ast.children[0].children[0]
        expect(nodeText.content).toBe("hi,mini-vue")
    })
})
  1. 具体实现
js 复制代码
import {
    NodeTypes
} from "./ast";

export function transform(root) {
    // 1.遍历-深度优先搜索
    traverseNode(root)
    // 2.修改 text content
}

function traverseNode(node: any) {
    if (node.type === NodeTypes.TEXT) { // 这里处理修改
        node.content += 'mini-vue'
    }
    const children = node.children
    if (children) {
        for (let i = 0; i < children.length; i++) {
            const node = children[i]
            traverseNode(node)
        }
    }
}
  1. 测试通过,我们进行优化
  • 如果我们在拼接 mini-vue 以后,还要处理 element 节点

  • 还需要处理插值节点

  • 有的时候需要根据不同的环境做不同的处理, 有些环境不需要处理 text,有些则需要。

  • 这时候我们修改,拼接的内容,应该师动态的,也就是 mini-vue 是动态的

  • 还有递归的流程是固定的,我们需要抽离出变动点和稳定点的

  1. 如果处理呢?
  • 我们把动态拼接部分抽离出来,放到页面上
js 复制代码
describe("transform", () => {
    it("happy path", () => {
        const ast = baseParse("<div>hi,{{message}}</div>")
        const plugin = (node: any) => {
            if (node.type === NodeTypes.TEXT) { // 想实现什么类型写什么类型,高内聚,低耦合,程序的可测试性
                node.content += 'mini-vue'
            }
        }
        // 把要处理的逻辑传入过去,程序调用我们传入的函数,并把节点传回来,这样在外部 plugin 中处理内容区域,可以方便灵活的处理节点
        transform(ast, {
            nodeTransforms: [plugin]
        })
        const nodeText = ast.children[0].children[0]
        expect(nodeText.content).toBe("hi,mini-vue")
    })
})
js 复制代码
export function transform(root, options) {
    // 缓存传入的 plugin
    const context = createTransformContext(root, options)
    // 1.遍历-深度优先搜索
    traverseNode(root, context)
    // 2.修改 text content
}

function createTransformContext(root, options) {
    const context = {
        root,
        nodeTransforms: options.nodeTransforms || []
    }
    return context
}

function traverseNode(node: any, context) {
    // 这里就是外面传入的 plugin
    const nodeTransforms = context.nodeTransforms
    for (let i = 0; i < nodeTransforms.length; i++) {
        const transform = nodeTransforms[i]
        transform(node)
    }
    const children = node.children
    if (children) {
        for (let i = 0; i < children.length; i++) {
            const node = children[i]
            traverseNode(node, context)
        }
    }
}
  1. 重构递归函数
js 复制代码
function traverseNode(node: any, context) {
  const nodeTransforms = context.nodeTransforms
  for(let i = 0; i < nodeTransforms.length;i++) {
    const transform = nodeTransforms[i]
    transform(node)
  }
  traverseChildren(node, context) // 
}

function traverseChildren(node: any, context: any) {
  const children = node.children
  if (children) {
    for (let i = 0; i < children.length; i++) {
      const node = children[i]
      traverseNode(node, context)
    }
  }
}
相关推荐
cpolar技术支持2 分钟前
本地 Playwright 测试报告怎么远程复盘?Trace Viewer 跑起来后,用 cpolar 分享失败现场
前端·自动化测试·测试工具·cpolar·playwright
wordbaby2 分钟前
企业级后台管理系统路由设计与最佳实践指南
前端
专业程序开发源3 分钟前
springboot篮球联赛管理系统13635-计算机课程设计、毕业设计
vue.js·spring boot·后端·python·django·php·课程设计
胡志辉的博客11 分钟前
【完全开源】IP 纯净度检测 可一键部署到自己的CF
前端·javascript·chrome·ip·chromium
Hilaku37 分钟前
作为面试官,我最怕遇到什么样的候选人?
前端·javascript·程序员
一 乐38 分钟前
自习室座位预约管理系统|基于springboot + vue自习室座位预约管理系统(源码+数据库+文档)
java·vue.js·spring boot
TiDi1 小时前
Pinia优化重复请求
前端
web3d5201 小时前
01-用 Leafletjs 10 分钟搭一张水利一张图(Vue3 + Vite 实战)
前端·javascript
晚安日记wanna1 小时前
Vue2 的 defineProperty 差在哪四层追问筛掉九成候选人
前端·vue.js·面试
TiDi1 小时前
吸顶导航交互实现
前端