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)
    }
  }
}
相关推荐
于慨17 小时前
Lambda 表达式、方法引用(Method Reference)语法
java·前端·servlet
石小石Orz17 小时前
油猴脚本实现生产环境加载本地qiankun子应用
前端·架构
从前慢丶17 小时前
前端交互规范(Web 端)
前端
像我这样帅的人丶你还17 小时前
别再让JS耽误你进步了。
css·vue.js
@yanyu66617 小时前
07-引入element布局及spring boot完善后端
javascript·vue.js·spring boot
CHU72903517 小时前
便捷约玩,沉浸推理:线上剧本杀APP功能版块设计详解
前端·小程序
GISer_Jing17 小时前
Page-agent MCP结构
前端·人工智能
王霸天17 小时前
💥别再抄网上的Scale缩放代码了!50行源码教你写一个永不翻车的大屏适配
前端·vue.js·数据可视化
小领航17 小时前
用 Three.js + Vue 3 打造炫酷的 3D 行政地图可视化组件
前端·github
@大迁世界17 小时前
2026年React大洗牌:React Hooks 将迎来重大升级
前端·javascript·react.js·前端框架·ecmascript