fedono / fe-questions

1 stars 0 forks source link

33 实现一个模板字符串,能够匹配到提供的数据 #34

Open fedono opened 3 years ago

fedono commented 3 years ago

实现一个 render 函数,第一个参数是模板,第二个参数是数据,将数据映射到模板中

render('你好,我们公司是{{ company }},我们属于{{group.name}}业务线,我们在招聘各种方向的人才,包括{{group.jobs[0]}}、{{group["jobs"][1] }}等。', {group: {name: '高德', jobs: ['前端', '后端']}, company: '阿里巴巴'});
fedono commented 3 years ago
function render(tpl, data) {
    // 第一步,匹配到所有的 {{}} 的数据,然后开始做替换
    return tpl.replace(/\{\{[^}]+\}\}/g, $1 => {
        // 把单个的 {{}} 中的 {{ }} 和空白字符串删除掉
        let name = $1.replace(/[{}]/g, '').replace(/\s+/g, '');
        if (data[name]) {
            return data[name];
        } else {
            let res = [];
            // 有 group.name 和 group.jobs[0] 、group["jobs"][1] 三者情况,所以划分一下,先使用.分割开来,然后就可以分别处理含有 [] 的情况了
            let names = name.split('.');
            names.forEach(item => {
                if (item.includes('[')) {
                    // 这里要拿到 group["jobs"][1] 中的 group 这个,使用的是 positive lookahead 的方式
                    item.replace(/([^\[]+)(?=\[)/, $1 => {
                        if ($1) {
                            res.push($1);
                        }
                    });

                    // 匹配到 [] 的情况
                    item.replace(/(\[['"]?)[^\[\]]+(['"]?\])/g, $1 => {
                        // 将[ 和 ] 拿到,然后 replace 掉
                        let v = $1.replace(/\[(['"])?|/, '').replace(/(['"])?\]/, '').replace(/\s+/g, '');
                        res.push(v);
                        return $1;
                    });
                }
                else {
                    res.push(item.replace(/\s+/g, ''));
                }
            })

            // 通过一个循环,从data 里面拿到 数据
            let temp = JSON.parse(JSON.stringify(data));
            while (res.length) {
                temp = temp[res.shift()];
            };
            return temp;
        }
    });
}
fedono commented 1 year ago

那个时候还天真,还不知道 eval 和 new Function 的妙用

使用 new Function 来直接获取到这个属性的值

function render(template, data) {
    return template.replace(/\{\{([^\}\}]+)\}\}/g, ($1) => {
        let name = $1.replace(/[{}]/g, '').trim()
        fn = new Function('data', `with(data) return ${name}`)
        let content = fn(data)

        return content;
    })
}

使用 eval 来获取属性的值

function render(template, data) {
    return template.replace(/\{\{([^\}\}]+)\}\}/g, ($1) => {
        const name = $1.replace(/[{}]/g, '').trim()
        const content = eval(`data.${name}`)
        return content;
    })
}