python下如何讓web元素的生成更簡(jiǎn)單的分析
更新時(shí)間:2008年07月17日 08:49:52 作者:
做web不簡(jiǎn)單,特別是當(dāng)你需要使用一些web效果的時(shí)候,
比如顯示個(gè)圓角矩形,提示框之類的,也許你認(rèn)為很簡(jiǎn)單,好讓我們分析一下:
1. 引用css。這可能是最常見的做法了,對(duì)一些特定的元素定義特定的樣式。那么使用它,你需要在HTML
頁(yè)面中加入<link>標(biāo)簽。
2. 引入js。許多特效也可以通過(guò)javascript來(lái)進(jìn)行處理,比如動(dòng)態(tài)顯示效果,或?qū)υ剡M(jìn)行封裝。使用
它你需要在HTML頁(yè)面加入<script>標(biāo)簽,必要時(shí)還要加一些javascript代碼。
3. HTML元素。需要設(shè)定一些特殊的屬性,比如class=某個(gè)屬性。這塊還相對(duì)簡(jiǎn)單。
因此從上面的分析可以看出,在通常情況下,加入一個(gè)好看的web元素可能到許多地方的修改。因此我一
直在思考如何讓這個(gè)過(guò)程可以更簡(jiǎn)化,麻煩的地方就是如何處理這些資源,如何讓這些資源可以與原始的
HTML很好的結(jié)合呢?最終我想出的辦法就是:代碼組裝。
對(duì)于css, javascript鏈接和代碼,它們可以按調(diào)用的順序依次拼成一段文本,然后插入到</head>元素前
面。然后對(duì)于html代碼,在模板中直接輸出。對(duì)于css, javascript的鏈接可以檢查是否重復(fù)。
那么如何定義web元素類和如何在模板中對(duì)其進(jìn)行處理?
一個(gè)web元素類定義如下:
class Snippet(object):
css = ''
csslink = ''
jslink = ''
html = ''
js = ''
def render(self):
return ''
def __str__(self):
return self.render()
定義為類屬性的將輸出到HTML的頭部,而render()的結(jié)果將顯示在模板中調(diào)用類的地方。先看一下在模板
中調(diào)用的示例:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>HTML Helper</title>
<script type="text/javascript" src="/static/js/jquery.js"></script>
</head>
<body>
{{
htmlbuf << htmlwidgets.Message('This is a test')
}}
</body>
</html>
這里你可以看到htmlbuf,它是什么,它就是用來(lái)采集每個(gè)Snippet類的類屬性的。這里使用<<來(lái)將一個(gè)
Snippet對(duì)象加到htmlbuf中去。同時(shí)它還會(huì)將Snippet的HTML代碼在調(diào)用位置輸出。
如何輸出?首先uliweb的模板將轉(zhuǎn)為python代碼,它有一個(gè)內(nèi)置的out對(duì)象,可以調(diào)用它的方法來(lái)輸出
HTML代碼。那么htmlbuf對(duì)象將在調(diào)用模板前被創(chuàng)建,在調(diào)用模板后被處理,在創(chuàng)建時(shí)將傳入out的write
屬性。這一切都是在SImpleFrame.py中通過(guò)plugin方法來(lái)實(shí)現(xiàn)的,但是這只是定義了一個(gè)調(diào)用點(diǎn),如:
fname, code = template.render_file(filename, vars, env, dirs)
out = template.Out()
template._prepare_run(vars, env, out)
callplugin(self, 'before_render_template', env, out)
if isinstance(code, (str, unicode)):
code = compile(code, fname, 'exec')
exec code in env, vars
text = out.getvalue()
output = execplugin(self, 'after_render_template', text, vars, env)
before_render_template 會(huì)在調(diào)用模板前被調(diào)用。after_render_template 會(huì)在調(diào)用模板后被調(diào)用。因
此你可以通過(guò)plugin機(jī)制來(lái)加入額外的處理。這是在settings.py中定義的,如:
@plugin('before_render_template')
def before_render_template(sender, env, out):
from uliweb.core import js
from uliweb.core.SimpleFrame import url_for
from uliweb.helpers import htmlwidgets
htmlbuf = js.HtmlBuf(write=out.noescape, static_suffix=url_for('Portal.views.static',
filename=''))
env['htmlbuf'] = htmlbuf
env['htmlwidgets'] = htmlwidgets
這里注入htmlbuf和htmlwidgets到模板的env環(huán)境中,所以可以在模板中直接使用。在htmlwidgets中已經(jīng)
定義了一些Snippet。htmlbuf在創(chuàng)建時(shí),會(huì)使用out.noescape方法,它將不會(huì)對(duì)Snippet中的代碼進(jìn)行轉(zhuǎn)
義。static_suffix表示靜態(tài)文件的前綴,缺省為/static/,這里由于使用了靜態(tài)服務(wù),所以通過(guò)url_for
來(lái)得到靜態(tài)URL前綴。
@plugin('after_render_template')
def after_render_template(sender, text, vars, env):
import re
r_links = re.compile('<link\s.*?\shref\s*=\s*"?(.*?)["\s>]|<script\s.*?\ssrc\s*=\s*"?
(.*?)["\s>]', re.I)
if 'htmlbuf' in env:
htmlbuf = env['htmlbuf']
if htmlbuf.modified:
b = re.search('(?i)</head>', text)
if b:
pos = b.start()
#find links
links = [x or y for x, y in r_links.findall(text[:pos])]
htmlbuf.remove_links(links)
t = htmlbuf.render()
if t:
return ''.join([text[:pos], t, text[pos:]])
else:
return t+text
return text
這里將在模板處理完畢后查找生成的HTML文本中的</head>標(biāo)簽,然后將相應(yīng)的信息插入到它的前面。同
時(shí)這里增加了對(duì)原HTML中已經(jīng)存在的鏈接進(jìn)行了判斷,如果存在則刪除之,這是通過(guò)remove_links來(lái)處理
的。
經(jīng)過(guò)這些的處理,你只要定義一個(gè)Snippet,Uliweb將自動(dòng)為你處理css, js的鏈接包括代碼,和HTML代碼
的生成。因此你就可以簡(jiǎn)單的:
{{
htmlbuf << htmlwidgets.Message('This is a test')
}}
來(lái)生成一個(gè)消息的提示信息。
我會(huì)慢慢擴(kuò)展這個(gè)htmlwidgets庫(kù)。
再簡(jiǎn)單描述一下如何配置:
1. 在settings.py中
INSTALLED_APPS = ['Documents', 'Examples', 'Portal', 'Post',
'uliweb.builtins.auth', 'uliweb.helpers.htmlwidgets']
這里要加入'uliweb.helpers.htmlwidgets',讓static目錄生效
2. 加入:
@plugin('before_render_template')
def before_render_template(sender, env, out):
和
@plugin('after_render_template')
def after_render_template(sender, text, vars, env):
3. 可以使用了。
頁(yè)面中加入<link>標(biāo)簽。
2. 引入js。許多特效也可以通過(guò)javascript來(lái)進(jìn)行處理,比如動(dòng)態(tài)顯示效果,或?qū)υ剡M(jìn)行封裝。使用
它你需要在HTML頁(yè)面加入<script>標(biāo)簽,必要時(shí)還要加一些javascript代碼。
3. HTML元素。需要設(shè)定一些特殊的屬性,比如class=某個(gè)屬性。這塊還相對(duì)簡(jiǎn)單。
因此從上面的分析可以看出,在通常情況下,加入一個(gè)好看的web元素可能到許多地方的修改。因此我一
直在思考如何讓這個(gè)過(guò)程可以更簡(jiǎn)化,麻煩的地方就是如何處理這些資源,如何讓這些資源可以與原始的
HTML很好的結(jié)合呢?最終我想出的辦法就是:代碼組裝。
對(duì)于css, javascript鏈接和代碼,它們可以按調(diào)用的順序依次拼成一段文本,然后插入到</head>元素前
面。然后對(duì)于html代碼,在模板中直接輸出。對(duì)于css, javascript的鏈接可以檢查是否重復(fù)。
那么如何定義web元素類和如何在模板中對(duì)其進(jìn)行處理?
一個(gè)web元素類定義如下:
class Snippet(object):
css = ''
csslink = ''
jslink = ''
html = ''
js = ''
def render(self):
return ''
def __str__(self):
return self.render()
定義為類屬性的將輸出到HTML的頭部,而render()的結(jié)果將顯示在模板中調(diào)用類的地方。先看一下在模板
中調(diào)用的示例:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>HTML Helper</title>
<script type="text/javascript" src="/static/js/jquery.js"></script>
</head>
<body>
{{
htmlbuf << htmlwidgets.Message('This is a test')
}}
</body>
</html>
這里你可以看到htmlbuf,它是什么,它就是用來(lái)采集每個(gè)Snippet類的類屬性的。這里使用<<來(lái)將一個(gè)
Snippet對(duì)象加到htmlbuf中去。同時(shí)它還會(huì)將Snippet的HTML代碼在調(diào)用位置輸出。
如何輸出?首先uliweb的模板將轉(zhuǎn)為python代碼,它有一個(gè)內(nèi)置的out對(duì)象,可以調(diào)用它的方法來(lái)輸出
HTML代碼。那么htmlbuf對(duì)象將在調(diào)用模板前被創(chuàng)建,在調(diào)用模板后被處理,在創(chuàng)建時(shí)將傳入out的write
屬性。這一切都是在SImpleFrame.py中通過(guò)plugin方法來(lái)實(shí)現(xiàn)的,但是這只是定義了一個(gè)調(diào)用點(diǎn),如:
fname, code = template.render_file(filename, vars, env, dirs)
out = template.Out()
template._prepare_run(vars, env, out)
callplugin(self, 'before_render_template', env, out)
if isinstance(code, (str, unicode)):
code = compile(code, fname, 'exec')
exec code in env, vars
text = out.getvalue()
output = execplugin(self, 'after_render_template', text, vars, env)
before_render_template 會(huì)在調(diào)用模板前被調(diào)用。after_render_template 會(huì)在調(diào)用模板后被調(diào)用。因
此你可以通過(guò)plugin機(jī)制來(lái)加入額外的處理。這是在settings.py中定義的,如:
@plugin('before_render_template')
def before_render_template(sender, env, out):
from uliweb.core import js
from uliweb.core.SimpleFrame import url_for
from uliweb.helpers import htmlwidgets
htmlbuf = js.HtmlBuf(write=out.noescape, static_suffix=url_for('Portal.views.static',
filename=''))
env['htmlbuf'] = htmlbuf
env['htmlwidgets'] = htmlwidgets
這里注入htmlbuf和htmlwidgets到模板的env環(huán)境中,所以可以在模板中直接使用。在htmlwidgets中已經(jīng)
定義了一些Snippet。htmlbuf在創(chuàng)建時(shí),會(huì)使用out.noescape方法,它將不會(huì)對(duì)Snippet中的代碼進(jìn)行轉(zhuǎn)
義。static_suffix表示靜態(tài)文件的前綴,缺省為/static/,這里由于使用了靜態(tài)服務(wù),所以通過(guò)url_for
來(lái)得到靜態(tài)URL前綴。
@plugin('after_render_template')
def after_render_template(sender, text, vars, env):
import re
r_links = re.compile('<link\s.*?\shref\s*=\s*"?(.*?)["\s>]|<script\s.*?\ssrc\s*=\s*"?
(.*?)["\s>]', re.I)
if 'htmlbuf' in env:
htmlbuf = env['htmlbuf']
if htmlbuf.modified:
b = re.search('(?i)</head>', text)
if b:
pos = b.start()
#find links
links = [x or y for x, y in r_links.findall(text[:pos])]
htmlbuf.remove_links(links)
t = htmlbuf.render()
if t:
return ''.join([text[:pos], t, text[pos:]])
else:
return t+text
return text
這里將在模板處理完畢后查找生成的HTML文本中的</head>標(biāo)簽,然后將相應(yīng)的信息插入到它的前面。同
時(shí)這里增加了對(duì)原HTML中已經(jīng)存在的鏈接進(jìn)行了判斷,如果存在則刪除之,這是通過(guò)remove_links來(lái)處理
的。
經(jīng)過(guò)這些的處理,你只要定義一個(gè)Snippet,Uliweb將自動(dòng)為你處理css, js的鏈接包括代碼,和HTML代碼
的生成。因此你就可以簡(jiǎn)單的:
{{
htmlbuf << htmlwidgets.Message('This is a test')
}}
來(lái)生成一個(gè)消息的提示信息。
我會(huì)慢慢擴(kuò)展這個(gè)htmlwidgets庫(kù)。
再簡(jiǎn)單描述一下如何配置:
1. 在settings.py中
INSTALLED_APPS = ['Documents', 'Examples', 'Portal', 'Post',
'uliweb.builtins.auth', 'uliweb.helpers.htmlwidgets']
這里要加入'uliweb.helpers.htmlwidgets',讓static目錄生效
2. 加入:
@plugin('before_render_template')
def before_render_template(sender, env, out):
和
@plugin('after_render_template')
def after_render_template(sender, text, vars, env):
3. 可以使用了。
相關(guān)文章
Python實(shí)現(xiàn)圖片批量加入水印代碼實(shí)例
這篇文章主要介紹了Python實(shí)現(xiàn)圖片批量加入水印代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11python基礎(chǔ)教程之popen函數(shù)操作其它程序的輸入和輸出示例
popen函數(shù)允許一個(gè)程序?qū)⒘硪粋€(gè)程序作為新進(jìn)程啟動(dòng),并可以傳遞數(shù)據(jù)給它或者通過(guò)它接收數(shù)據(jù),下面使用示例學(xué)習(xí)一下他的使用方法2014-02-02python代碼打印100-999之間的回文數(shù)示例
今天小編就為大家分享一篇python代碼打印100-999之間的回文數(shù)示例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11python實(shí)現(xiàn)求最長(zhǎng)回文子串長(zhǎng)度
最長(zhǎng)回文子串問題:給定一個(gè)字符串,求它的最長(zhǎng)回文子串長(zhǎng)度。如果一個(gè)字符串正著讀和反著讀是一樣的,那它就是回文串。今天我們就來(lái)探討下這個(gè)問題2018-01-01對(duì)numpy Array [: ,] 的取值方法詳解
今天小編就為大家分享一篇對(duì)numpy Array [: ,] 的取值方法詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-07-07基于Python實(shí)現(xiàn)體育彩票選號(hào)器功能代碼實(shí)例
這篇文章主要介紹了基于Python實(shí)現(xiàn)體育彩票選號(hào)器功能代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09python實(shí)現(xiàn)AI聊天機(jī)器人詳解流程
事情是這樣的,最近認(rèn)識(shí)的一位小姐姐有每天早晨看天氣預(yù)報(bào)的習(xí)慣。在我看來(lái),很多人起床第一件事情就是看微信消息,既然這樣,我就勉為其難每天早晨給小姐姐發(fā)送一則天氣預(yù)報(bào)吧2021-11-11