整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

HTML表单|如何在HTML页面创建表单的文本域和密码域?

TML 表单用于收集不同类型的用户输入,它是一个包含表单元素的区域。

表单元素是允许用户在表单中输入内容,比如:文本域(textarea)、下拉列表、单选框(radio-buttons)、复选框(checkboxes)等等。今天我们主要来说说文本域和密码域这两个部分,希望对大家学习有所帮助哟!

本文福利后台回复【学习】即可获得Python、HTML等编程学习资料

HTML 表单

表单使用表单标签 <form> 来设置:

<form>

First name: <input type="text" name="firstname"><br>

Last name: <input type="text" name="lastname">

</form>


HTML 表单 - 输入元素

多数情况下被用到的表单标签是输入标签(<input>)。输入类型是由类型属性(type)定义的。

如何在 HTML 页面创建文本域?

用户可以在文本域中写入文本,参考代码如下:

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

<title>菜鸟教程(runoob.com)</title>

</head>

<body>

<form action="">

First name: <input type="text" name="firstname"><br>

Last name: <input type="text" name="lastname">

</form>

<p><b>注意:</b> 表单本身是不可见的。并且注意一个文本字段的默认宽度是20个字符。</p>

</body>

</html>

运行结果为

如何创建 HTML 的密码域?

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

<title>菜鸟教程(runoob.com)</title>

</head>

<body>

<form action="">

Username: <input type="text" name="user"><br>

Password: <input type="password" name="password">

</form>

<p><b>注意:</b> 密码字段中的字符是隐藏的(显示为星号或圆圈)。</p>

</body>

</html>

运行结果如下


戳了解更多免费领取HTML试听课~

在开篇

什么是表单呢?当前端想要提交数据给后端,怎么搞?那么在前端开发中,表单是常用的手段,比如常见的场景有:登录框、账号注册页、主机信息录入CMDB等等场景都是需要表单。那么在本篇中,笔者除了讲一些基本的知识点,还会再结合后端的方式来演示如何接收表单提交的数据。希望这些小小的演示可以起到抛砖引玉的效果。

盘点HTML表单基础

1. from元素

构建表单,主要是通过from元素,我们先来一个最简单的小栗子,看下面代码:

<!DOCTYPE html>
<html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>彩虹运维技术栈社区主页</title>
    </head>
    <body>
        <h2>彩虹运维技术栈社区,公众号ID:TtrOpsStack</h2>
        <h3>主机信息录入CMDB</h3>
        <form>
            <label for="hostname">主机名:</label><br>
            <input type="text" id="hostname" name="hostname"><br>
            <label for="ipaddr">IP地址:</label><br>
            <input type="text" id="ipaddr" name="ipaddr"><br>
            <input type="submit" value="提交">
        </form>
    </body>
</html>

效果如下图:

通上面的小栗子可以知道,form表单的主要通途是用于收集用户的输入。在from表单里面,还包含着各种不同类型的input元素,比如我们上面小栗子中用到的文本(text)、提交按钮(submit)。

input元素是表单里最重要的元素,它有很多type属性,下面我们来总结下:

类型描述text文本输入radio单选按钮checkbox提交按钮submit提交按钮button可单击按钮

在上面小栗子中,除了input元素之外,不知道大家注意label元素没有。label元素的主要用途是为input元素定义标签,且用for属性和input元素的id属性进行绑定呢。

2. 单选按钮

什么是单选按钮?就是在多个选项中,你只能选其中1个,不能多选。下面我们看个小栗子,看下面代码:

<!DOCTYPE html>
<html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>彩虹运维技术栈社区主页</title>
    </head>
    <body>
        <h2>彩虹运维技术栈社区,公众号ID:TtrOpsStack</h2>
        <h3>问答题1(单选):某站长,工作经验不足1年,仅从互联网收集学习资料制定学习路线售卖盈利,从道德层面角度分析是否有问题?</h3>
        <form>
            <input type="radio" id="i1" name="problem" value="yes">
            <label for="i1">有</label>
            <input type="radio" id="i2" name="problem" value="no">
            <label for="i2">没有</label>
            <input type="radio" id="i3" name="problem" value="not_clear">
            <label for="i3">不清楚</label>
        </form>
        <h3>问答题2(单选):实际工作经验不足1年的人员折腾的学习资料您觉得是否对你有帮助?</h3>
        <form>
            <input type="radio" id="w1" name="problem" value="yes">
            <label for="w1">有</label>
            <input type="radio" id="w2" name="problem" value="no">
            <label for="w2">没有</label>
            <input type="radio" id="w3" name="problem" value="not_clear">
            <label for="w3">不清楚</label>
        </form>
    </body>
