抚顺市 网站建设网站分页需要前端做还是后端
- 作者: 五速梦信息网
- 时间: 2026年03月21日 11:15
当前位置: 首页 > news >正文
抚顺市 网站建设,网站分页需要前端做还是后端,成都住建局官网电话查询,优化什么前言#xff1a;本博客仅作记录学习使用#xff0c;部分图片出自网络#xff0c;如有侵犯您的权益#xff0c;请联系删除 目录 一、模板的基本用法 1.1、创建模板 1.2、模板语法 1.3、渲染模板 二、模板辅助工具 2.1、上下文 2.2、全局对象 2.3、过滤器 2.4、测试… 前言本博客仅作记录学习使用部分图片出自网络如有侵犯您的权益请联系删除 目录 一、模板的基本用法 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 htmlhtml langenheadmeta charsetUTF-8title{{ user.username }}s Watchlist/title/headbodya href{{ url_for(index) }}\(larr; Return/ah2{{ user.username }}/h2{% if user.bio %}i{{ user.bio }}/i{% else %}iThis user has not provided a bio/i{% endif %}{# 下面是电影清单这是注释 #}h5{{ user.username }}s Watchlist ({{ movies|length }}):/h5ul{% 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 %}iThis 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如果是第一个元素则为Trueloop.last如果是最后一个元素则为Trueloop.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, useruser, moviesmovies) 除了render_template()函数Flask还提供了一个render_template_string()函数用来渲染模板字符串。 其他类型的变量通过相同的方式传入。示例 p这是列表my_list的第一个元素{{ my_list[0] }}/pp这是元组my_tuple的第一个元素{{ my_tuple[0] }}/pp这是字典my_dict的键为name的值{{ my_dict[name] }}/pp这是函数my_func的返回值{{ my_func() }}/pp这是对象my_object调用某方法的返回值{{ my_object.name }}/p 二、模板辅助工具 为了方便测试在templates目录下创建一个根页面模板index.html from flask import render_templateapp.route(/)def index():return render_template(index.html) 2.1、上下文 除了渲染时传入变量也可以在模板中定义变量使用set标签 {% set navigation [(/,Home),(/about,About)] %} 也可以将一部分模板数据定义为变量使用set和endset标签声明开始和结束 {% set navigation %}lia href/Home/alia href/aboutAbout/a{% endset %} 2.1.1、内置上下文变量 Flask在模板上下文中提供了一些内置变量可以在模板中直接使用 变量说明config当前的配置对象request当前的请求对象在已激活的请求环境下可用session当前的会话对象在已激活的请求环境下可用g与请求绑定的全局变量在已激活的请求环境下可用 2.1.2、自定义上下文 如果多个模板都需要使用同一变量设置一个模板全局变量以供使用。Flask提供了一个app.context_processor装饰器可以用来注册模板上下文处理函数完成统一传入变量操作 app.context_processordef inject_foo():foo I am foo.return dict(foofoo) 当我们调用render_template()函数渲染任意一个模板时所有使用app.context_processor装饰器注册的模板上下文处理函数都会被执行这些函数的返回值会被添加到模板中因此我们可以在模板中直接使用foo变量。 除了使用app.context_processor装饰器也可以直接将其作为方法调用传入模板上下文处理函数 ...def inject_foo():foo I am foo.return dict(foofoo)app.context_processor(inject_foo) 使用lambda简化为 app.context_processor(lambda:dict(fooI am foo.)) 2.2、全局对象 全局对象值在所有模板中都可以直接使用的对象包括在模板中导入的模板。 2.2.1、内置全局函数 Jinja2在模板中默认提供了一些全局函数部分 函数说明range([satrt,]stop[,step])和Python中的range()用法相同lipsum(n5,htmlTrue,min20,max100)生成随机文本可以在测试时用来填充页面。默认生成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_globaldef 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别名为efirst(seq)返回序列的第一个元素last(seq)返回序列的最后一个元素length(object)返回变量的长度random(seq)返回序列中的随机元素 在使用过滤器时列表中过滤器函数的第一个参数表示过滤的变量值value或字符串s即竖线符号左侧的值其他的参数可以通过括号传入。 过滤器可以叠加使用 # 为变量name设置默认值并将其标题化h1Hello,{{ name|default(陌生人)|title }}!/h1 根据Flask设置Jinja2会自动对模板中的变量进行转义因此我们不需要手动使用escape过滤器或调用excape()函数对变量进行转义。若想避免转义将变量作为HTML解析可以对变量使用safe过滤器或者在渲染前将变量转换为Markup对象不要对用户输入的内容使用safe容易被攻击 # safe过滤器{{ sanitied_text|safe }}# 转换为markup对象from flask import Markupapp.route(/hello)def hello():text Markup(h1Hello,Flask!/h1)return render_template(index.html,texttext) # 这时可以在模板中直接使用{{ text }} 2.3.2、自定义过滤器 使用app.template_filter()装饰器可以注册自定义过滤器例注册一个musical过滤器 from flask import Markupapp.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)判断变量是否Nonenumber(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_testdef baz(n):if n baz:return Truereturn 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对象的globals、filters和tests属性中都是字典对象。 2.5.1、添加自定义全局对象 和app.template_global()装饰器不同直接操作globals字典允许我们传入任意Python对象而不仅仅是函数类似上下文处理函数的作用。 # 添加全局函数bar和全局变量foo:def bar():return I am barfoo I am fooapp.jinja_env.globals[bar] barapp.jinja_env.globals[foo] foo 2.5.2、添加自定义过滤器 # 添加自定义过滤器smilingdef smiling(s):return s :)app.jinja_env.filters[smiling] smiling 2.5.3、添加自定义测试器 # 添加自定义测试器bazdef baz(n):if n baz:return Truereturn Falseapp.jinja_env.tests[baz] baz 三、模板组织结构 Jinja2还提供了一些工具来在宏观上组织模板内容。更好实践DRYDont Repeat Yourself原则 3.1、局部模板 当多个独立模板都会使用同一块HTML代码时我们把这部分代码抽离出来存储到局部模板中。可以避免重复又方便统一管理。 我们使用include标签插入一个局部模板这会把局部模板的全部内容插在使用include标签的位置 {% include _banner.html %} 为了和普通模板区分开局部模板命名通常以一个下划线开始 3.2、宏 宏macro是Jinja2中的特性类似Python中的函数。使用宏可以将一部分模板代码封装到宏里使用传递的参数来构建内容最后返回构建后的内容。 为了便于管理通常把宏存储到单独文件中macros.html。 使用macro和endmacro标签声明宏的开始和结束在开始标签中定义宏的名称和接收的参数 {% macro qux(amount1) %}{% if amount 1 %}I am qux.{% elif amount 1 %}We are quxs.{% endif %}{% endmacro %} 使用时使用import语句导入然后作为函数调用传入必要的参数 {% from macros.html impor qux %}...{{ qux(amount5) }} 默认情况下包含include一个局部模板会传递当前上下文到局部模板但导入import不会。换句话当我们使用render_template()函数渲染一个foo.html模板时这个foo.html的模板上下文中包含下列对象 Flask使用内置的模板上下文处理函数提供的g、session、config、request。扩展使用内置的模板上下文处理函数提供的变量自定义模板上下文处理器传入的变量使用render_template()函数传入的变量Jinja2和Flask内置及自定义全局对象Jinja2内置及自定义过滤器Jinja2内置及自定义测试器 使用include标签插入的局部模板同样可以使用上述。而导入一个并非被直接渲染的模板这个模板仅包含下列对象 Jinja2和Flask内置及自定义全局对象Jinja2内置及自定义过滤器Jinja2内置及自定义测试器 因此若想在导入的宏中使用第一个列表中的23,4项就需要在导入时显式地使用with context声明传入当前模板的上下文 {% from macros.html impor foo with context %} 3.3、模板继承 Jinja2的模板允许定义一个基模板把像导航栏、页脚等通用部分放在基模板中。 3.3.1、编写基模板 基模板存储程序页面固定部分通常被命名为base.html或layout.html。 !DOCTYPE htmlhtmlheadmeta charsetUTF-8title{% block title %}Template - HelloFlask{% endblock %}/title{% block styles %}{% endblock %}/headbodynavullia href{{ url_for(index) }}Home/a/li/ul/navmain{% block content %}{% endblock %}/mainfooter{% block footer %}...{% endblock %}/footer{% block scripts %}{% endblock %}/body/html 当子模板继承基模板后会自动包含基模板的内容和结构。在基模板定义块block在子模板中可以通过定义同名的块来执行继承操作。 块的开始和结束用block和endblock标签声明可以嵌套。为了避免块的混乱块的结束标签可以指明块名确保前后名称一致。 {% block body %}...{% endblock body %} 3.3.2、编写子模板 在子模板中只需要对特定的块进行修改。 {% extends base.html %}{% from macro.html import qux %}{% block content %}{% set namebaz %}h1Template/h1ullia href{{ url_for(watchlist) }}Watchlist/a/liliFilter:{{ foo|musical }}/liliGlobal:{{ bar() }}/liliTest:{% if name is baz %}I am baz.{% endif %}/liliMacro:{{ qux(amount5) }}/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 %}iThis user has not provided a bio./i{% endif %}# 实际输出的HTML代码i{{ user.bio }}/iiThis user has not provided a bio./i 若想在渲染时自动去掉这些空行在定界符内侧添加减号。{%- endfor %}会移除该语句前的空白同理右边可以移除该语句后面的空白 {% if user.bio -%}i{{ user.bio }}/i{% else -%}iThis user has not provided a bio./i{%- endif %}# 现在输出的Html:i{{ user.bio }}/iiThis user has not provided a bio./i 除了使用减号还可以使用模板环境对象提供的trim_blocks删除语句后的第一个空行和lstrip_blocks属性删除语句所在行之前的空格和制表符设置。 app.jinja_env.trim_blocks Trueapp.jinja_env.lstrip_blocks True# trim_blocks值的block指的是使用{%...%}界定的代码块与继承的块无关 宏内的空白制作不受terim_blocks和lstrip_blocks属性控制我们需要手动设置 {% macro qux(amount1) %}{% 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:filenameURL变量filename是相对于static文件夹根目录的文件路径。 提示若想使用其他文件夹来存储静态文件可以在实例化Flask类时使用static_folder参数指定。在实例化Flask类时使用static_url_path参数则可以自定义静态文件的URL路径。 img src{{ url_for(static,filenameavatar.jpg) }} width50 另外我们还创建了一个存储CSS规则的styles.css文件加载方法 link relstylesheet typetext/css href{{ url_for(static,filenamestyle.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 relicon typeimage/x-icon href{{ url_for(static,filenamefavicon.ico) }} 4.2.2、使用CSS框架 自写CSS比较麻烦以Bootstrap为例访问官网下下载相应的资源文件然后分类放到static目录下。 {% block styles %}link relstylesheet href{{ url_for(static,filenamecss/bootstrap.min.css) }}{% endblock %}...{% block scripts %}script src{{ url_for(static,filenamejs/jquery.min.js) }}/scriptscript src{{ url_for(static,filenamejs/popper.min.js) }}/scriptscript src{{ url_for(static,filenamejs/bootstrap.min.js) }}/script{% endblock %} 若是想简化开发过程那么从CDN加载是更方便的做法。从CDN加载时只需要将相应的URL替换为CDN提供的资源URL例 {% block styles %}link hrefhttps://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.3/css/bootstrap-grid.css relstylesheet{% endblock %} 4.2.3、使用宏加载静态资源 创建一个专门用于加载静态资源的宏例如 {% macro static_file(type,filename_or_url,localTrue) %}{% if local %}{% set filename_or_url url_for(static,filename_or_url) %}{% endif %}{% if type css %}link relstylesheet href{{ filename_or_url }} typetext/css{% elif type js %}script typetext/javascript src{{ filename_or_url }}/script{% elif type icon %}link relicon href{{ filename_or_url }} {% endif %}{% endmacro %} 在模板 中导人宏后只需在调用时传入静态资源 别和文件路径就会获得完整的资源加载语句 # 使用它加载 css 文件的示例static_file(css,css/bootstrap.min.css)# 使用它加载CDN资源static_file (css,https://maxcdn.../css/bootstrap.min.css’,localFalse) 4.3、消息闪现 Flask提供的flash()函数用来“闪现”需要显示给用户的信息比如当用户登录成功后显示“欢迎回来”。 使用功能flash()函数发送的消息会存储在session中所有我们需要为程序设置密钥。可以通过app.secret_key属性或配置变量SECRET_KEY设置我们需要在模板中使用全局函数get_flashed_messages()获取消息并将其显示出来。 from flask import Flask, render_template, flash, redirect, url_forapp Flask(__name__)app.secret_key secret stringapp.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 classalert{{ 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 %}h1Page Not Found/h1pYou 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-iddata-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 typetext/javascriptvar foo {{ foo_variable }};/script# CSS同理style:root {–theme-color:{{ theme_color }};–background-url:{{ url_for(static,filenamebackground.jpg) }}}/style# 在CSS文件中使用var()函数传入变量名即可获取对应的变量值#foo {color: var(–theme-color);}#bar {background: var(–background-url);} 致谢 在此我要对所有为知识共享做出贡献的个人和机构表示最深切的感谢。同时也感谢每一位花时间阅读这篇文章的读者如果文章中有任何错误欢迎留言指正。 学习永无止境让我们共同进步
- 上一篇: 抚顺市 网站建设WordPress登录页提示
- 下一篇: 抚州城乡建设厅网站网站开发工程师资格证
相关文章
-
抚顺市 网站建设WordPress登录页提示
抚顺市 网站建设WordPress登录页提示
- 技术栈
- 2026年03月21日
-
抚宁网站建设电子商务网站需求分析
抚宁网站建设电子商务网站需求分析
- 技术栈
- 2026年03月21日
-
抚宁区建设局网站知识付费网站开发教程
抚宁区建设局网站知识付费网站开发教程
- 技术栈
- 2026年03月21日
-
抚州城乡建设厅网站网站开发工程师资格证
抚州城乡建设厅网站网站开发工程师资格证
- 技术栈
- 2026年03月21日
-
抚州建设工程网站贵阳网站建站建设定制
抚州建设工程网站贵阳网站建站建设定制
- 技术栈
- 2026年03月21日
-
抚州建设网站游戏网页游戏
抚州建设网站游戏网页游戏
- 技术栈
- 2026年03月21日






