grid.html 3.4 KB

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