grid.html 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  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">
  78. Search <input name="query" v-model="searchQuery">
  79. </form>
  80. <demo-grid
  81. :data="gridData"
  82. :columns="gridColumns"
  83. :filter-key="searchQuery">
  84. </demo-grid>
  85. </div>
  86. <!-- App script -->
  87. <script>
  88. Vue.createApp({
  89. components: {
  90. DemoGrid
  91. },
  92. data: () => ({
  93. searchQuery: '',
  94. gridColumns: ['name', 'power'],
  95. gridData: [
  96. { name: 'Chuck Norris', power: Infinity },
  97. { name: 'Bruce Lee', power: 9000 },
  98. { name: 'Jackie Chan', power: 7000 },
  99. { name: 'Jet Li', power: 8000 }
  100. ]
  101. })
  102. }).mount('#demo')
  103. </script>
  104. <style>
  105. body {
  106. font-family: Helvetica Neue, Arial, sans-serif;
  107. font-size: 14px;
  108. color: #444;
  109. }
  110. table {
  111. border: 2px solid #42b983;
  112. border-radius: 3px;
  113. background-color: #fff;
  114. }
  115. th {
  116. background-color: #42b983;
  117. color: rgba(255,255,255,0.66);
  118. cursor: pointer;
  119. -webkit-user-select: none;
  120. -moz-user-select: none;
  121. -ms-user-select: none;
  122. user-select: none;
  123. }
  124. td {
  125. background-color: #f9f9f9;
  126. }
  127. th, td {
  128. min-width: 120px;
  129. padding: 10px 20px;
  130. }
  131. th.active {
  132. color: #fff;
  133. }
  134. th.active .arrow {
  135. opacity: 1;
  136. }
  137. .arrow {
  138. display: inline-block;
  139. vertical-align: middle;
  140. width: 0;
  141. height: 0;
  142. margin-left: 5px;
  143. opacity: 0.66;
  144. }
  145. .arrow.asc {
  146. border-left: 4px solid transparent;
  147. border-right: 4px solid transparent;
  148. border-bottom: 4px solid #fff;
  149. }
  150. .arrow.dsc {
  151. border-left: 4px solid transparent;
  152. border-right: 4px solid transparent;
  153. border-top: 4px solid #fff;
  154. }
  155. </style>