</html>

效果如下图:

上面的小栗子中,出了两道问答题,均为单选题。那么,类似的需求都是可以使用输入类型为radio来实现需要使用单选按钮的场景。

3. 复选框

什么是复选框?复选框就是可以选择多个选项,当需要多选的时候,使用复选框输入类型就对了。看下面代码:

<!DOCTYPE html>
<html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>彩虹运维技术栈社区主页</title>
    </head>
    <body>
        <h2>彩虹运维技术栈社区,公众号ID:TtrOpsStack</h2>
        <h3>问答题1(单选):某站长,工作经验不足1年,仅从互联网收集学习资料制定学习路线售卖盈利,从道德层面角度分析是否有问题?</h3>
        <form>
            <input type="checkbox" id="i1" name="problem" value="yes">
            <label for="i1">有</label>
            <input type="checkbox" id="i2" name="problem" value="no">
            <label for="i2">没有</label>
            <input type="checkbox" id="i3" name="problem" value="not_clear">
            <label for="i3">不清楚</label><br>
            <input type="submit" value="提交">
        </form>
        <h3>问答题2(单选):实际工作经验不足1年的人员折腾的学习资料您觉得是否对你有帮助?</h3>
        <form>
            <input type="checkbox" id="w1" name="problem" value="yes">
            <label for="w1">有</label>
            <input type="checkbox" id="w2" name="problem" value="no">
            <label for="w2">没有</label>
            <input type="checkbox" id="w3" name="problem" value="not_clear">
            <label for="w3">不清楚</label><br>
            <input type="submit" value="提交">
        </form>
    </body>
</html>

效果如下图:

上面的小栗子中,实现复选框的输入类型是checkbox,这个是重点哦!

4. 提交按钮

当有数据要提交给后端的时候怎么搞?如果后端是API服务,可以给它提交json。如果是前端页面,就需要通过构建表单来获取用户的输入。基于表单提交数据给后端,怎么提交?需要一个可以点击的提交按钮,那这个按钮怎么来?先看下面代码:

<!DOCTYPE html>
<html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>彩虹运维技术栈社区主页</title>
    </head>
    <body>
        <h2>彩虹运维技术栈社区,公众号ID:TtrOpsStack</h2>
        <h3>主机信息</h3>
        <form>
            <label for="ipaddr">IP地址</label>
            <input type="text" id="ipaddr" name="ip"><br>
            <input type="submit" value="提交">
        </form>
    </body>
</html>

效果如下图:

输入类型为submit,说明它就是提交按钮,注意上面代码type="submit"了吗?

HTML表单重要属性

1. Action属性

在之前的例子中,前端表单需要将数据提交给后端,除了需要一个提交按钮外,还需要action属性。当点击提交按钮后,表单的数据该发到后端的哪个url进行处理,就是定义在action属性中。接下来,我们结合前端和后端直接来个小实战,后端代码用Python的Flask框架。

前端代码:

<!DOCTYPE html>
<html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>彩虹运维技术栈社区主页</title>
    </head>
    <body>
        <h2>彩虹运维技术栈社区,公众号ID:TtrOpsStack</h2>
        <h3>主机信息</h3>
        <form action="http://192.168.11.10:8088/ttropsstack" target="_blank">
            <label for="ipaddr">IP地址</label>
            <input type="text" id="ipaddr" name="ip"><br>
            <input type="submit" value="提交">
        </form>
    </body>
</html>

后端代码:

from flask import Flask, request

webapp = Flask(__name__)

