V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
rui6ye
V2EX  ›  JavaScript

渲染 node 的 value 时 如何分割多个花括号作为单独的 textnode,以方便下次的单节点局部渲染?

  •  
  •   rui6ye · 2021-05-28 09:31:27 +08:00 · 1301 次点击
    这是一个创建于 1267 天前的主题,其中的信息可能已经有所发展或是发生改变。
    (使用原因:我的 js 插件用虚拟 dom 重构遇到的渲染问题。)
    如:<span>{a} 是 {b}</span>
    为了追求性能,提取所有的花括号作为虚拟 dom 。
    这样简单的场景比较好提取出 "{a}"、 " 是 " 、“{b}” ,然后 创建 3 个 textnode 虚拟 dom
    当 a 更新时 只更新 {a}所在的 textnode 即可。


    问题是当 a 变成一个语法 嵌套多层花括号,双引号,内部混淆了转译的花括号时,如何提取出真正的{a},场景如:

    <span>{'{{{{{a}+1}+1}+1}+1}'==1?"a":"b"} 不是 {b}</span>

    我想提取出 "{'{{{{{a}+1}+1}+1}+1}'==1?"a":"b"}" 、 " 不是 " 和 " {b}" 有点烧脑。
    百度一下有人提问过,回答是:“匹配嵌套的括号需要用到正则表达式中的平衡组语法,但遗憾的是 javascript 中不支持平衡组语法,所以单用一条正则表达式实现不了,需要用循环逐个字符处理。”

    求彦祖们给个思路如何解决或绕开这个难点。
    参考答案
    https://www.php.cn/js-tutorial-390656.html
    codehz
        1
    codehz  
       2021-05-28 09:50:08 +08:00 via Android
    为啥用 regex ?处理这个你不怕"{"这样的问题吗。。。
    显然必须要手动写 parser 做 ast
    rui6ye
        2
    rui6ye  
    OP
       2021-05-28 10:35:37 +08:00
    @codehz 解决了。灵感来源: https://github.com/zhangzhaoaaa/anyJavascript/blob/master/%E5%BC%A5%E8%A1%A5js%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%97%A0%E5%B9%B3%E8%A1%A1%E7%BB%84%E5%8A%9F%E8%83%BD.md

    贴上我的代码:
    <script>
    var str = "{'{{{{{a}+1}+1}+1}+1}'==1?\"a{\":\"b}\"} 是 {'{{{{{a}+1}+1}+1}+1}'==1?\"a\":\"b\"} {a}";
    getOutStr = function(s) {
    var tmpSplitTag = 'lrSplit';
    var N =0;
    let newStr = s;
    newStr = newStr.replace(/({|})/g, function($0,$1)
    {
    if($1=="{") {
    return "<"+tmpSplitTag+(++N)+">";
    }
    if($1=="}"){
    return "</"+ tmpSplitTag+ (N--) +">";
    }
    });
    let regAdd1_ = new RegExp("<"+tmpSplitTag+"1>", 'g');
    newStr = newStr.replace(regAdd1_, '{');
    let regAdd2_ = new RegExp("<\/"+tmpSplitTag+"1>", 'g');
    newStr = newStr.replace(regAdd2_, '}');
    //提取 1 的节点
    let reg_ = new RegExp("{([^\}]+)}");
    let responseArray = [];
    function findTagStr(restStr) {
    let findTag = restStr.match(reg_);
    // console.log('findTag', findTag);
    if(findTag) {
    let findIndex = findTag.index;
    if(findIndex==0) {
    responseArray.push(findTag[0]);
    } else {
    responseArray.push(restStr.slice(0, findIndex));
    responseArray.push(findTag[0]);
    }
    // console.log('restStr', restStr);
    // console.log('findTag[0]', findTag[0]);
    // console.log('slice', findIndex + (findTag[0].length));
    let rightStr = restStr.slice(findIndex + (findTag[0].length));
    // console.log('rightStr', rightStr);return;
    if(rightStr) {
    // console.log('rightStr', rightStr);return;
    findTagStr(rightStr);
    }
    } else {
    responseArray.push(restStr);
    }
    };
    findTagStr(newStr);
    //复原
    let removeReg1 = new RegExp("<"+tmpSplitTag+"\\d+>", 'g');
    let removeReg2 = new RegExp("<\/"+tmpSplitTag+"\\d+>", 'g');
    responseArray.map(function (str_, n) {
    let newStr = str_;
    newStr = newStr.replace(removeReg1, '{');
    newStr = newStr.replace(removeReg2, '}');
    if(newStr != str_) {
    responseArray[n] = newStr;
    }
    });
    console.log('responseArray');
    console.log(responseArray);
    }
    getOutStr(str);
    </script>
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   984 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 20:54 · PVG 04:54 · LAX 12:54 · JFK 15:54
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.