Flask之模板

 前言:本博客仅作记录学习使用,部分图片出自网络,如有侵犯您的权益,请联系删除 

目录

一、模板的基本用法

1.1、创建模板

1.2、模板语法

1.3、渲染模板

二、模板辅助工具

2.1、上下文

2.2、全局对象

2.3、过滤器

2.4、测试器

2.5、模板环境对象

三、模板组织结构

3.1、局部模板

3.2、宏

3.3、模板继承

四、模板进阶实践

4.1、空白控制

4.2、加载静态文件

4.3、消息闪现

4.4、自定义错误页面

4.5、JavaScript和CSS中的Jinja2

致谢


一、模板的基本用法

1.1、创建模板

假设我们要编写一个用户的电影清单页面(用户信息、用户收藏的电影列表等)。首先创建一些虚拟数据用于测试显示效果:

 user = {
     'username': 'Grey Li',
     'bio': 'A boy who loves movies and music',
 }
 ​
 movies = [
     {'name': 'My Neighbor Totoro', 'year': '1988'},
     {'name': 'Three Colours trilogy', 'year': '1993'},
     {'name': 'John Harrison', 'year': '1994'},
     {'name': 'Perfect Blue', 'year': '1997'},
 ]

在templates目录下创建一个watchlist.html作为模板文件,然后使用Jinja2支持的语法在模板中操作这些变量:

 <!DOCTYPE html>
 <html lang="en">
 <head>
     <meta charset="UTF-8">
     <title>{{ user.username }}'s Watchlist</title>
 </head>
 <body>
 <a href="{{ url_for('index') }}">$larr; Return</a>
 <h2>{{ user.username }}</h2>
 {% if user.bio %}
     <i>{{ user.bio }}</i>
 {% else %}
     <i>This user has not provided a bio</i>
 {% endif %}
 {# 下面是电影清单(这是注释) #}
 <h5>{{ user.username }}'s Watchlist ({{ movies|length }}):</h5>
 <ul>
     {% for moive in movies %}
         <li>{{ movie.name }} - {{ moive.year }}</li>
     {% endfor %}
 </ul>
 </body>
 </html>

Jinja2里常见的三种定界符:

(1)语句
比如if判断、for循环等:
{% ... %}

(2)表达式
比如字符串、变量、函数调用等:
{{ ... }}

(3)注释
{# ... #}
另外,在模板中Jinja2 支持用"."获取变量的属性,比如user字典中的username键值通过"."获取,即user.username,在效果上等同于user['username']。

1.2、模板语法

Jinja2运行在模板中使用大部分Python对象,比如字符串、列表、字典、元组、整型、浮点型、布尔值等。支持基本的运算符号(+、-、*、/等)、比较符号(==、 !=等)、逻辑符号(and、or、not等)以及in、is、None和布尔值(True、False)。

还提供多种控制结构来控制模板的输出,其中for和if是最常用的两种。语句使用{% ... %}标识,尤其注意,在语句结束的地方,我们必须添加结束标签

 {% if user.bio %}
     <i>{{ user.bio }}</i>
 {% else %}
     <i>This user has not provided a bio.</i>
 {% endif %}

和Python一样,for语句用来迭代一个序列:

 <ul>
     {% for moive in movies %}
         <li>{{ movie.name }} - {{ moive.year }}</li>
     {% endfor %}
 </ul>

在for循环内,Jinja2提供了多个特殊变量,常用的循环变量

变量名说明
loop.index当前迭代数(从1开始计数)
loop.index0当前迭代数(从0开始计数)
loop.revindex当前反向迭代数(从1开始计数)
loop.revindex0当前反向迭代数(从0开始计数)
loop.first如果是第一个元素,则为True
loop.last如果是最后一个元素,则为True
loop.previtem上一个迭代的条目
loop.nextitem下一个迭代的条目
loop.length序列包含的元素数量

1.3、渲染模板

渲染一个模板就是执行模板中的代码,并传入所有在模板中使用的变量,渲染后的结果就是我们要返回给客户端的HTML响应。使用Flask提供的渲染函数render_template()

 from flask import Flask,render_template
 ...
 @app.route('/watchlist')
 def watchlist():
     return render_template('watchlist.html', user=user, movies=movies)

除了render_template()函数,Flask还提供了一个render_template_string()函数用来渲染模板字符串

其他类型的变量通过相同的方式传入。示例:

 <p>这是列表my_list的第一个元素:{{ my_list[0] }}</p>
 <p>这是元组my_tuple的第一个元素:{{ my_tuple[0] }}</p>
 <p>这是字典my_dict的键为name的值:{{ my_dict['name'] }}</p>
 <p>这是函数my_func的返回值:{{ my_func() }}</p>
 <p>这是对象my_object调用某方法的返回值:{{ my_object.name }}</p>

二、模板辅助工具

为了方便测试,在templates目录下创建一个根页面模板index.html:

 from flask import render_template
 ​
 @app.route('/')
 def index():
     return render_template('index.html')

2.1、上下文

除了渲染时传入变量,也可以在模板中定义变量,使用set标签

 {% set navigation = [('/','Home'),('/about','About')] %}

可以将一部分模板数据定义为变量,使用set和endset标签声明开始和结束:

 {% set navigation %}
     <li><a href="/">Home</a>
     <li><a href="/about">About</a>
 {% endset %}

2.1.1、内置上下文变量

Flask在模板上下文中提供了一些内置变量,可以在模板中直接使用:

变量说明
config当前的配置对象
request当前的请求对象,在已激活的请求环境下可用
session当前的会话对象,在已激活的请求环境下可用
g与请求绑定的全局变量,在已激活的请求环境下可用

2.1.2、自定义上下文

如果多个模板都需要使用同一变量,设置一个模板全局变量以供使用。Flask提供了一个app.context_processor装饰器,可以用来注册模板上下文处理函数,完成统一传入变量操作:

 @app.context_processor
 def inject_foo():
     foo = 'I am foo.'
     return dict(foo=foo)

当我们调用render_template()函数渲染任意一个模板时,所有使用app.context_processor装饰器注册的模板上下文处理函数都会被执行,这些函数的返回值会被添加到模板中,因此我们可以在模板中直接使用foo变量。

除了使用app.context_processor装饰器,也可以直接将其作为方法调用传入模板上下文处理函数

 ...
 def inject_foo():
     foo = 'I am foo.'
     return dict(foo=foo)
 app.context_processor(inject_foo)

使用lambda简化为:

 app.context_processor(lambda:dict(foo='I am foo.'))

2.2、全局对象

全局对象值在所有模板中都可以直接使用的对象,包括在模板中导入的模板。

2.2.1、内置全局函数

Jinja2在模板中默认提供了一些全局函数(部分):

函数说明
range([satrt,]stop[,step])和Python中的range()用法相同
lipsum(n=5,html=True,min=20,max=100)生成随机文本,可以在测试时用来填充页面。默认生成5段HTML文本,每段包含20-100个单词
dict(**items)和Python中的dict()用法相同

Flask也在模板中内置了两个全局函数:

函数说明
url_for()用于生成URL的函数
get_flashed_messages()用于获取flash消息的函数

url_for()用来获取URL,用法和在Python脚本中相同。在实际的代码中,这个URL使用url_for()生成,传入index视图的端点:

 <a href="{{ url_for('index')}}">&larr; Return</a>

2.2.2、自定义全局函数

使用app.template_global装饰器直接将函数注册为模板全局函数。(仅用于注册全局函数)

 # 把bar()函数注册为模板全局函数
 @app.template_global
 def bar():
     return 'I am bar'

默认使用函数的原名称传入模板,在app.template_global()装饰器中使用name参数可以指定一个自定义名称

2.3、过滤器

过滤器修改和过滤变量值的特殊函数,过滤器变量用一个竖线(管道符号)隔开,需要参数的过滤器可以像函数一样使用括号传递。

 {{ name|title }}
 # 这会将name变量的值标题化,相当于Python中调用name.title()。
 ​
 {{ movies|length }}
 # 获取moives长度,相当于Python值调用len(moives)

另一种方法是将过滤器作用于部分模板数据,使用filter标签和endfilter标签声明开始和结束:

 {% filter upper %}
  This text bacomes uppercase.
 {% endfilter %}

2.3.1、内置过滤器(部分)

过滤器说明
escape(s)转义HTML,别名为e
first(seq)返回序列的第一个元素
last(seq)返回序列的最后一个元素
length(object)返回变量的长度
random(seq)返回序列中的随机元素

在使用过滤器时,列表中过滤器函数的第一个参数表示过滤的变量值(value)或字符串(s),即竖线符号左侧的值,其他的参数可以通过括号传入。

过滤器可以叠加使用

 # 为变量name设置默认值,并将其标题化
 <h1>Hello,{{ name|default('陌生人')|title }}!</h1>

根据Flask设置,Jinja2会自动对模板中的变量进行转义,因此我们不需要手动使用escape过滤器或调用excape()函数对变量进行转义。若想避免转义,将变量作为HTML解析,可以对变量使用safe过滤器或者在渲染前将变量转换为Markup对象:(不要对用户输入的内容使用safe,容易被攻击)

 # safe过滤器
 {{ sanitied_text|safe }}
 # 转换为markup对象
 from flask import Markup
 ​
 @app.route('/hello')
 def hello():
     text = Markup('<h1>Hello,Flask!</h1>')
     return render_template('index.html',text=text)  # 这时可以在模板中直接使用{{ text }}

2.3.2、自定义过滤器

使用app.template_filter()装饰器可以注册自定义过滤器:例注册一个musical过滤器:

 from flask import Markup
 ​
 @app.template_filter()
 def musical(s):
     return s + Markup(' &#9835;')

与注册全局函数一样,可以在app.template_filter()中使用name关键字设置过滤器的名称,默认使用函数名称。用法与其他过滤器相同。

2.4、测试器

在Jinja2中,测试器(Test)是一些用来测试变量或表达式,返回布尔值的特殊函数。

 # number测试器用来判断一个变量或表达式是否为数字,我们使用is连接变量和测试器:
 {% if age is number %}
     {{ age * 365 }}
 {% else %}
     无效的数字
 {% endif %}

2.4.1、内置测试器(部分)

测试器说明
callable(object)判断对象是否可被调用
defined(value)判断变量是否已定义
undefined(value)判断变量是否未定义
none(value)判断变量是否None
number(value)判断变量是否是数字
string(value)判断变量是否字符串
sequence(value)判断变量是否是序列,比如字符串、列表、元组
iterable(value)判断变量是否可迭代
mapping(value)判断变量是否是匹配对象,比如字典
sameas(value,other)判断变量与 other是否指向相同的内存地址

使用测试器时,is的左侧是测试器函数的第一个参数(value),其他参数可以添加括号传入,也可以在右侧使用空格连接,以sameas为例:

 {% if foo is sameas(bar) %}...
 # 等同于
 {% if foo is sameas bar %}...

2.4.2、自定义测试器

使用app.template_test()装饰器来注册一个自定义测试器。例子:

 @app.template_test
 def baz(n):
     if n == 'baz':
         return True
     return False

同样,可以使用关键字name指定名称,默认为函数名称

2.5、模板环境对象

在Jinja2中,渲染行为由jinja2.Environment类控制,所有的配置选项、上下文变量、全局函数、过滤器和测试器都存储在Environment实例上。当与Flask结合后,我们直接使用Flask创建的Environment对象,它存储在app.jinja_env属性上(其可以更改Jinja2设置)

 #使用variable_start_string和variable_end_string自定义变量定界符的开始和结束
 app = Flask(__name__)
 app.jinja_env.variable_start_string = '[['
 app.jinja_env.variable_end_string = ']]'

模板环境中的全局函数、过滤器和测试器分别存储在Environment对象的globalsfilterstests属性中,都是字典对象

2.5.1、添加自定义全局对象

和app.template_global()装饰器不同,直接操作globals字典允许我们传入任意Python对象,而不仅仅是函数,类似上下文处理函数的作用。

 # 添加全局函数bar和全局变量foo:
  def bar():
     return 'I am bar'
 foo = 'I am foo'
 app.jinja_env.globals['bar'] = bar
 app.jinja_env.globals['foo'] = foo

2.5.2、添加自定义过滤器

 # 添加自定义过滤器smiling
 def smiling(s):
     return s + ':)'
 app.jinja_env.filters['smiling'] = smiling

2.5.3、添加自定义测试器

 # 添加自定义测试器baz
 def baz(n):
     if n == 'baz':
         return True
     return False
 app.jinja_env.tests['baz'] = baz

三、模板组织结构

Jinja2还提供了一些工具来在宏观上组织模板内容。更好实践DRY(Don't Repeat Yourself)原则

3.1、局部模板

当多个独立模板都会使用同一块HTML代码时,我们把这部分代码抽离出来,存储到局部模板中。可以避免重复又方便统一管理。

我们使用include标签插入一个局部模板,这会把局部模板的全部内容插在使用include标签的位置:

 {% include '_banner.html' %}

为了和普通模板区分开,局部模板命名通常以一个下划线开始

3.2、宏

宏(macro)是Jinja2中的特性,类似Python中的函数。使用宏可以将一部分模板代码封装到宏里,使用传递的参数来构建内容,最后返回构建后的内容。

为了便于管理,通常把宏存储到单独文件中(macros.html)。

使用macro和endmacro标签声明宏的开始和结束,在开始标签中定义宏的名称和接收的参数

 {% macro qux(amount=1) %}
     {% if amount ==1 %}
         I am qux.
     {% elif amount > 1 %}
         We are quxs.
     {% endif %}
 {% endmacro %}

使用时使用import语句导入,然后作为函数调用传入必要的参数

 {% from 'macros.html' impor qux %}
 ...
 {{ qux(amount=5) }}

默认情况下包含(include)一个局部模板会传递当前上下文到局部模板,但导入(import)不会。换句话:当我们使用render_template()函数渲染一个foo.html模板时,这个foo.html的模板上下文中包含下列对象:

  • Flask使用内置的模板上下文处理函数提供的g、session、config、request。
  • 扩展使用内置的模板上下文处理函数提供的变量
  • 自定义模板上下文处理器传入的变量
  • 使用render_template()函数传入的变量
  • Jinja2和Flask内置及自定义全局对象
  • Jinja2内置及自定义过滤器
  • Jinja2内置及自定义测试器

使用include标签插入的局部模板同样可以使用上述。而导入一个并非被直接渲染的模板,这个模板仅包含下列对象:

  • Jinja2和Flask内置及自定义全局对象
  • Jinja2内置及自定义过滤器
  • Jinja2内置及自定义测试器

因此,若想在导入的宏中使用第一个列表中的2,3,4项,就需要在导入时显式地使用with context声明传入当前模板的上下文

 {% from 'macros.html' impor foo with context %}

3.3、模板继承

Jinja2的模板允许定义一个基模板,把像导航栏、页脚等通用部分放在基模板中。

3.3.1、编写基模板

基模板存储程序页面固定部分,通常被命名为base.html或layout.html

 <!DOCTYPE html>
 <html>
 <head>
     <meta charset="UTF-8">
     <title>{% block title %}Template - HelloFlask{% endblock %}</title>
     {% block styles %}{% endblock %}
 </head>
 <body>
 <nav>
     <ul><li><a href="{{ url_for('index') }}">Home</a></li></ul>
 </nav>
 <main>
     {% block content %}{% endblock %}
 </main>
 <footer>
     {% block footer %}
         ...
     {% endblock %}
 </footer>
 {% block scripts %}{% endblock %}
 </body>
 </html>

当子模板继承基模板后,会自动包含基模板的内容和结构。在基模板定义块(block),在子模板中可以通过定义同名的块来执行继承操作

块的开始和结束用blockendblock标签声明,可以嵌套。为了避免块的混乱,块的结束标签可以指明块名,确保前后名称一致。

 {% block body %}
 ...
 {% endblock body %}

3.3.2、编写子模板

在子模板中只需要对特定的块进行修改。

 {% extends 'base.html' %}
 {% from 'macro.html' import qux %}
 ​
 {% block content %}
 {% set name='baz' %}
 <h1>Template</h1>
 <ul>
     <li><a href="{{ url_for('watchlist') }}">Watchlist</a></li>
     <li>Filter:{{ foo|musical }}</li>
     <li>Global:{{ bar() }}</li>
     <li>Test:{% if name is baz %}I am baz.{% endif %}</li>
     <li>Macro:{{ qux(amount=5) }}</li>
 </ul>
 {% endblock %}

extends标签声明扩展基模板,且必须是子模板的第一个标签。

我们在基模板中定义了四个块,在子模板中,我们可以对父模板中的块执行两种操作:

(1)覆盖内容

在子模板创建同名的块,会使用子块的内容覆盖父块的内容。

(2)追加内容

使用Jinja2提供的super()函数进行声明,这会向父块添加内容,例如(向基模板中的styles块追加一行<style>样式定义:

 {% block styles %}
     {{ super() }}
     <style>
     .foo{
         color:red;
     }
     </style>
 {% endblock %}

四、模板进阶实践

模板在Flask程序中的常见应用(加载静态文件和自定义错误页面)

4.1、空白控制

在实际输出的HTML文件中模板中的Jinja2语句、表达式和注释会保留移除后的空行。

{% if user.bio %}
     <i>{{ user.bio }}</i>
 {% else %}
     <i>This user has not provided a bio.</i>
 {% endif %}
 ​
 # 实际输出的HTML代码:
 ​
 <i>{{ user.bio }}</i>
 ​
 <i>This user has not provided a bio.</i>

若想渲染时自动去掉这些空行,在定界符内侧添加减号。{%- endfor %}会移除该语句前的空白,同理,右边可以移除该语句后面的空白

{% if user.bio -%}
     <i>{{ user.bio }}</i>
 {% else -%}
     <i>This user has not provided a bio.</i>
 {%- endif %}
 ​
 # 现在输出的Html:
 <i>{{ user.bio }}</i>
 <i>This user has not provided a bio.</i>

除了使用减号,还可以使用模板环境对象提供的trim_blocks(删除语句后的第一个空行)和lstrip_blocks属性(删除语句所在行之前的空格和制表符)设置。

 app.jinja_env.trim_blocks = True
 app.jinja_env.lstrip_blocks = True
 ​
 # trim_blocks值的block指的是使用{%...%}界定的代码块,与继承的块无关

内的空白制作不受terim_blocks和lstrip_blocks属性控制,我们需要手动设置

 {% macro qux(amount=1) %}
     {% if amount ==1 -%}
         I am qux.
     {% elif amount > 1 -%}
         We are quxs.
     {%- endif %}
 {% endmacro %}

事实上,我们没必要严格控制HTML输出,因为多余的空白并不影响浏览器的解析。

4.2、加载静态文件

在Flask程序中,默认将静态文件存储在与主脚本同级目录的static文件夹中。

使用url_for()函数获取静态文件的URL在HTML模板中引用。Flask内置了用于获取静态文件的视图函数,端点值为static,它的默认URL规则为/static/path:filename,URL变量filename是相对于static文件夹根目录的文件路径。

提示:若想使用其他文件夹来存储静态文件,可以在实例化Flask类时使用static_folder参数指定。在实例化Flask类时使用static_url_path参数则可以自定义静态文件的URL路径。

 <img src="{{ url_for('static',filename='avatar.jpg') }}" width="50">

另外,我们还创建了一个存储CSS规则的styles.css文件,加载方法:

 <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='style.css') }}">

4.2.1、添加Favicon

前两章运行的时候,会看到一条404状态请求记录,请求的URL是/favicon.ico

 127.0.0.1 - - [08/Feb/2024 18:30:12] "GET /Favicon.ico HTTP/1.1" 404 -

Favicon.icon文件指的是Favicon(收藏夹头像/网站头像),又称shortcut.icon、tab icon、website.icon或是bookmark.icon。作为网站的特殊标记。

将Favicon文件放在static目录下,Flask中静态文件的默认路径是/static/filename,为了正确返回Favicon,我们可以显式的在HTML页面中声明Favicon的路径。

 <link rel="icon" type="image/x-icon" href="{{ url_for('static',filename='favicon.ico') }}">

4.2.2、使用CSS框架

自写CSS比较麻烦,以Bootstrap为例,访问官网下下载相应的资源文件,然后分类放到static目录下。

 {% block styles %}
     <link rel="stylesheet" href="{{ url_for('static',filename='css/bootstrap.min.css') }}">
 {% endblock %}
 ...
 {% block scripts %}
 <script src="{{ url_for('static',filename='js/jquery.min.js') }}"></script>
 <script src="{{ url_for('static',filename='js/popper.min.js') }}"></script>
 <script src="{{ url_for('static',filename='js/bootstrap.min.js') }}"></script>
 {% endblock %}

若是想简化开发过程,那么从CDN加载是更方便的做法。从CDN加载时,只需要将相应的URL替换为CDN提供的资源URL,例:

 {% block styles %}
     <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.3/css/bootstrap-grid.css" rel="stylesheet">
 {% endblock %}

4.2.3、使用宏加载静态资源

创建一个专门用于加载静态资源的宏,例如:

 {% macro static_file(type,filename_or_url,local=True) %}
     {% if local %}
         {% set filename_or_url = url_for('static',filename_or_url) %}
     {% endif %}
     {% if type == 'css' %}
         <link rel="stylesheet" href="{{ filename_or_url }}" type="text/css">
     {% elif type == 'js' %}
         <script type="text/javascript" src="{{ filename_or_url }}"></script>
     {% elif type == 'icon' %}
         <link rel="icon" href="{{ filename_or_url }}" >
     {% endif %}
 {% endmacro %}

在模板 中导人宏后,只需在调用时传入静态资源 别和文件路径就会获得完整的资源加载语句

 # 使用它加载 css 文件的示例
 static_file('css','css/bootstrap.min.css')
 ​
 # 使用它加载CDN资源
 static_file ('css','https://maxcdn.../css/bootstrap.min.css’,local=False)

4.3、消息闪现

Flask提供的flash()函数用来“闪现”需要显示给用户的信息,比如当用户登录成功后显示“欢迎回来!”。

使用功能flash()函数发送的消息会存储在session中(所有我们需要为程序设置密钥。可以通过app.secret_key属性或配置变量SECRET_KEY设置),我们需要在模板中使用全局函数get_flashed_messages()获取消息并将其显示出来。

 from flask import Flask, render_template, flash, redirect, url_for
 ​
 app = Flask(__name__)
 app.secret_key = 'secret string'
 ​
 @app.route('/flash')
 def just_flash():
     flash('I am flash, who is looking for me?')
     return redirect(url_for('index'))
  • 在Python 2.x版本中,如果字符串包含中文或任何非ASCII字符,需要使用u前缀来声明这个字符串为Unicode字符串。
  • 同时,需要在Python文件的首行添加编码声明,通常是# -*- coding: utf-8 -*-,这告诉Python使用UTF-8编码来解码字符串。
  • 这样做可以避免发送中文消息时出现编码问题。
 # -*- coding: UTF-8 -*-
 ...
 @app.route('/flash')
 def just_flash():
     flash(u'你好!')
     return redirect(url_for('index'))

使用get_flashed_messages()函数渲染flash消息:

 <main>
     {% for message in get_flashed_messages() %}
         <div class="alert">{{ message }}</div>
     {% endfor %}
     {% block content %}{% endblock %}
 </main>

当get_flashed_messages()函数被调用时,session中存储的所有消息都会被移除。发现,重载后的页面不再出现这条消息。

4.4、自定义错误页面

首先创建错误页面的模板文件,可在templates里面创建一个errors子文件夹,最常见的有404和500错误的模板文件。下面是一个404.html模板示例

 {% extends 'base.html' %}
 ​
 {% block title %}404 - Page Not Found{% endblock %}
 ​
 {% block content %}
 <h1>Page Not Found</h1>
 <p>You are lost...</p>
 {% endblock %}

错误处理函数需要附加app.errorhandler()装饰器,并传入错误状态码作为参数。错误处理函数本身则需要接收异常类作为参数,并在返回值中注明对应的HTTP状态码。当发生错误时,对应的错误处理函数会被调用,它的返回值会作为错误响应的主体。

 ...
 @app.errorhandler(404)
 def page_not_found(e):
     return render_template('errors/404.html'),404

Werkzeug内置的HTTP异常类的常用属性

属性说明
code状态码
name原因短语
description错误描述,另外使用get_description()方法还可以获取HTML格式的错误描述代码

4.5、JavaScript和CSS中的Jinja2

程序变大时,有时我们需要在JavaScript和CSS代码中使用Jinja2提供的变量值,甚至是控制语句。比如通过传入模板的theme_color变量来为页面设置主题色彩,或是根据用户是否登录来决定是否执行某个JavaScript函数

只有使用remder_template()传入的模板文件才会被渲染,若把Jinja2代码写在单独的JavaScript或是CSS文件中,尽管在HTML中引用了它们,也不会被执行,以下是以下Tips:

4.5.1、行内/嵌入式JavaScript/CSS

在HTML中使用<style>和<script>标签来定义这部分CSS和JavaScript代码。不推荐,难以维护

4.5.2、定义为JavaScript/CSS变量

对于想要在JavaScript中获取的数据,如果是元素特定的数据,比如某个文章条目对应的id值,可以通过HTML元素的data-*属性存储。自定义横线后的名称,作为元素上的自定义数据变量,data-id,data-username等。

 <span data-id="{{ user.id }}" data-username="{{ user.username  }}">{{ user.username }}</span>

在JavaScript中使用DOM元素的dataset属性来获取data-*属性值,如element.dataset.username或使用getAttribute()方法:element.getAttribute('data-username');使用jQuery,直接调用data方法获取:$element.data('username')

对于全局使用的数据,则可在页面中使用嵌入式JavaScript定义变量,如果没法定义为JavaScript变量,就考虑定义为函数:(若使用太多,则考虑将程序转变为Web API。

 <script type="text/javascript">
     var foo = '{{ foo_variable }}';
 </script>
 ​
 # CSS同理
 <style>
     :root {
         --theme-color:{{ theme_color }};
         --background-url:{{ url_for('static',filename='background.jpg') }}
     }
 </style>
 ​
 # 在CSS文件中使用var()函数传入变量名即可获取对应的变量值
 #foo {
     color: var(--theme-color);
 }
 #bar {
     background: var(--background-url);
 }

致谢

在此,我要对所有为知识共享做出贡献的个人和机构表示最深切的感谢。同时也感谢每一位花时间阅读这篇文章的读者,如果文章中有任何错误,欢迎留言指正。 

学习永无止境,让我们共同进步!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/733046.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

投票多功能小程序(ThinkPHP+Uniapp+FastAdmin)

&#x1f389;你的决策小助手&#xff01; 支持图文投票、自定义选手报名内容、自定义主题色、礼物功能(高级授权)、弹幕功能(高级授权)、会员发布、支持数据库私有化部署&#xff0c;Uniapp提供全部无加密源码。​ 一、引言&#xff1a;为什么我们需要多功能投票小程序&#…

AI+前端技术的结合(实现图片识别功能)

随着人工智能技术的不断发展&#xff0c;AI在前端设计页面中的应用变得越来越普遍。比如&#xff1a;在电商平台上&#xff0c;可以利用对象检测技术实现商品的自动识别和分类&#xff1b;人脸识别&#xff1b;车辆检测&#xff1b;图片识别等等......其中一个显著的应用是在图…

ArcGIS与Excel分区汇总统计三调各地类面积!数据透视表与汇总统计!

​ 点击下方全系列课程学习 点击学习—>ArcGIS全系列实战视频教程——9个单一课程组合系列直播回放 点击学习——>遥感影像综合处理4大遥感软件ArcGISENVIErdaseCognition 01 需求说明 介绍一下ArcGIS与Excel统计分区各地类的三调地类面积。 ArcGIS统计分析不会&#x…

SpringBoot测试实践

测试按照粒度可分为3层&#xff1a; 单元测试&#xff1a;单元测试&#xff08;Unit Testing&#xff09;又称为模块测试 &#xff0c;是针对程序模块&#xff08;软件设计的最小单位&#xff09;来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中…

Linux驱动开发笔记(十三)Sysfs文件系统

文章目录 前言一、Sysfs1.1 Sysfs的引入1.2 Sysfs的目录结构1.2 Sysfs的目录详解1.2.1 devices1.2.2 bus1.2.3 class1.2.4 devices、bus、class目录之间的关系1.2.5 其他子目录 二、Sysfs使用2.1 核心数据结构2.2 相关函数2.2.1 kobject_create_and_add2.2.2 kobject_put()2.2.…

视觉理解与图片问答,学习如何使用 GPT-4o (GPT-4 Omni) 来理解图像

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 一、引言 OpenAI 最新发布的 GPT-4 Omni 模型&#xff0c;也被称为 GPT-4o&#xff0c;是一个多模态 AI 模型&#xff0c;旨在提供更加自然和全面的人机交互体验。 GPT-4o 与 GPT-4 Turbo 都具备视觉功…

MySQL程序使用的选项文件

MySQL程序使用的选项文件如下&#xff1a; 显示帮助消息并退出。 在具有多个网络接口的计算机上&#xff0c;使用此选项可以选择用于连接MySQL服务器的接口。 安装字符集的目录。 如果可能&#xff0c;压缩客户端和服务器之间发送的所有信息。 从MySQL 8.0.18开始&#xff0c;…

【因果推断python】50_去偏/正交机器学习2

目录 Frisch-Waugh-Lovell on Steroids CATE Estimation with Double-ML Frisch-Waugh-Lovell on Steroids 双重/偏差 ML 其思想非常简单&#xff1a;在构建结果和治疗残差时使用 ML 模型&#xff1a; 是估计&#xff0c;是估计 我们的想法是&#xff0c;ML 模型具有超强的…

【RK3588/算能/Nvidia智能盒子】AI算法应用于中国生物疫苗生产过程智能监测,赋能生产安全,提升品质管控

因操作失误导致食品药品质量事故频发 计算机视觉检测技术为监管提供新思路 近年来&#xff0c;各类因人员操作失误导致的食品药品质量事故不断发生。例如有员工取出原材料及称重确认时未进行双人复核导致“混药”、员工未能按照生产步骤对生牛奶进行杀菌导致奶酪污染、员工误将…

webpack5入门,根据官方文档简单学习,简单总结

c.**loader加载器&#xff1a;**webpack 只能理解 JS文件和 JSON 文件&#xff0c;loader 让 webpack 能够去处理其他类型的文件&#xff0c;并将它们转换为有效 模块&#xff0c;以供应用程序使用&#xff0c;以及被添加到依赖图中。&#xff08;比如css&#xff0c;less&…

人人讲视频如何下载

一、工具准备 1.VLC media player 2.谷歌浏览器 二、视频下载 1.打开人人讲网页&#xff0c;需要下载的视频 谷歌浏览器打开调试窗口 搜索m3u8链接 拷贝到VLCplayer打开网络串流方式打开测试是否能正常播放 2.下载视频 能正常播放后&#xff0c;切换播放为转换选择mp4格式…

分享excel全套教程速成,高效人士的Excel必修课,附视频课程!

我是阿星。今天&#xff0c;我要来聊聊那些让Excel变得像魔法一样的课程&#xff0c;它们能让你们在办公室里像超人一样高效。别急&#xff0c;听我慢慢道来。 首先&#xff0c;得说说这些课程&#xff0c;它们都是mp4格式&#xff0c;就像电影一样&#xff0c;但比电影实用多…

Python一文轻松搞定正则匹配

一、前言 日常工作中&#xff0c;不可避免需要进行文件及内容的查找&#xff0c;替换操作&#xff0c;python的正则匹配无疑是专门针对改场景而出现的&#xff0c;灵活地运用可以极大地提高效率&#xff0c;下图是本文内容概览。 ​ 二、正则表达式符号 对于所有的正则匹配表达…

强化学习中的自我博弈(self-play)

自我博弈&#xff08;Self-Play&#xff09;[1]是应用于智能体于智能体之间处于对抗关系的训练方法&#xff0c;这里的对抗关系指的是一方的奖励上升必然导致另一方的奖励下降。通过轮流训练双方的智能体就能使得双方的策略模型的性能得到显著提升&#xff0c;使得整个对抗系统…

动态规划02(Leetcode62、63、343、96)

参考资料&#xff1a; https://programmercarl.com/0062.%E4%B8%8D%E5%90%8C%E8%B7%AF%E5%BE%84.html 62. 不同路径 题目描述&#xff1a; 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移…

STM32之二:时钟树

目录 1. 时钟 2. STM3时钟源&#xff08;哪些可以作为时钟信号&#xff09; 2.1 HSE时钟 2.1.1 高速外部时钟信号&#xff08;HSE&#xff09;来源 2.1.2 HSE外部晶体电路配置 2.2 HSI时钟 2.3 PLL时钟 2.4 LSE时钟 2.5 LSI时钟 3. STM32时钟&#xff08;哪些系统使用时…

html做一个分组散点图图的软件

在HTML中创建一个分组散点图&#xff0c;可以结合JavaScript库如D3.js或Plotly.js来实现。这些库提供了强大的数据可视化功能&#xff0c;易于集成和使用。下面是一个使用Plotly.js创建分组散点图的示例&#xff1a; 要添加文件上传功能&#xff0c;可以让用户上传包含数据的文…

使用 Python 进行测试(6)Fake it...

总结 如果我有: # my_life_work.py def transform(param):return param * 2def check(param):return "bad" not in paramdef calculate(param):return len(param)def main(param, option):if option:param transform(param)if not check(param):raise ValueError(…

matlab入门基础笔记

1、绘制简单三角函数&#xff1a; 绘制正弦曲线和余弦曲线。x[0:0.5:360]*pi/180; plot(x,sin(x),x,cos(x)); &#xff08;1&#xff09;明确x轴与y轴变量&#xff1a; 要求为绘制三角函数&#xff1a; X轴&#xff1a;角度对应的弧度数组 Y轴&#xff1a;对应sin(x)的值 求…

python pynput实现鼠标点击两坐标生成截图

脚本主要实现以下功能&#xff1a; 按ctrl开始截图&#xff0c;点击两个坐标&#xff0c;保存截图tk输出截图文本信息&#xff0c;文本输出内容倒序处理默认命名为A0自增。支持自定义名称&#xff0c;自增编号&#xff0c;修改自定义名称自增重新计算清空文本框内容 from pyn…