@webapp.route('/ttropsstack', methods=["GET", "POST"])
def ttropsstack():
    args = request.args
    print 'ip addr is: %s' % args.get('ip')
    return 'ok'

if __name__ == '__main__':

    webapp.run(host="0.0.0.0", port=8088, debug=True)

前端和后端的代码写完后,我们接下来看看效果

输入IP地址后,点击提交

这个ok是后端返回的

后端接收到数据后,啥也没做,只是做了简单打印

这个小栗子很简单,通过这个小栗子,是不是对action属性的用法有了进一步的理解呢?

2. Method属性

method属性的用途是指定提交数据的http方法,通常有2个,get和post。接下来我们在上个小栗子的基础上做个小改造,看下面代码

前端代码:

<!DOCTYPE html>
<html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>彩虹运维技术栈社区主页</title>
    </head>
    <body>
        <h2>彩虹运维技术栈社区,公众号ID:TtrOpsStack</h2>
        <h3>主机信息</h3>
        <form action="http://192.168.11.10:8088/ttropsstack" target="_blank" method="get">
            <label for="ipaddr">IP地址</label>
            <input type="text" id="ipaddr" name="ip"><br>
            <input type="submit" value="提交">
        </form>
    </body>
</html>

后端代码:

from flask import Flask, request

webapp = Flask(__name__)

@webapp.route('/ttropsstack', methods=["POST"])
def ttropsstack():
    args = request.args
    print 'ip addr is: %s' % args.get('ip')
    return 'ok'

if __name__ == '__main__':

    webapp.run(host="0.0.0.0", port=8088, debug=True)

当前端输入数据后,提交表单时,直接告诉你这是不允许的方法

在这个例子中,是因为前端的表单了指定了method为get请求,而后端接收数据的method规定了需要post请求,故所以出现这个问题。

下面我们改造一下后端代码:

# coding: utf8
from flask import Flask, request

webapp = Flask(__name__)

@webapp.route('/ttropsstack', methods=['GET','POST'])
def ttropsstack():
    if request.method == 'POST':
        print request.get_data(as_text=True)
        return 'ok'
    else:
        return '提交数据需要post请求'

if __name__ == '__main__':

    webapp.run(host="0.0.0.0", port=8088, debug=True)

前端表单中的method还是保持get请求,再次提交,后端的返回如下:

看到了吗?后端判断前端过来的请求是get还是post,很显然,前端过来的请求是get,并且返回了非常友好的提示。

接下来我们继续改造一下前端的代码,将请求修改为post,代码如下:

<!DOCTYPE html>
<html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>彩虹运维技术栈社区主页</title>
    </head>
    <body>
        <h2>彩虹运维技术栈社区,公众号ID:TtrOpsStack</h2>
        <h3>主机信息</h3>
        <form action="http://192.168.11.10:8088/ttropsstack" target="_blank" method="post">
            <label for="ipaddr">IP地址</label>
            <input type="text" id="ipaddr" name="ip"><br>
            <input type="submit" value="提交">
        </form>
    </body>
</html>

后端代码也稍微改造一下,改变接收前端数据的方法

# coding: utf8
from flask import Flask, request

webapp = Flask(__name__)

@webapp.route('/ttropsstack', methods=['GET','POST'])
def ttropsstack():
    if request.method == 'POST':
        a = request.form
        print a.get('ip')
        print type(a)
        return 'ok'
    else:
        return '提交数据需要post请求'

if __name__ == '__main__':

    webapp.run(host="0.0.0.0", port=8088, debug=True)

输入IP地址,并点击提交

提交后,后端给前端返回了ok

接下来看下后端,后端啥也没做,就获取到表单的数据,然后打印了数据,并且打印了下数据类型

好了,关于前端的action属性和Method属性就讲到这里了。为了讲解action和method,还结合了后端的一丢丢知识,前端和后端的知识点以后都会慢慢讲到哈!

HTML表单常用元素

1. 下拉列表

先来个前端代码:

