AngularDart4.0 指南- 模板语法一 顶

学习如何编写显示数据并在数据绑定的帮助下使用用户事件的模板。 Angular应用程序管理用户看到和可以做的事情,通过组件类实例(组件)和面向用户的模板的交互来实现这一点。 您可以熟悉模型 - 视图 - 控制器(MVC)或模型 - 视图 - 视图模型(MVVM)的组件/模板。 在Angular中,组件扮演控制器/视图模型的一部分,模板表示视图。

内容

本指南涵盖了Angular模板语法的基本元素,以及构建视图所需的元素:

  • 模板中的HTML
  • 插值({{...}})
  • 模板表达式
  • 模板语句
  • 绑定语法
  • 属性绑定([property])
  • 属性,类和样式绑定
  • 事件绑定((event))
  • 双向数据绑定([(...)])
  • 内置指令
  • 内置的属性指令
  •       NgClass
  •       NgStyle
  •       NgModel ([(ngModel)])
  • 内置结构指令
  •      NgIf
  •      NgFor
  •           模板输入变量
  •           Microsyntax
  •     NgSwitch指令
  • 模板引用变量(#var)
  • 输入和输出属性(@Input和@Output)
  • 模板表达式运算符
  •     管道(|)
  •     安全导航操作员(?.)

现成示例(查看源代码)演示了本指南中描述的所有语法和代码片段。

模板中的HTML

HTML是Angular模板的语言。 几乎所有的HTML语法都是有效的模板语法。 <script>元素是一个值得注意的例外。 这是被禁止的,消除脚本注入攻击的风险。 在实践中,<script>被忽略,并在浏览器控制台中出现警告。 有关详情,请参阅安全性页面。

一些合法的HTML在模板中没有多大意义。 <html>,<body>和<base>元素没有用处。 剩下一切都是一致的。

您可以使用组件和指令出现的新元素和属性来扩展模板的HTML词汇表。 在下面的章节中,您将学习如何通过数据绑定来动态获取和设置DOM(文档对象模型)值。

从数据绑定插值的第一种形式开始,看看有多少更丰富的模板HTML可以使用。请回到顶部。

插值({{...}})

在Angular的早期教程中,你遇到了插值的双曲括号{{and}}。

<p>My current hero is {{currentHero.name}}</p>

您可以使用插值将计算的字符串组织到HTML元素标记和属性赋值之间的文本中。

<h3>
  {{title}}
  <img src="{{heroImageUrl}}" style="height:30px">
</h3>

大括号里的文本通常是组件属性的名称。 Angular用相应的属性值替换该名称。 在上面的例子中,Angular评估了title和heroImageUrl属性,并“填充空白”,首先直接显示一个应用标题,然后是一个英雄图像。

更多的,大括号之间的文本是一个模板表达式,Angular首先评估并转换为一个字符串, 通过添加这两个数字来进行以下内插:

<!-- "The sum of 1 + 1 is 2" -->
<p>The sum of 1 + 1 is {{1 + 1}}</p>

该表达式可以调用主机的方法,例如getVal(),如下所示:

<!-- "The sum of 1 + 1 is not 4" -->
<p>The sum of 1 + 1 is not {{1 + 1 + getVal()}}</p>

Angular用双曲花括号评估所有表达式,将表达式结果转换为字符串,并将它们与相邻的文字串相链接。最后,它将这个复合插值结果赋值给一个元素指令属性

您似乎在元素标记之间插入结果并将其分配给属性。这么想很方便,你会因为这个错误而受苦。虽然这不完全正确。插值是收敛到属性绑定中的一种特殊语法,如下所述。

但首先,让我们仔细看看模板表达式和语句。

模板表达式

模板表达式产生一个值。 Angular执行表达式并将其分配给绑定目标的属性; 目标可能是HTML元素,组件或指令。

{{1 + 1}}中的内插大括号包围模板表达式1 + 1.在下面的属性绑定部分中,在[property] =“expression”中,模板表达式显示在符号右侧的引号中。

你用类似Dart的语言编写这些模板表达式。 许多Dart表达式是合法的,但不是全部。

带有或促进副作用的Dart表达式是被禁止的,包括:

  • 赋值(=,+ =, - =,...)
  • new 或 const
  • 链接表达式;
  • 递增和递减运算符(++和 - -)

与Dart语法的其他显着差异包括:

不支持Dart字符串插值; 例如,而不是“'The title is $title'”,你必须写''The title is ' + title'“ 不支持按位运算符| 和& 新的模板表达式运算符,如|

表达式上下文

表达式上下文通常是组件实例。 在以下片段中,双花括号内的标题和引号中的isUnchanged引用了AppComponent的属性。

{{title}}
<span [hidden]="isUnchanged">changed</span>

一个表达式也可以用来引用模板上下文的属性,包括模板输入变量(let hero)或模板引用变量(#heroInput)。

<div *ngFor="let hero of heroes">{{hero.name}}</div>
<input #heroInput> {{heroInput.value}}

表达式中术语的上下文是模板变量和组件成员的混合。 如果引用这些名称空间的名称,则模板变量名称优先,后面是指令的上下文,最后是组件的成员名称。

前面的例子显示了这样一个名字冲突。 该组件具有hero属性,而* ngFor定义了英雄模板变量。 {{hero.name}}中的英雄是指变量输入变量,而不是组件的属性。 模板表达式不能引用静态属性,也不能引用顶层变量或函数,如来自dart:html的window 或document 。他们不能直接调用从dart:math导入的print或函数。 它们仅限于引用表达式上下文的成员。

表达式准则

模板表达式可以构建或破坏应用程序。 请遵循以下准则:

这些指导方针的例外情况应该是在你理解的情况下。

没有明显的副作用

模板表达式不应该更改目标属性的值以外的任何应用程序状态。

这个规则对Angular的“单向数据流”策略是必不可少的。您不必担心读取组件值可能会改变一些其他的显示值。这个视图在整个渲染过程中应该是稳定的。

快速执行

Angular在每个更改检测周期后执行模板表达式。 更改检测周期由许多异步活动触发,如承诺的分辨率,http结果,计时器事件,按键和鼠标移动。

表达式应该快速完成,否则用户可能会遇到卡帧,尤其是在较慢的设备上。 当他们的计算成本很高时,考虑缓存值。

简单

虽然可以编写相当复杂的模板表达式,但是应该避免使用它们。

属性名称或方法调用应该是标准。 偶尔的布尔否定(!)可以。  另外, 将应用和业务逻辑放到到组件本身,在那里它将更容易开发和测试。

幂等性

幂等表达式是理想的,因为它没有副作用,并且改善了Angular的变化检测性能。

对Angular来说,一个幂等表达式总是返回完全相同的东西,直到它的一个依赖值发生变化。

在事件循环的一个回合期间,依赖值不应该改变。如果一个幂等表达式返回一个字符串或一个数字,当它在一行中调用两次时会返回相同的字符串或数字。如果表达式返回一个对象(包括一个List),它将在连续调用两次时返回相同的对象引用。

模板语句

模板语句响应绑定目标(例如元素,组件或指令)引发的事件。 您会在事件绑定部分看到模板语句,并在(event)=“statement”中出现在=符号右侧的引号中。

<button (click)="deleteHero()">Delete hero</button>

模板语句有一方面的作用。 它是一个事件的全部。 就是如何从用户操作更新应用程序状态。

响应事件是Angular的“单向数据流”的另一面。在事件循环的这个周期中,您可以自由地在任何地方进行所有更改。

像模板表达式一样,模板语句使用了一种看起来像Dart的语言。 模板语句解析器与模板表达式解析器不同,特别支持基本的赋值(=)和链接表达式(with;)

但是,某些Dart语法是不允许的:

  • new 和 const
  • 递增和递减运算符,++和 --
  • 赋值运算符,例如 +=和 -=
  • 按位运算符| 和 &
  • 模板表达式运算符

语句上下文

与表达式一样,语句只能引用语句上下文中的内容,例如组件实例的事件处理方法。

语句上下文通常是组件实例。 (click)=“deleteHero()”中的deleteHero是数据绑定组件的一种方法。

<button (click)="deleteHero()">Delete hero</button>

语句上下文也可以引用模板自己的上下文的属性。 在以下示例中,将模板$ event对象,模板输入变量(let hero)和模板引用变量(#heroForm)传递给组件的事件处理方法。

<button (click)="onSave($event)">Save</button>
<button *ngFor="let hero of heroes" (click)="deleteHero(hero)">{{hero.name}}</button>
<form #heroForm (ngSubmit)="onSubmit(heroForm)"> ... </form>

模板上下文字段优先于组件上下文字段。 在上面的deleteHero(hero)中,hero是模板输入变量,而不是组件的hero属性。

模板语句不能引用类的静态属性,也不能引用顶层变量或函数,如来自dart:html的window或document 。 它们不能直接调用从dart:math导入的print或函数。

声明准则

与表达式一样,避免编写复杂的模板语句。 方法调用或简单的属性分配应该是标准。 现在您已经感觉到了模板表达式和语句,您已经准备好了解超越插值的各种数据绑定语法。

绑定语法:概述

数据绑定是一种协调用户看到应用程序数据值的机制。 虽然您可以将值推送到HTML中,并从HTML中提取值,但是如果将这些杂事转换为绑定框架,则应用程序更易于编写,读取和维护。 您只需声明绑定源和目标HTML元素之间的绑定,然后让框架完成工作。

Angular提供了多种数据绑定。 本指南涵盖了大部分的Angular数据绑定及其语法的高级使用。

绑定类型可以按照数据流的方向分为三类:source-to-view,view-to-source,以及双向顺序:view-to-source-to-view:

数据方向

语法

类型

单向 从数据源到目标视图

{{expression}} [target]="expression" bind-target="expression"

插值 组件属性 元素属性 元素类 元素样式

单向 从目标视图到数据源

(target)="statement" on-target="statement"

事件

双向

[(target)]="expression" bindon-target="expression"

双向

除插值以外的绑定类型在等号左边或者用标点符号([],())包围,或者带前缀(bind-,on-,bindon-)都有一个目标名称。

目标名称是一个属性的名称。 它可能看起来像一个元素属性的名称,但它不是。 为了体会差异性,您必须开发一种思考HTML模板的新方法。

一种新的心智模式

借助数据绑定的所有功能以及使用自定义标记扩展HTML词汇表的能力,将HTML模板视为HTML Plus是很有诱惑力的

它确实是HTML Plus。 但是它也与你习惯的HTML有很大的不同。 它需要一个新的心智模式。 在HTML开发的正常过程中,您可以使用HTML元素创建一个可视结构,并通过使用字符串常量设置元素属性来修改这些元素。

<div class="special">Mental Model</div>
<img src="assets/images/hero.png">
<button disabled>Save</button>

您仍然在Angular模板中以这种方式创建结构并初始化属性值。 然后,您将学习如何使用封装了HTML的组件创建新元素,并将它们放入模板中,就好像它们是原生HTML元素一样。

<!-- Normal HTML -->
<div class="special">Mental Model</div>
<!-- Wow! A new element! -->
<hero-detail></hero-detail>

这是HTML Plus。 然后你学习数据绑定。 你遇到的第一个绑定可能是这样的:

<!-- Bind button disabled state to `isUnchanged` property -->
<button [disabled]="isUnchanged">Save</button>

你的直觉可能表明你绑定了按钮的disabled属性,并将其值设置为组件的isUnchanged属性的当前值。 那个直觉是不正确的!

日常的HTML心智模式是误导性的。 一旦你开始数据绑定,你不再使用HTML Attributes 。 你不是设置属性(Attributes) ; 你应该设置DOM元素,组件和指令的属性(Properties)。

HTML属性(Attributes)与DOM属性(Properties) HTML属性和DOM属性的区别对于理解Angular绑定是如何工作是至关重要的。 Attributes 由HTML定义。Properties 由DOM(文档对象模型)定义。

  • 一些HTML属性(Attributes)映射到属性(Properties)1:1, id是一个例子。
  • 一些HTML属性(Attributes)没有相应的属性(Properties)。 colspan就是一个例子。
  • 一些DOM属性(Properties)没有相应的属性(Attributes)。 textContent就是一个例子。
  • 许多HTML属性(Attributes)似乎映射到属性(Properties)...但不是以你想象的方式!

最后一个类别含义模糊的,除非你知道这个一般规则: 属性(Attributes)初始化DOM属性(Properties),然后完工。 属性(Properties)值可以会改变; 属性(Attributes)值不能。 例如,当浏览器呈现<input type =“text” value =“Bob”>时,它会创建一个对应的DOM节点,其值属性(Properties)已初始化为“Bob”。 当用户在输入框中输入“Sally”时,DOM元素值属性变为“Sally”。 但是,HTML value属性保持不变,当访问输入元素的该属性:input.getAttribute('value')返回“Bob”。 HTML属性(Attributes) value指定初始值; DOM value属性(Properties)是当前值。 disabled 属性(Attributes)是另一个特殊的例子。 按钮的disabled 属性(Properties)默认为false,因此按钮已启用。 当您添加disabled属性(Attributes)时,它的存在会将按钮的disabled属性(Properties)初始化为true,因此该按钮被禁用。 添加和删除disabled属性(Attributes)将禁用和启用该按钮。 该属性(Attributes)的值是无关紧要的,这就是为什么您不能通过编写<button disabled =“false”> Still Disabled </ button>来启用按钮的原因。 设置按钮的disabled属性(Properties)(例如,使用Angular绑定)禁用或启用按钮。属性(Properties)的值很重要。 HTML属性(Attributes)和DOM属性(Properties)是不一样的,即使它们具有相同的名称。

这个事实值得重复:模板绑定使用属性(properties)和事件(events)发挥作用,而不是属性(attributes)。

一个没有属性的世界 在Angular的世界中,属性(attributes)的唯一作用是初始化元素和指令状态。 当你写数据绑定时,你只处理目标对象的属性(properties)和事件(events)。 HTML属性(attributes)不起作用。

记住这个模型,继续阅读以了解绑定目标。

绑定目标

数据绑定的目标是DOM中的东西。根据绑定类型,目标可以是(element | component |directive)属性,(element | component | directive)事件或(很少)属性(attributes)名称。 下表总结了这些情况:

Type

Target

Example

Property

Element property Component property Directive property

<img [src]="heroImageUrl"> <hero-detail [hero]="currentHero"></hero-detail> <div [ngClass]="{special: isSpecial}"></div>

Event

Element event Component event Directive event

<button (click)="onSave()">Save</button> <hero-detail (deleteRequest)="deleteHero()"></hero-detail> <div (myClick)="clicked=$event" clickable>click me</div>

Two-way

Event and property

<input [(ngModel)]="name">

Attribute

Attribute (例外)

<button [attr.aria-label]="help">help</button>

Class

class property

<div [class.special]="isSpecial">Special</div>

Style

style property

<button [style.color]="isSpecial ? 'red' : 'green'">

您现在已经准备好详细查看绑定类型。

属性绑定([property])

编写一个模板属性绑定来设置一个视图元素的属性。 该绑定将该属性设置为模板表达式的值。

最常见的属性绑定将元素属性设置为组件属性值。一个示例是将图像元素的src属性绑定到组件的heroImageUrl属性:

<img [src]="heroImageUrl">

另一个例子是当组件标识isUnchanged的时候禁用一个按钮:

<button [disabled]="isUnchanged">Cancel is disabled</button>

另一个是设置一个指令的属性:

<div [ngClass]="classes">[ngClass] binding to the classes property</div>

另一个是设置自定义组件的模型属性(父组件和子组件进行通信的一个好方法):

<hero-detail [hero]="currentHero"></hero-detail>

单向

人们通常将属性绑定描述为单向数据绑定,因为它从一个组件的数据属性向一个目标元素属性传递一个值。

您不能使用属性绑定将值从目标元素中拉出。 您不能绑定到目标元素的属性来读取它。 你只能设置它。

同样,您不能在目标元素上使用属性绑定来调用方法。 如果元素引发事件,则可以使用事件绑定来监听它们。 如果您必须读取目标元素属性或调用其中一个方法, 你需要一个不同的技术。 查看ViewChildContentChild的API参考。

绑定目标

方括号之间的元素属性标识目标属性。 以下代码中的目标属性是图像元素的src属性。

<img [src]="heroImageUrl">

有些人更喜欢绑定前缀bind-替代,称为规范形式:

<img bind-src="heroImageUrl">

目标名称始终是属性(property)的名称,即使它看起来是别的名称。 你可能会看到src,并认为它是一个属性(attribute)的名称。 不是; 这是一个图像元素属性(property)的名称。

元素属性(property)可能是更常见的目标,但Angular首先查看名称是否是已知指令的属性(property),如下例所示:

<div [ngClass]="classes">[ngClass] binding to the classes property</div>

从技术上讲,Angular将名称与指令输入或用@Input()装饰的属性相匹配。 这样的输入映射到指令自己的属性。

如果名称未能匹配已知指令或元素(property)的属性,则Angular会报告“未知指令”错误。

避免副作用

如前所述,模板表达式的评估必须没有可见的副作用。表达式语言本身是为了保证您的安全。您不能为属性绑定表达式中的任何东西赋值,也不能使用增量和减量运算符。

当然,该表达式可能会调用具有副作用的属性或方法。 Angular无法知道或阻止你。

该表达式可以调用类似getFoo()的东西。 只要你知道getFoo()是做什么的。如果getFoo()改变了某些东西,而且碰巧绑定了某些东西,你将冒着一定的风险。Angular可能会或可能不会显示更改的值。Angular可能会检测到更改并发出警告错误。通常来说,保留数据属性和方法返回值就够了。

返回适当的类型

模板表达式应通过目标属性计算预期值的类型:

  • 如果目标属性需要一个字符串,则返回一个字符串。
  • 如果目标属性期望一个数字,则返回一个数字。
  • 如果目标属性需要一个对象,则返回一个对象。

HeroDetail组件的hero属性需要一个Hero对象,这正是你在属性绑定中发送的内容: 

<hero-detail [hero]="currentHero"></hero-detail>

检查模式异常 在检查模式下,如果模板表达结果类型和目标属性类型不是赋值兼容的,则会抛出一个类型异常。 有关检查模式的信息,请参阅Dart语言指南中的重要概念

Dart 2.0注意:检查模式不会出现在飞镖2.0。 有关更多信息,请参阅Dart 2.0更新

记住括号

括号告诉Angular评估模板表达式。 如果省略方括号,Angular会将该字符串视为常量,并使用该字符串初始化目标属性。 它不评估字符串! 不要犯以下错误:

<!-- ERROR: A value of type 'String' can't be assigned to a variable of type 'Hero'.
<hero-detail hero="currentHero"></hero-detail>
-->

检查模式类型异常例子 在检查模式下,上面的代码将导致一个类型异常:String不是Hero的子类型。

一次性字符串初始化

满足以下所有条件时,省略括号:

  • 目标属性接受一个字符串值。
  • 该字符串是一个固定的值,您可以拷贝到模板中。
  • 这个初始值永远不会改变。

一次性字符串初始化在标准HTML中是常规的,并且它对于指令和组件属性也同样适用。 以下示例将HeroDetailComponent的prefix属性初始化为固定字符串,而不是模板表达式。 Angular设置它并不再管它。

<hero-detail prefix="You are my" [hero]="currentHero"></hero-detail>

另一方面,[hero]绑定仍然保留对组件的currentHero属性的有效绑定。

属性绑定或插值?

你经常有插值和属性绑定的选择。 以下绑定做同样的事情:

<p><img src="{{heroImageUrl}}"> is the <i>interpolated</i> image.</p>
<p><img [src]="heroImageUrl"> is the <i>property bound</i> image.</p>

<p><span>"{{title}}" is the <i>interpolated</i> title.</span></p>
<p>"<span [innerHTML]="title"></span>" is the <i>property bound</i> title.</p>

在许多情况下插值是属性绑定较为方便的替代品。 将数据值呈现为字符串时,没有技术上的理由去选择另一种形式,但插值更可读。我们建议建立编码风格规则,选择符合规则的形式,对于手头的任务来说是最自然的 将元素属性设置为非字符串数据值时,必须使用属性绑定。

内容安全

想象下面的恶意内容。

String evilTitle =
    'Template <script>alert("evil never sleeps")</script>Syntax';

幸运的是,Angular数据绑定对危险的HTML进行了警报。 它在显示它们之前清理这些值。 它不允许带脚本标记的HTML泄露到浏览器中,既不能使用插值也不能使用属性绑定。

<!--
  Angular generates warnings for these two lines as it sanitizes them
  WARNING: sanitizing HTML stripped some content (see http://g.co/ng/security#xss).
 -->
<p><span>"{{evilTitle}}" is the <i>interpolated</i> evil title.</span></p>
<p>"<span [innerHTML]="evilTitle"></span>" is the <i>property bound</i> evil title.</p>

插值处理脚本标记与属性绑定不同,但两种方法均无害地呈现内容。

属性(Attribute),类和样式绑定

模板语法为不太适合属性(property )绑定的场景提供了专门的单向绑定。

属性(Attribute)绑定

您可以直接使用属性绑定来设置属性的值。

这是绑定设置目标属性(property)的唯一例外规则。 这是创建和设置属性(attribute)的唯一一种绑定。

本指南反复强调,使用属性(property)绑定设置元素属性(property)始终优先于使用字符串设置属性(attribute)。 Angular为什么提供属性(attribute)绑定?

当没有要绑定的元素属性时,必须使用属性绑定。

考虑ARIASVG和table span属性。 他们是纯粹的属性。 它们不对应元素属性,也不设置元素属性。 没有属性目标绑定。

在写像这样的东西时,这个事实变得非常明显:

<tr><td colspan="{{1 + 1}}">Three-Four</td></tr>

结果是这个错误:

Template parse errors:
Can't bind to 'colspan' since it isn't a known native property

正如消息所述,<td>元素没有colspan属性。 它具有“colspan”属性(attribute),但是插值和属性(attribute)绑定只能设置属性(properties),而不能设置属性(attribute)。

您需要属性(attribute)绑定来创建和绑定到这些属性(attribute)。

属性(attribute)绑定语法类似于属性(properties)绑定。以前缀attr开头,后跟一个点(.)和属性名称代替括号之间的元素属性。然后使用解析为字符串的表达式来设置属性值。

将[attr.colspan]绑定到计算值:

<table border=1>
  <!--  expression calculates colspan=2 -->
  <tr><td [attr.colspan]="1 + 1">One-Two</td></tr>

  <!-- ERROR: There is no `colspan` property to set!
    <tr><td colspan="{{1 + 1}}">Three-Four</td></tr>
  -->

  <tr><td>Five</td><td>Six</td></tr>
</table>

以下是表格的呈现方式:

属性(attribute)绑定的主要用例之一是设置ARIA属性,如下例所示:

<!-- create and set an aria attribute for assistive technology -->
<button [attr.aria-label]="actionName">{{actionName}} with Aria</button>

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏编程

Python基础知识6:格式化字符、颜色

字符格式化,有两种方式: 1、通过%占位符方式,%s,%d,% 2、通过format,其中format比较好用,可以居中、可以用%、可以用二进制、可以填充字符自...

24950
来自专栏bboysoul

markdown简明指南

介绍:markdown是一种用来写作的标记语言,他用简单的语法来代替排版使我们注重文章的内容而不是排版

9730
来自专栏互联网杂技

h5新功能data-*,好好利用,还能做数据双向绑定

标题是data-,但是这里主要讲伪元素,看明白就知道了 1、jQuery Selectors 获取伪元素的属性值 虽然JS里没有可以直接操作伪元素的选择符,然而...

32840
来自专栏阿凯的Excel

自定义单元格格式(判断版)

前两期分别介绍了自定义单元格格式的数字版、文本版。本期将分享最后一个内容,自定义单元格格式的条件判断。同时也会分享一些比较偏,比较少用的应用! 一、基础知识分...

29640
来自专栏极客编程

用Vue.js递归组件构建一个可折叠的树形菜单

递归组件常用于在blog上显示注释、嵌套的菜单,或者基本上是父和子相同的类型,尽管具体内容不同。例如:

2.1K10
来自专栏软件开发

前端MVC Vue2学习总结(四)——条件渲染、列表渲染、事件处理器

一、条件渲染 1.1、v-if 在字符串模板中,如 Handlebars ,我们得像这样写一个条件块: <!-- Handlebars 模板 --> {{#if...

542110
来自专栏Golang语言社区

如何理解 golang nil

golang 中的 nil 是不同于其他语言的,为了更好的理解 nil,在此我将尝试一步一步揭示 nil 在 golang 中的一些操作和现象。 1. nil ...

33850
来自专栏LanceToBigData

SpringBoot(四)之thymeleaf的使用

这篇文章将更加全面详细的介绍thymeleaf的使用。thymeleaf 是新一代的模板引擎,在spring4.0中推荐使用thymeleaf来做前端模版引擎。...

660100
来自专栏与神兽党一起成长

手工实现表单重置的部分功能

首先我必须说几乎所有的人都不需要自己实现表单重置的功能,表单重置功能只需要一个reset类型的input就足够了。<input type="reset" />

18630
来自专栏python3

tkinter -- Spinbox

只是创建了一个 Spinbox,其它的什么也做不了,与 Scale 不同,Scale 使用缺省值就可以控制 值的改变

11130

扫码关注云+社区

领取腾讯云代金券