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)
    }
  }
}
相关推荐
陈随易4 小时前
真的,你可以不用TypeScript
前端·后端·程序员
郑州光合科技余经理4 小时前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
唐璜Taro5 小时前
Vue3 + TypeScript 后台管理系统完整方案
前端·javascript·typescript
dustcell.5 小时前
haproxy七层代理
java·开发语言·前端
掘金酱5 小时前
「寻找年味」 沸点活动|获奖名单公示🎊
前端·人工智能·后端
颜酱5 小时前
栈的经典应用:从基础到进阶,解决LeetCode高频栈类问题
javascript·后端·算法
患得患失9495 小时前
【前端】前端动画优化的核心
前端
Xin_z_5 小时前
Vue3 + Sticky 锚点跳转被遮挡问题解决方案
前端·javascript·vue.js
REDcker5 小时前
WebCodecs VideoDecoder 的 hardwareAcceleration 使用
前端·音视频·实时音视频·直播·webcodecs·videodecoder
修炼前端秘籍的小帅5 小时前
Stitch——Google热门的免费AI UI设计工具
前端·人工智能·ui