<!DOCTYPE html>
<html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>彩虹运维技术栈社区主页</title>
    </head>
    <body>
        <h2>彩虹运维技术栈社区,公众号ID:TtrOpsStack</h2>
        <form action="http://192.168.11.10:8088/ttropsstack" target="_blank" method="post">
            <label for="opslist">运维开发应掌握的技能:</label>
            <select id="opslist" name="opslist">
                <option value="python">Python语言</option>
                <option value="go">Go语言</option>
                <option value="shell">Shell语言</option>
                <option value="database">数据库</option>
                <option value="frontend">前端</option>
                <option value="linux">Linux</option>
                <option value="network">网络</option>
                <option value="storage">存储</option>
            </select>
            <input type="submit">
        </form>
    </body>
</html>

后端代码:

# coding: utf8
from flask import Flask, request

webapp = Flask(__name__)

@webapp.route('/ttropsstack', methods=['GET','POST'])
def ttropsstack():
    if request.method == 'POST':
        a = request.form
        print a.get('opslist')
        return 'ok'
    else:
        return '提交数据需要post请求'

if __name__ == '__main__':

    webapp.run(host="0.0.0.0", port=8088, debug=True)

在下拉框中选择“Go语言”,并提交

后端啥也没干,就只做了打印

2. 允许多选

前端代码:

<!DOCTYPE html>
<html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>彩虹运维技术栈社区主页</title>
    </head>
    <body>
        <h2>彩虹运维技术栈社区,公众号ID:TtrOpsStack</h2>
        <form action="http://192.168.11.10:8088/ttropsstack" target="_blank" method="post">
            <label for="opslist">运维开发应掌握的技能:</label>
            <select id="opslist" name="opslist" size="6" multiple>
                <option value="python">Python语言</option>
                <option value="go">Go语言</option>
                <option value="shell">Shell语言</option>
                <option value="database">数据库</option>
                <option value="frontend">前端</option>
                <option value="linux">Linux</option>
                <option value="network">网络</option>
                <option value="storage">存储</option>
            </select>
            <input type="submit">
        </form>
    </body>
</html>

上述前端代码中,是使用multiple属性来实现选择多个值。

后端代码的打印方式稍微做了些许调整:

# coding: utf8
from flask import Flask, request

webapp = Flask(__name__)

@webapp.route('/ttropsstack', methods=['GET','POST'])
def ttropsstack():
    if request.method == 'POST':
        data = request.get_data()
        print data
        return 'ok'
    else:
        return '提交数据需要post请求'

if __name__ == '__main__':

    webapp.run(host="0.0.0.0", port=8088, debug=True)

按住ctrl或者shift键可进行多选

后端打印的效果图下图:

写在最后

关于表单基础知识点的讲解就这么愉快的结束了,关于更多表单的元素、输入属性、输入类型可自行查阅和实战,笔者因时间有限就不一一演示。感谢您的阅读,望多多关注我们、点赞、转发!

本文转载于(喜欢的盆友关注我们):https://mp.weixin.qq.com/s/L-Msv39JrF7AzRx4K1OLjA

一章节我们通过在html中直接编写表单的方式进行数据传递,并且在视图中对前端传递的数据进行了简单的认证,但是如果把验证数据的代码与逻辑混合在一起,将使得视图的代码不够清晰,并且难以维护,稍加疏忽就会产生验证漏洞,如果细心的同学其实可以发现,在之前的登录注册中我们一直没有对空表单进行验证,当然这是我故意为之,但如果在生产环境,这将是一个灾难的开始,所以,在编程中无论是前端还是后端都要求要对数据进行验证,作为后端,更要保持一种永远不相信前端传递数据的态度去做数据校验。

本章节我们将使用Flask官方推荐的Flask-WTF扩展来重构我们的登录注册表单!

关于Flask-WTF

Flask-WTF是Flask 和 WTForms 的简单集成,包括 CSRF、文件上传和 reCAPTCHA。

  • 安装Flask-WTF:
pip install Flask-WTF

创建登录注册表单类

app/auth/目录下新建一个forms.py的文件,所有的表单验证代码都放到这个文件当中!

构建登录表单

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField
from wtforms.validators import DataRequired, Length, ValidationError, EqualTo
from werkzeug.security import check_password_hash
from .models import User

