整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          HTML的兩種渲染方法

          eb 服務存在兩種 HTML 渲染方法。

          最早的HTML(web 1.0時代),都是服務器端渲染的,瀏覽器發送請求,服務器端將整個html作為一個完整文檔發送給瀏覽器。最早響應瀏覽器請求的被稱為CGI .

          CGI

          Java語言進入web 開發領域后,首先出現的技術是 servlet,這個技術模仿的是CGI.也是在服務器端渲染好整個HTML文檔,然后反饋給瀏覽器。

          Servlet能夠很好地組織業務邏輯代碼,但是在Java源文件中通過字符串拼接的方式生成動態HTML內容會導致代碼維護困難、可讀性差。于是產生了JSP技術,JSP在靜態HTML內容中嵌入Java代碼,Java代碼被動態執行后生成HTML內容,類似的還有ASP,PHP等技術,這些技術本質上都是服務端渲染好整個HTML文檔,都屬于服務器端渲染。

          web2.0時代 最大的思想革命本質不是前后端分離,而是把網頁當作獨立的應用程序(app)。前后端分離只是實現這一新架構的必然結果。web 2.0 時代最重要的就是ajax技術。

          使用ajax技術后,HTTP GET拿到的不是渲染后的網頁,而是一個由html和Javascript組成的應用, 這個應用以瀏覽器為虛擬機。裝載和顯示數據是app啟動之后的運行邏輯。傳統上應用叫什么?叫Client,也就是前端。于是前后端就這么分離了,瀏覽器變成了應用的運行環境,后端蛻化成了單純的業務邏輯和數據接口。最典型的ajax 應用就是gmail,gmail實質上就是把過去桌面端的email 應用搬到了瀏覽器中。ajax這種技術也就是客戶端渲染。

          、前言

          模板語言由HTML代碼和邏輯控制代碼組成,此處 @PHP 。通過模板語言可以快速的生成預想的HTML頁面。應該算是后端渲染不可缺少的組成部分。

          二、功能介紹

          通過使用學習 tornadobottle 的模板語言,我也效仿著實現可以獨立使用的模板渲染的代碼模塊,模板語法來自 tornadobottle 的語法。可以用來做一些簡單的事情 網頁渲染郵件內容生成 等HTML顯示方面。以下就是簡單的語法使用介紹。

          1. 變量。使用 {{ }} 包裹起來,里面的變量為Python傳入。模板渲染時會將傳入的變量轉換成字符串并填入對應位置。

          # 模板文件內容
          <title>{{my_title}}</title>
          <label>{{ session.name }}</label>
          # py代碼調用  t_html 為上面的內容
          Template(t_html).render(my_title="標題", session = some_obj) 
          

          2. 轉義。默認傳入的數據都會進行HTML轉義,可以使用 {% raw value %} 來將value的內容按原始字符串輸出。

          # 模板文件內容
          <p>{% raw value %} </p>
          # Py調用內容
          Template(t_html).render(my_title="<label>顯示標簽</label>")
          

          3. 條件控制。支持Python的 if,elif,else 。條件代碼需要放在 {% %} 內部,并且在條件結束后需要額外增加 {% end %} ,用于標識條件控制語句塊范圍。

          # 模板文件內容
          {% if a > 1%}
          <label>A大于1</label>
          {% else %}
          <label>A小于或等于1</label>
          {% end %}
          # py調用
          Template(t_html).render(a=1)
          

          4. 循環控制。支持Python的 forwhile 。與條件控制一樣也需要放在 {% %} 內部,并且結束處需要額外增加 {% end %} ,用于標識循環控制語句塊的范圍。

          # 模板文件內容
          {% for i in range(10) %}
            <label>當前序號:{{i+1}}</label>
          {% end %}
          # py調用
          Template(t_html).render()  
          

          5. 變量聲明。如果需要在模板文件內聲明一個變量,方便使用時,可以通過 set 來實現。具體格式為 {% set v = xx %} 。通過 set 聲明的變量在整個模板文件中都可以使用,包括在條件控制和循環控制中作為條件判斷也可以。

          # 模板文件內容
          {% set a = 1 %}
          <label>a的值:{{a}}</label>
          

          三、源碼

          這個模板語言模塊是在 Python2.7 上面開發使用的,如果要在 Python3+ 上使用需要對 strbytes 進行一些處理即可,由于沒有引用任何其他模塊,可以很好地獨立使用。

            1 # -*- coding:utf-8 -*-
            2 
            3 """ 模板語言"""
            4 
            5 # TOKEN相關的定義
            6 TOKEN_S_BRACE = "{"
            7 TOKEN_S_BLOCK = "%"
            8 TOKEN_EXPRESSION_L = "{{"  
            9 TOKEN_EXPRESSION_R = "}}"
           10 TOKEN_BLOCK_L = "{%"
           11 TOKEN_BLOCK_R = "%}"
           12 TOKEN_KEY_SET = "set"
           13 TOKEN_KEY_RAW = "raw"
           14 TOKEN_KEY_IF = "if"
           15 TOKEN_KEY_ELIF = "elif"
           16 TOKEN_KEY_ELSE = "else"
           17 TOKEN_KEY_FOR = "for"
           18 TOKEN_KEY_WHILE = "while"
           19 TOKEN_KEY_END = "end"
           20 TOKEN_KEY_BREAK = "break"
           21 TOKEN_KEY_CONTINUE = "continue"
           22 TOKEN_SPACE = " "
           23 TOKEN_COLON = ":"
           24 # Token標記 {{}} {% %}
           25 TOKEN_FLAG_SET = {TOKEN_S_BRACE, TOKEN_S_BLOCK}
           26 # 簡單的語句
           27 TOKEN_KEY_SET_SIMPLE_EXPRESSION = {TOKEN_KEY_SET, TOKEN_KEY_RAW}
           28 # 前置條件
           29 TOKEN_KEY_PRE_CONDITION = {
           30     # end 必須在if/elif/else/for/while 后面
           31     TOKEN_KEY_END: {TOKEN_KEY_IF, TOKEN_KEY_ELIF, TOKEN_KEY_ELSE, 
           32                     TOKEN_KEY_FOR, TOKEN_KEY_WHILE},
           33     # elif 必須在if 后面
           34     TOKEN_KEY_ELIF: {TOKEN_KEY_IF},
           35     # else 必須在if/elif 后面
           36     TOKEN_KEY_ELSE: {TOKEN_KEY_IF, TOKEN_KEY_ELIF, TOKEN_KEY_FOR, TOKEN_KEY_WHILE},
           37 }
           38 # 循環語句
           39 TOKEN_KEY_LOOP = {TOKEN_KEY_WHILE, TOKEN_KEY_FOR}
           40 # 循環的控制break continue
           41 TOKEN_KEY_LOOP_CTRL = {TOKEN_KEY_BREAK, TOKEN_KEY_CONTINUE}
           42 
           43 class ParseException(Exception):
           44     pass
           45 
           46 class TemplateCode(object):
           47     def __init__(self):
           48         self.codeTrees = {"parent": None, "nodes": []}
           49         self.cursor = self.codeTrees
           50         self.compiled_code = None
           51 
           52     def create_code(self):
           53         """創建一個代碼子塊"""
           54         child_codes = {"parent": self.cursor, "nodes": []}
           55         self.cursor["nodes"].append(child_codes)
           56         self.cursor = child_codes
           57 
           58     def close_code(self):
           59         """ 關閉一個代碼子塊 """
           60         assert self.cursor["parent"] is not None, "overflow"
           61         self.cursor = self.cursor["parent"]
           62 
           63     def append_text(self, text):
           64         """ 添加文本 """
           65         # 排除空行
           66         self.cursor["nodes"].append("_add(%r)" % text)
           67 
           68     def append_express(self, express, raw=False):
           69         """ 表達式 """
           70         if raw:
           71             temp_exp = "_t_exp = _str_(%s)" % express
           72         else:
           73             temp_exp = "_t_exp = _esc_(%s)" % express
           74         self.cursor["nodes"].append(temp_exp)
           75         self.cursor["nodes"].append("_add(_t_exp)")
           76 
           77     def append_statement(self, statement):
           78         """ 語句 """
           79         temp_statement = "%s" % statement
           80         self.cursor["nodes"].append(temp_statement)
           81 
           82     def reset(self):
           83         self.codeTrees = {"parent": None, "nodes": []}
           84         self.cursor = self.codeTrees
           85         self.compiled_code = None
           86 
           87     def build_code(self, filename):
           88         temp_code_buff = []
           89         self.write_buff_with_indent(temp_code_buff, "def _template_render():", 0)
           90         self.write_buff_with_indent(temp_code_buff, "_codes = []", 4)
           91         self.write_buff_with_indent(temp_code_buff, "_add = _codes.append", 4)
           92         self.write_codes(temp_code_buff, self.codeTrees, 4)
           93         self.write_buff_with_indent(temp_code_buff, "return ''.join(_codes)", 4)
           94         temp_code = "".join(temp_code_buff)
           95         self.compiled_code = compile(temp_code,filename, "exec", dont_inherit=True)
           96 
           97     def write_codes(self, code_buff, codes, indent):
           98         for node in codes.get("nodes", []):
           99             if isinstance(node, dict):
          100                 self.write_codes(code_buff, node, indent+4)
          101             else:
          102                 self.write_buff_with_indent(code_buff, node, indent)
          103 
          104     def generate(self, **kwargs):
          105         temp_namespace = {}
          106         temp_namespace['_str_'] = self.to_utf8
          107         temp_namespace['_esc_'] = self.to_safe_utf8
          108         temp_namespace.update(kwargs)
          109         exec(self.compiled_code, temp_namespace)
          110         return temp_namespace['_template_render']()
          111 
          112     @staticmethod
          113     def write_buff_with_indent(code_buff, raw_str, indent):
          114         """"""
          115         temp = (" " * indent) + raw_str + "\n"
          116         code_buff.append(temp)
          117 
          118     @staticmethod
          119     def to_utf8(raw_str):
          120         """ 轉換 """
          121         if isinstance(raw_str, str):
          122             return raw_str
          123         elif isinstance(raw_str, bytes):
          124             return raw_str.decode()
          125         return str(raw_str)
          126 
          127     @staticmethod
          128     def to_safe_utf8(raw_str):
          129         """ 過濾html轉義 """
          130         text = TemplateCode.to_utf8(raw_str)
          131         return text.replace("&", "&").replace("<", "<").replace(">", ">")
          132 class Template(object):
          133     """模板類"""
          134     def __init__(self, input_obj,filename="<string>", **namespace):
          135         """模板初始化"""
          136         self.namespace = {}
          137         self.namespace.update(namespace)
          138         # 將數據丟進去解析生成編譯代碼
          139         self.lexer = TemplateLexer(input_obj, filename)
          140 
          141     def render(self, **kwargs):
          142         """渲染模板 """
          143         temp_name_space = {}
          144         temp_name_space.update(self.namespace)
          145         temp_name_space.update(kwargs)
          146         # 執行渲染
          147         return self.lexer.render(**kwargs)
          148 
          149 class TemplateLexer(object):
          150     """模板語法分析器 """
          151     def __init__(self, input_obb, filename="<string>"):
          152         if hasattr(input_obb, "read"):
          153             self.raw_string = input_obb.read()
          154         else:
          155             self.raw_string = input_obb
          156         self.filename = filename
          157         # 記錄當前的位置
          158         self.pos = 0
          159         # 記錄原始數據的總長度
          160         self.raw_str_len = len(self.raw_string)
          161         # 記錄解析的數據
          162         self.code_data = TemplateCode()
          163         # 開始解析
          164         self.parse_template()
          165 
          166     def match(self, keyword, pos=None):
          167         return self.raw_string.find(keyword, pos if pos is not None else self.pos)
          168 
          169     def cut(self, size=-1):
          170         """剪取數據 size切割數據的大小,-1表示全部"""
          171         if size == -1:
          172             new_pos = self.raw_str_len
          173         else:
          174             new_pos = self.pos + size
          175         s = self.raw_string[self.pos: new_pos]
          176         self.pos = new_pos
          177         return s
          178 
          179     def remaining(self):
          180         """獲取剩余大小 """
          181         return self.raw_str_len - self.pos
          182 
          183     def function_brace(self):
          184         """ 獲取{{  / {% """
          185         skip_index = self.pos
          186         while True:
          187             index = self.match(TOKEN_S_BRACE, skip_index)  # {% {{
          188             # 沒找到
          189             if index == -1:
          190                 return None, -1
          191             # 末尾
          192             if index >= self.raw_str_len:
          193                 return None, -1
          194             # 匹配類型
          195             next_value = self.raw_string[index + 1:index + 2]
          196             if next_value not in TOKEN_FLAG_SET:
          197                 skip_index = index + 1
          198                 # 說明不是關鍵類型
          199                 continue
          200             brace = self.raw_string[index: index + 2]
          201             return brace, index
          202         return None, -1
          203 
          204     def read_content_with_token(self, index, begin_token, end_token):
          205         """
          206         讀取匹配token的內容
          207         """
          208         end_index = self.match(end_token)
          209         if end_index == -1:
          210             return ParseException("{0} missing end token {1}".format(begin_token, end_token))
          211         # 過濾 begin_token
          212         self.pos = index + len(begin_token)
          213         content = self.cut(end_index - self.pos)
          214         # 去除末尾 end_token
          215         self.cut(len(end_token))
          216         return content
          217 
          218     def add_simple_block_statement(self, operator, suffix):
          219         if not suffix:
          220             raise ParseException("{0} missing content".format(operator))
          221         if operator == TOKEN_KEY_SET:
          222             self.code_data.append_statement(suffix)
          223         elif operator == TOKEN_KEY_RAW:
          224             self.code_data.append_express(suffix, True)
          225         else:
          226             raise ParseException("{0} is undefined".format(operator))
          227 
          228     def parse_template(self):
          229         """解析模板 """
          230         # TODO 檢查模板文件是否更改過,如果沒有則不需要重新解析
          231         self.code_data.reset()
          232         # 解析模板原文件
          233         self.__parse()
          234         # 生成編譯code
          235         self.__compiled_code()
          236 
          237     def render(self, **kwargs):
          238         return self.code_data.generate(**kwargs)
          239 
          240     def __parse(self, control_operator=None, in_loop=False):
          241         """開始解析"""
          242         while True:
          243             if self.remaining() <= 0:
          244                 if control_operator or in_loop:
          245                     raise ParseException("%s missing {%% end %%}" % control_operator)
          246                 break
          247             # 讀取 {{ {%
          248             brace, index = self.function_brace()
          249             # 說明沒有找到
          250             if not brace:
          251                 text = self.cut(index)
          252                 self.code_data.append_text(text)
          253                 continue
          254             else:
          255                 text = self.cut(index - self.pos)
          256                 if text:
          257                     self.code_data.append_text(text)
          258 
          259             if brace == TOKEN_EXPRESSION_L:
          260                 content = self.read_content_with_token(index, TOKEN_EXPRESSION_L, TOKEN_EXPRESSION_R).strip()
          261                 if not content:
          262                     raise ParseException("Empty Express")
          263                 self.code_data.append_express(content)
          264                 continue
          265             elif brace == TOKEN_BLOCK_L:
          266                 content = self.read_content_with_token(index, TOKEN_BLOCK_L, TOKEN_BLOCK_R).strip()
          267                 if not content:
          268                     raise ParseException("Empty block")
          269 
          270                 # 得到表達式 for x in x ;  if x ;  elif x ;  else ;  end ;  set ;  while x ;
          271                 operator, _, suffix = content.partition(TOKEN_SPACE)
          272                 if not operator:
          273                     raise ParseException("block missing operator")
          274 
          275                 suffix = suffix.strip()
          276                 # 簡單語句,set / raw
          277                 if operator in TOKEN_KEY_SET_SIMPLE_EXPRESSION:
          278                     self.add_simple_block_statement(operator, suffix)
          279                 elif operator in TOKEN_KEY_LOOP_CTRL:
          280                     if not in_loop:
          281                         raise ParseException("{0} must in loop block".format(operator))
          282                     self.code_data.append_statement(operator)
          283                 else:
          284                     # 控制語句 檢查匹配if 后面可以跟elif/else
          285                     pre_condition = TOKEN_KEY_PRE_CONDITION.get(operator, None)
          286                     if pre_condition:
          287                         # 里面就是elif/else/end
          288                         if control_operator not in pre_condition:
          289                             raise ParseException("{0} must behind with {1}".format(operator, pre_condition))
          290                         elif operator == TOKEN_KEY_END:
          291                             # 遇到{% end %}則結束
          292                             self.code_data.close_code()
          293                             return
          294                         else:
          295                             # 由于是依據if 進入 來計算elif ,因此elif與if是同級的
          296                             self.code_data.close_code()
          297                             self.code_data.append_statement(content + TOKEN_COLON)
          298                             self.code_data.create_code()
          299                             self.__parse(operator, in_loop or (operator in TOKEN_KEY_LOOP))
          300                             break
          301                     # 添加控制語句及內部語句體 if for while
          302                     self.code_data.append_statement(content + TOKEN_COLON)
          303                     self.code_data.create_code()
          304                     self.__parse(operator, in_loop or (operator in TOKEN_KEY_LOOP))
          305             else:
          306                 raise ParseException("Unkown brace")
          307         return
          308 
          309     def __compiled_code(self):
          310         """生成 編譯code """
          311         self.code_data.build_code(self.filename)
          312 if __name__ == "__main__":
          313         t = Template("<html>{{hello}}</html>")
          314         t.render(hello="你好"

          原文鏈接:
          http://www.cnblogs.com/jeffxun/p/15585073.html

          今天為大家帶來的是一個用于在微信小程序中渲染html和Markdown的富文本組件,而且支持代碼高亮,它就是html2wxml!






          Github

          https://github.com/qwqoffice/html2wxml

          三種版本介紹

          • 插件版本準備

          1、打開小程序管理后臺,轉到設置 - 第三方服務,點擊添加插件



          2、搜索 html2wxml ,選中并添加


          3、添加成功


          4、回到小程序開發環境,編輯 app.json ,添加插件聲明,最新版為 1.3.0

          "plugins": {
           	"htmltowxml": {
           		"version": "1.3.0",
           		"provider": "wxa51b9c855ae38f3c"
           	}
           }

          5、在對應頁面的 json 文件,比如首頁 index.json,添加使用插件組件的聲明

           "usingComponents": {
           	"htmltowxml": "plugin://htmltowxml/view"
           }
          • 組件版本準備

          1、復制整個 html2wxml-component 文件夾到小程序目錄

          2、在對應頁面的 json 文件,比如首頁 index.json,添加使用組件的聲明,注意路徑

           "usingComponents": {
           	"htmltowxml": "path/to/html2wxml-component/html2wxml"
           } 
          • 模板版本準備

          1、復制整個 html2wxml-template 文件夾到小程序目錄

          2、在對應頁面的 js 文件,比如首頁 index.js,添加引用聲明,并使用html2wxml方法進行數據綁定,注意路徑,參數分別為綁定的數據名、已解析的富文本數據、當前頁面對象和容器與屏幕邊緣的單邊的距離

           var html2wxml = require('path/to/html2wxml-template/html2wxml.js');
           html2wxml.html2wxml('article', res.data, this, 5);

          3、在對應頁面的 wxml 文件,比如首頁 index.wxml,添加引用模板的聲明,并使用模板,注意路徑和綁定的數據名

           <import src="path/to/html2wxml-template/html2wxml.wxml" />
           <template is="html2wxml" data="{{wxmlData:article}}" />

          4、在對應頁面的 wxss 文件,比如首頁 index.wxss或app.wxss, 引入樣式表和你喜歡的代碼高亮樣式,注意路徑

          @import "path/to/html2wxml-template/html2wxml.wxss";
          @import "path/to/html2wxml-template/highlight-styles/darcula.wxss";

          組件使用


          • 示例
          // 將Page中的content數據作為HTML格式渲染
          <htmltowxml text="{{content}}" bindWxmlTagATap="wxmlTagATap" ></htmltowxml>
          
          // 禁用代碼高亮功能
          <htmltowxml text="{{content}}" highlight="{{false}}" bindWxmlTagATap="wxmlTagATap" ></htmltowxml>
          
          // 禁用代碼行號顯示功能
          <htmltowxml text="{{content}}" linenums="{{false}}" bindWxmlTagATap="wxmlTagATap" ></htmltowxml>
          
          // 代碼高亮樣式改為tomorrow
          <htmltowxml text="{{content}}" highlightStyle="tomorrow" bindWxmlTagATap="wxmlTagATap" ></htmltowxml>
          
          // 設置代碼高亮檢測語言 (最多6個,自行搭建服務不受限制)
          <htmltowxml text="{{content}}" highlightLanguages="{{['html','js','php','css','cpp','ruby']}}" bindWxmlTagATap="wxmlTagATap" ></htmltowxml>
          
          // 對HTML數據中的img標簽的相對路徑補全域名
          <htmltowxml text="{{content}}" imghost="https://www.qwqoffice.com" bindWxmlTagATap="wxmlTagATap" ></htmltowxml>
          
          // 禁用加載中動畫
          <htmltowxml text="{{content}}" showLoading="{{false}}" bindWxmlTagATap="wxmlTagATap" ></htmltowxml>
          
          // 將Page中的text數據作為Markdown格式渲染
          <htmltowxml text="{{text}}" type="md" bindWxmlTagATap="wxmlTagATap" ></htmltowxml>
          
          // 直接渲染Page中的已經過解析的obj數據
          <htmltowxml json="{{obj}}" bindWxmlTagATap="wxmlTagATap" ></htmltowxml>
          • 服務端用法

          富文本的解析默認是由QwqOffice完成,存在不穩定因素,你可以自行搭建解析服務或將解析組件引入到你的項目中。

          1、復制整個 html2wxml-php 文件夾到項目目錄中

          2、引入類文件class.ToWXML.php

           include( 'path/to/html2wxml-php/class.ToWXML.php' );

          3、實例化html2wxml,進行解析并輸出,示例:

           $towxml = new ToWXML();
           $json = $towxml->towxml( '<h1>H1標題</h1>', array(
           	'type' => 'html',
           	'highlight' => true,
           	'linenums' => true,
           	'imghost' => null,
           	'encode' => false,
           	'highlight_languages' => array( 'html', 'js', 'php', 'css' )
           ) );
           echo json_encode( $json, JSON_UNESCAPED_UNICODE );


          可用的代碼高亮語言


          主站蜘蛛池模板: 亚洲熟妇无码一区二区三区导航| 色婷婷香蕉在线一区二区| 精品久久国产一区二区三区香蕉| AV无码精品一区二区三区宅噜噜| 日韩精品无码免费一区二区三区 | 国产精品无码一区二区三区毛片 | 久久精品国产一区二区电影| 精品三级AV无码一区| 精品人体无码一区二区三区| 理论亚洲区美一区二区三区| 日韩精品区一区二区三VR| 国产品无码一区二区三区在线蜜桃 | 视频一区视频二区制服丝袜| 亚洲熟妇AV一区二区三区宅男| 无码少妇一区二区三区浪潮AV| 国产免费一区二区三区免费视频 | 一区二区乱子伦在线播放| 日本一区视频在线播放| 国内精品一区二区三区在线观看| 国产福利一区二区三区视频在线| 无码国产精品一区二区免费式芒果| 国偷自产Av一区二区三区吞精 | 亚洲一区二区三区免费视频 | 午夜爽爽性刺激一区二区视频| 亚洲国产一区二区三区青草影视 | 国产探花在线精品一区二区| 一区二区三区杨幂在线观看| 免费一区二区视频| 日韩十八禁一区二区久久| 全国精品一区二区在线观看| 亚洲片国产一区一级在线观看| 日本在线观看一区二区三区| 国产精品无码不卡一区二区三区| 一区二区三区电影在线观看| 精品一区二区无码AV| 国产AV一区二区三区无码野战| 人妻无码第一区二区三区| 无码人妻AⅤ一区二区三区| 精品无码国产一区二区三区AV| 亚洲综合一区无码精品| 日本精品一区二区在线播放|