Hello, Flask!
首发于Hello, Flask!
Flask表单:自定义表单样式

Flask表单:自定义表单样式

这篇文章总结了控制表单样式的几种方式和常见的问题。

使用Flask-WTF

在表单类里控制样式

我们可以在表单类里传入一个字典(render_kw),把需要添加到字段的属性以键值对的形式写进去,像这样:

body = TextAreaField(u'正文', validators=[Required(u'内容不能为空!')],         
           render_kw={'class': 'text-body', 'rows': 20, 'placeholder': u'你有什么想法?'})

在HTML里渲染表单:

...
{{ form.body }}
...

渲染的结果:

<textarea class="text-body" id="body" name="body" placeholder="你有什么想法?" rows="20"></textarea>
注意事项:字段名将被作为id的值,这可能会和你定义的其他同名元素冲突。

在渲染时控制样式

我们也可以在渲染时传入字段的属性(不使用render_kw),类似这样:

...
{{ form.body(class="text-body", rows="20", placeholder="你有什么想法?") }}
...

渲染后的结果和上面一样。

render_kw在WTForms 2.1及以上版本适用。

使用Flask-Bootstrap

使用Flask-Bootstrap提供的表单函数来渲染表单时,也可以像上面那样在表单类或是渲染函数里传入字段的属性:

...
{{ wtf.form_field(form.body, class="text-body") }}
...
这里需要先导入Flask-Bootstrap提供的表单模板,另外完整的表单形式见Flask表单系列第一篇文章
这里需要注意的是,Flask-Bootstrap会给表单所有字段添加一个form-control来控制样式,这时你再通过render_kw传入已经被定义的属性(class)会失败。如果要传入指定的类,可以在渲染时传入并且增加form-control类
...
{{ wtf.form_field(form.body, class="form-control text-body") }}
...

或是:

...
{{ form.body(class="form-control text-body") }}
...
在一些文档里,推荐使用class_=' '的方式来传入类,因为class是Python的保留关键字(这在单独使用Flask-WTF时有效,在Flask-Bootstrap里未获得支持)。

小技巧:在输入框里添加图标

有一些网站会在表单左侧放一个图标来增加交互性,比如这样:

如果是普通的表单,那么使用Bootstrap提供的表单验证状态类,可以很容易的实现,但是使用Wtforms渲染表单却没法实现。我们可以这样解决:

在CSS里定义一个类,将glyphicon图标的base64数据作为背景图片:


.user-icon {
    padding-left:30px;
    background-repeat: no-repeat;
    background-position-x: 4px;
    background-position-y: 4px;
    background-image:     url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAAWCAYAAAArdgcFAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA+5pVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ1dWlkOjY1RTYzOTA2ODZDRjExREJBNkUyRDg4N0NFQUNCNDA3IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkIzOUVGMUYxMDY3MTExRTI5OUZEQTZGODg4RDc1ODdCIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkIzOUVGMUYwMDY3MTExRTI5OUZEQTZGODg4RDc1ODdCIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzYgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowMTgwMTE3NDA3MjA2ODExODA4M0ZFMkJBM0M1RUU2NSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowNjgwMTE3NDA3MjA2ODExODA4M0U3NkRBMDNEMDVDMSIvPiA8ZGM6dGl0bGU+IDxyZGY6QWx0PiA8cmRmOmxpIHhtbDpsYW5nPSJ4LWRlZmF1bHQiPmdseXBoaWNvbnM8L3JkZjpsaT4gPC9yZGY6QWx0PiA8L2RjOnRpdGxlPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PkX/peQAAACrSURBVHja7JSLCYAwDEQbJ3AER+kouoFu0FEcqSM4gk4QE4ggVRPxg1A8OFCSvkqC5xDRaSZ5ciTjyvzuzbMnwKjY34FHAx618yCQXQHAcVFE5+GoVijgyt3UN1/+hPKFd0a9ubxQa6naMjOdOY2jJAdjZIH7tJ8gzRNuZuho5MriUfpLNbhINXk4Cd27pN3AJVqvQlMPSxSz+oegqXuQhz9bNvDpJfY0CzAA6Ncngv5RALIAAAAASUVORK5CYII=);
}

然后在模板里渲染时传入这个类:

<form method="POST">
    {{ form.hidden_tag() }}
    {{ wtf.form_field(form.username, class="form-control user-icon") }}
    {{ wtf.form_field(form.password) }}
    {{ wtf.form_field(form.submit) }}
</form>

图标(glyphicon)的base64数据可以在这个网站上可以获取到。

另外,也可以使用一个小图片(25*25大小较合适)来代替base64数据,像这样:

background-image: url({{ url_for('static', filename='user.png') }});

效果如下:

相关链接

  1. wtforms.readthedocs.io/
  2. http://stackoverflow.com/questions/39520899/flask-wtf-forms-adding-a-glyphicon-in-a-form-field

- - - - -

更多关于Flask和Web开发的优质原创内容,欢迎关注Hello, Flask! - 知乎专栏

编辑于 2017-02-22

文章被以下专栏收录

    大家好,我是李辉,一个 Python 程序员。在这个专栏,你会看到我学习和使用 Flask 的经验和总结,你还会看到我所有的发明创造,以及它们的实现方法。欢迎加入这场 Flask 之旅,拿好你的小键盘,上车吧!helloflask.com