[关闭]
@mSolo 2015-05-13T14:38:03.000000Z 字数 11706 阅读 1289

MEAN 全栈工程师手札(一):前奏 - 表单

HTML5 CSS3 Bootstrap


HTML5: from documents to applications
An overview of the new DOM APIs in HTML5:

  • 2D Canvas
  • Audio and Video
  • Drag and Drop
  • Cross-document Messaging
  • Server-sent Events
  • WebSockets
  • Document Editing
  • Web Storage
  • Offline Web Applications

手抄

The new form input types introduced in HTML5

Type
color date datetime datetime-local email
month number range search tel
time url week

HTML5’s new input element attributes

Attribute
autocomplete autofocus list max min
multiple pattern placeholder required step

A partial list of the new features in CSS3

New selectors New pseudo-classes Rounded borders Border images
Gradients Box shadow Box sizing Background sizing
Text shadow Word wrapping Multiple columns Web fonts
Multiple backgrounds Alpha color channels Media queries Speech style
Transitions Animations 3D transforms 2D transforms
  1. <progress value="50" max="100"></progress>
  2. <meter min="0" max="10" low="3" high="7" optimum="9" value="0"></meter>
  3. <details>
  4. <summary>Section Heading</summary>
  5. This is an example of using &lt;details&gt; and &lt;summary&gt;
  6. to create collapsible content without using JavaScript.
  7. </details>

Form creation: input widgets, data binding, and data validation

  1. <link rel="stylesheet" href="style.css">
  2. <script src="modernizr.js"></script>
  3. <script src="app.js"></script>
  1. <form name="order" method="post" action="/submit">
  2. <h1>Order Form</h1>
  3. <fieldset>
  4. <legend>Contact Details</legend>
  5. <ul>
  6. <li>
  7. <label class="required">
  8. <div>Full Name</div><input name="name" required autofocus>
  9. </label>
  10. </li>
  11. <li>
  12. <label class="required">
  13. <div>Email Address</div><input type="email" name="email" required>
  14. </label>
  15. </li>
  16. <li>
  17. <label>
  18. <div>Postal Address</div>
  19. <input name="address1" placeholder="Address Line 1">
  20. </label>
  21. <div>&nbsp;</div>
  22. <input name="address2" placeholder="Address Line 2">
  23. <div>&nbsp;</div>
  24. <input name="city" class="city" placeholder="Town/City">
  25. <input name="state" class="state" placeholder="State">
  26. <input name="zip" class="zip" placeholder="Zip Code">
  27. <div>&nbsp;</div>
  28. <select name="country">
  29. <option value="0">Country</option>
  30. <option value="US">United States</option>
  31. <option value="CA">Canada</option>
  32. </select>
  33. </li>
  34. <li>
  35. <label><div>Home Phone No.</div><input type="tel" name="homephone"></label>
  36. </li>
  37. <li>
  38. <label><div>Cell Phone No.</div><input type="tel" name="cellphone"></label>
  39. </li>
  40. <li>
  41. <label><div>Skype Name</div><input name="skype"></label>
  42. </li>
  43. <li>
  44. <label>
  45. <div>Twitter</div><span class="twitter_prefix">@</span>
  46. <input name="twitter" class="twitter">
  47. </label>
  48. </li>
  49. </ul>
  50. </fieldset>
  51. <fieldset>
  52. <legend>Login Details</legend>
  53. <ul>
  54. <li>
  55. <label class="required">
  56. <div>Password</div><input type="password" name="password" required>
  57. </label>
  58. </li>
  59. <li>
  60. <label class="required">
  61. <div>Confirm Password</div>
  62. <input type="password" name="confirm_password" required>
  63. </label>
  64. </li>
  65. </ul>
  66. </fieldset>
  67. <fieldset>
  68. <legend>Order Details</legend>
  69. <table>
  70. <thead>
  71. <tr>
  72. <th>Product Code</th><th>Description</th><th>Qty</th>
  73. <th>Price</th><th>Total</th>
  74. </tr>
  75. </thead>
  76. <tbody>
  77. <tr>
  78. <td>COMP001<input type="hidden" name="product_code" value="COMP001"></td>
  79. <td>The Ultimate Smartphone</td>
  80. <td>
  81. <input type="number" data-price="399.99" name="quantity"
  82. value="0" min="0" max="99" maxlength="2">
  83. </td>
  84. <td>$399.99</td>
  85. <td><output name="item_total" class="item_total">$0.00</output></td>
  86. </tr>
  87. <tr>
  88. <td>COMP002<input type="hidden" name="product_code" value="COMP002"></td>
  89. <td>The Ultimate Tablet</td>
  90. <td>
  91. <input type="number" data-price="499.99" name="quantity"
  92. value="0" min="0" max="99" maxlength="2">
  93. </td>
  94. <td>$499.99</td>
  95. <td><output name="item_total" class="item_total">$0.00</output> </td>
  96. </tr>
  97. <tr>
  98. <td>COMP003<input type="hidden" name="product_code" value="COMP003"></td>
  99. <td>The Ultimate Netbook</td>
  100. <td>
  101. <input type="number" data-price="299.99" name="quantity"
  102. value="0" min="0" max="99" maxlength="2">
  103. </td>
  104. <td>$299.99</td>
  105. <td><output name="item_total" class="item_total">$0.00</output></td>
  106. </tr>
  107. </tbody>
  108. <tfoot>
  109. <tr>
  110. <td colspan="4">Order Total</td>
  111. <td><output name="order_total" id="order_total">$0.00</output></td>
  112. </tr>
  113. </tfoot>
  114. </table>
  115. </fieldset>
  116. <fieldset>
  117. <legend>Payment Details</legend>
  118. <ul>
  119. <li>
  120. <label class="required">
  121. <div>Name on Card</div><input name="card_name" required>
  122. </label>
  123. </li>
  124. <li>
  125. <label class="required">
  126. <div>Credit Card No.</div>
  127. <input name="card_number" pattern="[0-9]{13,16}"
  128. maxlength="16" required title="13-16 digits, no spaces">
  129. </label>
  130. </li>
  131. <li>
  132. <label class="required">
  133. <div>Expiry Date</div>
  134. <input type="month" name="card_expiry" maxlength="7"
  135. placeholder="YYYY-MM" required value="2015-06">
  136. </label>
  137. </li>
  138. <li>
  139. <label class="required">
  140. <div>CVV2 No.</div>
  141. <input name="card_cvv2" class="cvv" maxlength="3"
  142. pattern="[0-9]{3}" required title="exactly 3 digits">
  143. <span>(Three digit code at back of card)</span>
  144. </label>
  145. </li>
  146. </ul>
  147. </fieldset>
  148. <div class="buttons">
  149. <input type="submit" value="Submit Order">
  150. <input type="submit" id="saveOrder" value="Save Order" formnovalidate formaction="/save">
  151. </div>
  152. </form>
  1. (function() {
  2. var init = function() {
  3. var orderForm = document.forms.order,
  4. saveBtn = document.getElementById('saveOrder'),
  5. saveBtnClicked = false;
  6. var saveForm = function() {
  7. if(!('formAction' in document.createElement('input'))) {
  8. var formAction = saveBtn.getAttribute('formaction');
  9. orderForm.setAttribute('action',formAction);
  10. }
  11. saveBtnClicked = true;
  12. };
  13. saveBtn.addEventListener('click',saveForm, false);
  14. var qtyFields = orderForm.quantity,
  15. totalFields = document.getElementsByClassName('item_total'),
  16. orderTotalField = document.getElementById('order_total');
  17. var formatMoney = function(value) {
  18. return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  19. }
  20. var calculateTotals = function() {
  21. var i = 0,
  22. ln = qtyFields.length,
  23. itemQty = 0,
  24. itemPrice = 0.00,
  25. itemTotal = 0.00,
  26. itemTotalMoney = '$0.00',
  27. orderTotal = 0.00,
  28. orderTotalMoney = '$0.00';
  29. for(;i<ln;i++) {
  30. if(!!qtyFields[i].valueAsNumber) {
  31. itemQty =qtyFields[i].valueAsNumber || 0; // HTML5 version
  32. } else {
  33. itemQty =parseFloat(qtyFields[i].value) || 0; // Fallback version
  34. }
  35. if(!!qtyFields[i].dataset) {
  36. itemPrice =parseFloat(qtyFields[i].dataset.price);
  37. } else {
  38. itemPrice =parseFloat(qtyFields[i].getAttribute('data-price'));
  39. }
  40. itemTotal =itemQty *itemPrice;
  41. itemTotalMoney = '$'+formatMoney(itemTotal.toFixed(2));
  42. orderTotal +=itemTotal;
  43. orderTotalMoney = '$'+formatMoney(orderTotal.toFixed(2));
  44. if(!!totalFields[i].value) {
  45. totalFields[i].value =itemTotalMoney;
  46. orderTotalField.value =orderTotalMoney;
  47. } else {
  48. totalFields[i].innerHTML =itemTotalMoney;
  49. orderTotalField.innerHTML =orderTotalMoney;
  50. }
  51. }
  52. };
  53. calculateTotals();
  54. var qtyListeners = function() {
  55. var i = 0,
  56. ln = qtyFields.length;
  57. for(;i<ln;i++) {
  58. qtyFields[i].addEventListener('input',calculateTotals, false);
  59. qtyFields[i].addEventListener('keyup',calculateTotals, false);
  60. }
  61. };
  62. qtyListeners();
  63. var doCustomValidity = function(field, msg) {
  64. if('setCustomValidity' in field) {
  65. field.setCustomValidity(msg);
  66. } else {
  67. field.validationMessage = msg;
  68. }
  69. };
  70. var validateForm = function() {
  71. doCustomValidity(orderForm.name, '');
  72. doCustomValidity(orderForm.password, '');
  73. //...
  74. if(!Modernizr.inputtypes.month || !Modernizr.input.pattern) {
  75. fallbackValidation();
  76. }
  77. if(orderForm.name.value.length < 4) {
  78. doCustomValidity(orderForm.name, 'Full Name must be at least 4 characters long');
  79. }
  80. //...
  81. };
  82. orderForm.addEventListener('input', validateForm, false);
  83. orderForm.addEventListener('keyup', validateForm, false);
  84. var styleInvalidForm = function() {
  85. orderForm.className = 'invalid';
  86. }
  87. orderForm.addEventListener('invalid', styleInvalidForm, true);
  88. Modernizr.load({
  89. test: Modernizr.inputtypes.month,
  90. nope: 'monthpicker.js'
  91. });
  92. var getFieldLabel = function(field) {
  93. if('labels' in field && field.labels.length > 0) {
  94. return field.labels[0].innerText;
  95. }
  96. if(field.parentNode && field.parentNode.tagName.toLowerCase()=== 'label') {
  97. return field.parentNode.innerText;
  98. }
  99. return '';
  100. }
  101. var submitForm = function(e) {
  102. if(!saveBtnClicked) {
  103. validateForm();
  104. var i = 0,
  105. ln = orderForm.length,
  106. field,
  107. errors = [],
  108. errorFields = [],
  109. errorMsg = '';
  110. for(; i<ln; i++) {
  111. field = orderForm[i];
  112. if( (!!field.validationMessage && field.validationMessage.length > 0) ||
  113. (!!field.checkValidity && !field.checkValidity()) ) {
  114. errors.push(getFieldLabel(field)+': '+field.validationMessage);
  115. errorFields.push(field);
  116. }
  117. }
  118. if(errors.length > 0) {
  119. e.preventDefault();
  120. errorMsg = errors.join('\n');
  121. alert('Please fix the following errors:\n'+errorMsg, 'Error');
  122. orderForm.className = 'invalid';
  123. errorFields[0].focus();
  124. }
  125. }
  126. };
  127. orderForm.addEventListener('submit', submitForm, false);
  128. var fallbackValidation = function() {
  129. var i = 0,
  130. ln = orderForm.length,
  131. field;
  132. for(;i<ln;i++) {
  133. field = orderForm[i];
  134. doCustomValidity(field, '');
  135. if(field.hasAttribute('pattern')) {
  136. var pattern = new RegExp(field.getAttribute('pattern').toString());
  137. if(!pattern.test(field.value)) {
  138. var msg = 'Please match the requested format.';
  139. if(field.hasAttribute('title') && field.getAttribute('title').length > 0) {
  140. msg += ' '+field.getAttribute('title');
  141. }
  142. doCustomValidity(field, msg);
  143. }
  144. }
  145. if(field.hasAttribute('type') &&
  146. field.getAttribute('type').toLowerCase()=== 'email') {
  147. var pattern = new RegExp(/\S+@\S+\.\S+/);
  148. if(!pattern.test(field.value)) {
  149. doCustomValidity(field, 'Please enter an email address.');
  150. }
  151. }
  152. if(field.hasAttribute('required') && field.value.length < 1) {
  153. doCustomValidity(field, 'Please fill out this field.');
  154. }
  155. }
  156. };
  157. };
  158. window.addEventListener('load',init, false);
  159. }) ();
  1. html, body, form, fieldset, legend, h1, ul {
  2. margin: 0;
  3. padding: 0;
  4. border: 0;
  5. outline: 0;
  6. font-weight: inherit;
  7. font-style: inherit;
  8. font-size: 100%;
  9. font-family: inherit;
  10. vertical-align: baseline;
  11. font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
  12. font-weight: 300;
  13. }
  14. form {
  15. width: 800px; margin: 30px auto;
  16. background-color: #DCD4CE;
  17. border: 1px solid #423021;
  18. box-shadow: 2px 2px 10px #666;
  19. }
  20. h1 {
  21. background-color: #BEB0A3;
  22. border-bottom: 1px solid #423021;
  23. font-size: 2em; font-weight: 600;
  24. padding: 5px 15px;
  25. text-shadow: 1px 1px 0px #fff;
  26. }
  27. fieldset {
  28. border: none; margin: 20px 20px;
  29. border-bottom: 1px dashed #BEB0A3; padding-bottom: 20px;
  30. }
  31. legend {
  32. display: block; font-weight: bold; font-size: 1.25em;
  33. width: 100%; padding-bottom: 10px;
  34. text-shadow: 1px 1px 0px #fff;
  35. }
  36. input:not([type=submit]), select {
  37. border: 1px solid #999;
  38. padding: 2px;
  39. }
  40. input:required, select:required {
  41. background-color: lightyellow;
  42. }
  43. form.invalid input:invalid, form.invalid select:invalid,
  44. form.invalid input.invalid, form.invalid select.invalid {
  45. background-color: #FFD4D4;
  46. border: 1px solid maroon;
  47. }
  48. ul {
  49. list-style-type: none;
  50. }
  51. li {
  52. display: block; width: 380px; float: left;
  53. }
  54. li div {
  55. width: 130px; float: left; margin-top: 5px;
  56. color: #444; font-size: 0.8em; font-weight: 300;
  57. }
  58. li label.required div {
  59. font-weight: bold;
  60. }
  61. li label span {
  62. font-size: 11px; font-weight: 300; color: #333;
  63. }
  64. li input, li select {
  65. width: 225px; margin-bottom: 5px;
  66. font-size: 0.9em;
  67. }
  68. span.twitter_prefix { color: #666; font-size: .95em; font-weight: bold; }
  69. input.city { width: 80px; margin-right: 0; }
  70. input.state { width: 35px; margin-right: 0; }
  71. input.zip { width: 90px; }
  72. input.twitter { width: 206px; }
  73. table {
  74. width: 100%;
  75. border: 1px solid #705536;
  76. border-collapse: collapse;
  77. box-shadow: 1px 1px 10px #666;
  78. }
  79. th, td {
  80. border: 1px solid #705536;
  81. padding: 5px 10px;
  82. }
  83. th {
  84. text-shadow: 1px 1px 0px #000; font-weight: bold;
  85. }
  86. thead th:nth-child(1), thead th:nth-child(2) {
  87. text-align: left;
  88. }
  89. thead th:nth-child(4), thead th:nth-child(5) {
  90. text-align: right;
  91. }
  92. tbody tr td {
  93. background-color: #e5dad2;
  94. }
  95. tbody tr:nth-child(even) td {
  96. background-color: #fff3e9;
  97. }
  98. tbody td:nth-child(1) {
  99. width: 110px;
  100. }
  101. tbody td:nth-child(3) {
  102. width: 60px; text-align: center;
  103. }
  104. td input {
  105. width: 50px; height: 28px; font-size: 1.1em; text-align: right;
  106. }
  107. tbody td:nth-child(4) {
  108. width: 60px; text-align: right;
  109. }
  110. tbody td:nth-child(5) {
  111. width: 80px; text-align: right;
  112. }
  113. th {
  114. background-color: #614023;
  115. color: #fff;
  116. }
  117. tfoot td {
  118. background-color: #BEB0A3;
  119. text-align: right; font-weight: bold;
  120. font-size: 1.15em;
  121. text-shadow: 1px 1px 0px #fff;
  122. }
  123. input[type=month] { width: 100px; }
  124. input.cvv { width: 60px; text-align: right; }
  125. .buttons {
  126. margin: 15px 20px 10px; text-align: right;
  127. }
  128. input[type=submit], input[type=button] {
  129. border: 1px solid #423021;
  130. background-color: #896640;
  131. color: #fff; padding: 6px 10px;
  132. border-radius: 6px;
  133. text-shadow: 1px 1px 0px #000;
  134. font-size: 0.9em; cursor: pointer;
  135. font-weight: bold;
  136. background-image: -webkit-linear-gradient(top, #896640 0%, #705536 100%);
  137. # -moz-linear-gradient, -o-linear-gradient, -ms-linear-gradient
  138. background-image: linear-gradient(to bottom, #896640 0%, #705536 100%);
  139. }
  140. input[type=submit]:active, input[type=button]:active {
  141. background-color: #705536;
  142. background-image: -webkit-linear-gradient(bottom, #896640 0%, #705536 100%);
  143. #
  144. }
  145. .placeholder {
  146. color: #999;
  147. }
  148. .month-picker-month { width: 115px; }
  149. .month-picker-year { width: 55px; text-align: right; }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注