class LoginForm(FlaskForm):
    # 登录表单

    def qs_username(username):
        # 对该字段进行在传递之前处理
        u = f'{username}123456'
        print(u)
        return username

    username = StringField('username', validators=[
        DataRequired(message="不能为空"), 
        Length(max=32, message="不符合字数要求!")
        ], filters=(qs_username,))
    password = PasswordField('password', validators=[
        DataRequired(message="不能为空"),
        Length(max=32, message="不符合字数要求!")
        ])

    def validate_username(form, field):
        user = User.query.filter_by(username=field.data).first()
        if user is None:
            error = '该用户不存在!'
            raise ValidationError(error)
        elif not check_password_hash(user.password, form.password.data):
            raise ValidationError('密码不正确')

代码详解:

class LoginForm(FlaskForm): 创建了一个登录表单类,继承了FlaskForm类

StringField, PasswordField

这些都是wtforms内置的字段,负责呈现和数据转换。

官方文档:https://wtforms.readthedocs.io/en/3.0.x/fields/

他继承自Filed的基类,其中有一些比较重要的参数我们大概在这里理解一下!

第一个字符串其实是该类的label参数,字段的标签,也就是转换到html中的label!

validators传入对该字段的一些验证器,在提交数据之前对数据进行验证!

filters这个参数比较特殊,官方文档并没有对其详细说明,只说是筛选器,其实怎么说就是在额外的方法中对该字段的值提前处理过滤,元组中的每个值都是一个回调函数,函数不需要传入括号,但这个回调函数默认有一个参数,这个参数就是本身该字段的值,所以在定义该函数时就必须传入一个参数!例如:我们定义username之前定义的这个方法!

def qs_username(username):
    # 对该字段进行在传递之前处理
    u = f'{username}123456'
    print(u)
    return username

备注:必须返回处理后的这个参数,否则会触发DataRequired验证器,后端获取不到该表单的值!

  • DataRequired, Length 这是内置的验证器,第一个是验证字段是否为空,第二个Length是验证输入长度,当然内置的还有很多,这里就不一一列举,具体我们可参考文档!

官方文档: https://wtforms.readthedocs.io/en/3.0.x/validators/#custom-validators

自定义验证用户名和密码

在之前的视图函数中我们对用户名和密码都做了校验,现在我们需要把验证的代码全部移动到表单类中,代码如下:

def validate_username(form, field):
    user = User.query.filter_by(username=field.data).first()
    if user is None:
        error = '该用户不存在!'
        raise ValidationError(error)
    elif not check_password_hash(user.password, form.password.data):
        raise ValidationError('密码不正确')
  • validate_username(form, field)

这个函数的写法是固定的validate_{filed},validate_后边的filed是指你需要验证的某个字段名,比如我们这个验证,他主要就是对username字段进行验证,这个函数中参数的filed就是这个字段,通过field.data就可以获取到usernam的值。form参数则指代的是整个表单,可以用form.{filed}.data的方式获取表单类中某个具体字段的值!

构建注册表单

当了解了登录表单后,我们完全就可以参照登录表单去实现注册表单,代码如下:

路径:app/auth/forms.py

class RegisterForm(FlaskForm):
    # 注册表单
    username = StringField('username', validators=[
        DataRequired(message="不能为空"), 
        Length(min=2, max=32, message="超过限制字数!")
        ])
    password = PasswordField('password', validators=[
        DataRequired(message="不能为空"),
        Length(min=2, max=32, message="超过限制字数!"),
        EqualTo('password1', message='两次密码输入不一致!')
        ])
    password1 = PasswordField('password1')

    def validate_username(form, field):
        user = User.query.filter_by(username=field.data).first()
        if user is not None:
            error = '该用户名称已存在!'
            raise ValidationError(error)

这里唯一需要注意的是两次密码是否输入一致,我们用了一个内置的验证器EqualTo,使用方式可完全参照代码,他会自动校验password和password1输入的值是否一致!

重构登录和注册视图

  • 路径:app/auth/views/auth.py
from ..forms import LoginForm, RegisterForm

@bp.route('/login', methods=['GET', 'POST'])
def login():
    # 登录视图
    # form = LoginForm(meta={'csrf': False}) # 禁用csrf
    form = LoginForm()
    if form.validate_on_submit():
        user = auth.User.query.filter_by(username=form.username.data).first()
        session.clear()
        session['user_id'] = user.id
        return redirect(url_for('index'))
    return render_template('login.html', form=form)


@bp.route('/register', methods=['GET', 'POST'])
def register():
    # 注册视图
    form = RegisterForm()
    if form.validate_on_submit():
        user = auth.User(username=form.username.data, password=generate_password_hash(form.password.data))
        db.session.add(user)
        db.session.commit()
        session.clear()
        session['user_id'] = user.id
        return redirect(url_for('index'))
    return render_template('register.html', form=form)

1、首先从forms.py中引入了我们定义的登录(LoginForm)和注册(RegisterForm)表单类!

2、form = RegisterForm() 实例化表单类

3、if form.validate_on_submit(): 验证前端传递的数据是否有效,并且会自动判断是POST请求还是GET请求!

4、 数据验证通过则进入之后的逻辑,未验证通过则返回我们在表单类中传入的验证提示!

模板中调用验证信息

我们以调用username字段的验证提示为例,在模板中加入这段代码即可获得错误提示!

<!-- 表单验证 -->
{% if form.username.errors %}
<b-message type="is-danger">
    <ul class="errors">
        {% for error in form.username.errors %}
            <li>{{ error }}</li>
        {% endfor %}
    </ul>
</b-message>
{% endif %}

重构登录注册html模板

路径:app/auth/templates/login.html 以登陆表单为例,代码如下:

{% block auth_form %}
    <form action="" method="post" style="margin-top: 40%;" class="box">
        <div class=" has-text-centered mb-3">
          <p class=" subtitle">登录</p>
          <h1 class="title">FlaskBlog</h1>
        </div>
        {{ form.csrf_token }}
        <!-- 消息闪现 -->
        {% with messages = get_flashed_messages() %}
        <b-message type="is-danger">
          {% if messages %}
          <ul class=flashes>
            {% for message in messages %}
            <li>{{ message }}</li>
            {% endfor %}
          </ul>
          {% endif %}
        </b-message>
        {% endwith %}

        <!-- 表单验证 -->
        {% if form.username.errors %}
        <b-message type="is-danger">
          <ul class="errors">
            {% for error in form.username.errors %}
            <li>{{ error }}</li>
            {% endfor %}
          </ul>
        </b-message>
        {% endif %}

        <div class="field">
          <p class="control has-icons-left has-icons-right">
            {{ form.username(class='input', placeholder='Username') }}
            <span class="icon is-small is-left">
              <i class="fas fa-envelope"></i>
            </span>
            <span class="icon is-small is-right">
              <i class="fas fa-check"></i>
            </span>
          </p>
        </div>
        <div class="field">
          <p class="control has-icons-left">
            {{ form.password(class='input', placeholder='Password') }}
            <span class="icon is-small is-left">
              <i class="fas fa-lock"></i>
            </span>
          </p>
        </div>
        <div class="field">
          <p class="control">
            <input class="button is-success is-fullwidth" type="submit" value="Login">
          </p>
        </div>
      </form>
    {% endblock auth_form %}

{{ form.csrf_token }} 隐式的创建一个csrftoken的表单

{{ form.username(class='input', placeholder='Username') }} 这样就可以直接获得一个表单html并自动渲染,向该表单增加书香的方式就是像代码中这样传入参数和值即可,当然也可以提前在表单类中定义!

剩下的注册表单,就当是给大家留作的一个作业,大家自行去参照登录表单完善重构一下,加油哦!我相信你可以!

到这里我们的表单验证就大概了解了,之后的章节就是基本的增删改查以及表单验证,都是基于我们这些章节学习的知识点,所以之后的章节就不会过多的去讲解每行代码的意思,重心放在逻辑的展示上,如果基础较差的同学,到这里,可以去反复的把前边所有章节的内容去练习,写代码其实就是写的多了就会了,也就理解了,练习 练习 再练习!