sisterAn/JavaScript-Algorithms

百度:模版渲染

sisterAn opened this issue · 12 comments

实现一个 render(template, context) 方法,将 template 中的占位符用 context 填充。

示例:

var template = "{{name}}很厉害,才{{age}}岁"
var context = {name:"bottle",age:"15"}
输入:template context
输出:bottle很厉害,才15岁

要求:

  • 级联的变量也可以展开
  • 分隔符与变量之间允许有空白字符

相关文章可查看:一行代码实现一个简单的模板字符串替换

const answer = (contentTpl, contentTplData, noMatchStr = "-") => {
        let reg = "(.*)";
        const keys = [];
        let current = [];
        Object.keys(contentTplData).forEach((key) => {
            const index = contentTpl.indexOf(key);
            if(index >= 0) {
                current.push({
                    index,
                    value: key
                })
            }
        });
    
        const sortBy = (field) => (a,b) => (a[field] - b[field]);
    
        current.sort(sortBy('index')).forEach(item => {
            reg += `\\\{{${item.value}}}(.*)`;
            keys.push(item.value);
        });
    
        const contents = [];
        const matchArr = contentTpl.match(new RegExp(reg));
    
        (matchArr ? matchArr.slice(1) : []).forEach((item, index) => {
            item = item.replace(/\{{(.*)}}/, noMatchStr);
    
            contents.push(item);

            const key = keys[index]

            if(key !== undefined){
                contents.push(contentTplData[key]);
            }
        });
        return contents.join('');
    }
let render = (template, context)=>{
        let tem = template
        let reg = /\{\{(\w{1,})\}\}/g;
        return tem.replace(reg,function(v,x,y){
            return context[x.trim()]
        })
    }
const render = (template, context) => {
    const getVal = (obj, props) => {
        if (props.length === 0) {
            return obj
        }
        return getVal(obj[props.shift()], props)
    }

    return template.replace(/\{\{\s*(\w+(\.\w+)*)\s*\}\}/g, (p1, p2) => {
        return getVal(context, p2.split('.'))
    })
}

const template = '{{name}}很厉害,才{{age}}岁,他少年{{obj.a}},独力支持,做了{{obj.b.c}}。'
const context = {
    name: '二月',
    age: '15',
    obj: {
        a: '出外谋生',
        b: {
            c: '许多大事'
        }
    }
}

console.log(render(template, context))
// 二月很厉害,才15岁,他少年出外谋生,独力支持,做了许多大事。
function render(template, context) {
	return template.replace(/{{(.*?)}}/g, function (match, key, index) {
		return context[key.trim()] || ''
	})
}

解答:使用正则 + trim

  • 利用非贪婪匹配 /\{\{(.*?)\}\}/g 匹配到到所有的 {{name}}{{age}}
  • 利用 str.replace(regexp|substr, newSubStr|function) ,其中第二个参数可以是 fucntion (replacement) ,该函数的返回值将替换掉第一个参数匹配到的结果,将所有匹配到的字符替换成指定的字符
  • 最后,String.prototype.trim() 去除分隔符与变量之间空白字符
var template = "{{name}}很厉害,才{{age}}岁"
var context = {name:"bottle",age:"15"}
function render(template, context) {
  return template.replace(/{{(.*?)}}/g, (match, key) => context[key.trim()])
}
render(template, context)
// "bottle很厉害,才15岁"

详细解答可查看:一行代码实现一个简单的模板字符串替换

function render(template, context) {
const rule = /{{(.*?)}}/g;
return template.replace(rule, function($, key) {
const arr = key.trim().split('.');
return arr.reduce((cal, item) => {
return cal[item];
}, context);
});
}

var str = "{{name}}很厉害,才{{age}}岁,他才华横溢,这是第{{queue.ll.cc}}首歌了。";
var obj = {name: '周杰伦', age: 15, queue: { queue1: '1001', ll: { cc: '337' } }};
str.replace(/\{\{(.*?)\}\}/g, ($0, $1) => !$1.includes('.') ? obj[$1] : $1.split('.').reduce((acc, current) => acc[current], obj));
let template = '<div><p>{{ name }}</p><p>{{ age }}</p><p>{{ info.member }}</p><p>{{ list.join("+") }}</p></div>';

function render(template, context) {
    return template.replace(/\{\{\s*(.*?)\s*\}\}/g, function(match, $1) {
        let str = '';
        with(context) {
            str = $1 ? eval($1) : '';
        }
        return str; 
    });
}
render(template, {
    name: '李雷',
    age: 10,
    info: {
        member: 5,
        active: 10
    },
    list: [1,2,3,4]
});
// <div><p>李雷</p><p>10</p><p>5</p><p>1+2+3+4</p></div>
function render(template,context){
    let reg = /\{\{\s*\w+(\.\w+)*\s*\}\}/g
    return template.replace(reg,function(match){
      return match.replace(/{|}/g,'').trim().split('.').reduce((prev,cur) => prev[cur],context)
    })
}
let context = {
  name:'lily',
  age:18,
  family:{
    count:3
  }
}
let template = '{{ name }}很name厉害,才{{age}}岁,家里有{{family.count}}口人'

let result = render(template,context)
console.log(result)
const render = (template,context) => {
    let defaultTagRe = /\{\{((?:.|\r?\n)+?)\}\}/g
    return template.replace(defaultTagRe,(match,key,index,str)=>{
        return context[key.trim()]
    })
}
console.log(render(template,context))
AirKK commented
function render(template, context) {
    return template.replace(/\{\{(.*?)\}\}/g,(match,key)=>{
        let arr =key.split('.')
        return arr.reduce((pre,cur)=>{
            return pre[cur.trim()]
        },context)
    })
}

const template = "{{name}}很厉害,才{{age }}岁,就可以帮{{person.father}}做事,{{deep.a.b}}";

const context = { name: "marcKun", age: "22" ,person:{father:'父亲'},deep:{a:{b:'减轻家里负担'}} }

console.log(render(template, context));//marcKun很厉害,才22岁,就可以帮父亲做事,减轻家里负担

续楼上另一直处理方法

function render(template, context) {
  // 使用正则表达式匹配模板字符串中的变量名,并用上下文对象中的对应值替换
  var result = template.replace(/{{(.*?)}}/g, function(match, key) {
    // 使用 eval 函数将变量名转换为上下文对象中对应的值
    try {
      return eval('context.' + key.trim());
    } catch (e) {
      return '';
    }
  });

  return result;
}