原作者:http://www.thinksaas.cn/group/topic/399775/
这是源于两年前,当我在做人生中第一个真正意义上的网站时遇到的一个问题
该网站采用前后端分离的方式,由后端的 REST 接口返回 JSON 数据,再由前端渲染到页面上。
同许多初学 Javascript 的菜鸟一样,起初,我也是采用拼接字符串的形式,将 JSON 数据嵌入 HTML 中。开始时代码量较少,暂时还可以接受。但当页面结构复杂起来后,其弱点开始变得无法忍受起来:
-
书写不连贯。每写一个变量就要断一下,插入一个
+
和"
。十分容易出错。 -
无法重用。HTML 片段都是离散化的数据,难以对其中重复的部分进行提取。
-
无法很好地利用
<template>
标签。这是 HTML5 中新增的一个标签,标准极力推荐将 HTML 模板放入<template>
标签中,使代码更简洁。
当时我的心情就是这样的:
为了解决这个问题,我暂时放下了手上的项目,花了半个小时实现一个极简易的字符串模板。
需求描述
实现一个render(template, context)
方法,将template
中的占位符用context
填充。要求:
-
不需要有控制流成分(如 循环、条件 等等),只要有变量替换功能即可
-
级联的变量也可以展开
-
被转义的的分隔符
{
和}
不应该被渲染,分隔符与变量之间允许有空白字符
例子:
render('My name is {name}', {
name: 'hsfzxjy'
}); // My name is hsfzxjy
render('I am in {profile.location}', {
name: 'hsfzxjy',
profile: {
location: 'Guangzhou'
}
}); // I am in Guangzhou
render('{ greeting }. \{ This block will not be rendered }', {
greeting: 'Hi'
}); // Hi. { This block will not be rendered }
实现
先写下函数的框架:
function render(template, context) {
}
显然,要做的第一件事便是匹配模板中的占位符。
匹配占位符
匹配的事,肯定是交给正则表达式来完成。那么,这个正则表达式应该长什么样呢?
根据 需求 1、2 的描述,我们可以写出:
var reg = /{([^{}]+)}/g;
至于需求 3,我第一个想到的概念是 前向匹配,可惜 Javascript 并不支持,只好用一个折衷的办法:
var reg = /(\)?{([^{}\]+)(\)?}/g;
// 若是第一个或第三个分组值不为空,则不渲染
现在,代码应该是这样:
function render(template, context) {
var tokenReg = /(\)?{([^{}\]+)(\)?}/g;
return template.replace(tokenReg, function (word, slash1, token, slash2) {
if (slash1 || slash2) { // 匹配到转义字符
return word.replace('\', ''); // 如果 分隔符被转义,则不渲染
}
// ...
})
}
占位符替换
嗯,正则表达式确定了,接下来要做的便是替换工作。
根据 需求2,模板引擎不仅要能渲染一级变量,更要渲染多级变量。这该怎么做呢?
其实很简单:将token
按.
分隔开,逐级查找即可:
var variables = token.replace(/s/g, '').split('.'); // 切割 token
var currentObject = context;
var i, length, variable;
// 逐级查找 context
for (i = 0, length = variables.length, variable = variables[i]; i < length; ++i)
currentObject = currentObject[variable];
return currentObject;
不过,有可能token
指定的变量并不存在,这时上面的代码便会报错。为了更好的体验,代码最好有一定的容错能力:
var variables = token.replace(/s/g, '').split('.'); // 切割 token
var currentObject = context;
var i, length, variable;
for (i = 0, length = variables.length; i < length; ++i) {
variable = variables[i];
currentObject = currentObject[variable];
if (currentObject === undefined || currentObject === null) return ''; // 如果当前索引的对象不存在,则直接返回空字符串。
}
return currentObject;
把所有的代码组合在一起,便得到了最终的版本:
function render(template, context) {
var tokenReg = /(\)?{([^{}\]+)(\)?}/g;
return template.replace(tokenReg, function (word, slash1, token, slash2) {
if (slash1 || slash2) {
return word.replace('\', '');
}
var variables = token.replace(/s/g, '').split('.');
var currentObject = context;
var i, length, variable;
for (i = 0, length = variables.length; i < length; ++i) {
variable = variables[i];
currentObject = currentObject[variable];
if (currentObject === undefined || currentObject === null) return '';
}
return currentObject;
})
}
除去空白行,一共 17 行。
将函数挂到 String 的原型链
甚至,我们可以通过修改原型链,实现一些很酷的效果:
String.prototype.render = function (context) {
return render(this, context);
};
之后,我们便可以这样调用啦:
"{greeting}! My name is { author.name }.".render({
greeting:"Hi",
author: {
name:"hsfzxjy"
}
});
// Hi! My name is hsfzxjy.
相关推荐
1. **预编译**:将模板字符串转换为JavaScript函数,这个函数负责渲染模板。 2. **数据绑定**:将数据对象传递给预编译得到的函数,函数会根据数据填充模板。 3. **渲染**:执行函数,生成最终的HTML字符串。 **...
7. **过滤器(filters)**:Vue中的过滤器允许我们对数据进行格式化,如将数字价格转换为带有货币符号的字符串。`showPrice`过滤器用于格式化总价。 8. **数据(data)**:Vue实例的数据对象,`books`是一个包含...
ES6,也称为 ECMAScript 2015,是 JavaScript 的一个重要更新,引入了许多新特性,如箭头函数、模板字符串、类和模块等。这些特性使得编写更简洁、可读性强的代码成为可能,同时也为创建服务器端模板引擎提供了便利...
我们可能还涉及到了一些JavaScript的高级特性,如闭包、异步操作(如Promise或async/await)、AJAX(Asynchronous JavaScript and XML)用于前后端数据交换,以及可能的ES6语法糖,如箭头函数、模板字符串等。...
这里,`webBrowser1`是WebBrowser控件的实例名,`Navigate()`方法接收一个字符串参数,表示要访问的URL。 **5. 监听导航事件** 我们可以监听WebBrowser控件的导航事件,如`Navigating`和`DocumentCompleted`,以...
10. **ES6及以后的新特性**:包括类(class)、模板字符串、解构赋值、let和const、箭头函数、Promise等,这些都是现代JavaScript开发的必备知识。 此外,"www.pudn.com.txt"可能是提供下载资源或额外信息的文本...
在ES6中,我们可以使用模板字符串、箭头函数、let和const变量声明、类和模块等新特性,使代码更简洁、易读。例如,可以创建一个JavaScript对象表示学生,用数组存储所有学生对象,然后使用数组方法(如push、pop、...
此外,现代浏览器还支持ES6(ECMAScript 2015)等新特性,如箭头函数、模板字符串、类等,提供了更简洁、高效的编程语法。 在压缩包中的"简易个人网站"文件夹中,你可能会找到以下文件: 1. HTML文件(如index.html...
3. **数值处理**:JavaScript提供了处理数学运算的内置对象Math,以及字符串和数字的转换方法,如`parseInt`和`parseFloat`,这些都是计算过程中必不可少的部分。 4. **用户界面更新**:每次计算完成后,需要更新...
**views** 为了简化,我们可以使用字符串模板来模拟视图。在 `views` 文件夹下创建 `templates` 子文件夹,然后创建 `list.html` 模板文件,用于展示演员列表。 **views/templates/list.html** ```html <h1>Actor ...
在这个环境中,我们可以使用MFC库,并通过其向导生成MFC应用程序模板,然后添加自定义代码来实现网页解析功能。 为了实现这个简易网页解析器,开发者可能首先会使用`CInternetSession`和`CHttpFile`类从网络上下载...
传统的方法中,页面模板化常常是通过字符串拼接的方式实现的。例如,使用JavaScript的`+=`操作符或数组的`push`方法来逐步构建HTML字符串,然后将其赋值给页面中的某个元素。这种方法虽简单,但在处理复杂的HTML结构...
这涉及到JavaScript的字符串拼接或模板字符串的使用。 6. 函数封装与模块化:为了代码的可读性和可维护性,源码通常会将不同的功能封装成独立的函数,甚至采用模块化设计,如立即执行函数表达式(IIFE)或ES6的模块...
1. **ES6**:ECMAScript 2015(也称为ES6)是JavaScript语言的一个新版本,引入了许多现代编程特性,如类、模块、箭头函数、模板字符串等。在这个项目中,开发者可能利用了ES6的这些新特性来编写更简洁、可维护的...
在实际使用中,开发者可以通过JsonCpp简易封装库提供的接口,轻松地将C++对象转换成JSON字符串进行网络传输,或者接收JSON数据并解码为C++对象进行本地处理。例如,一个简单的例子可能涉及读取JSON文件,解析成...
在本文中,我们将深入探讨如何使用JavaScript实现一个简易的天数计算器。这个计算器的主要功能包括支持用户选择日期、自动计算闰年以及允许用户选择使用当前日期。以下是对这个实例的详细解析: 首先,HTML文件是...
9. **代码优化**:为了提高代码的可读性和性能,可以使用ES6的语法特性,如箭头函数、模板字符串等,并遵循良好的编码规范。 10. **测试与调试**:编写完成后,务必进行详尽的测试,确保所有功能正常运行。使用...
4. **ES6**:ECMAScript 6(也称为ES2015)是JavaScript语言的一个重要版本,引入了许多新特性,如类、箭头函数、模板字符串、解构赋值等。在这个项目中,开发者使用了ES6的语法糖来编写更简洁、可读性更强的代码,...
在iOS开发中,实现简易天气预报功能是一项常见的需求,尤其对于初学者来说,这是一个很好的实践项目。本教程将介绍如何利用iOS技术栈,包括Objective-C(OC)编程语言、AFNetworking库以及JSON数据解析,来创建一个...