grid.html 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. <script src="../../dist/vue.global.js"></script>
  2. <!-- DemoGrid component template -->
  3. <script type="text/x-template" id="grid-template">
  4. <table v-if="filteredData.length">
  5. <thead>
  6. <tr>
  7. <th v-for="key in columns"
  8. @click="sortBy(key)"
  9. :class="{ active: sortKey == key }">
  10. {{ capitalize(key) }}
  11. <span class="arrow" :class="sortOrders[key] > 0 ? 'asc' : 'dsc'">
  12. </span>
  13. </th>
  14. </tr>
  15. </thead>
  16. <tbody>
  17. <tr v-for="entry in filteredData">
  18. <td v-for="key in columns">
  19. {{entry[key]}}
  20. </td>
  21. </tr>
  22. </tbody>
  23. </table>
  24. <p v-else>No matches found.</p>
  25. </script>
  26. <!-- DemoGrid component script -->
  27. <script>
  28. const DemoGrid = {
  29. template: '#grid-template',
  30. props: {
  31. data: Array,
  32. columns: Array,
  33. filterKey: String,
  34. },
  35. data() {
  36. return {
  37. sortKey: '',
  38. sortOrders: this.columns.reduce((o, key) => ((o[key] = 1), o), {}),
  39. }
  40. },
  41. computed: {
  42. filteredData() {
  43. const sortKey = this.sortKey
  44. const filterKey = this.filterKey && this.filterKey.toLowerCase()
  45. const order = this.sortOrders[sortKey] || 1
  46. let data = this.data
  47. if (filterKey) {
  48. data = data.filter(row => {
  49. return Object.keys(row).some(key => {
  50. return String(row[key]).toLowerCase().indexOf(filterKey) > -1
  51. })
  52. })
  53. }
  54. if (sortKey) {
  55. data = data.slice().sort((a, b) => {
  56. a = a[sortKey]
  57. b = b[sortKey]
  58. return (a === b ? 0 : a > b ? 1 : -1) * order
  59. })
  60. }
  61. return data
  62. },
  63. },
  64. methods: {
  65. sortBy(key) {
  66. this.sortKey = key
  67. this.sortOrders[key] = this.sortOrders[key] * -1
  68. },
  69. capitalize(str) {
  70. return str.charAt(0).toUpperCase() + str.slice(1)
  71. },
  72. },
  73. }
  74. </script>
  75. <!-- App template (in DOM) -->
  76. <div id="demo">
  77. <form id="search">Search <input name="query" v-model="searchQuery" /></form>
  78. <demo-grid :data="gridData" :columns="gridColumns" :filter-key="searchQuery">
  79. </demo-grid>
  80. </div>
  81. <!-- App script -->
  82. <script>
  83. Vue.createApp({
  84. components: {
  85. DemoGrid,
  86. },
  87. data: () => ({
  88. searchQuery: '',
  89. gridColumns: ['name', 'power'],
  90. gridData: [
  91. { name: 'Chuck Norris', power: Infinity },
  92. { name: 'Bruce Lee', power: 9000 },
  93. { name: 'Jackie Chan', power: 7000 },
  94. { name: 'Jet Li', power: 8000 },
  95. ],
  96. }),
  97. }).mount('#demo')
  98. </script>
  99. <style>
  100. body {
  101. font-family:
  102. Helvetica Neue,
  103. Arial,
  104. sans-serif;
  105. font-size: 14px;
  106. color: #444;
  107. }
  108. table {
  109. border: 2px solid #42b983;
  110. border-radius: 3px;
  111. background-color: #fff;
  112. }
  113. th {
  114. background-color: #42b983;
  115. color: rgba(255, 255, 255, 0.66);
  116. cursor: pointer;
  117. -webkit-user-select: none;
  118. -moz-user-select: none;
  119. -ms-user-select: none;
  120. user-select: none;
  121. }
  122. td {
  123. background-color: #f9f9f9;
  124. }
  125. th,
  126. td {
  127. min-width: 120px;
  128. padding: 10px 20px;
  129. }
  130. th.active {
  131. color: #fff;
  132. }
  133. th.active .arrow {
  134. opacity: 1;
  135. }
  136. .arrow {
  137. display: inline-block;
  138. vertical-align: middle;
  139. width: 0;
  140. height: 0;
  141. margin-left: 5px;
  142. opacity: 0.66;
  143. }
  144. .arrow.asc {
  145. border-left: 4px solid transparent;
  146. border-right: 4px solid transparent;
  147. border-bottom: 4px solid #fff;
  148. }
  149. .arrow.dsc {
  150. border-left: 4px solid transparent;
  151. border-right: 4px solid transparent;
  152. border-top: 4px solid #fff;
  153. }
  154. </style>