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

2021-05-28 09:31:27 +08:00
 rui6ye
(使用原因:我的 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
1158 次点击
所在节点    JavaScript
2 条回复
codehz
2021-05-28 09:50:08 +08:00
为啥用 regex ?处理这个你不怕"{"这样的问题吗。。。
显然必须要手动写 parser 做 ast
rui6ye
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>

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/779718

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX