index.html 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <title>Vue benchmark</title>
  6. <style type="text/css">
  7. html, body {
  8. margin: 0;
  9. padding: 0 10px;
  10. font-family: sans-serif;
  11. }
  12. #fps {
  13. position: fixed;
  14. top: 0px;
  15. right: 0px;
  16. padding: 32px;
  17. font-size: 32px;
  18. text-align: right;
  19. }
  20. * {
  21. box-sizing: border-box;
  22. }
  23. .server-uptime {
  24. display: block;
  25. overflow: hidden;
  26. margin: 0 auto;
  27. width: 50%;
  28. }
  29. .server-uptime + .server-uptime {
  30. margin: 20px auto 0 auto;
  31. border-top: 1px solid #999;
  32. }
  33. .days {
  34. display: flex;
  35. flex-direction: row;
  36. flex-wrap: wrap;
  37. }
  38. .uptime-day {
  39. display: flex;
  40. }
  41. span.uptime-day-status {
  42. width: 10px;
  43. height: 10px;
  44. margin: 1px;
  45. }
  46. .hover {
  47. display: none;
  48. }
  49. .uptime-day-status:hover + .hover {
  50. display: flex;
  51. position: absolute;
  52. margin-top: -35px;
  53. margin-left: -30px;
  54. border-radius: 4px;
  55. color: #eee;
  56. background-color: #333;
  57. padding: 10px;
  58. font-size: 11px;
  59. }
  60. </style>
  61. </head>
  62. <body>
  63. <p>Reference: <a href="https://github.com/tildeio/glimmer/blob/master/packages/glimmer-demos/lib/uptime.ts">Ember Glimmer 2 demo</a></p>
  64. <div id="app">
  65. <p>FPS: {{ fps }}</p>
  66. <button @click="toggle">{{ playing ? 'pause' : 'play' }}</button>
  67. <server-uptime
  68. v-for="server in servers"
  69. :key="server.name"
  70. :name="server.name"
  71. :days="server.days">
  72. </server-uptime>
  73. </div>
  74. <script src="../../dist/vue.min.js"></script>
  75. <script>
  76. // functional components are perfect for small, presentational components
  77. // and they are much more efficient than stateful ones.
  78. Vue.component('uptime-day', {
  79. props: ['day'],
  80. functional: true,
  81. render (h, ctx) {
  82. var day = ctx.props.day
  83. return h('div', { staticClass: 'uptime-day'}, [
  84. h('span', { staticClass: 'uptime-day-status', style: { backgroundColor: day.up ? '#8cc665' : '#ccc' } }),
  85. h('span', { staticClass: 'hover' }, [day.number + ': ' + day.up ? 'Servers operational!' : 'Red alert!'])
  86. ])
  87. }
  88. })
  89. Vue.component('server-uptime', {
  90. props: ['name', 'days'],
  91. computed: {
  92. upDays () {
  93. return this.days.reduce(function (upDays, day) {
  94. return upDays += (day.up ? 1 : 0)
  95. }, 0)
  96. },
  97. maxStreak () {
  98. var streak = this.days.reduce(([max, streak], day) => {
  99. if (day.up && streak + 1 > max) {
  100. return [streak + 1, streak + 1]
  101. } else if (day.up) {
  102. return [max, streak + 1]
  103. } else {
  104. return [max, 0]
  105. }
  106. }, [0, 0])
  107. return streak.max
  108. }
  109. },
  110. template: `
  111. <div class="server-uptime">
  112. <h1>{{name}}</h1>
  113. <h2>{{upDays}} Days Up</h2>
  114. <h2>Biggest Streak: {{maxStreak}}</h2>
  115. <div class="days">
  116. <uptime-day
  117. v-for="day in days"
  118. :key="day.number"
  119. :day="day">
  120. </uptime-day>
  121. </div>
  122. </div>
  123. `
  124. })
  125. function generateServer (name) {
  126. var days = []
  127. for (var i=0; i<=364; i++) {
  128. var up = Math.random() > 0.2
  129. days.push({ number: i, up })
  130. }
  131. return { name, days }
  132. }
  133. function generateServers () {
  134. return [
  135. generateServer("Stefan's Server"),
  136. generateServer("Godfrey's Server"),
  137. generateServer("Yehuda's Server")
  138. ]
  139. }
  140. var s = window.performance.now()
  141. var app = new Vue({
  142. el: '#app',
  143. data: {
  144. fps: 0,
  145. playing: false,
  146. servers: Object.freeze(generateServers())
  147. },
  148. methods: {
  149. toggle () {
  150. this.playing = !this.playing
  151. if (this.playing) {
  152. update()
  153. } else {
  154. clearTimeout(timeoutId)
  155. }
  156. }
  157. }
  158. })
  159. console.log('initial render: ' + (window.performance.now() - s) + 'ms')
  160. var fpsMeter = {
  161. alpha: 2/121,
  162. lastValue: null,
  163. push (dataPoint) {
  164. if (this.lastValue) {
  165. return this.lastValue = this.lastValue + this.alpha * (dataPoint - this.lastValue)
  166. } else {
  167. return this.lastValue = dataPoint
  168. }
  169. }
  170. }
  171. var timeoutId
  172. var lastFrame = null
  173. function update () {
  174. var thisFrame = window.performance.now()
  175. if (lastFrame) {
  176. app.fps = Math.round(fpsMeter.push(1000 / (thisFrame - lastFrame)))
  177. }
  178. app.servers = Object.freeze(generateServers())
  179. timeoutId = setTimeout(update, 0) // not using rAF because that limits us to 60fps!
  180. lastFrame = thisFrame
  181. }
  182. </script>
  183. </body>
  184. </html>