Heim  >  Artikel  >  Web-Frontend  >  Was ist ein Frontend-Template? Einführung in die Prinzipien und Beispiele von Frontend-Vorlagen

Was ist ein Frontend-Template? Einführung in die Prinzipien und Beispiele von Frontend-Vorlagen

不言
不言Original
2018-09-04 10:35:226686Durchsuche

Was ist ein Frontend-Template? Wie implementiert man eine Frontend-Vorlage? Viele Freunde wissen möglicherweise nicht viel darüber, daher werden Ihnen im folgenden Artikel die Prinzipien von Front-End-Vorlagen und einfachen Implementierungscodes vorgestellt.

Die Entwicklung von Front-End-Vorlagen

Vorlage kann als eines der am häufigsten verwendeten Tools in der Front-End-Entwicklung bezeichnet werden. Extrahieren Sie den festen Inhalt der Seite in eine Vorlage, füllen Sie die vom Server zurückgegebenen dynamischen Daten in die reservierten Felder der Vorlage, fügen Sie sie schließlich zu einer vollständigen HTML-Zeichenfolge der Seite zusammen und übergeben Sie sie zum Parsen an den Browser.

Vorlagen können die Entwicklungseffizienz erheblich verbessern. Ohne Vorlagen müssen Entwickler Zeichenfolgen möglicherweise manuell buchstabieren.

var tpl = &#39;<p>&#39; + user.name + &#39;</p>&#39;;
$(&#39;body&#39;).append(tpl);

Im Prozess der Frontend-Entwicklung haben sich in den letzten Jahren auch Vorlagen geändert:

1. PHP-Vorlage JSP-Vorlage

In der Anfangszeit gab es noch keine Ära der Trennung von Front-End und Back-End. Das Front-End war nur ein Ordner im Back-End-Projekt. In dieser Zeit stellten sowohl PHP als auch Java ihre eigenen bereit Template-Engines. Nehmen Sie JSP als Beispiel: Die Seiten von Java-Webanwendungen sind normalerweise .jsp-Dateien, und einige Vorlagen haben ihre eigene Syntax. Es handelt sich im Wesentlichen um einfachen Text, es handelt sich jedoch weder um HTML noch um Java.

JSP-Syntax: index.jsp

<html>
<head><title>Hello World</title></head>
<body>
Hello World!<br/>
<%
out.println("Your IP address is " + request.getRemoteAddr());
%>
</body>
</html>

Die Template-Engines dieser Zeit verwendeten häufig den -Server, um Template-Strings zu kompilieren und HTML-Strings für den Client zu generieren.

2. Lenkerschnurrbart-Universalvorlage

Node wurde 2009 veröffentlicht. JavaScript kann auch serverseitige Funktionen implementieren, was Entwicklern ebenfalls erheblich erleichtert. Die Geburt von Schnurrbart- und Lenkervorlagen hat es Frontend-Entwicklern erleichtert, beide Vorlagen mit JavaScript zu implementieren. Von nun an kann diese Frontend-Vorlage sowohl auf dem Server als auch auf dem Client ausgeführt werden , aber die meisten verwenden Szenario Alle js werden basierend auf den asynchron vom Server erhaltenen Daten in die Vorlage eingefügt, um einen neuen Dom zum Einfügen der Seitenzahl zu generieren. Es ist sowohl für die Front-End- als auch für die Back-End-Entwicklung von großem Nutzen.

Mustache-Syntax: index.mustache

<p>Username: {{user.name}}</p>
{{#if (user.gender === 2)}}
    <p>女</p>
{{/if}}

3. Vorlage in vue JSX in React

Als nächstes kommt die neue Generation, die Vorlage Die Schreibmethode in Vue unterscheidet sich von den vorherigen Vorlagen und ist leistungsfähiger. Es kann sowohl auf dem Client als auch auf dem Server verwendet werden, die Verwendungsszenarien sind jedoch sehr unterschiedlich: Die Seite ändert sich häufig entsprechend den Daten und das durch die Vorlage generierte DOM ändert sich, was eine hohe Leistung der Vorlage erfordert.

vue-Syntax: index.vue

<p>Username: {{user.name}}</p>
<template v-if="user.gender === 2">
    <p>女</p>
</div>

Durch Vorlagen implementierte Funktion

Ob von JSP bis zu Vue-Vorlagen, Vorlagen werden in der Syntax immer komfortabler und immer komfortabler Weitere Funktionen Reichhaltig, aber grundlegende Funktionen sind unverzichtbar:

  1. Variablenausgabe (escaped/unescaped): Aus Sicherheitsgründen maskieren Vorlagen grundsätzlich die Zeichenfolgen von Variablen und geben sie standardmäßig aus. Implementiert natürlich auch die Funktion der Ausgabe ohne Escapezeichen. Verwenden Sie sie daher mit Vorsicht.

  2. Bedingte Beurteilung (falls vorhanden): eine Funktion, die häufig in der Entwicklung benötigt wird.

  3. Schleifenvariable: Durchläuft das Array und erzeugt viele wiederholte Codeausschnitte.

  4. Vorlagenverschachtelung: Mit der Vorlagenverschachtelung können Sie viel doppelten Code reduzieren und verschachtelte Vorlagen integrieren Bereiche.

Die oben genannten Funktionen decken im Wesentlichen die Grundfunktionen der meisten Vorlagen ab. Für diese Grundfunktionen können Sie erkunden, wie die Vorlage implementiert wird.

Prinzip der Vorlagenimplementierung

Wie der Titel schon sagt, sind Vorlagen im Wesentlichen reine Textzeichenfolgen. Wie funktionieren Zeichenfolgen in JS-Programmen?

Vorlagenverwendung:

var domString = template(templateString, data);

Die Vorlagen-Engine ruft die Vorlagenzeichenfolge und den Umfang der Vorlage ab und generiert nach der Kompilierung eine vollständige DOM-Zeichenfolge.

Die meisten Vorlagenimplementierungsprinzipien sind grundsätzlich gleich:

Die Vorlagenzeichenfolge trennt zunächst die gewöhnliche Zeichenfolge und die Vorlagensyntaxzeichenfolge auf verschiedene Weise, um einen abstrakten Syntaxbaum AST zu generieren Syntaxfragmente Während der Kompilierung werden die Vorlagenvariablen in den von der Engine eingegebenen Variablen durchsucht. Das Vorlagensyntaxfragment generiert ein gewöhnliches HTML-Fragment, das zur Ausgabe mit der ursprünglichen gewöhnlichen Zeichenfolge gespleißt wird.

Tatsächlich ist die Vorlagenkompilierungslogik nicht besonders kompliziert. Bei Vorlagen wie Vue, die Daten dynamisch binden, können Sie auf den Link am Ende des Artikels verweisen, wenn Sie Zeit haben.

Schnell eine einfache Vorlage implementieren

Nehmen Sie nun die Schnurrbart-Vorlage als Beispiel, um manuell eine Vorlage zu implementieren, die Grundfunktionen implementiert.

Template-String-Vorlage: index.txt

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>Page Title</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" type="text/css" media="screen" href="main.css" />
  <script src="main.js"></script>
</head>
<body>
  <h1>Panda模板编译</h1>
  <h2>普通变量输出</h2>
  <p>username: {{common.username}}</p>
  <p>escape:{{common.escape}}</p>
  <h2>不转义输出</h2>
  <p>unescape:{{&common.escape}}</p>
  <h2>列表输出:</h2>
  <ul>
  {{#each list}}
    <li class="{{value}}">{{key}}</li>
  {{/each}}
  </ul>
  <h2>条件输出:</h2>
  {{#if shouldEscape}}
    <p>escape{{common.escape}}</p>
  {{else}}
    <p>unescape:{{&common.escape}}</p>
  {{/if}}
</body>
</html>

Template-entsprechende Daten:

module.exports = {
  common: {
    username: &#39;Aus&#39;,
    escape: &#39;<p>Aus</p>&#39;
  },
  shouldEscape: false,
  list: [
    {key: &#39;a&#39;, value: 1},
    {key: &#39;b&#39;, value: 2},
    {key: &#39;c&#39;, value: 3},
    {key: &#39;d&#39;, value: 4}
  ]
};

So verwenden Sie die Vorlage:

var fs = require("fs");
var tpl = fs.readFileSync(&#39;./index.txt&#39;, &#39;utf8&#39;);
var state = require(&#39;./test&#39;);
var Panda = require(&#39;./panda&#39;);

Panda.render(tpl, state)

Dann implementieren Sie die Vorlage:

1. Regulär ausgeschnittene Zeichenfolgen

Nachdem die Vorlagen-Engine die Vorlagenzeichenfolge erhalten hat, verwendet sie normalerweise reguläre ausgeschnittene Zeichenfolgen, um zwischen statischen Zeichenfolgen und zu kompilierenden Zeichenfolgen zu unterscheiden Syntaxbaum (AST).

// 将未处理过的字符串进行分词,形成字符组tokens
Panda.prototype.parse = function (tpl) {
  var tokens = [];
  var tplStart = 0;
  var tagStart = 0;
  var tagEnd = 0;

  while (tagStart >= 0) {
    tagStart = tpl.indexOf(openTag, tplStart);
    if (tagStart < 0) break;
    // 纯文本
    tokens.push(new Token(&#39;text&#39;, tpl.slice(tplStart, tagStart)));

    tagEnd = tpl.indexOf(closeTag, tagStart) + 2;
    if (tagEnd < 0) throw new Error(&#39;{{}}标签未闭合&#39;);
    // 细分js

    var tplValue = tpl.slice(tagStart + 2, tagEnd - 2);
    var token = this.classifyJs(tplValue);
    tokens.push(token);

    tplStart = tagEnd;
  }

  // 最后一段
  tokens.push(new Token(&#39;text&#39;, tpl.slice(tagEnd, tpl.length)));

  return this.parseJs(tokens);
};

Dieser Schritt des Aufteilens von Zeichenfolgen erfolgt normalerweise mithilfe regulärer Ausdrücke. Beim späteren Abrufen von Zeichenfolgen werden häufig reguläre Methoden verwendet.

In diesem Schritt können Sie normalerweise überprüfen, ob das Vorlagen-Tag abnormal geschlossen wurde, und einen Fehler melden.

2. Klassifizierung der Vorlagensyntax

Nach der Generierung von AST müssen normale Zeichenfolgen nicht mehr verwaltet werden und werden am Ende direkt ausgegeben, wobei der Schwerpunkt auf der Klassifizierung der Vorlagensyntax liegt.

// 专门处理模板中的js
Panda.prototype.parseJs = function (tokens) {
  var sections = [];
  var nestedTokens = [];
  var conditionsArray = [];
  var collector = nestedTokens;
  var section;
  var currentCondition;

  for (var i = 0; i < tokens.length; i++) {
    var token = tokens[i];
    var value = token.value;
    var symbol = token.type;

    switch (symbol) {
      case &#39;#&#39;: {
        collector.push(token);
        sections.push(token);

        if(token.action === &#39;each&#39;){
          collector = token.children = [];
        } else if (token.action === &#39;if&#39;) {
          currentCondition = value;
          var conditionArray;
          collector = conditionArray = [];
          token.conditions = token.conditions || conditionsArray;

          conditionsArray.push({
            condition: currentCondition,
            collector: collector
          });
        }
        break;
      }
      case &#39;else&#39;: {
        if(sections.length === 0 || sections[sections.length - 1].action !== &#39;if&#39;) {
          throw new Error(&#39;else 使用错误&#39;);
        }

        currentCondition = value;
        collector = [];

        conditionsArray.push({
          condition: currentCondition,
          collector: collector
        });

        break;
      }
      case &#39;/&#39;: {
        section = sections.pop();

        if (section && section.action !== token.value) {
          throw new Error(&#39;指令标签未闭合&#39;);
        }

        if(sections.length > 0){
          var lastSection = sections[sections.length - 1];
          if(lastSection.action === &#39;each&#39;){
            collector = lastSection.chidlren;
          } else if (lastSection.action = &#39;if&#39;) {
            conditionsArray = [];
            collector = nestedTokens;
          }
        } else {
          collector = nestedTokens;
        }

        break;
      }
      default: {
        collector.push(token);
        break;
      }
    }
  }

  return nestedTokens;
}

Im vorherigen Schritt haben wir einen AST generiert. Dieser AST ist hier ein Array von Wortsegmentierungstokens:

[
    Token {},
    Token {},
    Token {},
]

Dieses Token ist jede Zeichenfolge, die den Tokentyp, die Aktion und aufzeichnet Unter-Token bzw. Bedingungs-Token und andere Informationen.

/**
 * token类表示每个分词的标准数据结构
 */
function Token (type, value, action, children, conditions) {
  this.type = type;
  this.value = value;

  this.action = action;
  this.children = children;
  this.conditions = conditions;
}

在这一步要将循环方法中的子token嵌套到对应的token中,以及条件渲染子token嵌套到对应token中。

这步完成之后,一个标准的带有嵌套关系的AST完成了。

3. 变量查找与赋值

现在开始根据token中的变量查找到对应的值,根据相应功能生成值得字符串。

/**
 * 解析数据结构的类
 */
function Context (data, parentContext) {
  this.data = data;
  this.cache = { '.': this.data };
  this.parent = parentContext;
}

Context.prototype.push = function (data) {
  return new Context(data, this);
}

// 根据字符串name找到真实的变量值
Context.prototype.lookup = function lookup (name) {
  name = trim(name);

  var cache = this.cache;

  var value;
  // 查询过缓存
  if (cache.hasOwnProperty(name)) {
    value = cache[name];
  } else {
    var context = this, names, index, lookupHit = false;

    while (context) {
      // user.username
      if (name.indexOf('.') > 0) {
        value = context.data;
        names = name.split('.');
        index = 0;

        while (value != null && index < names.length) {
          if (index === names.length - 1) {
            lookupHit = hasProperty(value, names[index]);
          }

          value = value[names[index++]];
        }
      } else {
        value = context.data[name];
        lookupHit = hasProperty(context.data, name);
      }

      if (lookupHit) {
        break;
      }

      context = context.parent;
    }

    cache[name] = value;
  }

  return value;
}

为了提高查找效率,采用缓存代理,每次查找到的变量存储路径方便下次快速查找。

不同于JavaScript编译器,模板引擎在查找变量的时候找不到对应变量即终止查找,返回空并不会报错。

4. 节点的条件渲染与嵌套

这里开始讲模板语法token和普通字符串token开始统一编译生成字符串,并拼接成完整的字符串。

// 根据tokens和context混合拼接字符串输出结果
Panda.prototype.renderTokens = function (tokens, context) {
  var result = '';
  var token, symbol, value;

  for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
    value = undefined;
    token = tokens[i];
    symbol = token.type;

    if (symbol === '#') value = this.renderSection(token, context);
    else if (symbol === '&') value = this.unescapedValue(token, context);
    else if (symbol === '=') value = this.escapedValue(token, context);
    else if (symbol === 'text') value = this.rawValue(token);

    if (value !== undefined) result += value;
  }

  return result;
}

5. 绘制页面

页面字符串已经解析完成,可以直接输出:

Panda.prototype.render = function (tpl, state) {
  if (typeof tpl !== 'string') {
    return new Error('请输入字符串!');
  }

  // 解析字符串
  var tokens = this.cache[tpl] ? tokens : this.parse(tpl);
  // 解析数据结构
  var context = state instanceof Context ? state : new Context(state);
  // 渲染模板
  return this.renderTokens(tokens, context);
};

输出页面字符串被浏览器解析,就出现了页面。

以上只是简单的模板实现,并没有经过系统测试,仅供学习使用,源码传送门。成熟的模板引擎是有完整的异常处理,变量查找解析,作用域替换,优化渲染,断点调试等功能的。

总结

前端模板这块能做的东西还很多,很多框架都是集成模板的功能,配合css,js等混合编译生成解析好样式和绑定成功事件的dom。

另外实现模板的方式也有很多,本文的实现方式参考了mustache源码,模板标签内的代码被解析,但是是通过代码片段分类,变量查找的方式来执行的,将纯字符串的代码变成了被解释器执行的代码。

另外向vue这种可以实现双向绑定的模板可以抽空多看一看。

相关推荐:

javascript - 大家前端js模板是用underscore还是handlebars呢?

学习前端模板引擎 jade (一)_html/css_WEB-ITnose

Das obige ist der detaillierte Inhalt vonWas ist ein Frontend-Template? Einführung in die Prinzipien und Beispiele von Frontend-Vorlagen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn