标签:validator 管理系 方法 就是 失败 duration 大型网站 模板 空白
form组件主要是帮助我们做验证的插件。这个是Django给我们提供的一个插件,比如用户名密码多少位,由什么组成,邮箱的格式等等。如果没有form组件,我们也可以做,就是麻烦一些。
验证分为:
前端验证
但是,前端验证不太安全,我们可以通过浏览器屏蔽掉。一般的网站验证数据时:前端验证+后端验证,或者hi直接时后端验证。
大型万丈为什么不用模板语言,去前端渲染数据?
因为大型网站,需要获取后端的数据非常多,如果你用模板语言,render,你是一个一个按顺序从上至下同步的替换,效率太低,就会出现白屏效应。出现大白屏,用户体验感非常不好。所以一般中小型项目,内部管理系统都是模板语言MTV模式,而大型网站都是前后端分离技术(MVC的模式)。
这个组件提供了三个功能:
1、可以自动生成前端标签
2、可以对用户提交的数据进行验证
3、可以保留用户之前输入的内容
点击登录、页面刷新,还保留了我之前输入的用户名密码
再三强调,form组件提供的功能,我们自己都可以实现,只不过有了它更加方便和快速的开发。锦上添花。
form组件的标签有:
Radioselect ——> radio单选
select --> 单选select框
selectMultiple --> 多选select框
checkboxinput --> 单选checkbox
Checkboxselectmultiple --> 多选的checkbox
date --> 日期
?
# 在下面都有详细的讲述
1、重新创建一个项目启动一个流程
我们写一个注册的功能。
需求:用户名长度8到14位之间。
如果用户名没有满足此要求,我们要在前端希纳是错误提示。
不基于form组件的注册功能:
urls:
from django.conf.urls import url
from django.contrib import admin
from app01 import views
?
urlpatterns = [
url(r‘^admin/‘, admin.site.urls),
url(r‘^register/‘, views.register, name=‘register‘),
]
?
?
?
views:
from django.shortcuts import render, HttpResponse
?
# Create your views here.
?
def register(request):
error_msg = ‘‘
if request.method == ‘POST‘:
username = request.POST.get(‘username‘)
password = request.POST.get(‘password‘)
if 8 <= len(username) <= 14:
print(‘将用户名、密码写入数据库‘)
return HttpResponse(‘注册成功‘)
else:
error_msg = ‘用户名或密码错误‘
return render(request, ‘register.html‘, {‘error_msg‘: error_msg})
html:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
span{
color:red;
font-size: 15px;
}
</style>
</head>
<body>
<h1>注册界面</h1>
<form action="" method="post">
{% csrf_token %}
用户名:<input type="text" name="username">
<br>
密码:<input type="password" name="password">
<br>
<span>{{ error_msg }}</span>
<br>
<input type="submit">
</form>
</body>
</html>
我们先利用哦个form组件,帮助我么能生产前端的input标签(form主键主要是针对input标签的自动生、校验、保留之前的数据)
urls:
from django.conf.urls import url
from django.contrib import admin
from app01 import views
?
urlpatterns = [
url(r‘^admin/‘, admin.site.urls),
url(r‘^register/‘, views.register, name=‘register‘),
]
?
?
?
views:
from django.shortcuts import render, HttpResponse
from django import forms
?
# Create your views here.
?
class RegisterForm(forms.Form):
"""
form组件生成前端的标签写法,与models构架类的表结构非常相似
"""
name = forms.CharField()
password = forms.CharField()
?
def register(request):
form_obj = RegisterForm()
?
if request.method == ‘POST‘:
username = request.POST.get(‘name‘)
password = request.POST.get(‘password‘)
if 8 <= len(username) <= 14:
print(‘将用户名、密码写入数据库‘)
return HttpResponse(‘注册成功‘)
else:
return HttpResponse(‘验证失败‘)
return render(request, ‘register.html‘, {‘form_obj‘: form_obj})
?
html:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
span{
color:red;
font-size: 15px;
}
</style>
</head>
<body>
<h1>注册界面</h1>
<form action="" method="post">
{% csrf_token %}
{{ form_obj.as_p }}
<input type="submit">
</form>
</body>
</html>
?
# 一个as_p方法,帮助我们自动生成了两个input标签,还有两个label表亲啊,并且增加了一些属性,name、id属性。
as_p这个方法一般我们不用,这个时一键生成,用起来虽然简单,封装程度高,不利于自定制。工作中一般都是一个一个标签去生成的,不要一键生成。
单独生成某些标签
单独生成某些标签,需要我们自己配置中文的 用户名、密码
我们的form表单中,常用的有什么样的标签?下面这些标签,我通过form组件都可以生成,并且可以配置样式,也可以引入bootstrap等插件。
input:
type = text
type = password
type = redio
type = checkbox
select 单选
select 多选
password
widget这个功能可以当成一个小工具,这个工具就是确定标签类型以及增加标签的属性。
之前的密码是:明文的
利用widget将密码变成密文的形式
引入bootstrap的样式:
在引入bootstrap.css后 :利用attrs增加bootstrap样式
password = forms.CharField(
label=‘密码:‘,
widget=forms.widgets.PasswordInput(attrs={‘class‘: ‘form-control‘}),
)
Radioselect
radio单选
views:
from django.shortcuts import render, HttpResponse
from django import forms
?
# Create your views here.
?
class RegisterForm(forms.Form):
"""
form组件生成前端的标签写法,与models构架类的表结构非常相似
"""
name = forms.CharField(label=‘用户名:‘)
password = forms.CharField(
label=‘密码:‘,
widget=forms.widgets.PasswordInput(attrs={‘class‘: ‘form-control‘}),
)
sex = forms.ChoiceField(
label=‘性别:‘,
initial=1, # 设置初始值
choices=((1, ‘男‘), (2, ‘?‘), (3, ‘未知‘)),
widget=forms.widgets.RadioSelect, # 标签类型
)
?
?
def register(request):
form_obj = RegisterForm()
?
if request.method == ‘POST‘:
username = request.POST.get(‘name‘)
password = request.POST.get(‘password‘)
if 8 <= len(username) <= 14:
print(‘将用户名、密码写入数据库‘)
return HttpResponse(‘注册成功‘)
else:
return HttpResponse(‘验证失败‘)
return render(request, ‘register.html‘, {‘form_obj‘: form_obj})
html:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
span{
color:red;
font-size: 15px;
}
</style>
</head>
<body>
<h1>注册界面</h1>
<form action="" method="post">
{% csrf_token %}
<div>
<label for="">{{ form_obj.name.label }}</label>
{{ form_obj.name }}
</div>
<div>
<label for="">{{ form_obj.password.label }}</label>
{{ form_obj.password }}
</div>
<div>
<label for="">{{ form_obj.sex.label }}</label>
{{ form_obj.sex }}
</div>
<input type="submit">
</form>
</body>
</html>
select
单选select框
views:
from django.shortcuts import render, HttpResponse
from django import forms
?
# Create your views here.
?
class RegisterForm(forms.Form):
"""
form组件生成前端的标签写法,与models构架类的表结构非常相似
"""
name = forms.CharField(label=‘用户名:‘)
password = forms.CharField(
label=‘密码:‘,
widget=forms.widgets.PasswordInput(attrs={‘class‘: ‘form-control‘}),
)
sex = forms.ChoiceField(
label=‘性别:‘,
initial=1, # 设置初始值
choices=((1, ‘男‘), (2, ‘?‘), (3, ‘未知‘)),
widget=forms.widgets.RadioSelect, # 标签类型
)
area = forms.ChoiceField(
label=‘地区:‘,
initial=1, # 设置初始值
choices=((1, ‘涿州‘), (2, ‘北京‘), (3, ‘保定‘)),
widget=forms.widgets.Select, # 标签类型
)
?
?
def register(request):
form_obj = RegisterForm()
?
if request.method == ‘POST‘:
username = request.POST.get(‘name‘)
password = request.POST.get(‘password‘)
if 8 <= len(username) <= 14:
print(‘将用户名、密码写入数据库‘)
return HttpResponse(‘注册成功‘)
else:
return HttpResponse(‘验证失败‘)
return render(request, ‘register.html‘, {‘form_obj‘: form_obj})
?
?
?
?
html:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
span{
color:red;
font-size: 15px;
}
</style>
</head>
<body>
<h1>注册界面</h1>
<form action="" method="post">
{% csrf_token %}
<div>
<label for="">{{ form_obj.name.label }}</label>
{{ form_obj.name }}
</div>
<div>
<label for="">{{ form_obj.password.label }}</label>
{{ form_obj.password }}
</div>
<div>
<label for="">{{ form_obj.sex.label }}</label>
{{ form_obj.sex }}
</div>
<div>
<label for="">{{ form_obj.area.label }}</label>
{{ form_obj.area }}
</div>
<input type="submit">
</form>
</body>
</html>
selectMultiple
多选select选框
views:
from django.shortcuts import render, HttpResponse
from django import forms
?
# Create your views here.
?
class RegisterForm(forms.Form):
"""
form组件生成前端的标签写法,与models构架类的表结构非常相似
"""
name = forms.CharField(label=‘用户名:‘)
password = forms.CharField(
label=‘密码:‘,
widget=forms.widgets.PasswordInput(attrs={‘class‘: ‘form-control‘}),
)
sex = forms.ChoiceField(
label=‘性别:‘,
initial=1, # 设置初始值
choices=((1, ‘男‘), (2, ‘?‘), (3, ‘未知‘)),
widget=forms.widgets.RadioSelect, # 标签类型
)
area = forms.ChoiceField(
label=‘地区:‘,
initial=1, # 设置初始值
choices=((1, ‘涿州‘), (2, ‘北京‘), (3, ‘保定‘)),
widget=forms.widgets.Select, # 标签类型
)
author = forms.MultipleChoiceField(
label=‘作者:‘,
initial=(1, 2), # 设置初始值
choices=((1, ‘张三‘), (2, ‘李四‘), (3, ‘王五‘)),
widget=forms.widgets.SelectMultiple, # 标签类型
)
?
?
def register(request):
form_obj = RegisterForm()
?
if request.method == ‘POST‘:
username = request.POST.get(‘name‘)
password = request.POST.get(‘password‘)
if 8 <= len(username) <= 14:
print(‘将用户名、密码写入数据库‘)
return HttpResponse(‘注册成功‘)
else:
return HttpResponse(‘验证失败‘)
return render(request, ‘register.html‘, {‘form_obj‘: form_obj})
?
?
html:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
span{
color:red;
font-size: 15px;
}
</style>
</head>
<body>
<h1>注册界面</h1>
<form action="" method="post">
{% csrf_token %}
<div>
<label for="">{{ form_obj.name.label }}</label>
{{ form_obj.name }}
</div>
<div>
<label for="">{{ form_obj.password.label }}</label>
{{ form_obj.password }}
</div>
<div>
<label for="">{{ form_obj.sex.label }}</label>
{{ form_obj.sex }}
</div>
<div>
<label for="">{{ form_obj.area.label }}</label>
{{ form_obj.area }}
</div>
<div>
<label for="">{{ form_obj.author.label }}</label>
{{ form_obj.author }}
</div>
<input type="submit">
</form>
</body>
</html>
checkboxinput
单选checkbox
views: from django.shortcuts import render, HttpResponse from django import forms # Create your views here. class RegisterForm(forms.Form): """ form组件生成前端的标签写法,与models构架类的表结构非常相似 """ name = forms.CharField(label=‘用户名:‘) password = forms.CharField( label=‘密码:‘, widget=forms.widgets.PasswordInput(attrs={‘class‘: ‘form-control‘}), ) sex = forms.ChoiceField( label=‘性别:‘, initial=1, # 设置初始值 choices=((1, ‘男‘), (2, ‘?‘), (3, ‘未知‘)), widget=forms.widgets.RadioSelect, # 标签类型 ) area = forms.ChoiceField( label=‘地区:‘, initial=1, # 设置初始值 choices=((1, ‘涿州‘), (2, ‘北京‘), (3, ‘保定‘)), widget=forms.widgets.Select, # 标签类型 ) author = forms.MultipleChoiceField( label=‘作者:‘, initial=(1, 2), # 设置初始值 choices=((1, ‘张三‘), (2, ‘李四‘), (3, ‘王五‘)), widget=forms.widgets.SelectMultiple, # 标签类型 ) keep = forms.ChoiceField( label=‘是否记住密码‘, initial=1, # 设置初始值 choices=((‘True‘, 1), (‘Flase‘, 0)), widget=forms.widgets.CheckboxInput, # 标签类型 ) def register(request): form_obj = RegisterForm() if request.method == ‘POST‘: username = request.POST.get(‘name‘) password = request.POST.get(‘password‘) if 8 <= len(username) <= 14: print(‘将用户名、密码写入数据库‘) return HttpResponse(‘注册成功‘) else: return HttpResponse(‘验证失败‘) return render(request, ‘register.html‘, {‘form_obj‘: form_obj}) html: <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <style> span{ color:red; font-size: 15px; } </style> </head> <body> <h1>注册界面</h1> <form action="" method="post"> {% csrf_token %} <div> <label for="">{{ form_obj.name.label }}</label> {{ form_obj.name }} </div> <div> <label for="">{{ form_obj.password.label }}</label> {{ form_obj.password }} </div> <div> <label for="">{{ form_obj.sex.label }}</label> {{ form_obj.sex }} </div> <div> <label for="">{{ form_obj.area.label }}</label> {{ form_obj.area }} </div> <div> <label for="">{{ form_obj.author.label }}</label> {{ form_obj.author }} </div> <div> {{ form_obj.keep }} <label for="">{{ form_obj.keep.label }}</label> </div> <input type="submit"> </form> </body> </html>
Checkboxselectmultiple
多选的checkbox
views: from django.shortcuts import render, HttpResponse from django import forms # Create your views here. class RegisterForm(forms.Form): """ form组件生成前端的标签写法,与models构架类的表结构非常相似 """ name = forms.CharField(label=‘用户名:‘) password = forms.CharField( label=‘密码:‘, widget=forms.widgets.PasswordInput(attrs={‘class‘: ‘form-control‘}), ) sex = forms.ChoiceField( label=‘性别:‘, initial=1, # 设置初始值 choices=((1, ‘男‘), (2, ‘?‘), (3, ‘未知‘)), widget=forms.widgets.RadioSelect, # 标签类型 ) area = forms.ChoiceField( label=‘地区:‘, initial=1, # 设置初始值 choices=((1, ‘涿州‘), (2, ‘北京‘), (3, ‘保定‘)), widget=forms.widgets.Select, # 标签类型 ) author = forms.MultipleChoiceField( label=‘作者:‘, initial=(1, 2), # 设置初始值 choices=((1, ‘张三‘), (2, ‘李四‘), (3, ‘王五‘)), widget=forms.widgets.SelectMultiple, # 标签类型 ) keep = forms.ChoiceField( label=‘是否记住密码‘, initial=1, # 设置初始值 choices=((‘True‘, 1), (‘Flase‘, 0)), widget=forms.widgets.CheckboxInput, # 标签类型 ) hobby = forms.MultipleChoiceField( label=‘爱好‘, choices=((1, ‘抽烟‘), (2, ‘喝酒‘), (3, ‘烫头‘)), widget=forms.widgets.CheckboxSelectMultiple, # 标签类型 ) def register(request): form_obj = RegisterForm() if request.method == ‘POST‘: username = request.POST.get(‘name‘) password = request.POST.get(‘password‘) if 8 <= len(username) <= 14: print(‘将用户名、密码写入数据库‘) return HttpResponse(‘注册成功‘) else: return HttpResponse(‘验证失败‘) return render(request, ‘register.html‘, {‘form_obj‘: form_obj}) html: <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <style> span{ color:red; font-size: 15px; } </style> </head> <body> <h1>注册界面</h1> <form action="" method="post"> {% csrf_token %} <div> <label for="">{{ form_obj.name.label }}</label> {{ form_obj.name }} </div> <div> <label for="">{{ form_obj.password.label }}</label> {{ form_obj.password }} </div> <div> <label for="">{{ form_obj.sex.label }}</label> {{ form_obj.sex }} </div> <div> <label for="">{{ form_obj.area.label }}</label> {{ form_obj.area }} </div> <div> <label for="">{{ form_obj.author.label }}</label> {{ form_obj.author }} </div> <div> {{ form_obj.keep }} <label for="">{{ form_obj.keep.label }}</label> </div> <div> <label for="">{{ form_obj.hobby.label }}</label> {{ form_obj.hobby }} </div> <input type="submit"> </form> </body> </html>
date
views: from django.shortcuts import render, HttpResponse from django import forms # Create your views here. class RegisterForm(forms.Form): """ form组件生成前端的标签写法,与models构架类的表结构非常相似 """ name = forms.CharField(label=‘用户名:‘) password = forms.CharField( label=‘密码:‘, widget=forms.widgets.PasswordInput(attrs={‘class‘: ‘form-control‘}), ) sex = forms.ChoiceField( label=‘性别:‘, initial=1, # 设置初始值 choices=((1, ‘男‘), (2, ‘?‘), (3, ‘未知‘)), widget=forms.widgets.RadioSelect, # 标签类型 ) area = forms.ChoiceField( label=‘地区:‘, initial=1, # 设置初始值 choices=((1, ‘涿州‘), (2, ‘北京‘), (3, ‘保定‘)), widget=forms.widgets.Select, # 标签类型 ) author = forms.MultipleChoiceField( label=‘作者:‘, initial=(1, 2), # 设置初始值 choices=((1, ‘张三‘), (2, ‘李四‘), (3, ‘王五‘)), widget=forms.widgets.SelectMultiple, # 标签类型 ) keep = forms.ChoiceField( label=‘是否记住密码‘, initial=1, # 设置初始值 choices=((‘True‘, 1), (‘Flase‘, 0)), widget=forms.widgets.CheckboxInput, # 标签类型 ) hobby = forms.MultipleChoiceField( label=‘爱好‘, choices=((1, ‘抽烟‘), (2, ‘喝酒‘), (3, ‘烫头‘)), widget=forms.widgets.CheckboxSelectMultiple, # 标签类型 ) date = forms.CharField( label=‘出生日期:‘, initial=‘2000-06-23‘, # 默认日期 widget=forms.widgets.TextInput(attrs={‘type‘: ‘date‘}), # 标签类型 ) def register(request): form_obj = RegisterForm() if request.method == ‘POST‘: username = request.POST.get(‘name‘) password = request.POST.get(‘password‘) if 8 <= len(username) <= 14: print(‘将用户名、密码写入数据库‘) return HttpResponse(‘注册成功‘) else: return HttpResponse(‘验证失败‘) return render(request, ‘register.html‘, {‘form_obj‘: form_obj}) html: <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <style> span{ color:red; font-size: 15px; } </style> </head> <body> <h1>注册界面</h1> <form action="" method="post"> {% csrf_token %} <div> <label for="">{{ form_obj.name.label }}</label> {{ form_obj.name }} </div> <div> <label for="">{{ form_obj.password.label }}</label> {{ form_obj.password }} </div> <div> <label for="">{{ form_obj.sex.label }}</label> {{ form_obj.sex }} </div> <div> <label for="">{{ form_obj.area.label }}</label> {{ form_obj.area }} </div> <div> <label for="">{{ form_obj.author.label }}</label> {{ form_obj.author }} </div> <div> {{ form_obj.keep }} <label for="">{{ form_obj.keep.label }}</label> </div> <div> <label for="">{{ form_obj.hobby.label }}</label> {{ form_obj.hobby }} </div> <div> <label for="">{{ form_obj.date.label }}</label> {{ form_obj.date }} </div> <input type="submit"> </form> </body> </html>
form组件已经生成了前端的标签,要对你输入的内容在后端进行验证。
我们现在研究的form组件的校验,我们先把浏览器的校验屏蔽掉。
然后我们在前端:
接下来我们在放开password字段:
form_obj.errors将所有的报错字段的错误信息全部展示出来了。我们不因该将所有的错误信息都显示出来,我们应该是哪个标签有错误,就在哪个标签后面显示这个标签的错误即可。
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <style> span{ color:red; font-size: 15px; } </style> </head> <body> <h1>注册界面</h1> <form action="" method="post"> {% csrf_token %} <div> <label for="">{{ form_obj.name.label }}</label> {{ form_obj.name }} {# {{ form_obj.errors }}#} {{ form_obj.name.errors }} </div> <div> <label for="">{{ form_obj.password.label }}</label> {{ form_obj.password }} {# {{ form_obj.errors }}#} {{ form_obj.password.errors }} </div> <input type="submit"> </form> </body> </html>
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <style> span{ color:red; font-size: 15px; } </style> </head> <body> <h1>注册界面</h1> <form action="" method="post"> {% csrf_token %} <div> <label for="">{{ form_obj.name.label }}</label> {{ form_obj.name }} {# {{ form_obj.errors }}#} <span style="color: red; font-size: 14px">{{ form_obj.name.errors.0 }}</span> </div> <div> <label for="">{{ form_obj.password.label }}</label> {{ form_obj.password }} {# {{ form_obj.errors }}#} <span style="color: red; font-size: 14px">{{ form_obj.password.errors.0 }}</span> </div> <input type="submit"> </form> </body> </html>
class RegisterForm(forms.Form): """ form组件生成前端的标签写法,与models构建的表结构非常相似 """ name = forms.CharField( label=‘用户名:‘, required=True, # 必须填入内容的设置,默认为True initial=‘dong‘, # 设置初始值 min_length=8, max_length=14, error_messages={‘min_length‘: ‘太短了‘, ‘max_length‘: ‘太长了‘, ‘required‘: ‘必须填写内容‘}, widget=forms.widgets.TextInput(), ) password = forms.CharField( label=‘密码:‘, min_length=6, # widget这个功能可以当成一个工具,这个工具就是确认标签类型以及i增加标签属性的 error_messages={‘min_length‘: ‘太短了‘}, widget=forms.widgets.PasswordInput, )
Field required=True, 是否允许为空 widget=None, HTML插件 label=None, 用于生成Label标签或显示内容 initial=None, 初始值 hele_text=‘‘, 帮助信息(在标签旁边显示) error_mesages=None, 错误信息{‘required‘:‘不能为空‘, ‘invalid‘:‘格式错误‘} validators=[], 自定义验证规则 localize=False, 是否支持本地化 disabled=False, 是否可以编辑 label_suffix=None Label内容后缀
name = forms.CharField( label=‘用户名:‘, required=True, # 必须填入内容的设置,默认为True initial=‘dong‘, # 设置初始值 min_length=8, max_length=12, help_text=‘用户名不能有特殊字符‘, error_messages={‘min_length‘: ‘太短了‘, ‘max_length‘: ‘太长了‘, ‘required‘: ‘必须填写内容‘}, widget=forms.widgets.TextInput(), ) password = forms.CharField( label=‘密码:‘, min_length=6, help_text=‘密码不得少于8位‘, # widget这个功能可以当成一个工具,这个工具就是确认标签类型以及i增加标签属性的 error_messages={‘min_length‘: ‘太短了‘}, widget=forms.widgets.PasswordInput, )
CharField(Field) max_length=None, 最大长度 min_length=None, 最小长度 strip=True 是否移除用户输入空白 IntegerField(Field) max_value=None, 最大值 min_value=None, 最小值 FloatField(IntegerField) ... DecimalField(IntegerField) max_value=None, 最大值 min_value=None, 最小值 max_digits=None, 总长度 decimal_places=None, 小数位长度 BaseTemporalField(Field) input_formats=None 时间格式化 DateField(BaseTemporalField) 格式:2015-09-01 TimeField(BaseTemporalField) 格式:11:12 DateTimeField(BaseTemporalField)格式:2015-09-01 11:12 DurationField(Field) 时间间隔:%d %H:%M:%S.%f ...
标签:validator 管理系 方法 就是 失败 duration 大型网站 模板 空白
原文地址:https://www.cnblogs.com/muyangxiaodong/p/13196259.html